Panda3D
configVariableManager.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 configVariableManager.cxx
10  * @author drose
11  * @date 2004-10-15
12  */
13 
14 #include "configVariableManager.h"
15 #include "configVariableCore.h"
16 #include "configDeclaration.h"
17 #include "configPage.h"
18 #include "config_prc.h"
19 
20 using std::string;
21 
22 ConfigVariableManager *ConfigVariableManager::_global_ptr = nullptr;
23 
24 /**
25  * The constructor is private (actually, just protected, but only to avoid a
26  * gcc compiler warning) because it should not be explicitly constructed.
27  * There is only one ConfigVariableManager, and it constructs itself.
28  */
29 ConfigVariableManager::
30 ConfigVariableManager() {
32 }
33 
34 /**
35  * The ConfigVariableManager destructor should never be called, because this
36  * is a global object that is never freed.
37  */
38 ConfigVariableManager::
39 ~ConfigVariableManager() {
40  prc_cat->error()
41  << "Internal error--ConfigVariableManager destructor called!\n";
42 }
43 
44 /**
45  * Creates and returns a new, undefined ConfigVariableCore with the indicated
46  * name; or if a variable with this name has already been created, returns
47  * that one instead.
48  */
50 make_variable(const string &name) {
51  VariablesByName::iterator ni;
52  ni = _variables_by_name.find(name);
53  if (ni != _variables_by_name.end()) {
54  return (*ni).second;
55  }
56 
57  ConfigVariableCore *variable = nullptr;
58 
59  // See if there's a template that matches this name.
60  VariableTemplates::const_iterator ti;
61  for (ti = _variable_templates.begin();
62  ti != _variable_templates.end() && variable == nullptr;
63  ++ti) {
64  const GlobPattern &pattern = (*ti).first;
65  ConfigVariableCore *templ = (*ti).second;
66  if (pattern.matches(name)) {
67  variable = new ConfigVariableCore(*templ, name);
68  }
69  }
70 
71  if (variable == nullptr) {
72  variable = new ConfigVariableCore(name);
73  }
74 
75  _variables_by_name[name] = variable;
76  _variables.push_back(variable);
77 
78  return variable;
79 }
80 
81 /**
82  * Defines a variable "template" to match against dynamically-defined
83  * variables that may or may not be created in the future.
84  *
85  * The template consists of a glob pattern, e.g. "notify-level-*", which will
86  * be tested against any config variable passed to a future call to
87  * make_variable(). If the pattern matches, the returned ConfigVariableCore
88  * is copied to define the new variable, instead of creating a default, empty
89  * one.
90  *
91  * This is useful to pre-specify default values for a family of variables that
92  * all have similar properties, and all may not be created at the same time.
93  * It is especially useful to avoid cluttering up the list of available
94  * variables with user-declared variables that have not been defined yet by
95  * the application (e.g. "egg-object-type-*").
96  *
97  * This method basically pre-defines all variables that match the specified
98  * glob pattern.
99  */
101 make_variable_template(const string &pattern,
102  ConfigFlags::ValueType value_type,
103  const string &default_value,
104  const string &description, int flags) {
105  ConfigVariableCore *core;
106 
107  GlobPattern gp(pattern);
108  VariableTemplates::const_iterator ti = _variable_templates.find(gp);
109  if (ti != _variable_templates.end()) {
110  core = (*ti).second;
111 
112  } else {
113  core = new ConfigVariableCore(pattern);
114  _variable_templates[gp] = core;
115  }
116 
117  if (value_type != ConfigFlags::VT_undefined) {
118  core->set_value_type(value_type);
119  }
120  if (!default_value.empty() ||
121  core->get_default_value() == nullptr) {
122  core->set_default_value(default_value);
123  }
124  if (!description.empty()) {
125  core->set_description(description);
126  }
127  if (flags != 0) {
128  core->set_flags(flags);
129  }
130  core->set_used();
131 
132  // Also apply the same changes to any previously-defined variables that
133  // match the pattern.
134  Variables::iterator vi;
135  for (vi = _variables.begin(); vi != _variables.end(); ++vi) {
136  ConfigVariableCore *variable = (*vi);
137  if (gp.matches(variable->get_name())) {
138  if (value_type != ConfigFlags::VT_undefined) {
139  variable->set_value_type(value_type);
140  }
141  if (!default_value.empty() ||
142  variable->get_default_value() == nullptr) {
143  variable->set_default_value(default_value);
144  }
145  if (!description.empty()) {
146  variable->set_description(description);
147  }
148  if (flags != 0) {
149  variable->set_flags(flags);
150  }
151  variable->set_used();
152  }
153  }
154 
155  return core;
156 }
157 
158 /**
159  * Returns the name of the nth active ConfigVariable in the list.
160  */
162 get_variable_name(size_t n) const {
163  if (n < _variables.size()) {
164  return _variables[n]->get_name();
165  }
166  return string();
167 }
168 
169 /**
170  * Returns true if the nth active ConfigVariable in the list has been used by
171  * code, false otherwise.
172  */
174 is_variable_used(size_t n) const {
175  if (n < _variables.size()) {
176  return _variables[n]->is_used();
177  }
178  return false;
179 }
180 
181 /**
182  *
183  */
184 void ConfigVariableManager::
185 output(std::ostream &out) const {
186  out << "ConfigVariableManager, " << _variables.size() << " variables.";
187 }
188 
189 /**
190  *
191  */
192 void ConfigVariableManager::
193 write(std::ostream &out) const {
194  VariablesByName::const_iterator ni;
195  for (ni = _variables_by_name.begin();
196  ni != _variables_by_name.end();
197  ++ni) {
198  ConfigVariableCore *variable = (*ni).second;
199  if (variable->get_num_trusted_references() != 0 ||
200  variable->has_local_value()) {
201  list_variable(variable, false);
202  }
203  }
204 }
205 
206 /**
207  * Writes all of the prc-set config variables, as they appear in a prc file
208  * somewhere, one per line, very concisely. This lists the dominant value in
209  * the prc file; it does not list shadowed values, and it does not list
210  * locally-set values.
211  *
212  * This is mainly intended for generating a hash of the input config file
213  * state.
214  */
216 write_prc_variables(std::ostream &out) const {
217  VariablesByName::const_iterator ni;
218  for (ni = _variables_by_name.begin();
219  ni != _variables_by_name.end();
220  ++ni) {
221  ConfigVariableCore *variable = (*ni).second;
222  if (variable->get_num_trusted_references() != 0) {
223  if (variable->get_value_type() == ConfigVariableCore::VT_list ||
224  variable->get_value_type() == ConfigVariableCore::VT_search_path) {
225  // List all of the values for a "list" variable.
226  size_t num_references = variable->get_num_trusted_references();
227  for (size_t i = 0; i < num_references; ++i) {
228  out << variable->get_name() << " "
229  << variable->get_trusted_reference(i)->get_string_value()
230  << "\n";
231  }
232  } else {
233  // List just the one value for a non-list variable.
234  out << variable->get_name() << " "
235  << variable->get_trusted_reference(0)->get_string_value()
236  << "\n";
237  }
238  }
239  }
240 }
241 
242 /**
243  * Writes a list of all the variables that have been defined in a prc file
244  * without having been declared somewhere in code.
245  */
248  VariablesByName::const_iterator ni;
249  for (ni = _variables_by_name.begin();
250  ni != _variables_by_name.end();
251  ++ni) {
252  ConfigVariableCore *variable = (*ni).second;
253  if (!variable->is_used()) {
254  nout << variable->get_name() << "\n";
255  size_t num_references = variable->get_num_references();
256  for (size_t i = 0; i < num_references; i++) {
257  nout << " " << variable->get_reference(i)->get_page()->get_name()
258  << "\n";
259  }
260  }
261  }
262 }
263 
264 /**
265  * Writes a list of all the variables that have been declared somewhere in
266  * code, along with a brief description.
267  */
269 list_variables() const {
270  VariablesByName::const_iterator ni;
271  for (ni = _variables_by_name.begin();
272  ni != _variables_by_name.end();
273  ++ni) {
274  const ConfigVariableCore *variable = (*ni).second;
275  if (variable->is_used() && !variable->is_dynamic()) {
276  list_variable(variable, true);
277  }
278  }
279 }
280 
281 /**
282  * Writes a list of all the "dynamic" variables that have been declared
283  * somewhere in code, along with a brief description. This is a (usually
284  * large) list of config variables that are declared with a generated variable
285  * name.
286  */
289  VariablesByName::const_iterator ni;
290  for (ni = _variables_by_name.begin();
291  ni != _variables_by_name.end();
292  ++ni) {
293  const ConfigVariableCore *variable = (*ni).second;
294  if (variable->is_used() && variable->is_dynamic()) {
295  list_variable(variable, false);
296  }
297  }
298 }
299 
300 /**
301  *
302  */
303 ConfigVariableManager *ConfigVariableManager::
304 get_global_ptr() {
305  if (_global_ptr == nullptr) {
306  _global_ptr = new ConfigVariableManager;
307  }
308  return _global_ptr;
309 }
310 
311 /**
312  * Lists a single variable and its value.
313  */
314 void ConfigVariableManager::
315 list_variable(const ConfigVariableCore *variable,
316  bool include_descriptions) const {
317  if (!variable->is_used()) {
318  // If the variable is unused, just show its name.
319  nout << variable->get_name() << " not used";
320  if (variable->get_num_references() > 0) {
321  nout << " (referenced in "
322  << variable->get_reference(0)->get_page()->get_name()
323  << ")";
324  }
325  nout << "\n";
326 
327  } else {
328  // If the variable is used--it's been defined somewhere--show its name,
329  // its type, its current and default values, and if available, its
330  // description.
331 
332  nout << variable->get_name() << " "
333  << variable->get_value_type() << "\n";
334 
335  const ConfigDeclaration *decl;
336 
337  if (variable->get_value_type() == ConfigVariableCore::VT_list ||
338  variable->get_value_type() == ConfigVariableCore::VT_search_path) {
339  // We treat a "list" variable as a special case: list all of its values.
340  nout << " current value:\n";
341  size_t num_references = variable->get_num_trusted_references();
342  for (size_t i = 0; i < num_references; ++i) {
343  decl = variable->get_trusted_reference(i);
344  nout << " " << decl->get_string_value()
345  << " (from " << decl->get_page()->get_name() << ")\n";
346  }
347 
348  } else {
349  // An ordinary, non-list variable gets one line for its current value
350  // (if it has one) and another line for its default value.
351  decl = variable->get_declaration(0);
352  if (decl != variable->get_default_value()) {
353  nout << " current value = " << decl->get_string_value();
354  if (!decl->get_page()->is_special()) {
355  nout << " (from " << decl->get_page()->get_name() << ")\n";
356  } else {
357  nout << " (defined locally)\n";
358  }
359  }
360 
361  decl = variable->get_default_value();
362  if (decl != nullptr) {
363  nout << " default value = " << decl->get_string_value() << "\n";
364  }
365  }
366 
367  if (!variable->get_description().empty() && include_descriptions) {
368  nout << " " << variable->get_description() << "\n";
369  }
370  }
371 
372  nout << "\n";
373 }
const std::string & get_string_value() const
Returns the value assigned to this variable.
The internal definition of a ConfigVariable.
set_description
Specifies the one-line description of this variable.
std::string get_variable_name(size_t n) const
Returns the name of the nth active ConfigVariable in the list.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_num_references
Returns the number of prc files that reference this variable.
void list_dynamic_variables() const
Writes a list of all the "dynamic" variables that have been declared somewhere in code,...
get_page
Returns the page on which this declaration can be found.
void init_memory_hook()
Any code that might need to use PANDA_MALLOC or PANDA_FREE, or any methods of the global memory_hook ...
Definition: dtoolbase.cxx:38
get_default_value
Returns the default variable specified for this variable.
get_reference
Returns the nth declaration in a prc file that references this variable.
get_value_type
Returns the stated type of this variable.
ConfigVariableCore * make_variable(const std::string &name)
Creates and returns a new, undefined ConfigVariableCore with the indicated name; or if a variable wit...
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:122
bool has_local_value() const
Returns true if this variable's value has been shadowed by a local assignment (as created via make_lo...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A global object that maintains the set of ConfigVariables (actually, ConfigVariableCores) everywhere ...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
ConfigVariableCore * make_variable_template(const std::string &pattern, ConfigFlags::ValueType type, const std::string &default_value, const std::string &description=std::string(), int flags=0)
Defines a variable "template" to match against dynamically-defined variables that may or may not be c...
set_default_value
Specifies the default value for this variable if it is not defined in any prc file.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_description
Returns the brief description of this variable, if it has been defined.
is_used
Returns true if the variable has been referenced by a ConfigVariable somewhere in code,...
void set_used()
Marks that the variable has been "declared" by a ConfigVariable.
is_dynamic
Returns true if the variable was indicated as "dynamic" by its constructor, indicating that its name ...
get_num_trusted_references
Returns the number of trusted prc files that reference this variable.
void set_flags(int flags)
Specifies the trust level of this variable.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
get_name
Returns the name of the variable.
get_declaration
Returns the nth declarations that contributes to this variable's value.
bool is_variable_used(size_t n) const
Returns true if the nth active ConfigVariable in the list has been used by code, false otherwise.
void list_variables() const
Writes a list of all the variables that have been declared somewhere in code, along with a brief desc...
set_value_type
Specifies the type of this variable.
A single declaration of a config variable, typically defined as one line in a .prc file,...
void list_unused_variables() const
Writes a list of all the variables that have been defined in a prc file without having been declared ...
get_trusted_reference
Returns the nth declaration in a trusted prc file that references this variable.
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32
void write_prc_variables(std::ostream &out) const
Writes all of the prc-set config variables, as they appear in a prc file somewhere,...