Panda3D

configVariableManager.cxx

00001 // Filename: configVariableManager.cxx
00002 // Created by:  drose (15Oct04)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "configVariableManager.h"
00016 #include "configVariableCore.h"
00017 #include "configDeclaration.h"
00018 #include "configPage.h"
00019 #include "config_prc.h"
00020 
00021 ConfigVariableManager *ConfigVariableManager::_global_ptr = NULL;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: ConfigVariableManager::Constructor
00025 //       Access: Protected
00026 //  Description: The constructor is private (actually, just protected,
00027 //               but only to avoid a gcc compiler warning) because it
00028 //               should not be explicitly constructed.  There is only
00029 //               one ConfigVariableManager, and it constructs
00030 //               itself.
00031 ////////////////////////////////////////////////////////////////////
00032 ConfigVariableManager::
00033 ConfigVariableManager() {
00034   init_memory_hook();
00035 }
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: ConfigVariableManager::Destructor
00039 //       Access: Protected
00040 //  Description: The ConfigVariableManager destructor should never be
00041 //               called, because this is a global object that is never
00042 //               freed.
00043 ////////////////////////////////////////////////////////////////////
00044 ConfigVariableManager::
00045 ~ConfigVariableManager() {
00046   prc_cat->error()
00047     << "Internal error--ConfigVariableManager destructor called!\n";
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: ConfigVariableManager::make_variable
00052 //       Access: Published
00053 //  Description: Creates and returns a new, undefined
00054 //               ConfigVariableCore with the indicated name; or if a
00055 //               variable with this name has already been created,
00056 //               returns that one instead.
00057 ////////////////////////////////////////////////////////////////////
00058 ConfigVariableCore *ConfigVariableManager::
00059 make_variable(const string &name) {
00060   VariablesByName::iterator ni;
00061   ni = _variables_by_name.find(name);
00062   if (ni != _variables_by_name.end()) {
00063     return (*ni).second;
00064   }
00065 
00066   ConfigVariableCore *variable = NULL;
00067 
00068   // See if there's a template that matches this name.
00069   VariableTemplates::const_iterator ti;
00070   for (ti = _variable_templates.begin();
00071        ti != _variable_templates.end() && variable == (ConfigVariableCore *)NULL;
00072        ++ti) {
00073     const GlobPattern &pattern = (*ti).first;
00074     ConfigVariableCore *templ = (*ti).second;
00075     if (pattern.matches(name)) {
00076       variable = new ConfigVariableCore(*templ, name);
00077     }
00078   }
00079 
00080   if (variable == (ConfigVariableCore *)NULL) {
00081     variable = new ConfigVariableCore(name);
00082   }
00083 
00084   _variables_by_name[name] = variable;
00085   _variables.push_back(variable);
00086 
00087   return variable;
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: ConfigVariableManager::make_variable_template
00092 //       Access: Published
00093 //  Description: Defines a variable "template" to match against
00094 //               dynamically-defined variables that may or may not be
00095 //               created in the future.
00096 //
00097 //               The template consists of a glob pattern,
00098 //               e.g. "notify-level-*", which will be tested against
00099 //               any config variable passed to a future call to
00100 //               make_variable().  If the pattern matches, the
00101 //               returned ConfigVariableCore is copied to define the
00102 //               new variable, instead of creating a default, empty
00103 //               one.
00104 //
00105 //               This is useful to pre-specify default values for a
00106 //               family of variables that all have similar properties,
00107 //               and all may not be created at the same time.  It is
00108 //               especially useful to avoid cluttering up the list of
00109 //               available variables with user-declared variables that
00110 //               have not been defined yet by the application
00111 //               (e.g. "egg-object-type-*").
00112 //
00113 //               This method basically pre-defines all variables that
00114 //               match the specified glob pattern.
00115 ////////////////////////////////////////////////////////////////////
00116 ConfigVariableCore *ConfigVariableManager::
00117 make_variable_template(const string &pattern, 
00118                        ConfigFlags::ValueType value_type,
00119                        const string &default_value,
00120                        const string &description, int flags) {
00121   ConfigVariableCore *core;
00122 
00123   GlobPattern gp(pattern);
00124   VariableTemplates::const_iterator ti = _variable_templates.find(gp);
00125   if (ti != _variable_templates.end()) {
00126     core = (*ti).second;
00127 
00128   } else {
00129     core = new ConfigVariableCore(pattern);
00130     _variable_templates[gp] = core;
00131   }
00132 
00133   if (value_type != ConfigFlags::VT_undefined) {
00134     core->set_value_type(value_type);
00135   }
00136   if (!default_value.empty() || 
00137       core->get_default_value() == (ConfigDeclaration *)NULL) {
00138     core->set_default_value(default_value);
00139   }
00140   if (!description.empty()) {
00141     core->set_description(description);
00142   }
00143   if (flags != 0) {
00144     core->set_flags(flags);
00145   }
00146   core->set_used();
00147 
00148   // Also apply the same changes to any previously-defined variables
00149   // that match the pattern.
00150   Variables::iterator vi;
00151   for (vi = _variables.begin(); vi != _variables.end(); ++vi) {
00152     ConfigVariableCore *variable = (*vi);
00153     if (gp.matches(variable->get_name())) {
00154       if (value_type != ConfigFlags::VT_undefined) {
00155         variable->set_value_type(value_type);
00156       }
00157       if (!default_value.empty() || 
00158           variable->get_default_value() == (ConfigDeclaration *)NULL) {
00159         variable->set_default_value(default_value);
00160       }
00161       if (!description.empty()) {
00162         variable->set_description(description);
00163       }
00164       if (flags != 0) {
00165         variable->set_flags(flags);
00166       }
00167       variable->set_used();
00168     }
00169   }
00170 
00171   return core;
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: ConfigVariableManager::get_variable_name
00176 //       Access: Published
00177 //  Description: Returns the name of the nth active ConfigVariable in
00178 //               the list.
00179 ////////////////////////////////////////////////////////////////////
00180 string ConfigVariableManager::
00181 get_variable_name(int n) const {
00182   if (n >= 0 && n < (int)_variables.size()) {
00183     return _variables[n]->get_name();
00184   }
00185   return string();
00186 }
00187 
00188 ////////////////////////////////////////////////////////////////////
00189 //     Function: ConfigVariableManager::is_variable_used
00190 //       Access: Published
00191 //  Description: Returns true if the nth active ConfigVariable in
00192 //               the list has been used by code, false otherwise.
00193 ////////////////////////////////////////////////////////////////////
00194 bool ConfigVariableManager::
00195 is_variable_used(int n) const {
00196   if (n >= 0 && n < (int)_variables.size()) {
00197     return _variables[n]->is_used();
00198   }
00199   return false;
00200 }
00201 
00202 ////////////////////////////////////////////////////////////////////
00203 //     Function: ConfigVariableManager::output
00204 //       Access: Published
00205 //  Description: 
00206 ////////////////////////////////////////////////////////////////////
00207 void ConfigVariableManager::
00208 output(ostream &out) const {
00209   out << "ConfigVariableManager, " << _variables.size() << " variables.";
00210 }
00211 
00212 ////////////////////////////////////////////////////////////////////
00213 //     Function: ConfigVariableManager::write
00214 //       Access: Published
00215 //  Description: 
00216 ////////////////////////////////////////////////////////////////////
00217 void ConfigVariableManager::
00218 write(ostream &out) const {
00219   VariablesByName::const_iterator ni;
00220   for (ni = _variables_by_name.begin();
00221        ni != _variables_by_name.end();
00222        ++ni) {
00223     ConfigVariableCore *variable = (*ni).second;
00224     if (variable->get_num_trusted_references() != 0 ||
00225         variable->has_local_value()) {
00226       list_variable(variable, false);
00227     }
00228   }
00229 }
00230 
00231 ////////////////////////////////////////////////////////////////////
00232 //     Function: ConfigVariableManager::write_prc_variables
00233 //       Access: Published
00234 //  Description: Writes all of the prc-set config variables, as they
00235 //               appear in a prc file somewhere, one per line, very
00236 //               concisely.  This lists the dominant value in the prc
00237 //               file; it does not list shadowed values, and it does
00238 //               not list locally-set values.
00239 //
00240 //               This is mainly intended for generating a hash of the
00241 //               input config file state.
00242 ////////////////////////////////////////////////////////////////////
00243 void ConfigVariableManager::
00244 write_prc_variables(ostream &out) const {
00245   VariablesByName::const_iterator ni;
00246   for (ni = _variables_by_name.begin();
00247        ni != _variables_by_name.end();
00248        ++ni) {
00249     ConfigVariableCore *variable = (*ni).second;
00250     if (variable->get_num_trusted_references() != 0) {
00251       if (variable->get_value_type() == ConfigVariableCore::VT_list ||
00252           variable->get_value_type() == ConfigVariableCore::VT_search_path) {
00253         // List all of the values for a "list" variable.
00254         int num_references = variable->get_num_trusted_references();
00255         for (int i = 0; i < num_references; i++) {
00256           out << variable->get_name() << " " 
00257               << variable->get_trusted_reference(i)->get_string_value()
00258               << "\n";
00259         }
00260       } else {
00261         // List just the one value for a non-list variable.
00262         out << variable->get_name() << " " 
00263             << variable->get_trusted_reference(0)->get_string_value()
00264             << "\n";
00265       }
00266     }
00267   }
00268 }
00269   
00270 ////////////////////////////////////////////////////////////////////
00271 //     Function: ConfigVariableManager::list_unused_variables
00272 //       Access: Published
00273 //  Description: Writes a list of all the variables that have been
00274 //               defined in a prc file without having been declared
00275 //               somewhere in code.
00276 ////////////////////////////////////////////////////////////////////
00277 void ConfigVariableManager::
00278 list_unused_variables() const {
00279   VariablesByName::const_iterator ni;
00280   for (ni = _variables_by_name.begin();
00281        ni != _variables_by_name.end();
00282        ++ni) {
00283     ConfigVariableCore *variable = (*ni).second;
00284     if (!variable->is_used()) {
00285       nout << variable->get_name() << "\n";
00286       int num_references = variable->get_num_references();
00287       for (int i = 0; i < num_references; i++) {
00288         nout << "  " << variable->get_reference(i)->get_page()->get_name()
00289              << "\n";
00290       }
00291     }
00292   }
00293 }
00294 
00295 ////////////////////////////////////////////////////////////////////
00296 //     Function: ConfigVariableManager::list_variables
00297 //       Access: Published
00298 //  Description: Writes a list of all the variables that have been
00299 //               declared somewhere in code, along with a brief
00300 //               description.
00301 ////////////////////////////////////////////////////////////////////
00302 void ConfigVariableManager::
00303 list_variables() const {
00304   VariablesByName::const_iterator ni;
00305   for (ni = _variables_by_name.begin();
00306        ni != _variables_by_name.end();
00307        ++ni) {
00308     const ConfigVariableCore *variable = (*ni).second;
00309     if (variable->is_used() && !variable->is_dynamic()) {
00310       list_variable(variable, true);
00311     }
00312   }
00313 }
00314 
00315 ////////////////////////////////////////////////////////////////////
00316 //     Function: ConfigVariableManager::list_dynamic_variables
00317 //       Access: Published
00318 //  Description: Writes a list of all the "dynamic" variables that
00319 //               have been declared somewhere in code, along with a
00320 //               brief description.  This is a (usually large) list of
00321 //               config variables that are declared with a generated
00322 //               variable name.
00323 ////////////////////////////////////////////////////////////////////
00324 void ConfigVariableManager::
00325 list_dynamic_variables() const {
00326   VariablesByName::const_iterator ni;
00327   for (ni = _variables_by_name.begin();
00328        ni != _variables_by_name.end();
00329        ++ni) {
00330     const ConfigVariableCore *variable = (*ni).second;
00331     if (variable->is_used() && variable->is_dynamic()) {
00332       list_variable(variable, false);
00333     }
00334   }
00335 }
00336 
00337 ////////////////////////////////////////////////////////////////////
00338 //     Function: ConfigVariableManager::get_global_ptr
00339 //       Access: Published
00340 //  Description: 
00341 ////////////////////////////////////////////////////////////////////
00342 ConfigVariableManager *ConfigVariableManager::
00343 get_global_ptr() {
00344   if (_global_ptr == (ConfigVariableManager *)NULL) {
00345     _global_ptr = new ConfigVariableManager;
00346   }
00347   return _global_ptr;
00348 }
00349 
00350 ////////////////////////////////////////////////////////////////////
00351 //     Function: ConfigVariableManager::list_variable
00352 //       Access: Private
00353 //  Description: Lists a single variable and its value.
00354 ////////////////////////////////////////////////////////////////////
00355 void ConfigVariableManager::
00356 list_variable(const ConfigVariableCore *variable, 
00357               bool include_descriptions) const {
00358   if (!variable->is_used()) {
00359     // If the variable is unused, just show its name.
00360     nout << variable->get_name() << "  not used";
00361     if (variable->get_num_references() > 0) {
00362       nout << " (referenced in " 
00363            << variable->get_reference(0)->get_page()->get_name()
00364            << ")";
00365     }
00366     nout << "\n";
00367   
00368   } else {
00369     // If the variable is used--it's been defined somewhere--show its
00370     // name, its type, its current and default values, and if
00371     // available, its description.
00372 
00373     nout << variable->get_name() << " " 
00374          << variable->get_value_type() << "\n";
00375     
00376     const ConfigDeclaration *decl;
00377     
00378     if (variable->get_value_type() == ConfigVariableCore::VT_list ||
00379         variable->get_value_type() == ConfigVariableCore::VT_search_path) {
00380       // We treat a "list" variable as a special case: list all of
00381       // its values.
00382       nout << "  current value:\n";
00383       int num_references = variable->get_num_trusted_references();
00384       for (int i = 0; i < num_references; i++) {
00385         decl = variable->get_trusted_reference(i);
00386         nout << "    " << decl->get_string_value()
00387              << "  (from " << decl->get_page()->get_name() << ")\n";
00388       }
00389       
00390     } else {
00391       // An ordinary, non-list variable gets one line for its
00392       // current value (if it has one) and another line for its
00393       // default value.
00394       decl = variable->get_declaration(0);
00395       if (decl != variable->get_default_value()) {
00396         nout << "  current value = " << decl->get_string_value();
00397         if (!decl->get_page()->is_special()) {
00398           nout << "  (from " << decl->get_page()->get_name() << ")\n";
00399         } else {
00400           nout << "  (defined locally)\n";
00401         }
00402       }
00403       
00404       decl = variable->get_default_value();
00405       if (decl != (ConfigDeclaration *)NULL) {
00406         nout << "  default value = " << decl->get_string_value() << "\n";
00407       }
00408     }
00409     
00410     if (!variable->get_description().empty() && include_descriptions) {
00411       nout << "  " << variable->get_description() << "\n";
00412     }
00413   }
00414 
00415   nout << "\n";
00416 }
 All Classes Functions Variables Enumerations