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  */
247 list_unused_variables() const {
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  */
288 list_dynamic_variables() const {
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 }
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.
The internal definition of a ConfigVariable.
void set_flags(int flags)
Specifies the trust level of this variable.
get_trusted_reference
Returns the nth declaration in a trusted prc file that references 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_num_trusted_references
Returns the number of trusted prc files that reference this variable.
get_declaration
Returns the nth declarations that contributes to this variable's value.
get_value_type
Returns the stated type of this variable.
set_default_value
Specifies the default value for this variable if it is not defined in any prc file.
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.
is_dynamic
Returns true if the variable was indicated as "dynamic" by its constructor, indicating that its name ...
void set_used()
Marks that the variable has been "declared" by a ConfigVariable.
set_description
Specifies the one-line description of this variable.
get_num_references
Returns the number of prc files that reference this variable.
get_description
Returns the brief description of this variable, if it has been defined.
get_name
Returns the name of the variable.
set_value_type
Specifies the type of this variable.
is_used
Returns true if the variable has been referenced by a ConfigVariable somewhere in code,...
A global object that maintains the set of ConfigVariables (actually, ConfigVariableCores) everywhere ...
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_unused_variables() const
Writes a list of all the variables that have been defined in a prc file without having been declared ...
std::string get_variable_name(size_t n) const
Returns the name of the nth active ConfigVariable in the list.
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...
void write_prc_variables(std::ostream &out) const
Writes all of the prc-set config variables, as they appear in a prc file somewhere,...
void list_variables() const
Writes a list of all the variables that have been declared somewhere in code, along with a brief desc...
void list_dynamic_variables() const
Writes a list of all the "dynamic" variables that have been declared somewhere in code,...
ConfigVariableCore * make_variable(const std::string &name)
Creates and returns a new, undefined ConfigVariableCore with the indicated name; or if a variable wit...
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32
bool matches(const std::string &candidate) const
Returns true if the candidate string matches the pattern, false otherwise.
Definition: globPattern.I:122
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.
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