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