Browse Source

refinements to prc system

David Rose 21 years ago
parent
commit
fa32be5de4
63 changed files with 1557 additions and 1729 deletions
  1. 2 0
      direct/src/showbase/ShowBase.py
  2. 3 9
      dtool/src/dconfig/Sources.pp
  3. 0 57
      dtool/src/dconfig/configTable.I
  4. 0 798
      dtool/src/dconfig/configTable.cxx
  5. 0 71
      dtool/src/dconfig/configTable.h
  6. 3 41
      dtool/src/dconfig/dconfig.h
  7. 0 87
      dtool/src/dconfig/test_serialization.cxx
  8. 4 11
      dtool/src/interrogatedb/config_interrogatedb.cxx
  9. 2 2
      dtool/src/interrogatedb/config_interrogatedb.h
  10. 1 1
      dtool/src/interrogatedb/interrogateDatabase.cxx
  11. 9 1
      dtool/src/interrogatedb/interrogate_interface.cxx
  12. 1 0
      dtool/src/interrogatedb/interrogate_interface.h
  13. 8 0
      dtool/src/prc/Sources.pp
  14. 18 0
      dtool/src/prc/configFlags.I
  15. 54 0
      dtool/src/prc/configFlags.cxx
  16. 62 0
      dtool/src/prc/configFlags.h
  17. 5 0
      dtool/src/prc/configPage.cxx
  18. 10 2
      dtool/src/prc/configPageManager.cxx
  19. 20 122
      dtool/src/prc/configVariable.I
  20. 0 24
      dtool/src/prc/configVariable.cxx
  21. 8 27
      dtool/src/prc/configVariable.h
  22. 207 0
      dtool/src/prc/configVariableBase.I
  23. 40 0
      dtool/src/prc/configVariableBase.cxx
  24. 73 0
      dtool/src/prc/configVariableBase.h
  25. 4 5
      dtool/src/prc/configVariableBool.I
  26. 2 3
      dtool/src/prc/configVariableBool.h
  27. 75 30
      dtool/src/prc/configVariableCore.I
  28. 47 58
      dtool/src/prc/configVariableCore.cxx
  29. 12 17
      dtool/src/prc/configVariableCore.h
  30. 1 1
      dtool/src/prc/configVariableDouble.I
  31. 3 4
      dtool/src/prc/configVariableDouble.cxx
  32. 2 3
      dtool/src/prc/configVariableDouble.h
  33. 188 0
      dtool/src/prc/configVariableEnum.I
  34. 19 0
      dtool/src/prc/configVariableEnum.cxx
  35. 79 0
      dtool/src/prc/configVariableEnum.h
  36. 1 1
      dtool/src/prc/configVariableInt.I
  37. 3 4
      dtool/src/prc/configVariableInt.cxx
  38. 2 3
      dtool/src/prc/configVariableInt.h
  39. 0 90
      dtool/src/prc/configVariableList.I
  40. 2 14
      dtool/src/prc/configVariableList.cxx
  41. 4 24
      dtool/src/prc/configVariableList.h
  42. 72 70
      dtool/src/prc/configVariableManager.cxx
  43. 3 1
      dtool/src/prc/configVariableManager.h
  44. 214 0
      dtool/src/prc/configVariableSearchPath.I
  45. 74 0
      dtool/src/prc/configVariableSearchPath.cxx
  46. 90 0
      dtool/src/prc/configVariableSearchPath.h
  47. 18 6
      dtool/src/prc/configVariableString.I
  48. 4 3
      dtool/src/prc/configVariableString.h
  49. 0 41
      dtool/src/prc/configVariableTempl.h
  50. 2 1
      dtool/src/prc/notify.cxx
  51. 2 1
      dtool/src/prc/notify.h
  52. 1 11
      dtool/src/prc/notifyCategory.I
  53. 41 35
      dtool/src/prc/notifyCategory.cxx
  54. 7 5
      dtool/src/prc/notifyCategory.h
  55. 5 7
      dtool/src/prc/prcKeyRegistry.cxx
  56. 1 1
      dtool/src/prc/prcKeyRegistry.h
  57. 2 0
      dtool/src/pystub/pystub.cxx
  58. 9 3
      dtool/src/test_interrogate/test_interrogate.cxx
  59. 2 0
      panda/src/express/config_express.N
  60. 2 0
      panda/src/express/config_express.h
  61. 28 33
      panda/src/pstatclient/pStatProperties.cxx
  62. 5 1
      panda/src/putil/Sources.pp
  63. 1 0
      panda/src/putil/putil_composite1.cxx

+ 2 - 0
direct/src/showbase/ShowBase.py

@@ -262,6 +262,8 @@ class ShowBase(DirectObject.DirectObject):
         __builtins__["directNotify"] = directNotify
         __builtins__["globalClock"] = ClockObject.getGlobalClock()
         __builtins__["vfs"] = vfs
+        __builtins__["cpMgr"] = ConfigPageManager.getGlobalPtr()
+        __builtins__["cvMgr"] = ConfigVariableManager.getGlobalPtr()
         __builtins__["__dev__"] = base.config.GetBool('want-dev', 0)
         if __debug__:
             __builtins__["deltaProfiler"] = DeltaProfiler.DeltaProfiler("ShowBase")

+ 3 - 9
dtool/src/dconfig/Sources.pp

@@ -9,7 +9,7 @@
     configTable.I configTable.h \
     config_dconfig.h config_setup.h \
     dconfig.I dconfig.h \
-    serialization.I serialization.h  \
+    serialization.I serialization.h \
     symbolEnt.I  symbolEnt.h
     
  #define INCLUDED_SOURCES \
@@ -19,8 +19,8 @@
   #define INSTALL_HEADERS                                               \
     configTable.I configTable.h config_dconfig.h config_setup.h         \
     dconfig.I dconfig.h \
-    serialization.I serialization.h symbolEnt.I        \
-    symbolEnt.h
+    serialization.I serialization.h \
+    symbolEnt.I symbolEnt.h
 
 #end lib_target
 
@@ -47,9 +47,3 @@
   #define SOURCES test_searchpath.cxx
   #define LOCAL_LIBS dconfig $[LOCAL_LIBS]
 #end test_bin_target
-
-#begin test_bin_target
-  #define TARGET test_serialization
-  #define SOURCES test_serialization.cxx
-  #define LOCAL_LIBS dconfig $[LOCAL_LIBS]
-#end test_bin_target

+ 0 - 57
dtool/src/dconfig/configTable.I

@@ -15,60 +15,3 @@
 // [email protected] .
 //
 ////////////////////////////////////////////////////////////////////
-
-
-INLINE void ConfigTable::ConfigDbgDefault() {
-  // this should not be called if  CONFIG_CONFIG=:configdbg=1 
-  configdbg = false;
-  microconfig_cat->set_severity(NS_info);
-  dconfig_cat->set_severity(NS_info);
-}
-
-INLINE void ConfigTable::ConfigExeDefault() {
-  configexe = false;
-}
-
-INLINE void ConfigTable::ReadArgsDefault() {
-  readargs = true;
-}
-
-INLINE void ConfigTable::ReadEnvsDefault() {
-  readenvs = true;
-}
-
-INLINE void ConfigTable::PathSepDefault() {
-  pathsep = ": ";
-}
-
-INLINE void ConfigTable::FileSepDefault() {
-  filesep = "/";
-}
-
-INLINE void ConfigTable::ConfigNameDefault() {
-  configname.push_back(GlobPattern("Configrc"));
-  configname.push_back(GlobPattern("*.prc"));
-}
-
-INLINE void ConfigTable::ConfigArgsDefault() {
-  configargs = "";
-}
-
-INLINE void ConfigTable::ConfigPathDefault() {
-  configpath = "";
-}
-
-INLINE void ConfigTable::ConfigCmtDefault() {
-  configcmt = "#";
-}
-
-INLINE void ConfigTable::ArgSuffixDefault() {
-  argsuffix = "_ARGS";
-}
-
-INLINE void ConfigTable::CommandStubDefault() {
-  commandstub = "CONFIG";
-}
-
-INLINE ConfigString ConfigTable::GetConfigPath() const {
-  return configpath;
-}

+ 0 - 798
dtool/src/dconfig/configTable.cxx

@@ -16,802 +16,4 @@
 //
 ////////////////////////////////////////////////////////////////////
 
-#include "dconfig.h"
 #include "configTable.h"
-#include "dSearchPath.h"
-#include "executionEnvironment.h"
-#include "config_dconfig.h"
-#include "pfstream.h"
-#include "serialization.h"
-
-#ifdef PENV_PS2
-
-#include <string.h>
-#include <sifdev.h>
-#include <eekernel.h>
-
-#endif // PENV_PS2
-
-//#define DISABLE_CONFIG
-
-using namespace Config;
-
-ConfigTable* ConfigTable::_instance = (ConfigTable*)0L;
-
-void ConfigTable::CropString(ConfigString& S) {
-  size_t i = S.find_first_not_of(" \t\r\f\n");
-  if (i != ConfigString::npos) {
-    size_t j = S.find_last_not_of(" \t\r\f\n");
-    if (j != ConfigString::npos)
-      S = S.substr(i, j-i+1);
-    else
-      S = S.substr(i, ConfigString::npos);
-  } else
-    S.erase(0, ConfigString::npos);
-}
-
-void ConfigTable::DeComment(ConfigString& S) {
-  // If the comment delimiter appears in the line followed by
-  // whitespace, strip that part of the line out.
-
-  size_t i = S.find(configcmt);
-  while (i != ConfigString::npos) {
-    if (i + configcmt.length() < S.length() && 
-        isspace(S[i + configcmt.length()])) {
-      // Here's a comment.
-      S.erase(i, ConfigString::npos);
-      return;
-    }
-
-    i = S.find(configcmt, i + 1);
-  }
-}
-
-bool ConfigTable::IsComment(const ConfigString& S) {
-  // Returns true if the line begins with the comment delimiter,
-  // whether or not the delimiter is followed by whitespace.
-  return (S.substr(0, configcmt.length()) == configcmt);
-}
-
-void ConfigTable::UpCase(ConfigString& S) {
-   for (ConfigString::iterator i=S.begin(); i!=S.end(); ++i)
-      (*i) = toupper(*i);
-}
-
-ConfigString ConfigTable::NextWord(const ConfigString& S) {
-  int i(S.find_first_of(" \t\r\f\n"));
-  return S.substr(0, i);
-}
-
-ConfigString ConfigTable::PopNextWord(ConfigString& S) {
-  int i(S.find_first_of(" \t\r\f\n"));
-  ConfigString ret(S.substr(0, i));
-  S.erase(0, i);
-  CropString(S);
-  return ret;
-}
-
-void ConfigTable::ParseConfigFile(istream& is, const ConfigString& Filename) {
-   ConfigString line;
-
-   while (!is.eof() && !is.fail()) {
-      std::getline(is, line);
-      if (microconfig_cat->is_spam())
-         microconfig_cat->spam() << "read from " << Filename << ": '" << line
-                                 << "'" << endl;
-      DeComment(line);
-      CropString(line);
-      if (microconfig_cat->is_spam())
-         microconfig_cat->spam() << "cropped line to: '" << line << "'"
-                                 << endl;
-      if (!IsComment(line)) {
-         ConfigString protosym(PopNextWord(line));
-         if (microconfig_cat->is_spam())
-            microconfig_cat->spam() << "protosym is '" << protosym
-                                    << "' with value of '" << line << "'"
-                                    << endl;
-         size_t i(protosym.find("."));
-         if (i == ConfigString::npos) {
-            if (microconfig_cat->is_spam())
-               microconfig_cat->spam() << "this is an unqualified symbol"
-                                       << endl;
-            unqualified[protosym].push_back(SymEnt(SymEnt::ConfigFile, line, Filename));
-         } else {
-           ConfigString scope(protosym.substr(0, i));
-           ConfigString sym(protosym.substr(i+1, ConfigString::npos));
-           if (microconfig_cat->is_spam())
-             microconfig_cat->spam() << "this is a qualified symbol."
-                                     << " scope '" << scope
-                                     << "', symbol '" << sym << "'" << endl;
-           (qualified[scope])[sym].push_back(SymEnt(SymEnt::ConfigFile, line, Filename));
-         }
-      } else if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "line is detected as a comment" << endl;
-   }
-}
-
-void ConfigTable::ReadConfigFile() {
-  // The configpath variable lists the environment variables that
-  // themselves should be considered to contain search paths for
-  // Configrc files.  This is one level of indirection from the
-  // intuitive definition.
-
-  DSearchPath config_search;
-
-  // The configdir variable gets priority--it names a directory that
-  // ends up first on the search path.
-  if (!configdir.empty()) {
-    config_search.append_directory(Filename::from_os_specific(configdir));
-  }
-
-  // Then all of the directories named (indirectly) by configpath.
-  // This variable actually names a space-delimited list of
-  // environment variable names, each of which contains a space- or
-  // colon-delimited search path.
-  while (!configpath.empty()) {
-    int i = configpath.find_first_of(" ");
-    ConfigString stmp = configpath.substr(0, i);
-    if (ExecutionEnvironment::has_environment_variable(stmp)) {
-      string path = ExecutionEnvironment::get_environment_variable(stmp);
-
-      size_t p = 0;
-      while (p < path.length()) {
-        size_t q = path.find_first_of(pathsep, p);
-        if (q == string::npos) {
-          config_search.append_directory(Filename::from_os_specific(path.substr(p)));
-          break;
-        }
-        if (q != p) {
-          config_search.append_directory(Filename::from_os_specific(path.substr(p, q - p)));
-        }
-        p = q + 1;
-      }
-    }
-    configpath.erase(0, i);
-    CropString(configpath);
-  }
-
-  if (microconfig_cat->is_spam()) {
-    microconfig_cat->spam()
-      << "search path from configdir and configpath is: " 
-      << config_search << endl;
-  }
-
-  DSearchPath::Results config_files;
-
-  if (microconfig_cat->is_spam()) {
-    microconfig_cat->spam() << "searching for files matching:\n";
-    for (Globs::const_iterator gi = configname.begin();
-         gi != configname.end();
-         ++gi) {
-      microconfig_cat->spam() << "  " << (*gi) << endl;
-    }
-  }
-
-  for (int di = 0; di < config_search.get_num_directories(); di++) {
-    const Filename &directory = config_search.get_directory(di);
-    if (directory.is_directory()) {
-      vector_string files;
-      directory.scan_directory(files);
-      // Scan the files into reverse alphabetical order, to re-invert
-      // the native Config sorting, so that the alphabetically last
-      // file has precedence.
-      for (vector_string::reverse_iterator fi = files.rbegin();
-           fi != files.rend();
-           ++fi) {
-        bool matches = false;
-        for (Globs::const_iterator gi = configname.begin();
-             gi != configname.end() && !matches;
-             ++gi) {
-          matches = (*gi).matches(*fi);
-        }
-        if (matches) {
-          Filename file(directory, (*fi));
-          config_files.add_file(file);
-        }
-      }
-    }
-  }
-
-  if (microconfig_cat->is_spam())
-    microconfig_cat->spam() << "found " << config_files.get_num_files()
-                            << " files" << endl;
-
-  int num_config_files = config_files.get_num_files();
-  for (int i = num_config_files - 1; i >= 0; i--) {
-    Filename config_file = config_files.get_file(i);
-
-    if (microconfig_cat->is_spam())
-      microconfig_cat->spam() << "examining file '" << config_file << "'"
-                               << endl;
-
-    if (!config_file.is_regular_file()) {
-      if (microconfig_cat->is_spam()) {
-        microconfig_cat->spam()
-          << "file is not a regular file, ignoring.\n";
-      }
-
-    } else if (configexe && config_file.is_executable()) {
-      ConfigString line = config_file.to_os_specific() + " " + configargs;
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "file is executable, running '"
-                                 << line << "'" << endl;
-      IPipeStream ifs(line);
-      ParseConfigFile(ifs, config_file);
-    } else {
-      #if 0
-        microconfig_cat->info() << "Reading .prc file '" << config_file << "'"<< endl;
-      #endif
-
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam()
-          << "file is not executable, reading normally" << endl;
-
-#ifdef PENV_PS2
-      ConfigString line = PS2_FILE_PREFIX + convert_pathname(config_file);
-
-      int fd = sceOpen((char *) line.c_str(), SCE_RDONLY);
-      char line_buffer[2048];
-
-      memset(line_buffer, 0, 2048);
-
-      ConfigString file_buffer;
-
-      while (sceRead(fd, line_buffer, 2048) > 0)
-      {
-        file_buffer += line_buffer;
-        memset(line_buffer, 0, 2048);
-      }
-
-      sceClose(fd);
-
-      istrstream ifs(file_buffer.c_str());
-#else
-      ifstream ifs(config_file.to_os_specific().c_str());
-#endif
-      ParseConfigFile(ifs, config_file);
-    }
-  }
-}
-
-void ConfigTable::ParseCommandEnv(ConfigString& S, const ConfigString& sym)
-{
-   if (microconfig_cat->is_spam())
-      microconfig_cat->spam() << "value of '" << sym << "' is '" << S << "'"
-                               << endl;
-   while (!S.empty()) {
-      ConfigString protosym(PopNextWord(S));
-      bool ok = false;
-      bool state = false;
-      if (protosym[0] == '-')
-         ok = true;
-      else if (protosym[0] == '+') {
-         ok = true;
-         state = true;
-      }
-      if (ok) {
-         protosym.erase(0, 1);
-         CropString(protosym);
-         size_t i(protosym.find("."));
-         if (i == ConfigString::npos) {
-            unqualified[protosym].push_back(SymEnt(SymEnt::CommandEnv,
-                                                   NextWord(S), sym, state));
-            if (microconfig_cat->is_spam())
-               microconfig_cat->spam() << "unqualified symbol '" << protosym
-                                       << "' with value '" << NextWord(S)
-                                       << "'" << endl;
-         } else {
-            ConfigString scope(protosym.substr(0, i));
-            ConfigString sym(protosym.substr(i+1, ConfigString::npos));
-            (qualified[scope])[sym].push_back(SymEnt(SymEnt::CommandEnv,
-                                                     NextWord(S), sym, state));
-            if (microconfig_cat->is_spam())
-               microconfig_cat->spam() << "qualified symbol '" << sym
-                                       << "' in scope '" << scope
-                                       << "' and value '" << NextWord(S)
-                                       << "'" << endl;
-         }
-      } else if (microconfig_cat->is_spam())
-         microconfig_cat->spam() << "'" << protosym
-                                 << "' was not recognized as an option"
-                                 << endl;
-   }
-}
-
-void ConfigTable::ParseArgs() {
-   int n = 0;
-   int num_args = ExecutionEnvironment::get_num_args();
-
-   while ( n < num_args) {
-     bool ok = false;
-     bool state = false;
-     ConfigString line(ExecutionEnvironment::get_arg(n));
-     CropString(line);
-     if (line[0] == '-')
-       ok = true;
-     else if (line[0] == '+') {
-       ok = true;
-       state = true;
-     }
-     if (ok) {
-       line.erase(0, 1);
-       CropString(line);
-       size_t i(line.find("."));
-       ConfigString aparam;
-       if (n + 1 < num_args) {
-         aparam = ExecutionEnvironment::get_arg(n + 1);
-       }
-
-       if (i == ConfigString::npos) {
-         unqualified[line].push_back(SymEnt(SymEnt::Commandline,
-                                            aparam, "", state));
-         if (microconfig_cat->is_spam())
-           microconfig_cat->spam() << "unqualified symbol '" << line
-                                   << "' with value '" << aparam
-                                   << "'" << endl;
-       } else {
-         ConfigString scope(line.substr(0, i));
-         ConfigString sym(line.substr(i+1, ConfigString::npos));
-         (qualified[scope])[sym].push_back(SymEnt(SymEnt::Commandline,
-                                                  aparam, "", state));
-         if (microconfig_cat->is_spam())
-           microconfig_cat->spam() << "qualified symbol '" << sym
-                                   << "' with scope '" << scope
-                                   << "' and value '" << aparam
-                                   << "'" << endl;
-       }
-     } else if (microconfig_cat->is_spam()) {
-       microconfig_cat->spam() << "argument #" << n << " ('" << line
-                               << "') is not recognized as an option"
-                               << endl;
-     }
-     ++n;
-   }
-}
-
-void ConfigTable::ConfigDirDefault() {
-  // The configdir default comes from $PRC_DIR, or from the
-  // compiled in DEFAULT_PRC_DIR if that's unspecified.
-  configdir = ExecutionEnvironment::get_environment_variable("PRC_DIR");
-  if (configdir.empty()) {
-    configdir = DEFAULT_PRC_DIR;
-  }
-}
-
-void ConfigTable::MicroConfig() {
-/*
-#ifndef NDEBUG
-   NotifySeverity mcs = microconfig_cat->get_severity();
-   microconfig_cat->set_severity(NS_spam);
-
-   NotifySeverity cs = config_cat->get_severity();
-   config_cat->set_severity(NS_spam);
-#else * NDEBUG *
-*/
-  //   NotifySeverity mcs = microconfig_cat->get_severity();
-   microconfig_cat->set_severity(NS_info);
-
-   //   NotifySeverity cs = dconfig_cat->get_severity();
-   dconfig_cat->set_severity(NS_info);
-/*
-#endif * NDEBUG *
-*/
-   string cc = ExecutionEnvironment::get_environment_variable("CONFIG_CONFIG");
-   if (microconfig_cat->is_spam()) {
-     microconfig_cat->spam() << "CONFIG_CONFIG = '" << cc << "'" << endl;
-   }
-   bool cdbg = false;
-   bool cexe = false;
-   bool psep = false;
-   bool fsep = false;
-   bool cname = false;
-   bool cargs = false;
-   bool cpath = false;
-   bool cdir = false;
-   bool ccmt = false;
-   bool asuff = false;
-   bool cstub = false;
-   bool rdarg = false;
-   bool rdenv = false;
-   if (!cc.empty()) {
-      ConfigString configconfig(cc);
-      if (configconfig.length() > 1) {
-         ConfigString assign = "=";
-         ConfigString sep = configconfig.substr(0, 1);
-         if (microconfig_cat->is_spam()) {
-            microconfig_cat->spam() << "separator character is: '" << sep
-                                    << "'" << endl;
-         }
-         typedef std::vector<ConfigString> strvec;
-         strvec sv;
-         size_t q = 1;
-         size_t p = configconfig.find(sep, q);
-         while (p != ConfigString::npos) {
-           sv.push_back(configconfig.substr(q, p - q));
-           q = p + 1;
-           p = configconfig.find(sep, q);
-         }
-         if (q + 1 < configconfig.size()) {
-           sv.push_back(configconfig.substr(q));
-         }
-         
-         if (microconfig_cat->is_spam())
-            microconfig_cat->spam()
-               << "extracted vector of microconfig options" << endl;
-         for (strvec::iterator i=sv.begin(); i!=sv.end(); ++i) {
-            if (microconfig_cat->is_spam())
-               microconfig_cat->spam() << "parsing microconfig option '"
-                                       << *i << "'" << endl;
-            if ((*i).length() == 1) {
-              // new assignment character
-              assign += *i;
-              continue;
-            }
-            size_t j = (*i).find_first_of(assign);
-            if (j != ConfigString::npos) {
-               ConfigString tok = (*i).substr(0, j);
-               ConfigString rest = (*i).substr(j+1, ConfigString::npos);
-               if (microconfig_cat->is_spam())
-                  microconfig_cat->spam() << "split microconfig option into '"
-                                          << tok << "' and '" << rest << "'"
-                                          << endl;
-               if (tok == "pathsep") {
-                  pathsep = rest;
-                  psep = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig pathsep directive, "
-                        << "setting the path separator to '" << pathsep << "'"
-                        << endl;
-               } else if (tok == "filesep") {
-                  filesep = rest;
-                  fsep = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig filesep directive, "
-                        << "setting the file separator to '" << filesep << "'"
-                        << endl;
-               } else if (tok == "configname") {
-                 configname.push_back(GlobPattern(rest));
-                 cname = true;
-                 if (microconfig_cat->is_spam())
-                   microconfig_cat->spam()
-                     << "got a microconfig configname directive, "
-                     << "adding configname '" << rest << "'" << endl;
-               } else if (tok == "configargs") {
-                  configargs = rest;
-                  cargs = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig configargs directive, "
-                        << "setting the config file args to '"
-                        << configargs << "'"
-                        << endl;
-               } else if (tok == "configpath") {
-                  if (cpath) {
-                    configpath += " " + rest;
-                    if (microconfig_cat->is_spam())
-                      microconfig_cat->spam()
-                        << "got a microconfig configpath directive, "
-                        << "adding '" << rest << "' to the configpath (now '"
-                        << configpath << "')"
-                        << endl;
-                  } else {
-                    configpath = rest;
-                    if (microconfig_cat->is_spam())
-                      microconfig_cat->spam()
-                        << "got a microconfig configpath directive, "
-                        << "setting the configpath to '" << configpath << "'"
-                        << endl;
-                  }
-                  cpath = true;
-               } else if (tok == "configdir") {
-                 configdir = rest;
-                 if (microconfig_cat->is_spam())
-                   microconfig_cat->spam()
-                     << "got a microconfig configdir directive, "
-                     << "setting the configdir to '" << configdir << "'"
-                     << endl;
-                  cdir = true;
-               } else if (tok == "configcmt") {
-                  configcmt = rest;
-                  ccmt = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig configcmt directive, "
-                        << "setting the config comment to '" << configcmt
-                        << "'" << endl;
-               } else if (tok == "argsuffix") {
-                  argsuffix = rest;
-                  asuff = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig argsuffix directive, "
-                        << "setting the argument environment suffix to '"
-                        << argsuffix << "'" << endl;
-               } else if (tok == "commandstub") {
-                  commandstub = rest;
-                  cstub = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig commandstub directive, "
-                        << "setting the command environment stub "
-                        << "to '" << commandstub << "'" << endl;
-               } else if (tok == "configdbg") {
-                  configdbg = TrueOrFalse(rest);
-                  cdbg = true;
-                  if (configdbg) {
-                     microconfig_cat->set_severity(NS_spam);
-                     dconfig_cat->set_severity(NS_spam);
-                  } else {
-                     microconfig_cat->set_severity(NS_info);
-                     dconfig_cat->set_severity(NS_info);
-                  }
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig configdbg directive, "
-                        << "setting the config spam state to " << configdbg
-                        << endl;
-               } else if (tok == "configexe") {
-                  configexe = TrueOrFalse(rest);
-                  cexe = true;
-                  if (configexe) {
-                     microconfig_cat->set_severity(NS_spam);
-                     dconfig_cat->set_severity(NS_spam);
-                  } else {
-                     microconfig_cat->set_severity(NS_info);
-                     dconfig_cat->set_severity(NS_info);
-                  }
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig configexe directive, "
-                        << "setting the config spam state to " << configexe
-                        << endl;
-               } else if (tok == "readargs") {
-                  readargs = TrueOrFalse(rest);
-                  rdarg = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig readargs directive, "
-                        << (readargs?"will":"will not")
-                        << " read from the commandline." << endl;
-               } else if (tok == "readenv") {
-                  readenvs = TrueOrFalse(rest);
-                  rdenv = true;
-                  if (microconfig_cat->is_spam())
-                     microconfig_cat->spam()
-                        << "got a microconfig readenv directive, "
-                        << (readargs?"will":"will not")
-                        << " read the environment." << endl;
-               }
-            } else if (microconfig_cat->is_spam())
-               microconfig_cat->spam()
-                  << "no '=' in microconfig option, ignoring it" << endl;
-         }
-      } else if (microconfig_cat->is_spam())
-         microconfig_cat->spam()
-            << "CONFIG_CONFIG contains only a single character" << endl;
-   } else if (microconfig_cat->is_spam())
-      microconfig_cat->spam() << "CONFIG_CONFIG is empty" << endl;
-   if (!cdbg)
-      ConfigDbgDefault();
-   if (!cexe)
-      ConfigExeDefault();
-   if (!psep) {
-      PathSepDefault();
-      if (microconfig_cat->is_spam())
-         microconfig_cat->spam() << "no microconfig for pathsep, "
-                                  << "setting to default '" << pathsep << "'"
-                                  << endl;
-   }
-   if (!fsep) {
-      FileSepDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for filesep, "
-                                << "setting to default '" << filesep << "'"
-                                << endl;
-   }
-   if (!cname) {
-      ConfigNameDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for configname, "
-                                << "setting to default" << endl;
-   }
-   if (!cargs) {
-      ConfigArgsDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for configargs, "
-                                << "setting to default '" << configargs
-                                << "'" << endl;
-   }
-   if (!cpath) {
-      ConfigPathDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for configpath, "
-                                << "setting to default '" << configpath
-                                << "'" << endl;
-   }
-   if (!cdir) {
-      ConfigDirDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for configdir, "
-                                << "setting to default '" << configdir
-                                << "'" << endl;
-   }
-   if (!ccmt) {
-      ConfigCmtDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for configcmt, "
-                                << "setting to default '" << configcmt
-                                << "'" << endl;
-   }
-   if (!asuff) {
-      ArgSuffixDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for argsuffix, "
-                                << "setting to default '" << argsuffix
-                                << "'" << endl;
-   }
-   if (!cstub) {
-      CommandStubDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for commandstub, "
-                                << "setting to default '" << commandstub
-                                << "'" << endl;
-   }
-   if (!rdarg) {
-      ReadArgsDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for readargs, "
-                                << "setting to default: "
-                                << (readargs?"true":"false") << endl;
-   }
-   if (!rdenv) {
-      ReadEnvsDefault();
-      if (microconfig_cat->is_spam())
-        microconfig_cat->spam() << "no microconfig for readenv, "
-                                << "setting to default: "
-                                << (readargs?"true":"false") << endl;
-   }
-}
-
-void ConfigTable::GetData() {
-  MicroConfig();
-#ifndef DISABLE_CONFIG
-  ReadConfigFile();
-  if (readenvs) {
-    ConfigString comarg = commandstub + argsuffix;
-    if (microconfig_cat->is_spam())
-      microconfig_cat->spam() << "comarg is '" << comarg << "'"
-                              << endl;
-    if (ExecutionEnvironment::has_environment_variable(comarg)) {
-      ConfigString env = ExecutionEnvironment::get_environment_variable(comarg);
-      ParseCommandEnv(env, comarg);
-    }
-    ConfigString line = ExecutionEnvironment::get_binary_name() + argsuffix;
-    UpCase(line);
-    if (microconfig_cat->is_spam())
-      microconfig_cat->spam() << "binarg is '" << line << "'"
-                              << endl;
-    if (ExecutionEnvironment::has_environment_variable(line)) {
-      ConfigString env = ExecutionEnvironment::get_environment_variable(line);
-      ParseCommandEnv(env, line);
-    }
-  }
-  if (readargs)
-    ParseArgs();
-#endif  // DISABLE_CONFIG
-}
-
-ConfigTable* ConfigTable::Instance() {
-  if (_instance == (ConfigTable*)0L) {
-    _instance = new ConfigTable;
-    _instance->GetData();
-    _instance->_initializing = false;
-  }
-  return _instance;
-}
-
-bool ConfigTable::AmInitializing() {
-  return _initializing;
-}
-
-bool ConfigTable::TrueOrFalse(const ConfigString& in, bool def) {
-  bool ret = def;
-  ConfigString S = in;
-  UpCase(S);
-  if (S[0] == '#') {
-    if (S[1] == 'F') {
-      ret = false;
-    } else if (S[1] == 'T') {
-      ret = true;
-    }
-  } else if (S == "0") {
-    ret = false;
-  } else if (S == "1") {
-    ret = true;
-  } else if (S == "FALSE") {
-    ret = false;
-  } else if (S == "TRUE") {
-    ret = true;
-  }
-  return ret;
-}
-
-bool ConfigTable::Defined(const ConfigString& sym,
-                                 const ConfigString qual) {
-#ifdef DISABLE_CONFIG
-  return false;
-#else
-  if (qual.empty()) {
-    return (unqualified.count(sym) != 0 ||
-            ExecutionEnvironment::has_environment_variable(sym));
-
-  } else {
-    TableMap::const_iterator ti;
-    ti = qualified.find(qual);
-    if (ti != qualified.end()) {
-      const SymbolTable &table = (*ti).second;
-      if (table.count(sym) != 0) {
-        return true;
-      }
-    }
-
-    return ExecutionEnvironment::has_environment_variable(qual + "." + sym);
-  }
-#endif // DISABLE_CONFIG
-}
-
-ConfigTable::SymEnt ConfigTable::Get(const ConfigString& sym,
-                                     const ConfigString qual) {
-#ifndef DISABLE_CONFIG
-  const ConfigTable::Symbol &symbol = GetSym(sym, qual);
-  if (!symbol.empty()) {
-    return symbol.back();
-  }
-
-  // No explicit config definition; fall back to the environment.
-  string envvar = sym;
-  if (!qual.empty()) {
-    envvar = qual + "." + sym;
-  }
-
-  if (ExecutionEnvironment::has_environment_variable(sym)) {
-    string def = ExecutionEnvironment::get_environment_variable(sym);
-    return ConfigTable::SymEnt(ConfigTable::SymEnt::Environment, def);
-  }
-#endif // DISABLE_CONFIG
-
-  // No definition for the variable.  Too bad for you.
-  return ConfigTable::SymEnt();
-}
-
-const ConfigTable::Symbol& ConfigTable::GetSym(const ConfigString& sym,
-                                               const ConfigString qual) {
-  static ConfigTable::Symbol empty_symbol;
-
-#ifndef DISABLE_CONFIG
-  total_num_get++;
-  if (qual.empty()) {
-    SymbolTable::const_iterator si;
-    si = unqualified.find(sym);
-    if (si != unqualified.end()) {
-      return (*si).second;
-    }
-
-  } else {
-    TableMap::const_iterator ti;
-    ti = qualified.find(qual);
-    if (ti != qualified.end()) {
-      const SymbolTable &table = (*ti).second;
-      SymbolTable::const_iterator si;
-      si = table.find(sym);
-      if (si != table.end()) {
-        return (*si).second;
-      }
-    }
-  }
-#endif // DISABLE_CONFIG
-
-  return empty_symbol;
-}

+ 0 - 71
dtool/src/dconfig/configTable.h

@@ -21,85 +21,14 @@
 
 #include "dtoolbase.h"
 
-#include "config_setup.h"
-#include "config_dconfig.h"
 #include "symbolEnt.h"
-#include "globPattern.h"
-
-#include "pvector.h"
-#include "pmap.h"
 
 namespace Config {
 
 class EXPCL_DTOOLCONFIG ConfigTable {
-private:
-  static ConfigTable* _instance;
-
 public:
   typedef SymbolEnt           SymEnt;
   typedef vector_SymbolEnt    Symbol;
-
-private:
-  typedef phash_map<ConfigString, Symbol, sequence_hash<ConfigString> >      SymbolTable;
-  typedef phash_map<ConfigString, SymbolTable, sequence_hash<ConfigString> > TableMap;
-  typedef pvector<GlobPattern> Globs;
-
-  SymbolTable unqualified;
-  TableMap qualified;
-  bool _initializing;
-  bool configexe;
-  bool configdbg;
-  bool readargs;
-  bool readenvs;
-  ConfigString pathsep;
-  ConfigString filesep;
-  Globs configname;
-  ConfigString configargs;
-  ConfigString configpath;
-  ConfigString configdir;
-  ConfigString configcmt;
-  ConfigString argsuffix;
-  ConfigString commandstub;
-
-  static void CropString(ConfigString& S);
-  void DeComment(ConfigString& S);
-  bool IsComment(const ConfigString&);
-  static void UpCase(ConfigString&);
-  ConfigString NextWord(const ConfigString& S);
-  ConfigString PopNextWord(ConfigString& S);
-  void ParseConfigFile(istream&, const ConfigString&);
-  void ReadConfigFile();
-  void ParseCommandEnv(ConfigString&, const ConfigString&);
-  void ParseArgs();
-  INLINE void ConfigDbgDefault();
-  INLINE void ConfigExeDefault();
-  INLINE void ReadArgsDefault();
-  INLINE void ReadEnvsDefault();
-  INLINE void PathSepDefault();
-  INLINE void FileSepDefault();
-  INLINE void ConfigNameDefault();
-  INLINE void ConfigArgsDefault();
-  INLINE void ConfigPathDefault();
-  void ConfigDirDefault();
-  INLINE void ConfigCmtDefault();
-  INLINE void ArgSuffixDefault();
-  INLINE void CommandStubDefault();
-  void MicroConfig();
-  void GetData();
-
-protected:
-  ConfigTable() : _initializing(true) {}
-
-public:
-  static ConfigTable* Instance();
-  bool AmInitializing();
-  static bool TrueOrFalse(const ConfigString& in, bool def = false);
-  bool Defined(const ConfigString& sym, const ConfigString qual="");
-  SymEnt Get(const ConfigString& sym, const ConfigString qual = "");
-  const Symbol& GetSym(const ConfigString& sym,
-                       const ConfigString qual = "");
-  INLINE ConfigString GetConfigPath() const;
-  INLINE bool IsConfigDbg() { return configdbg; };
 };
 
 #include "configTable.I"

+ 3 - 41
dtool/src/dconfig/dconfig.h

@@ -100,10 +100,7 @@ void Config<GetConfig>::ConfigFunc() {
 
 template<class GetConfig>
 bool Config<GetConfig>::AmInitializing() {
-   ConfigTable* tab = ConfigTable::Instance();
-   if (tab == (ConfigTable *)0L)
-      return Flag();
-   return tab->AmInitializing();
+  return false;
 }
 
 template<class GetConfig>
@@ -125,38 +122,10 @@ template<class GetConfig>
 void Config<GetConfig>::Init() {
    if (Flag())
       return;
-   total_time_config_init -= clock();
-   Flag(true);
-   ConfigTable* tab = ConfigTable::Instance();
-
-   if (Defined("notify-level-config")) {
-      ConfigString s = Get("notify-level-config");
-      NotifySeverity sev = Notify::string_severity(s);
-      if (sev != NS_unspecified) {
-         microconfig_cat->set_severity(sev);
-         dconfig_cat->set_severity(sev);
-      } else {
-         microconfig_cat->set_severity(NS_info);
-         dconfig_cat->set_severity(NS_info);
-      }
-   } else {
-      if(!tab->IsConfigDbg()) {
-          microconfig_cat->set_severity(NS_info);
-          dconfig_cat->set_severity(NS_info);
-      }
-   }
 
-   total_time_config_init += clock();
-   total_time_external_init -= clock();
+   Flag(true);
 
-   if (dconfig_cat->is_spam())
-      dconfig_cat->spam() << "calling ConfigFunc for '" << Name() << "'"
-                         << endl;
    ConfigFunc();
-   if (dconfig_cat->is_spam())
-      dconfig_cat->spam() << "back from ConfigFunc for '" << Name() << "'"
-                         << endl;
-   total_time_external_init += clock();
 }
 
 template<class GetConfig>
@@ -172,14 +141,7 @@ template<class GetConfig>
 bool Config<GetConfig>::Defined(const ConfigString& sym)
 {
    Init();
-   ConfigTable* tab = ConfigTable::Instance();
-   if (tab->Defined(sym, Name()))
-      return true;
-   else if (tab->Defined(sym, ExecutionEnvironment::get_binary_name()))
-      return true;
-   else if (tab->Defined(sym))
-      return true;
-   return false;
+   return true;
 }
 
 template<class GetConfig>

+ 0 - 87
dtool/src/dconfig/test_serialization.cxx

@@ -1,87 +0,0 @@
-// Filename: test_serialization.cxx
-// Created by:  cary (31Aug98)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "serialization.h"
-#include <list>
-#include <vector>
-#include <algo.h>
-#include <string>
-
-typedef std::list<int> intlist;
-typedef std::vector<float> floatvec;
-
-intlist refints;
-floatvec reffloats;
-
-int ints[10] = { 3, 1, 4, 1, 5, 9, 2, 6, 5, 3 };
-float floats[10] = { 0.1, 1.2, 2.3, 3.4, 4.5, 5.6, 6.7, 7.8, 8.9, 9.0 };
-
-void TestToString()
-{
-   std::string line;
-   Serialize::Serializer<intlist> intser(refints);
-   Serialize::Serializer<floatvec> floatser(reffloats);
-
-   line = intser;
-   cout << "Int list serialization: '" << line << "'" << endl;
-   line = floatser;
-   cout << "Float vector serialization: '" << line << "'" << endl;
-}
-
-void TestFromString()
-{
-   std::string line;
-   Serialize::Serializer<intlist> intser(refints);
-   Serialize::Serializer<floatvec> floatser(reffloats);
-
-   line = intser;
-   Serialize::Deserializer<intlist> intdes1(line);
-   cout << "Int list deserialization: ";
-   intlist ides1 = intdes1;
-   for (intlist::iterator i=ides1.begin(); i!=ides1.end(); ++i) {
-      if (i != ides1.begin())
-         cout << ", ";
-      cout << (*i);
-   }
-   cout << endl;
-   line = floatser;
-   Serialize::Deserializer<floatvec> floatdes1(line);
-   cout << "Float vector deserialization: ";
-   floatvec fdes1 = floatdes1;
-   for (floatvec::iterator j=fdes1.begin(); j!=fdes1.end(); ++j) {
-      if (j != fdes1.begin())
-         cout << ", ";
-      cout << (*j);
-   }
-   cout << endl;
-}
-
-main()
-{
-   // initialize the collections
-   for (int i=0; i<10; ++i) {
-      refints.push_back(ints[i]);
-      reffloats.push_back(floats[i]);
-   }
-
-   // now run tests
-   cout << "Serialization to string:" << endl;
-   TestToString();
-   cout << endl << "Deserialization from string:" << endl;
-   TestFromString();
-}

+ 4 - 11
dtool/src/interrogatedb/config_interrogatedb.cxx

@@ -18,7 +18,7 @@
 
 #include "config_interrogatedb.h"
 #include "interrogate_request.h"
-
+#include "configVariableString.h"
 #include "dconfig.h"
 
 #if defined(WIN32_VC) && defined(_DEBUG)
@@ -69,14 +69,7 @@ ConfigureFn(config_interrogatedb) {
 #endif
 }
 
-DSearchPath &
-get_interrogatedb_path() {
-  static DSearchPath *interrogatedb_path = NULL;
-  if (interrogatedb_path == (DSearchPath *)NULL) {
-    interrogatedb_path = new DSearchPath(".");
-    interrogatedb_path->append_path
-      (config_interrogatedb.GetString("ETC_PATH", "."));
-  }
-  return *interrogatedb_path;
-}
+ConfigVariableSearchPath interrogatedb_path
+("interrogatedb-path", 0,
+ "The search path for interrogate's *.in files.");
 

+ 2 - 2
dtool/src/interrogatedb/config_interrogatedb.h

@@ -21,10 +21,10 @@
 
 #include "dtoolbase.h"
 #include "notifyCategoryProxy.h"
-#include "dSearchPath.h"
+#include "configVariableSearchPath.h"
 
 NotifyCategoryDecl(interrogatedb, EXPCL_DTOOLCONFIG, EXPTP_DTOOLCONFIG);
 
-DSearchPath &get_interrogatedb_path();
+extern ConfigVariableSearchPath interrogatedb_path;
 
 #endif

+ 1 - 1
dtool/src/interrogatedb/interrogateDatabase.cxx

@@ -892,7 +892,7 @@ read(istream &in, InterrogateModuleDef *def) {
 ////////////////////////////////////////////////////////////////////
 void InterrogateDatabase::
 load_latest() {
-  const DSearchPath &searchpath = get_interrogatedb_path();
+  const DSearchPath &searchpath = interrogatedb_path;
 
   Requests copy_requests;
   copy_requests.swap(_requests);

+ 9 - 1
dtool/src/interrogatedb/interrogate_interface.cxx

@@ -27,7 +27,15 @@
 // passed in by the code generator.
 void 
 interrogate_add_search_directory(const char *dirname) {
-  get_interrogatedb_path().append_directory(Filename::from_os_specific(dirname));
+  interrogatedb_path.append_directory(Filename::from_os_specific(dirname));
+}
+
+// This function works similar to the above, but adds a complete path
+// string--a list of multiple directories, separated by the standard
+// delimiter--to the search path.
+void 
+interrogate_add_search_path(const char *pathstring) {
+  interrogatedb_path.append_path(pathstring);
 }
 
 bool interrogate_error_flag() {

+ 1 - 0
dtool/src/interrogatedb/interrogate_interface.h

@@ -91,6 +91,7 @@ enum AtomicToken {
 };
 
 EXPCL_DTOOLCONFIG void interrogate_add_search_directory(const char *dirname);
+EXPCL_DTOOLCONFIG void interrogate_add_search_path(const char *pathstring);
 EXPCL_DTOOLCONFIG bool interrogate_error_flag();
 
 //////////////////////////////////////////////////////////////////////////

+ 8 - 0
dtool/src/prc/Sources.pp

@@ -7,15 +7,19 @@
   #define SOURCES \
     config_prc.cxx config_prc.h \
     configDeclaration.cxx configDeclaration.I configDeclaration.h \
+    configFlags.cxx configFlags.I configFlags.h \
     configPage.cxx configPage.I configPage.h \
     configPageManager.cxx configPageManager.I configPageManager.h \
     configVariable.cxx configVariable.I configVariable.h \
+    configVariableBase.cxx configVariableBase.I configVariableBase.h \
     configVariableBool.cxx configVariableBool.I configVariableBool.h \
     configVariableCore.cxx configVariableCore.I configVariableCore.h \
     configVariableDouble.cxx configVariableDouble.I configVariableDouble.h \
+    configVariableEnum.cxx configVariableEnum.I configVariableEnum.h \
     configVariableInt.cxx configVariableInt.I configVariableInt.h \
     configVariableList.cxx configVariableList.I configVariableList.h \
     configVariableManager.cxx configVariableManager.I configVariableManager.h \
+    configVariableSearchPath.cxx configVariableSearchPath.I configVariableSearchPath.h \
     configVariableString.cxx configVariableString.I configVariableString.h \
     globPattern.cxx globPattern.I globPattern.h \
     notify.cxx notify.I notify.h \
@@ -27,15 +31,19 @@
   #define INSTALL_HEADERS \
     config_prc.h \
     configDeclaration.I configDeclaration.h \
+    configFlags.I configFlags.h \
     configPage.I configPage.h \
     configPageManager.I configPageManager.h \
     configVariable.I configVariable.h \
+    configVariableBase.I configVariableBase.h \
     configVariableBool.I configVariableBool.h \
     configVariableCore.I configVariableCore.h \
     configVariableDouble.I configVariableDouble.h \
+    configVariableEnum.I configVariableEnum.h \
     configVariableInt.I configVariableInt.h \
     configVariableList.I configVariableList.h \
     configVariableManager.I configVariableManager.h \
+    configVariableSearchPath.I configVariableSearchPath.h \
     configVariableString.I configVariableString.h \
     globPattern.I globPattern.h \
     notify.I notify.h \

+ 18 - 0
dtool/src/prc/configFlags.I

@@ -0,0 +1,18 @@
+// Filename: configFlags.I
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+

+ 54 - 0
dtool/src/prc/configFlags.cxx

@@ -0,0 +1,54 @@
+// Filename: configFlags.cxx
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "configFlags.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigFlags::Type output operator
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ostream &
+operator << (ostream &out, ConfigFlags::ValueType type) {
+  switch (type) {
+  case ConfigFlags::VT_undefined:
+    return out << "undefined";
+
+  case ConfigFlags::VT_list:
+    return out << "list";
+
+  case ConfigFlags::VT_string:
+    return out << "string";
+
+  case ConfigFlags::VT_bool:
+    return out << "bool";
+
+  case ConfigFlags::VT_int:
+    return out << "int";
+
+  case ConfigFlags::VT_double:
+    return out << "double";
+
+  case ConfigFlags::VT_enum:
+    return out << "enum";
+
+  case ConfigFlags::VT_search_path:
+    return out << "search-path";
+  }
+
+  return out << "**invalid(" << (int)type << ")**";
+}

+ 62 - 0
dtool/src/prc/configFlags.h

@@ -0,0 +1,62 @@
+// Filename: configFlags.h
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIGFLAGS_H
+#define CONFIGFLAGS_H
+
+#include "dtoolbase.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConfigFlags
+// Description : This class is the base class of both ConfigVariable
+//               and ConfigVariableCore.  It exists only to provide a
+//               convenient name scoping for some enumerated values
+//               common to both classes.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DTOOLCONFIG ConfigFlags {
+PUBLISHED:
+  enum ValueType {
+    VT_undefined,
+    VT_list,
+    VT_string,
+    VT_bool,
+    VT_int,
+    VT_double,
+    VT_enum,
+    VT_search_path,
+  };
+
+  enum VariableFlags {
+    // Trust level.  We have the bottom twelve bits reserved for a
+    // trust level indicator; then the open and closed bits are a
+    // special case.
+    F_trust_level_mask  = 0x00000fff,
+    F_open              = 0x00001000,
+    F_closed            = 0x00002000,
+
+    // F_dynamic means that the variable name is generated dynamically
+    // (possibly from a very large pool) and should not be included in
+    // the normal list of variable names.
+    F_dynamic           = 0x00004000,
+  };
+};
+
+ostream &operator << (ostream &out, ConfigFlags::ValueType type);
+
+#endif
+

+ 5 - 0
dtool/src/prc/configPage.cxx

@@ -116,6 +116,11 @@ clear() {
 //               returned by the indicated istream, into the current
 //               page file.  Returns true on success, or false on some
 //               I/O error.
+//
+//               This is a low-level interface.  Normally you do not
+//               need to call it directly.  See the global functions
+//               load_prc_file() and unload_prc_file(), defined in
+//               panda/src/putil, for a higher-level interface.
 ////////////////////////////////////////////////////////////////////
 bool ConfigPage::
 read_prc(istream &in) {

+ 10 - 2
dtool/src/prc/configPageManager.cxx

@@ -245,8 +245,16 @@ reload_implicit_pages() {
     if ((file._file_flags & FF_execute) != 0 &&
         filename.is_executable()) {
       // Attempt to execute the file as a command.
-      string args = ExecutionEnvironment::get_environment_variable(PRC_EXECUTABLE_ARGS_ENVVAR);
-      string command = filename.to_os_specific() + " " + args;
+      string command = filename.to_os_specific();
+
+      string envvar = PRC_EXECUTABLE_ARGS_ENVVAR;
+      if (!envvar.empty()) {
+        string args = ExecutionEnvironment::get_environment_variable(envvar);
+        if (!args.empty()) {
+          command += " ";
+          command += args;
+        }
+      }
       IPipeStream ifs(command);
 
       ConfigPage *page = new ConfigPage(filename, true, i);

+ 20 - 122
dtool/src/prc/configVariable.I

@@ -24,20 +24,35 @@
 //               specialized ConfigVariableFoo derived class.
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariable::
-ConfigVariable(const string &name, ConfigVariableCore::ValueType value_type) :
-  _core(ConfigVariableManager::get_global_ptr()->make_variable(name))
+ConfigVariable(const string &name, ConfigVariable::ValueType value_type) :
+  ConfigVariableBase(name, value_type)
+{
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariable::Constructor
+//       Access: Protected
+//  Description: This constructor is only intended to be called from a
+//               specialized ConfigVariableFoo derived class.
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariable::
+ConfigVariable(const string &name, ConfigVariable::ValueType value_type,
+               int flags, const string &description) :
+  ConfigVariableBase(name, value_type, flags, description)
 {
-  _core->set_value_type(value_type);
 }
 
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariable::Constructor
 //       Access: Published
-//  Description: 
+//  Description: Use this constructor to make a ConfigVariable of an
+//               unspecified type.  Usually you'd want to do this just
+//               to reference a previously-defined ConfigVariable of a
+//               specific type, without having to know what type it is.
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariable::
 ConfigVariable(const string &name) :
-  _core(ConfigVariableManager::get_global_ptr()->make_variable(name))
+  ConfigVariableBase(name, VT_undefined)
 {
   _core->set_used();
 }
@@ -51,70 +66,6 @@ INLINE ConfigVariable::
 ~ConfigVariable() {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::get_name
-//       Access: Published
-//  Description: Returns the name of the variable.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariable::
-get_name() const {
-  return _core->get_name();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::get_value_type
-//       Access: Published
-//  Description: Returns the stated type of this variable.  If the
-//               variable has not yet been defined, this will be
-//               VT_undefined.
-////////////////////////////////////////////////////////////////////
-INLINE ConfigVariableCore::ValueType ConfigVariable::
-get_value_type() const {
-  return _core->get_value_type();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::get_trust_level
-//       Access: Published
-//  Description: Returns the minimum trust_level a prc file must
-//               demonstrate in order to redefine the value for this
-//               variable.  -1 indicates infinite trust: no prc file
-//               can redefine it.  Arguably, this should be called the
-//               "mistrust level", since the larger the value, the
-//               more suspicious we are of prc files.
-//
-//               This value only has effect in a release build.
-////////////////////////////////////////////////////////////////////
-INLINE int ConfigVariable::
-get_trust_level() const {
-  return _core->get_trust_level();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::get_description
-//       Access: Published
-//  Description: Returns the one-line description of this variable.
-//               If the variable has not yet been defined, this will
-//               be empty.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariable::
-get_description() const {
-  return _core->get_description();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::get_text
-//       Access: Published
-//  Description: Returns the paragraph help text describing the
-//               purpose of this variable in greater detail than
-//               get_description().  If the variable has not yet been
-//               defined, this will be empty.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariable::
-get_text() const {
-  return _core->get_text();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariable::get_default_value
 //       Access: Published
@@ -152,33 +103,6 @@ set_string_value(const string &string_value) {
   _core->make_local_value()->set_string_value(string_value);
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::clear_local_value
-//       Access: Published
-//  Description: Removes the local value defined for this variable,
-//               and allows its value to be once again retrieved from
-//               the .prc files.
-//
-//               Returns true if the value was successfully removed,
-//               false if it did not exist in the first place.
-////////////////////////////////////////////////////////////////////
-INLINE bool ConfigVariable::
-clear_local_value() {
-  return _core->clear_local_value();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::has_local_value
-//       Access: Published
-//  Description: Returns true if this variable's value has been
-//               shadowed by a local assignment (as created via
-//               make_local_value()), or false otherwise.
-////////////////////////////////////////////////////////////////////
-INLINE bool ConfigVariable::
-has_local_value() const {
-  return _core->has_local_value();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariable::get_num_words
 //       Access: Published
@@ -337,29 +261,3 @@ INLINE void ConfigVariable::
 set_double_word(int n, double value) {
   _core->make_local_value()->set_double_word(n, value);
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::output
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void ConfigVariable::
-output(ostream &out) const {
-  _core->output(out);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::write
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void ConfigVariable::
-write(ostream &out) const {
-  _core->write(out);
-}
-
-INLINE ostream &
-operator << (ostream &out, const ConfigVariable &variable) {
-  variable.output(out);
-  return out;
-}

+ 0 - 24
dtool/src/prc/configVariable.cxx

@@ -17,27 +17,3 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "configVariable.h"
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariable::Constructor
-//       Access: Protected
-//  Description: This constructor is only intended to be called from a
-//               specialized ConfigVariableFoo derived class.
-////////////////////////////////////////////////////////////////////
-ConfigVariable::
-ConfigVariable(const string &name, ConfigVariableCore::ValueType value_type,
-               int trust_level, const string &description, 
-               const string &text) :
-  _core(ConfigVariableManager::get_global_ptr()->make_variable(name))
-{
-  _core->set_value_type(value_type);
-  if (trust_level > -2) {
-    _core->set_trust_level(trust_level);
-  }
-  if (!description.empty()) {
-    _core->set_description(description);
-  }
-  if (!text.empty()) {
-    _core->set_text(text);
-  }
-}

+ 8 - 27
dtool/src/prc/configVariable.h

@@ -20,47 +20,36 @@
 #define CONFIGVARIABLE_H
 
 #include "dtoolbase.h"
-#include "configVariableCore.h"
-#include "configDeclaration.h"
-#include "configVariableManager.h"
+#include "configVariableBase.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ConfigVariable
 // Description : This is a generic, untyped ConfigVariable.  It is
 //               also the base class for the typed ConfigVariables,
 //               and contains all of the code common to
-//               ConfigVariables of all types.
+//               ConfigVariables of all types (except
+//               ConfigVariableList, which is a bit of a special
+//               case).
 //
 //               Mostly, this class serves as a thin wrapper around
 //               ConfigVariableCore and/or ConfigDeclaration, more or
 //               less duplicating the interface presented there.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_DTOOLCONFIG ConfigVariable {
+class EXPCL_DTOOLCONFIG ConfigVariable : public ConfigVariableBase {
 protected:
-  INLINE ConfigVariable(const string &name, 
-                        ConfigVariableCore::ValueType type);
-  ConfigVariable(const string &name, ConfigVariableCore::ValueType type,
-                 int trust_level, const string &description,
-                 const string &text);
+  INLINE ConfigVariable(const string &name, ValueType type);
+  INLINE ConfigVariable(const string &name, ValueType type,
+                        int flags, const string &description);
 
 PUBLISHED:
   INLINE ConfigVariable(const string &name);
   INLINE ~ConfigVariable();
 
-  INLINE const string &get_name() const;
-
-  INLINE ConfigVariableCore::ValueType get_value_type() const;
-  INLINE int get_trust_level() const;
-  INLINE const string &get_description() const;
-  INLINE const string &get_text() const;
   INLINE const ConfigDeclaration *get_default_value() const;
 
   INLINE string get_string_value() const;
   INLINE void set_string_value(const string &value);
 
-  INLINE bool clear_local_value();
-  INLINE bool has_local_value() const;
-
   INLINE int get_num_words() const;
 
   INLINE bool has_string_word(int n) const;
@@ -77,16 +66,8 @@ PUBLISHED:
   INLINE void set_bool_word(int n, bool value);
   INLINE void set_int_word(int n, int value);
   INLINE void set_double_word(int n, double value);
-
-  INLINE void output(ostream &out) const;
-  INLINE void write(ostream &out) const;
-
-protected:
-  ConfigVariableCore *_core;
 };
 
-INLINE ostream &operator << (ostream &out, const ConfigVariable &variable);
-
 #include "configVariable.I"
 
 #endif

+ 207 - 0
dtool/src/prc/configVariableBase.I

@@ -0,0 +1,207 @@
+// Filename: configVariableBase.I
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::Constructor
+//       Access: Protected
+//  Description: This constructor is only intended to be called from a
+//               specialized ConfigVariableFoo derived class.
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariableBase::
+ConfigVariableBase(const string &name, 
+                   ConfigVariableBase::ValueType value_type) :
+  _core(ConfigVariableManager::get_global_ptr()->make_variable(name))
+{
+  _core->set_value_type(value_type);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::Destructor
+//       Access: Protected
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariableBase::
+~ConfigVariableBase() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::get_name
+//       Access: Published
+//  Description: Returns the name of the variable.
+////////////////////////////////////////////////////////////////////
+INLINE const string &ConfigVariableBase::
+get_name() const {
+  return _core->get_name();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::get_value_type
+//       Access: Published
+//  Description: Returns the stated type of this variable.  This
+//               should be VT_list, unless a later variable
+//               declaration has changed it.
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariableBase::ValueType ConfigVariableBase::
+get_value_type() const {
+  return _core->get_value_type();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::get_flags
+//       Access: Public
+//  Description: Returns the flags value as set by set_flags().  This
+//               includes the trust level and some other settings.
+//               See the individual methods is_closed(),
+//               get_trust_level(), etc. to pull out the semantic
+//               meaning of these flags individually.
+////////////////////////////////////////////////////////////////////
+INLINE int ConfigVariableBase::
+get_flags() const {
+  return _core->get_flags();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::is_closed
+//       Access: Public
+//  Description: Returns true if the variable is not trusted by any
+//               prc file (and hence cannot be modified from its
+//               compiled-in default value), or false for the normal
+//               case, in which the variable can be modified by any
+//               prc file at or above its trust level (see
+//               get_trust_level()).
+//
+//               This value only has effect in a release build
+//               (specifically, when PRC_RESPECT_TRUST_LEVEL is
+//               defined true in Config.pp).
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableBase::
+is_closed() const {
+  return _core->is_closed();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::get_trust_level
+//       Access: Public
+//  Description: Returns the minimum trust_level a prc file must
+//               demonstrate in order to redefine the value for this
+//               variable.  Arguably, this should be called the
+//               "mistrust level", since the larger the value, the
+//               more suspicious we are of prc files.  This value is
+//               not used if is_closed() returns true, which indicates
+//               no file may be trusted.
+//
+//               This value only has effect in a release build
+//               (specifically, when PRC_RESPECT_TRUST_LEVEL is
+//               defined true in Config.pp).
+////////////////////////////////////////////////////////////////////
+INLINE int ConfigVariableBase::
+get_trust_level() const {
+  return _core->get_trust_level();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::is_dynamic
+//       Access: Public
+//  Description: Returns true if the variable was indicated as
+//               "dynamic" by its constructor, indicating that its
+//               name was dynamically generated, possibly from a large
+//               pool, and it should not be listed along with the
+//               other variables.
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableBase::
+is_dynamic() const {
+  return _core->is_dynamic();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::get_description
+//       Access: Published
+//  Description: Returns the one-line description of this variable.
+//               If the variable has not yet been defined, this will
+//               be empty.
+////////////////////////////////////////////////////////////////////
+INLINE const string &ConfigVariableBase::
+get_description() const {
+  return _core->get_description();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::clear_local_value
+//       Access: Published
+//  Description: Removes the local value defined for this variable,
+//               and allows its value to be once again retrieved from
+//               the .prc files.
+//
+//               Returns true if the value was successfully removed,
+//               false if it did not exist in the first place.
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableBase::
+clear_local_value() {
+  return _core->clear_local_value();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::has_local_value
+//       Access: Published
+//  Description: Returns true if this variable's value has been
+//               shadowed by a local assignment (as created via
+//               make_local_value()), or false otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableBase::
+has_local_value() const {
+  return _core->has_local_value();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::has_value
+//       Access: Public
+//  Description: Returns true if this variable has an explicit value,
+//               either from a prc file or locally set, or false if
+//               variable has its default value.
+////////////////////////////////////////////////////////////////////
+bool ConfigVariableBase::
+has_value() const {
+  return _core->has_value();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableBase::
+output(ostream &out) const {
+  _core->output(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::write
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableBase::
+write(ostream &out) const {
+  _core->write(out);
+}
+
+INLINE ostream &
+operator << (ostream &out, const ConfigVariableBase &variable) {
+  variable.output(out);
+  return out;
+}

+ 40 - 0
dtool/src/prc/configVariableBase.cxx

@@ -0,0 +1,40 @@
+// Filename: configVariableBase.cxx
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "configVariableBase.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableBase::Constructor
+//       Access: Protected
+//  Description: This constructor is only intended to be called from a
+//               specialized ConfigVariableFoo derived class.
+////////////////////////////////////////////////////////////////////
+ConfigVariableBase::
+ConfigVariableBase(const string &name, 
+                   ConfigVariableBase::ValueType value_type,
+                   int flags, const string &description) :
+  _core(ConfigVariableManager::get_global_ptr()->make_variable(name))
+{
+  _core->set_value_type(value_type);
+  if (flags != 0) {
+    _core->set_flags(flags);
+  }
+  if (!description.empty()) {
+    _core->set_description(description);
+  }
+}

+ 73 - 0
dtool/src/prc/configVariableBase.h

@@ -0,0 +1,73 @@
+// Filename: configVariableBase.h
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIGVARIABLEBASE_H
+#define CONFIGVARIABLEBASE_H
+
+#include "dtoolbase.h"
+#include "configFlags.h"
+#include "configVariableCore.h"
+#include "configDeclaration.h"
+#include "configVariableManager.h"
+#include "vector_string.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConfigVariableBase
+// Description : This class is the base class for both
+//               ConfigVariableList and ConfigVariable (and hence for
+//               all of the ConfigVariableBool, ConfigVaribleString,
+//               etc. classes).  It collects together the common
+//               interface for all generic ConfigVariables.
+//
+//               Mostly, this class serves as a thin wrapper around
+//               ConfigVariableCore and/or ConfigDeclaration, more or
+//               less duplicating the interface presented there.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DTOOLCONFIG ConfigVariableBase : public ConfigFlags {
+protected:
+  INLINE ConfigVariableBase(const string &name, ValueType type);
+  ConfigVariableBase(const string &name, ValueType type,
+                     int flags, const string &description);
+  INLINE ~ConfigVariableBase();
+
+PUBLISHED:
+  INLINE const string &get_name() const;
+
+  INLINE ValueType get_value_type() const;
+  INLINE int get_flags() const;
+  INLINE bool is_closed() const;
+  INLINE int get_trust_level() const;
+  INLINE bool is_dynamic() const;
+  INLINE const string &get_description() const;
+
+  INLINE bool clear_local_value();
+  INLINE bool has_local_value() const;
+  INLINE bool has_value() const;
+  
+  INLINE void output(ostream &out) const;
+  INLINE void write(ostream &out) const;
+
+protected:
+  ConfigVariableCore *_core;
+};
+
+INLINE ostream &operator << (ostream &out, const ConfigVariableBase &variable);
+
+#include "configVariableBase.I"
+
+#endif

+ 4 - 5
dtool/src/prc/configVariableBool.I

@@ -24,7 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariableBool::
 ConfigVariableBool(const string &name) :
-  ConfigVariable(name, ConfigVariableCore::VT_bool)
+  ConfigVariable(name, VT_bool)
 {
   _core->set_used();
 }
@@ -35,10 +35,9 @@ ConfigVariableBool(const string &name) :
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariableBool::
-ConfigVariableBool(const string &name, bool default_value, int trust_level,
-                   const string &description, const string &text) :
-  ConfigVariable(name, ConfigVariableCore::VT_bool, trust_level, 
-                 description, text)
+ConfigVariableBool(const string &name, bool default_value, int flags,
+                   const string &description) :
+  ConfigVariable(name, VT_bool, flags, description)
 {
   _core->set_default_value(default_value ? "1" : "0");
   _core->set_used();

+ 2 - 3
dtool/src/prc/configVariableBool.h

@@ -31,9 +31,8 @@ class EXPCL_DTOOLCONFIG ConfigVariableBool : public ConfigVariable {
 PUBLISHED:
   INLINE ConfigVariableBool(const string &name);
   INLINE ConfigVariableBool(const string &name, bool default_value,
-                            int trust_level = -2,
-                            const string &description = string(),
-                            const string &text = string());
+                            int flags = 0,
+                            const string &description = string());
 
   INLINE void operator = (bool value);
   INLINE operator bool () const;

+ 75 - 30
dtool/src/prc/configVariableCore.I

@@ -50,21 +50,71 @@ get_value_type() const {
   return _value_type;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableCore::get_flags
+//       Access: Public
+//  Description: Returns the flags value as set by set_flags().  This
+//               includes the trust level and some other settings.
+//               See the individual methods is_closed(),
+//               get_trust_level(), etc. to pull out the semantic
+//               meaning of these flags individually.
+////////////////////////////////////////////////////////////////////
+INLINE int ConfigVariableCore::
+get_flags() const {
+  return _flags;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableCore::is_closed
+//       Access: Public
+//  Description: Returns true if the variable is not trusted by any
+//               prc file (and hence cannot be modified from its
+//               compiled-in default value), or false for the normal
+//               case, in which the variable can be modified by any
+//               prc file at or above its trust level (see
+//               get_trust_level()).
+//
+//               This value only has effect in a release build
+//               (specifically, when PRC_RESPECT_TRUST_LEVEL is
+//               defined true in Config.pp).
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableCore::
+is_closed() const {
+  return (_flags & F_closed) != 0;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableCore::get_trust_level
 //       Access: Public
 //  Description: Returns the minimum trust_level a prc file must
 //               demonstrate in order to redefine the value for this
-//               variable.  -1 indicates infinite trust: no prc file
-//               can redefine it.  Arguably, this should be called the
+//               variable.  Arguably, this should be called the
 //               "mistrust level", since the larger the value, the
-//               more suspicious we are of prc files.
+//               more suspicious we are of prc files.  This value is
+//               not used if is_closed() returns true, which indicates
+//               no file may be trusted.
 //
-//               This value only has effect in a release build.
+//               This value only has effect in a release build
+//               (specifically, when PRC_RESPECT_TRUST_LEVEL is
+//               defined true in Config.pp).
 ////////////////////////////////////////////////////////////////////
 INLINE int ConfigVariableCore::
 get_trust_level() const {
-  return _trust_level;
+  return (_flags & F_trust_level_mask);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableCore::is_dynamic
+//       Access: Public
+//  Description: Returns true if the variable was indicated as
+//               "dynamic" by its constructor, indicating that its
+//               name was dynamically generated, possibly from a large
+//               pool, and it should not be listed along with the
+//               other variables.
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableCore::
+is_dynamic() const {
+  return (_flags & F_dynamic) != 0;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -79,19 +129,6 @@ get_description() const {
   return _description;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableCore::get_text
-//       Access: Public
-//  Description: Returns the paragraph help text describing the
-//               purpose of this variable in greater detail than
-//               get_description().  If the variable has not yet been
-//               defined, this will be empty.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariableCore::
-get_text() const {
-  return _text;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableCore::get_default_value
 //       Access: Public
@@ -127,6 +164,20 @@ has_local_value() const {
   return _local_value != (ConfigDeclaration *)NULL;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableCore::get_value_seq
+//       Access: Public
+//  Description: Returns a sequence number that changes every time the
+//               value of the variable might have changed.  This is
+//               useful for caching values from the variable, and
+//               detecting when the cache has expired.  It is
+//               initially zero and will increment from there.
+////////////////////////////////////////////////////////////////////
+INLINE int ConfigVariableCore::
+get_value_seq() const {
+  return _value_seq;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableCore::get_num_references
 //       Access: Public
@@ -154,10 +205,8 @@ get_num_references() const {
 INLINE const ConfigDeclaration *ConfigVariableCore::
 get_reference(int n) const {
   check_sort_declarations();
-  if (n >= 0 && n < (int)_declarations.size()) {
-    return _declarations[n];
-  }
-  return NULL;
+  nassertr(n >= 0 && n < (int)_declarations.size(), NULL);
+  return _declarations[n];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -190,10 +239,8 @@ get_num_trusted_references() const {
 INLINE const ConfigDeclaration *ConfigVariableCore::
 get_trusted_reference(int n) const {
   check_sort_declarations();
-  if (n >= 0 && n < (int)_trusted_declarations.size()) {
-    return _trusted_declarations[n];
-  }
-  return NULL;
+  nassertr(n >= 0 && n < (int)_trusted_declarations.size(), NULL);
+  return _trusted_declarations[n];
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -219,10 +266,8 @@ get_num_unique_references() const {
 INLINE const ConfigDeclaration *ConfigVariableCore::
 get_unique_reference(int n) const {
   check_sort_declarations();
-  if (n >= 0 && n < (int)_unique_declarations.size()) {
-    return _unique_declarations[n];
-  }
-  return NULL;
+  nassertr(n >= 0 && n < (int)_unique_declarations.size(), NULL);
+  return _unique_declarations[n];
 }
 
 ////////////////////////////////////////////////////////////////////

+ 47 - 58
dtool/src/prc/configVariableCore.cxx

@@ -37,11 +37,12 @@ ConfigVariableCore(const string &name) :
   _name(name),
   _is_used(false),
   _value_type(VT_undefined),
-  _trust_level(0),
+  _flags(0),
   _default_value(NULL),
   _local_value(NULL),
   _declarations_sorted(true),
-  _value_queried(false)
+  _value_queried(false),
+  _value_seq(0)
 {
 }
 
@@ -87,23 +88,23 @@ set_value_type(ConfigVariableCore::ValueType value_type) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableCore::set_trust_level
+//     Function: ConfigVariableCore::set_flags
 //       Access: Public
 //  Description: Specifies the trust level of this variable.  See
-//               get_trust_level().  It is not an error to call this
+//               get_flags().  It is not an error to call this
 //               multiple times, but if the value changes once
 //               get_declaration() has been called, a warning is printed.
 ////////////////////////////////////////////////////////////////////
 void ConfigVariableCore::
-set_trust_level(int trust_level) {
-  if (_value_queried && _trust_level != trust_level) {
+set_flags(int flags) {
+  if (_value_queried && _flags != flags) {
     prc_cat->warning()
       << "changing trust level for ConfigVariable " 
-      << get_name() << " from " << _trust_level << " to " 
-      << trust_level << ".\n";
+      << get_name() << " from " << _flags << " to " 
+      << flags << ".\n";
   }
 
-  _trust_level = trust_level;
+  _flags = flags;
 
   // Changing the trust level will require re-sorting the
   // declarations.
@@ -136,25 +137,6 @@ set_description(const string &description) {
   _description = description;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableCore::set_text
-//       Access: Public
-//  Description: Specifies the long text description of this variable.
-//               See get_text().  It is not an error to call
-//               this multiple times, but if the value changes once
-//               get_declaration() has been called, a warning is printed.
-////////////////////////////////////////////////////////////////////
-void ConfigVariableCore::
-set_text(const string &text) {
-  if (_value_queried && _text != text) {
-    prc_cat->warning()
-      << "changing text for ConfigVariable " 
-      << get_name() << ".\n";
-  }
-
-  _text = text;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableCore::set_default_value
 //       Access: Public
@@ -208,8 +190,20 @@ make_local_value() {
     ConfigPage *local_page = ConfigPage::get_local_page();
     string string_value = get_declaration(0)->get_string_value();
     _local_value = local_page->make_declaration(this, string_value);
+
+    if (is_closed()) {
+      prc_cat.warning()
+        << "Assigning a local value to a \"closed\" ConfigVariable.  "
+        "This is legal in a development build, but illegal in a release "
+        "build and may result in a compilation error or exception.\n";
+    }
   }
 
+  // Assume that everytime someone asks for the local value, they're
+  // about to change it; further assume that no one changes the local
+  // value without calling this method immediately before.
+  _value_seq++;
+
   return _local_value;
 }
 
@@ -228,12 +222,29 @@ clear_local_value() {
   if (_local_value != (ConfigDeclaration *)NULL) {
     ConfigPage::get_local_page()->delete_declaration(_local_value);
     _local_value = NULL;
+    _value_seq++;
     return true;
   }
 
   return false;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableCore::has_value
+//       Access: Public
+//  Description: Returns true if this variable has an explicit value,
+//               either from a prc file or locally set, or false if
+//               variable has its default value.
+////////////////////////////////////////////////////////////////////
+bool ConfigVariableCore::
+has_value() const {
+  if (has_local_value()) {
+    return true;
+  }
+  check_sort_declarations();
+  return (!_trusted_declarations.empty());
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableCore::get_num_declarations
 //       Access: Public
@@ -343,6 +354,10 @@ add_declaration(ConfigDeclaration *decl) {
   _declarations.push_back(decl);
 
   _declarations_sorted = false;
+
+  if (!has_local_value()) {
+    _value_seq++;
+  }
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -365,6 +380,9 @@ remove_declaration(ConfigDeclaration *decl) {
       (*di) = (*di2);
       _declarations.erase(di2);
       _declarations_sorted = false;
+      if (!has_local_value()) {
+        _value_seq++;
+      }
       return;
     }
   }
@@ -402,7 +420,7 @@ sort_declarations() {
   _untrusted_declarations.clear();
   for (di = _declarations.begin(); di != _declarations.end(); ++di) {
     const ConfigDeclaration *decl = (*di);
-    if (get_trust_level() >= 0 && 
+    if (!is_closed() &&
         get_trust_level() <= decl->get_page()->get_trust_level()) {
       _trusted_declarations.push_back(decl);
     } else {
@@ -436,32 +454,3 @@ sort_declarations() {
 
   _declarations_sorted = true;
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableCore::Type output operator
-//  Description: 
-////////////////////////////////////////////////////////////////////
-ostream &
-operator << (ostream &out, ConfigVariableCore::ValueType type) {
-  switch (type) {
-  case ConfigVariableCore::VT_undefined:
-    return out << "undefined";
-
-  case ConfigVariableCore::VT_list:
-    return out << "list";
-
-  case ConfigVariableCore::VT_string:
-    return out << "string";
-
-  case ConfigVariableCore::VT_bool:
-    return out << "bool";
-
-  case ConfigVariableCore::VT_int:
-    return out << "int";
-
-  case ConfigVariableCore::VT_double:
-    return out << "double";
-  }
-
-  return out << "**invalid(" << (int)type << ")**";
-}

+ 12 - 17
dtool/src/prc/configVariableCore.h

@@ -20,7 +20,9 @@
 #define CONFIGVARIABLECORE_H
 
 #include "dtoolbase.h"
+#include "configFlags.h"
 #include "configPageManager.h"
+#include "notify.h"
 #include "pvector.h"
 #include "pmap.h"
 
@@ -37,34 +39,26 @@ class ConfigDeclaration;
 //               return a shared instance.  Once created, these
 //               objects are never destructed.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_DTOOLCONFIG ConfigVariableCore {
+class EXPCL_DTOOLCONFIG ConfigVariableCore : public ConfigFlags {
 private:
   ConfigVariableCore(const string &name);
   ~ConfigVariableCore();
 
 public:
-  enum ValueType {
-    VT_undefined,
-    VT_list,
-    VT_string,
-    VT_bool,
-    VT_int,
-    VT_double,
-  };
-
   INLINE const string &get_name() const;
   INLINE bool is_used() const;
 
   INLINE ValueType get_value_type() const;
+  INLINE int get_flags() const;
+  INLINE bool is_closed() const;
   INLINE int get_trust_level() const;
+  INLINE bool is_dynamic() const;
   INLINE const string &get_description() const;
-  INLINE const string &get_text() const;
   INLINE const ConfigDeclaration *get_default_value() const;
 
   void set_value_type(ValueType value_type);
-  void set_trust_level(int trust_level);
+  void set_flags(int flags);
   void set_description(const string &description);
-  void set_text(const string &text);
   void set_default_value(const string &default_value);
   INLINE void set_used();
 
@@ -72,9 +66,12 @@ public:
   bool clear_local_value();
   INLINE bool has_local_value() const;
 
+  bool has_value() const;
   int get_num_declarations() const;
   const ConfigDeclaration *get_declaration(int n) const;
 
+  INLINE int get_value_seq() const;
+
   INLINE int get_num_references() const;
   INLINE const ConfigDeclaration *get_reference(int n) const;
 
@@ -98,9 +95,8 @@ private:
   string _name;
   bool _is_used;
   ValueType _value_type;
-  int _trust_level;
+  int _flags;
   string _description;
-  string _text;
   ConfigDeclaration *_default_value;
   ConfigDeclaration *_local_value;
 
@@ -111,6 +107,7 @@ private:
   Declarations _unique_declarations;
   bool _declarations_sorted;
   bool _value_queried;
+  int _value_seq;
 
   friend class ConfigDeclaration;
   friend class ConfigVariableManager;
@@ -118,8 +115,6 @@ private:
 
 INLINE ostream &operator << (ostream &out, const ConfigVariableCore &variable);
 
-ostream &operator << (ostream &out, ConfigVariableCore::ValueType type);
-
 #include "configVariableCore.I"
 
 #endif

+ 1 - 1
dtool/src/prc/configVariableDouble.I

@@ -24,7 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariableDouble::
 ConfigVariableDouble(const string &name) :
-  ConfigVariable(name, ConfigVariableCore::VT_double)
+  ConfigVariable(name, VT_double)
 {
   _core->set_used();
 }

+ 3 - 4
dtool/src/prc/configVariableDouble.cxx

@@ -24,10 +24,9 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ConfigVariableDouble::
-ConfigVariableDouble(const string &name, double default_value, int trust_level,
-                     const string &description, const string &text) :
-  ConfigVariable(name, ConfigVariableCore::VT_double, trust_level, 
-                 description, text)
+ConfigVariableDouble(const string &name, double default_value, int flags,
+                     const string &description) :
+  ConfigVariable(name, ConfigVariableCore::VT_double, flags, description)
 {
   ostringstream strm;
   strm << default_value;

+ 2 - 3
dtool/src/prc/configVariableDouble.h

@@ -31,9 +31,8 @@ class EXPCL_DTOOLCONFIG ConfigVariableDouble : public ConfigVariable {
 PUBLISHED:
   INLINE ConfigVariableDouble(const string &name);
   ConfigVariableDouble(const string &name, double default_value,
-                       int trust_level = -2,
-                       const string &description = string(),
-                       const string &text = string());
+                       int flags = 0,
+                       const string &description = string());
 
   INLINE void operator = (double value);
   INLINE operator double () const;

+ 188 - 0
dtool/src/prc/configVariableEnum.I

@@ -0,0 +1,188 @@
+// Filename: configVariableEnum.I
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE ConfigVariableEnum<EnumType>::
+ConfigVariableEnum(const string &name, ParseFunc *func,
+                   EnumType default_value, int flags,
+                   const string &description) :
+  ConfigVariable(name, ConfigVariableCore::VT_enum, flags, description),
+  _func(func),
+  _value_seq(-1),
+  _value(default_value),
+  _got_default_value(true),
+  _default_value(default_value)
+{
+  _core->set_default_value(format_enum(default_value));
+  _core->set_used();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::Destructor
+//       Access: Public
+//  Description: 
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE ConfigVariableEnum<EnumType>::
+~ConfigVariableEnum() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::operator =
+//       Access: Public
+//  Description: Reassigns the variable's local value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE void ConfigVariableEnum<EnumType>::
+operator = (EnumType value) {
+  set_value(value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::typecast operator
+//       Access: Public
+//  Description: Returns the variable's value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE ConfigVariableEnum<EnumType>::
+operator EnumType () const {
+  return get_value();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::size()
+//       Access: Public
+//  Description: Returns the number of unique words in the variable.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE int ConfigVariableEnum<EnumType>::
+size() const {
+  return get_num_words();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::operator []
+//       Access: Public
+//  Description: Returns the value of the variable's nth word.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE EnumType ConfigVariableEnum<EnumType>::
+operator [] (int n) const {
+  return get_word(n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::set_value
+//       Access: Public
+//  Description: Reassigns the variable's local value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE void ConfigVariableEnum<EnumType>::
+set_value(EnumType value) {
+  set_string_value(format_enum(value));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::get_value
+//       Access: Public
+//  Description: Returns the variable's value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE EnumType ConfigVariableEnum<EnumType>::
+get_value() const {
+  if (_value_seq != _core->get_value_seq()) {
+    ((ConfigVariableEnum<EnumType> *)this)->_value = (EnumType)parse_string(get_string_value());
+    ((ConfigVariableEnum<EnumType> *)this)->_value_seq = _core->get_value_seq();
+  }
+  return _value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::get_default_value
+//       Access: Public
+//  Description: Returns the variable's default value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE EnumType ConfigVariableEnum<EnumType>::
+get_default_value() const {
+  if (!_got_default_value) {
+    const ConfigDeclaration *decl = ConfigVariable::get_default_value();
+    if (decl != (ConfigDeclaration *)NULL) {
+      ((ConfigVariableEnum<EnumType> *)this)->_default_value = (EnumType)parse_string(decl->get_string_value());
+      ((ConfigVariableEnum<EnumType> *)this)->_got_default_value = true;
+    }
+  }
+  return _default_value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::get_word
+//       Access: Public
+//  Description: Returns the variable's nth value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE EnumType ConfigVariableEnum<EnumType>::
+get_word(int n) const {
+  return (EnumType)parse_string(get_string_word(n));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::set_word
+//       Access: Public
+//  Description: Reassigns the variable's nth value.  This makes a
+//               local copy of the variable's overall value.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE void ConfigVariableEnum<EnumType>::
+set_word(int n, EnumType value) {
+  set_string_word(n, format_enum(value));
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::parse_string
+//       Access: Public, Virtual
+//  Description: Turns the string value into a value of the enumerated
+//               type by calling the parse function.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE EnumType ConfigVariableEnum<EnumType>::
+parse_string(const string &value) const {
+  return (*_func)(value);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableEnum::format_enum
+//       Access: Public, Virtual
+//  Description: The format_enum() method assumes the enumerated type
+//               has a valid operator << (ostream) defined, which
+//               balances against the parse function passed to the
+//               constructor.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+INLINE string ConfigVariableEnum<EnumType>::
+format_enum(EnumType value) const {
+  ostringstream strm;
+  strm << value;
+  return strm.str();
+}

+ 19 - 0
dtool/src/prc/configVariableEnum.cxx

@@ -0,0 +1,19 @@
+// Filename: configVariableEnum.cxx
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "configVariableEnum.h"

+ 79 - 0
dtool/src/prc/configVariableEnum.h

@@ -0,0 +1,79 @@
+// Filename: configVariableEnum.h
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIGVARIABLEENUM_H
+#define CONFIGVARIABLEENUM_H
+
+#include "dtoolbase.h"
+#include "configVariable.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConfigVariableEnum
+// Description : This class specializes ConfigVariable as an
+//               enumerated type.  It is a template class, so it
+//               cannot be easily published; it's not really necessary
+//               outside of C++ anyway.
+//
+//               This variable assumes that the enumerated type in
+//               question has an output operator defined that does the
+//               right thing (outputting a sensible string for the
+//               type).  It also requires a function that converts
+//               from the strings written by the output operator back
+//               to the type; this function pointer should be passed
+//               to the constructor.
+////////////////////////////////////////////////////////////////////
+template<class EnumType>
+class ConfigVariableEnum : public ConfigVariable {
+public:
+  typedef EnumType ParseFunc(const string &value);
+
+  ConfigVariableEnum(const string &name, ParseFunc *func,
+                     EnumType default_value, int flags = 0,
+                     const string &description = string());
+  INLINE ~ConfigVariableEnum();
+
+  INLINE void operator = (EnumType value);
+  INLINE operator EnumType () const;
+
+  INLINE int size() const;
+  INLINE EnumType operator [] (int n) const;
+
+  INLINE void set_value(EnumType value);
+  INLINE EnumType get_value() const;
+  INLINE EnumType get_default_value() const;
+
+  INLINE EnumType get_word(int n) const;
+  INLINE void set_word(int n, EnumType value);
+
+private:
+  INLINE EnumType parse_string(const string &value) const;
+  INLINE string format_enum(EnumType value) const;
+
+  ParseFunc *_func;
+
+  int _value_seq;
+  EnumType _value;
+
+  bool _got_default_value;
+  EnumType _default_value;
+};
+
+#include "configVariableEnum.I"
+
+#endif
+

+ 1 - 1
dtool/src/prc/configVariableInt.I

@@ -24,7 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariableInt::
 ConfigVariableInt(const string &name) :
-  ConfigVariable(name, ConfigVariableCore::VT_int)
+  ConfigVariable(name, VT_int)
 {
   _core->set_used();
 }

+ 3 - 4
dtool/src/prc/configVariableInt.cxx

@@ -24,10 +24,9 @@
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 ConfigVariableInt::
-ConfigVariableInt(const string &name, int default_value, int trust_level,
-                  const string &description, const string &text) :
-  ConfigVariable(name, ConfigVariableCore::VT_int, trust_level, 
-                 description, text)
+ConfigVariableInt(const string &name, int default_value, int flags,
+                  const string &description) :
+  ConfigVariable(name, ConfigVariableCore::VT_int, flags, description)
 {
   ostringstream strm;
   strm << default_value;

+ 2 - 3
dtool/src/prc/configVariableInt.h

@@ -31,9 +31,8 @@ class EXPCL_DTOOLCONFIG ConfigVariableInt : public ConfigVariable {
 PUBLISHED:
   INLINE ConfigVariableInt(const string &name);
   ConfigVariableInt(const string &name, int default_value,
-                    int trust_level = -2,
-                    const string &description = string(),
-                    const string &text = string());
+                    int flags = 0,
+                    const string &description = string());
 
   INLINE void operator = (int value);
   INLINE operator int () const;

+ 0 - 90
dtool/src/prc/configVariableList.I

@@ -26,70 +26,6 @@ INLINE ConfigVariableList::
 ~ConfigVariableList() {
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::get_name
-//       Access: Published
-//  Description: Returns the name of the variable.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariableList::
-get_name() const {
-  return _core->get_name();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::get_value_type
-//       Access: Published
-//  Description: Returns the stated type of this variable.  This
-//               should be VT_list, unless a later variable
-//               declaration has changed it.
-////////////////////////////////////////////////////////////////////
-INLINE ConfigVariableCore::ValueType ConfigVariableList::
-get_value_type() const {
-  return _core->get_value_type();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::get_trust_level
-//       Access: Published
-//  Description: Returns the minimum trust_level a prc file must
-//               demonstrate in order to redefine the value for this
-//               variable.  -1 indicates infinite trust: no prc file
-//               can redefine it.  Arguably, this should be called the
-//               "mistrust level", since the larger the value, the
-//               more suspicious we are of prc files.
-//
-//               This value only has effect in a release build.
-////////////////////////////////////////////////////////////////////
-INLINE int ConfigVariableList::
-get_trust_level() const {
-  return _core->get_trust_level();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::get_description
-//       Access: Published
-//  Description: Returns the one-line description of this variable.
-//               If the variable has not yet been defined, this will
-//               be empty.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariableList::
-get_description() const {
-  return _core->get_description();
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::get_text
-//       Access: Published
-//  Description: Returns the paragraph help text describing the
-//               purpose of this variable in greater detail than
-//               get_description().  If the variable has not yet been
-//               defined, this will be empty.
-////////////////////////////////////////////////////////////////////
-INLINE const string &ConfigVariableList::
-get_text() const {
-  return _core->get_text();
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableList::get_num_values
 //       Access: Published
@@ -160,29 +96,3 @@ INLINE string ConfigVariableList::
 operator [] (int n) const {
   return get_unique_value(n);
 }
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::output
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void ConfigVariableList::
-output(ostream &out) const {
-  _core->output(out);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableList::write
-//       Access: Published
-//  Description: 
-////////////////////////////////////////////////////////////////////
-INLINE void ConfigVariableList::
-write(ostream &out) const {
-  _core->write(out);
-}
-
-INLINE ostream &
-operator << (ostream &out, const ConfigVariableList &variable) {
-  variable.output(out);
-  return out;
-}

+ 2 - 14
dtool/src/prc/configVariableList.cxx

@@ -25,21 +25,9 @@
 ////////////////////////////////////////////////////////////////////
 ConfigVariableList::
 ConfigVariableList(const string &name, 
-                   int trust_level, const string &description, 
-                   const string &text) :
-  _core(ConfigVariableManager::get_global_ptr()->make_variable(name))
+                   int flags, const string &description) :
+  ConfigVariableBase(name, VT_list, flags, description)
 {
-  _core->set_value_type(ConfigVariableCore::VT_list);
-  if (trust_level > -2) {
-    _core->set_trust_level(trust_level);
-  }
-  if (!description.empty()) {
-    _core->set_description(description);
-  }
-  if (!text.empty()) {
-    _core->set_text(text);
-  }
-
   // A list variable implicitly defines a default value of the empty
   // string.  This is just to prevent the core variable from
   // complaining should anyone ask for its solitary value.

+ 4 - 24
dtool/src/prc/configVariableList.h

@@ -20,10 +20,7 @@
 #define CONFIGVARIABLELIST_H
 
 #include "dtoolbase.h"
-#include "configVariableCore.h"
-#include "configDeclaration.h"
-#include "configVariableManager.h"
-#include "vector_string.h"
+#include "configVariableBase.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ConfigVariableList
@@ -39,20 +36,12 @@
 //
 //               A ConfigVariableList cannot be modified locally.
 ////////////////////////////////////////////////////////////////////
-class EXPCL_DTOOLCONFIG ConfigVariableList {
+class EXPCL_DTOOLCONFIG ConfigVariableList : public ConfigVariableBase {
 PUBLISHED:
-  ConfigVariableList(const string &name, int trust_level = -2,
-                     const string &description = string(),
-                     const string &text = string());
+  ConfigVariableList(const string &name, int flags = 0,
+                     const string &description = string());
   INLINE ~ConfigVariableList();
 
-  INLINE const string &get_name() const;
-
-  INLINE ConfigVariableCore::ValueType get_value_type() const;
-  INLINE int get_trust_level() const;
-  INLINE const string &get_description() const;
-  INLINE const string &get_text() const;
-
   INLINE int get_num_values() const;
   INLINE string get_string_value(int n) const;
 
@@ -61,17 +50,8 @@ PUBLISHED:
 
   INLINE int size() const;
   INLINE string operator [] (int n) const;
-  
-  INLINE void output(ostream &out) const;
-  INLINE void write(ostream &out) const;
-
-protected:
-  ConfigVariableCore *_core;
-  vector_string _unique_values;
 };
 
-INLINE ostream &operator << (ostream &out, const ConfigVariableList &variable);
-
 #include "configVariableList.I"
 
 #endif

+ 72 - 70
dtool/src/prc/configVariableManager.cxx

@@ -123,16 +123,18 @@ write(ostream &out) const {
        ni != _variables_by_name.end();
        ++ni) {
     ConfigVariableCore *variable = (*ni).second;
-    out << "  " << variable->get_name();
-    if (!variable->is_used()) {
-      out << "  (not used)";
-    } else {
-      out << " " << variable->get_declaration(0)->get_string_value();
+    if (!variable->is_dynamic()) {
+      out << "  " << variable->get_name();
+      if (!variable->is_used()) {
+        out << "  (not used)";
+      } else {
+        out << " " << variable->get_declaration(0)->get_string_value();
+      }
+      out << "\n";
     }
-    out << "\n";
   }
 }
-
+  
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableManager::list_unused_variables
 //       Access: Published
@@ -148,10 +150,10 @@ list_unused_variables() const {
        ++ni) {
     ConfigVariableCore *variable = (*ni).second;
     if (!variable->is_used()) {
-      cout << variable->get_name() << "\n";
+      nout << variable->get_name() << "\n";
       int num_references = variable->get_num_references();
       for (int i = 0; i < num_references; i++) {
-        cout << "  " << variable->get_reference(i)->get_page()->get_name()
+        nout << "  " << variable->get_reference(i)->get_page()->get_name()
              << "\n";
       }
     }
@@ -171,79 +173,31 @@ list_variables() const {
   for (ni = _variables_by_name.begin();
        ni != _variables_by_name.end();
        ++ni) {
-    ConfigVariableCore *variable = (*ni).second;
-    if (variable->is_used()) {
-      
-      cout << variable->get_name() << " " 
-           << variable->get_value_type() << "\n";
-
-      const ConfigDeclaration *decl;
-
-      if (variable->get_value_type() == ConfigVariableCore::VT_list) {
-        // We treat a "list" variable as a special case: list all of
-        // its values.
-        cout << "  current value =\n";
-        int num_references = variable->get_num_trusted_references();
-        for (int i = 0; i < num_references; i++) {
-          decl = variable->get_trusted_reference(i);
-          cout << "    " << decl->get_string_value()
-               << "  (from " << decl->get_page()->get_name() << ")\n";
-        }
-        
-      } else {
-        // An ordinary, non-list variable gets one line for its
-        // current value (if it has one) and another line for its
-        // default value.
-        decl = variable->get_declaration(0);
-        if (decl != variable->get_default_value()) {
-          cout << "  current value = " << decl->get_string_value();
-          if (!decl->get_page()->is_special()) {
-            cout << "  (from " << decl->get_page()->get_name() << ")\n";
-          } else {
-            cout << "  (defined locally)\n";
-          }
-        }
-
-        decl = variable->get_default_value();
-        if (decl != (ConfigDeclaration *)NULL) {
-          cout << "  default value = " << decl->get_string_value() << "\n";
-        }
-      }
-
-      if (!variable->get_description().empty()) {
-        cout << "  " << variable->get_description() << "\n";
-      }
+    const ConfigVariableCore *variable = (*ni).second;
+    if (variable->is_used() && !variable->is_dynamic()) {
+      list_variable(variable);
     }
   }
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableManager::describe_variables
+//     Function: ConfigVariableManager::list_dynamic_variables
 //       Access: Published
-//  Description: Writes a list of all the variables along with each
-//               variable's long description.
+//  Description: Writes a list of all the "dynamic" variables that
+//               have been declared somewhere in code, along with a
+//               brief description.  This is a (usually large) list of
+//               config variables that are declared with a generated
+//               variable name.
 ////////////////////////////////////////////////////////////////////
 void ConfigVariableManager::
-describe_variables() const {
+list_dynamic_variables() const {
   VariablesByName::const_iterator ni;
   for (ni = _variables_by_name.begin();
        ni != _variables_by_name.end();
        ++ni) {
-    ConfigVariableCore *variable = (*ni).second;
-    if (variable->is_used()) {
-      cout << variable->get_name() << " "
-           << variable->get_value_type() << "\n";
-
-      const ConfigDeclaration *decl = variable->get_default_value();
-      if (decl != (ConfigDeclaration *)NULL) {
-        cout << "  default value = " << decl->get_string_value() << "\n";
-      }
-
-      if (!variable->get_text().empty()) {
-        cout << "  " << variable->get_text() << "\n";
-      } else if (!variable->get_description().empty()) {
-        cout << "  " << variable->get_description() << "\n";
-      }
+    const ConfigVariableCore *variable = (*ni).second;
+    if (variable->is_used() && variable->is_dynamic()) {
+      list_variable(variable);
     }
   }
 }
@@ -260,3 +214,51 @@ get_global_ptr() {
   }
   return _global_ptr;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableManager::list_variable
+//       Access: Private
+//  Description: Lists a single variable and its value.
+////////////////////////////////////////////////////////////////////
+void ConfigVariableManager::
+list_variable(const ConfigVariableCore *variable) const {
+  nout << variable->get_name() << " " 
+       << variable->get_value_type() << "\n";
+
+  const ConfigDeclaration *decl;
+  
+  if (variable->get_value_type() == ConfigVariableCore::VT_list) {
+    // We treat a "list" variable as a special case: list all of
+    // its values.
+    nout << "  current value =\n";
+    int num_references = variable->get_num_trusted_references();
+    for (int i = 0; i < num_references; i++) {
+      decl = variable->get_trusted_reference(i);
+      nout << "    " << decl->get_string_value()
+           << "  (from " << decl->get_page()->get_name() << ")\n";
+    }
+    
+  } else {
+    // An ordinary, non-list variable gets one line for its
+    // current value (if it has one) and another line for its
+    // default value.
+    decl = variable->get_declaration(0);
+    if (decl != variable->get_default_value()) {
+      nout << "  current value = " << decl->get_string_value();
+      if (!decl->get_page()->is_special()) {
+        nout << "  (from " << decl->get_page()->get_name() << ")\n";
+      } else {
+        nout << "  (defined locally)\n";
+      }
+    }
+    
+    decl = variable->get_default_value();
+    if (decl != (ConfigDeclaration *)NULL) {
+      nout << "  default value = " << decl->get_string_value() << "\n";
+    }
+  }
+  
+  if (!variable->get_description().empty()) {
+    nout << "  " << variable->get_description() << "\n";
+  }
+}

+ 3 - 1
dtool/src/prc/configVariableManager.h

@@ -50,11 +50,13 @@ PUBLISHED:
 
   void list_unused_variables() const;
   void list_variables() const;
-  void describe_variables() const;
+  void list_dynamic_variables() const;
 
   static ConfigVariableManager *get_global_ptr();
 
 private:
+  void list_variable(const ConfigVariableCore *variable) const;
+
   typedef pvector<ConfigVariableCore *> Variables;
   Variables _variables;
 

+ 214 - 0
dtool/src/prc/configVariableSearchPath.I

@@ -0,0 +1,214 @@
+// Filename: configVariableSearchPath.I
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::Destructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariableSearchPath::
+~ConfigVariableSearchPath() {
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::DSearchPath typecast
+//       Access: Published
+//  Description: Returns the variable's value.
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariableSearchPath::
+operator const DSearchPath & () const {
+  return get_value();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::clear_local_value
+//       Access: Published
+//  Description: Removes all the directories locally added to the
+//               search list, and restores it to its original form.
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableSearchPath::
+clear_local_value() {
+  bool any_to_clear = !_prefix.is_empty() || _postfix.is_empty();
+  _prefix.clear();
+  _postfix.clear();
+  
+  if (_core->clear_local_value()) {
+    any_to_clear = true;
+  }
+
+  _value_stale = true;
+  return any_to_clear;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::clear
+//       Access: Published
+//  Description: Removes all the directories locally added to the
+//               search list, and restores it to its original form.
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+clear() {
+  clear_local_value();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::append_directory
+//       Access: Published
+//  Description: Adds a new directory to the end of the search list.
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+append_directory(const Filename &directory) {
+  _postfix.append_directory(directory);
+  _value_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::prepend_directory
+//       Access: Published
+//  Description: Adds a new directory to the front of the search list.
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+prepend_directory(const Filename &directory) {
+  _prefix.prepend_directory(directory);
+  _value_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::append_path
+//       Access: Published
+//  Description: Adds all of the directories listed in the search path
+//               to the end of the search list.
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+append_path(const string &path, const string &separator) {
+  _postfix.append_path(path, separator);
+  _value_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::append_path
+//       Access: Published
+//  Description: Adds all of the directories listed in the search path
+//               to the end of the search list.
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+append_path(const DSearchPath &path) {
+  _postfix.append_path(path);
+  _value_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::prepend_path
+//       Access: Published
+//  Description: Adds all of the directories listed in the search path
+//               to the beginning of the search list.
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+prepend_path(const DSearchPath &path) {
+  _prefix.prepend_path(path);
+  _value_stale = true;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::is_empty
+//       Access: Published
+//  Description: Returns true if the search list is empty, false
+//               otherwise.
+////////////////////////////////////////////////////////////////////
+INLINE bool ConfigVariableSearchPath::
+is_empty() const {
+  return get_value().is_empty();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::get_num_directories
+//       Access: Published
+//  Description: Returns the number of directories on the search list.
+////////////////////////////////////////////////////////////////////
+INLINE int ConfigVariableSearchPath::
+get_num_directories() const {
+  return get_value().get_num_directories();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::get_directory
+//       Access: Published
+//  Description: Returns the nth directory on the search list.
+////////////////////////////////////////////////////////////////////
+INLINE const Filename &ConfigVariableSearchPath::
+get_directory(int n) const {
+  return get_value().get_directory(n);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::find_file
+//       Access: Published
+//  Description: Searches all the directories in the search list for
+//               the indicated file, in order.  Returns the full
+//               matching pathname of the first match if found, or the
+//               empty string if not found.
+////////////////////////////////////////////////////////////////////
+INLINE Filename ConfigVariableSearchPath::
+find_file(const Filename &filename) const {
+  return get_value().find_file(filename);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::find_all_files
+//       Access: Published
+//  Description: Searches all the directories in the search list for
+//               the indicated file, in order.  Fills up the results
+//               list with *all* of the matching filenames found, if
+//               any.  Returns the number of matches found.
+//
+//               It is the responsibility of the the caller to clear
+//               the results list first; otherwise, the newly-found
+//               files will be appended to the list.
+////////////////////////////////////////////////////////////////////
+INLINE int ConfigVariableSearchPath::
+find_all_files(const Filename &filename,
+               DSearchPath::Results &results) const {
+  return get_value().find_all_files(filename, results);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::output
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+output(ostream &out) const {
+  get_value().output(out);
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::write
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+INLINE void ConfigVariableSearchPath::
+write(ostream &out) const {
+  get_value().write(out);
+}
+
+INLINE ostream &
+operator << (ostream &out, const ConfigVariableSearchPath &variable) {
+  variable.output(out);
+  return out;
+}

+ 74 - 0
dtool/src/prc/configVariableSearchPath.cxx

@@ -0,0 +1,74 @@
+// Filename: configVariableSearchPath.cxx
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#include "configVariableSearchPath.h"
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::Constructor
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+ConfigVariableSearchPath::
+ConfigVariableSearchPath(const string &name, 
+                   int flags, const string &description) :
+  ConfigVariableBase(name, VT_search_path, flags, description),
+  _value_seq(-1),
+  _value_stale(true)
+{
+  // A SearchPath variable implicitly defines a default value of the empty
+  // string.  This is just to prevent the core variable from
+  // complaining should anyone ask for its solitary value.
+  if (_core->get_default_value() == (ConfigDeclaration *)NULL) {
+    _core->set_default_value("");
+  }
+  _core->set_used();
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::get_value
+//       Access: Published
+//  Description: 
+////////////////////////////////////////////////////////////////////
+const DSearchPath &ConfigVariableSearchPath::
+get_value() const {
+  if (_value_stale || _value_seq != _core->get_value_seq()) {
+    ((ConfigVariableSearchPath *)this)->reload_search_path();
+  }
+  return _value;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableSearchPath::reload_search_path
+//       Access: Private
+//  Description: Recopies the config variable into the search path for
+//               returning its value.
+////////////////////////////////////////////////////////////////////
+void ConfigVariableSearchPath::
+reload_search_path() {
+  _value.clear();
+
+  _value.append_path(_prefix);
+  int num_declarations = _core->get_num_declarations();
+  for (int i = 0; i < num_declarations; i++) {
+    _value.append_directory(_core->get_declaration(i)->get_string_value());
+  }
+  _value.append_path(_postfix);
+
+  _value_seq = _core->get_value_seq();
+  _value_stale = false;
+}

+ 90 - 0
dtool/src/prc/configVariableSearchPath.h

@@ -0,0 +1,90 @@
+// Filename: configVariableSearchPath.h
+// Created by:  drose (21Oct04)
+//
+////////////////////////////////////////////////////////////////////
+//
+// PANDA 3D SOFTWARE
+// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
+//
+// All use of this software is subject to the terms of the Panda 3d
+// Software license.  You should have received a copy of this license
+// along with this source code; you will also find a current copy of
+// the license at http://etc.cmu.edu/panda3d/docs/license/ .
+//
+// To contact the maintainers of this program write to
+// [email protected] .
+//
+////////////////////////////////////////////////////////////////////
+
+#ifndef CONFIGVARIABLESEARCHPATH_H
+#define CONFIGVARIABLESEARCHPATH_H
+
+#include "dtoolbase.h"
+#include "configVariableBase.h"
+#include "dSearchPath.h"
+
+////////////////////////////////////////////////////////////////////
+//       Class : ConfigVariableSearchPath
+// Description : This is similar to a ConfigVariableList, but it
+//               returns its list as a DSearchPath, as a list of
+//               directories.
+//
+//               You may locally append directories to the end of the
+//               search path with the methods here, or prepend them to
+//               the beginning.  Use these methods to make adjustments
+//               to the path; do not attempt to directly modify the
+//               const DSearchPath object returned by get_value().
+//
+//               Unlike other ConfigVariable types, local changes
+//               (made by calling append_directory() and
+//               prepend_directory()) are specific to this particular
+//               instance of the ConfigVariableSearchPath.  A separate
+//               instance of the same variable, created by using the
+//               same name to the constructor, will not reflect the
+//               local changes.
+////////////////////////////////////////////////////////////////////
+class EXPCL_DTOOLCONFIG ConfigVariableSearchPath : public ConfigVariableBase {
+PUBLISHED:
+  ConfigVariableSearchPath(const string &name, int flags = 0,
+                           const string &description = string());
+  INLINE ~ConfigVariableSearchPath();
+
+  INLINE operator const DSearchPath & () const;
+  const DSearchPath &get_value() const;
+
+  INLINE bool clear_local_value();
+
+  INLINE void clear();
+  INLINE void append_directory(const Filename &directory);
+  INLINE void prepend_directory(const Filename &directory);
+  INLINE void append_path(const string &path,
+                          const string &separator = string());
+  INLINE void append_path(const DSearchPath &path);
+  INLINE void prepend_path(const DSearchPath &path);
+
+  INLINE bool is_empty() const;
+  INLINE int get_num_directories() const;
+  INLINE const Filename &get_directory(int n) const;
+
+  INLINE Filename find_file(const Filename &filename) const;
+  INLINE int find_all_files(const Filename &filename, 
+                            DSearchPath::Results &results) const;
+
+  INLINE void output(ostream &out) const;
+  INLINE void write(ostream &out) const;
+
+private:
+  void reload_search_path();
+
+  int _value_seq;
+  bool _value_stale;
+
+  DSearchPath _value;
+  DSearchPath _prefix, _postfix;
+};
+
+INLINE ostream &operator << (ostream &out, const ConfigVariableSearchPath &variable);
+
+#include "configVariableSearchPath.I"
+
+#endif

+ 18 - 6
dtool/src/prc/configVariableString.I

@@ -24,7 +24,7 @@
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariableString::
 ConfigVariableString(const string &name) :
-  ConfigVariable(name, ConfigVariableCore::VT_string)
+  ConfigVariable(name, VT_string)
 {
   _core->set_used();
 }
@@ -35,10 +35,9 @@ ConfigVariableString(const string &name) :
 //  Description: 
 ////////////////////////////////////////////////////////////////////
 INLINE ConfigVariableString::
-ConfigVariableString(const string &name, string default_value, int trust_level,
-                     const string &description, const string &text) :
-  ConfigVariable(name, ConfigVariableCore::VT_string, trust_level, 
-                 description, text)
+ConfigVariableString(const string &name, string default_value, int flags,
+                     const string &description) :
+  ConfigVariable(name, VT_string, flags, description)
 {
   _core->set_default_value(default_value);
   _core->set_used();
@@ -55,7 +54,7 @@ operator = (const string &value) {
 }
 
 ////////////////////////////////////////////////////////////////////
-//     Function: ConfigVariableString::typecast operator
+//     Function: ConfigVariableString::string typecast operator
 //       Access: Published
 //  Description: Returns the variable's value.
 ////////////////////////////////////////////////////////////////////
@@ -64,6 +63,19 @@ operator string () const {
   return get_value();
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: ConfigVariableString::Filename typecast operator
+//       Access: Published
+//  Description: Returns the variable's value.  This typecast operator
+//               is a convenience in case you happen to want to assign
+//               a ConfigVariableString into a Filename; C++ won't
+//               make the implicit typecast for you.
+////////////////////////////////////////////////////////////////////
+INLINE ConfigVariableString::
+operator Filename () const {
+  return get_value();
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: ConfigVariableString::empty
 //       Access: Published

+ 4 - 3
dtool/src/prc/configVariableString.h

@@ -21,6 +21,7 @@
 
 #include "dtoolbase.h"
 #include "configVariable.h"
+#include "filename.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : ConfigVariableString
@@ -31,12 +32,12 @@ class EXPCL_DTOOLCONFIG ConfigVariableString : public ConfigVariable {
 PUBLISHED:
   INLINE ConfigVariableString(const string &name);
   INLINE ConfigVariableString(const string &name, string default_value,
-                              int trust_level = -2,
-                              const string &description = string(),
-                              const string &text = string());
+                              int flags = 0,
+                              const string &description = string());
 
   INLINE void operator = (const string &value);
   INLINE operator string () const;
+  INLINE operator Filename () const;
   INLINE bool empty() const;
 
   // Comparison operators are handy.

+ 0 - 41
dtool/src/prc/configVariableTempl.h

@@ -1,41 +0,0 @@
-// Filename: configVariableTempl.h
-// Created by:  drose (20Oct04)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef CONFIGVARIABLETEMPL_H
-#define CONFIGVARIABLETEMPL_H
-
-#include "dtoolbase.h"
-#include "configVariable.h"
-
-////////////////////////////////////////////////////////////////////
-//       Class : ConfigVariableTempl
-// Description : This is a template class to define ConfigVaribleInt,
-//               ConfigVariableBool, etc.
-////////////////////////////////////////////////////////////////////
-template<class ValueType, int EnumValue>
-class ConfigVariableTempl {
-PUBLISHED:
-  INLINE ConfigVariableTempl(const string &name);
-  INLINE ConfigVariableTempl(const string &name, ValueType default_value,
-                             int trust_level = -1,
-                             const string &description = string(),
-                             const string &text = string());
-
-  INLINE operator ValueType () const;
-  INLINE void operator = (const ValueType &value);
-

+ 2 - 1
dtool/src/prc/notify.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "notify.h"
+#include "notifyCategory.h"
 #include "configPageManager.h"
 #include "configVariableString.h"
 #include "configVariableBool.h"
@@ -539,7 +540,7 @@ config_initialized() {
         set_ostream_ptr(&cerr, false);
 
       } else {
-        Filename filename = notify_output.get_value();
+        Filename filename = notify_output;
         filename.set_text();
         ofstream *out = new ofstream;
         if (!filename.open_write(*out)) {

+ 2 - 1
dtool/src/prc/notify.h

@@ -21,13 +21,14 @@
 
 #include "dtoolbase.h"
 
-#include "notifyCategory.h"
 #include "notifySeverity.h"
 
 #include <string>
 #include <vector>
 #include <map>
 
+class NotifyCategory;
+
 ////////////////////////////////////////////////////////////////////
 //       Class : Notify
 // Description : An object that handles general error reporting to the

+ 1 - 11
dtool/src/prc/notifyCategory.I

@@ -37,16 +37,6 @@ get_basename() const {
   return _basename;
 }
 
-////////////////////////////////////////////////////////////////////
-//     Function: NotifyCategory::get_severity
-//       Access: Public
-//  Description:
-////////////////////////////////////////////////////////////////////
-INLINE NotifySeverity NotifyCategory::
-get_severity() const {
-  return _severity;
-}
-
 ////////////////////////////////////////////////////////////////////
 //     Function: NotifyCategory::set_severity
 //       Access: Public
@@ -67,7 +57,7 @@ set_severity(NotifySeverity severity) {
 ////////////////////////////////////////////////////////////////////
 INLINE bool NotifyCategory::
 is_on(NotifySeverity severity) const {
-  return (int)severity >= (int)_severity;
+  return (int)severity >= (int)get_severity();
 }
 
 #if defined(NOTIFY_DEBUG) || defined(CPPPARSER)

+ 41 - 35
dtool/src/prc/notifyCategory.cxx

@@ -41,54 +41,41 @@ NotifyCategory(const string &fullname, const string &basename,
                NotifyCategory *parent) :
   _fullname(fullname),
   _basename(basename),
-  _parent(parent)
+  _parent(parent),
+  _severity(get_config_name(), Notify::string_severity, NS_unspecified,
+            ConfigVariable::F_dynamic)
 {
   if (_parent != (NotifyCategory *)NULL) {
     _parent->_children.push_back(this);
   }
 
-  _severity = NS_unspecified;
-
-  // See if there's a config option to set the severity level for this
-  // Category.
-
-  string config_name;
-
-  if (_fullname.empty()) {
-    config_name = "notify-level";
-  } else if (!_basename.empty()) {
-    config_name = "notify-level-" + _basename;
-  }
-
-  if (!config_name.empty()) {
-    ConfigVariableString severity_name
-      (config_name, "", 0,
-       "Indicates the verbosity level of notify messages for the given category.");
-    if (!severity_name.empty()) {
-      // The user specified a particular severity for this category at
-      // config time.  Use it.
-      _severity = Notify::string_severity(severity_name);
-      
-      if (_severity == NS_unspecified) {
-        nout << "Invalid severity name for " << config_name << ": "
-             << severity_name << "\n";
-      }
-    }
-  }
+  // Only the unnamed top category is allowed not to have a parent.
+  nassertv(_parent != (NotifyCategory *)NULL || _fullname.empty());
+}
 
+////////////////////////////////////////////////////////////////////
+//     Function: NotifyCategory::get_severity
+//       Access: Public
+//  Description:
+////////////////////////////////////////////////////////////////////
+NotifySeverity NotifyCategory::
+get_severity() const {
   if (_severity == NS_unspecified) {
-    // If we didn't get an explicit severity level, inherit our
+    // If we don't have an explicit severity level, inherit our
     // parent's.
+    if (_severity.has_value()) {
+      nout << "Invalid severity name for " << _severity.get_name() << ": "
+           << _severity.get_string_value() << "\n";
+    }
     if (_parent != (NotifyCategory *)NULL) {
-      _severity = _parent->_severity;
+      return _parent->get_severity();
+
     } else {
       // Unless, of course, we're the root.
-      _severity = NS_info;
+      return NS_info;
     }
   }
-
-  // Only the unnamed top category is allowed not to have a parent.
-  nassertv(_parent != (NotifyCategory *)NULL || _fullname.empty());
+  return _severity;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -163,3 +150,22 @@ void NotifyCategory::
 set_server_delta(time_t delta) {
   _server_delta = delta;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: NotifyCategory::get_config_name
+//       Access: Private
+//  Description: Returns the name of the config variable that controls
+//               this category.  This is called at construction time.
+////////////////////////////////////////////////////////////////////
+string NotifyCategory::
+get_config_name() const {
+  string config_name;
+
+  if (_fullname.empty()) {
+    config_name = "notify-level";
+  } else if (!_basename.empty()) {
+    config_name = "notify-level-" + _basename;
+  }
+
+  return config_name;
+}

+ 7 - 5
dtool/src/prc/notifyCategory.h

@@ -22,8 +22,8 @@
 #include "dtoolbase.h"
 
 #include "notifySeverity.h"
-
-#include <vector>
+#include "configVariableEnum.h"
+#include "pvector.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : NotifyCategory
@@ -42,7 +42,7 @@ private:
 PUBLISHED:
   INLINE string get_fullname() const;
   INLINE string get_basename() const;
-  INLINE NotifySeverity get_severity() const;
+  NotifySeverity get_severity() const;
   INLINE void set_severity(NotifySeverity severity);
 
   INLINE bool is_on(NotifySeverity severity) const;
@@ -79,11 +79,13 @@ PUBLISHED:
   static void set_server_delta(time_t delta);
 
 private:
+  string get_config_name() const;
+
   string _fullname;
   string _basename;
   NotifyCategory *_parent;
-  NotifySeverity _severity;
-  typedef vector<NotifyCategory *> Children;
+  ConfigVariableEnum<NotifySeverity> _severity;
+  typedef pvector<NotifyCategory *> Children;
   Children _children;
 
   static time_t _server_delta;

+ 5 - 7
dtool/src/prc/prcKeyRegistry.cxx

@@ -17,6 +17,7 @@
 ////////////////////////////////////////////////////////////////////
 
 #include "prcKeyRegistry.h"
+#include "config_prc.h"
 
 // This file requires OpenSSL to compile, because we use routines in
 // the OpenSSL library to manage keys and to sign and validate
@@ -45,7 +46,8 @@ PrcKeyRegistry() {
 ////////////////////////////////////////////////////////////////////
 PrcKeyRegistry::
 ~PrcKeyRegistry() {
-  cerr << "Internal error--PrcKeyRegistry destructor called!\n";
+  prc_cat.error()
+    << "Internal error--PrcKeyRegistry destructor called!\n";
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -134,9 +136,7 @@ get_num_keys() const {
 ////////////////////////////////////////////////////////////////////
 EVP_PKEY *PrcKeyRegistry::
 get_key(int n) const {
-  if (n < 0 || n >= (int)_keys.size()) {
-    return NULL;
-  }
+  nassertr(n >= 0 && n < (int)_keys.size(), NULL);
 
   if (_keys[n]._def != (KeyDef *)NULL) {
     if (_keys[n]._pkey == (EVP_PKEY *)NULL) {
@@ -165,9 +165,7 @@ get_key(int n) const {
 ////////////////////////////////////////////////////////////////////
 time_t PrcKeyRegistry::
 get_generated_time(int n) const {
-  if (n < 0 || n >= (int)_keys.size()) {
-    return 0;
-  }
+  nassertr(n >= 0 && n < (int)_keys.size(), 0);
 
   return _keys[n]._generated_time;
 }

+ 1 - 1
dtool/src/prc/prcKeyRegistry.h

@@ -36,7 +36,7 @@
 //               verify the signature on a prc file.  The actual
 //               public keys themselves are generated by the
 //               make-prc-key utility; the output of this utility is a
-//               .c file which should be named by the
+//               .cxx file which should be named by the
 //               PRC_PUBLIC_KEYS_FILENAME variable in Config.pp.
 //
 //               This class requires the OpenSSL library.

+ 2 - 0
dtool/src/pystub/pystub.cxx

@@ -23,6 +23,7 @@ extern "C" {
   EXPCL_DTOOLCONFIG int PyErr_Occurred(...);
   EXPCL_DTOOLCONFIG int PyErr_SetString(...);
   EXPCL_DTOOLCONFIG int PyExc_TypeError(...);
+  EXPCL_DTOOLCONFIG int PyDict_GetItem(...);
   EXPCL_DTOOLCONFIG int PyFloat_AsDouble(...);
   EXPCL_DTOOLCONFIG int PyFloat_FromDouble(...);
   EXPCL_DTOOLCONFIG int PyFloat_Type(...);
@@ -70,6 +71,7 @@ int PyArg_ParseTuple(...) { return 0; }
 int PyErr_Occurred(...) { return 0; }
 int PyErr_SetString(...) { return 0; }
 int PyExc_TypeError(...) { return 0; }
+int PyDict_GetItem(...) { return 0; }
 int PyFloat_AsDouble(...) { return 0; }
 int PyFloat_FromDouble(...) { return 0; }
 int PyFloat_Type(...) { return 0; }

+ 9 - 3
dtool/src/test_interrogate/test_interrogate.cxx

@@ -26,7 +26,7 @@
 
 #include <stdlib.h>
 
-#ifndef HAVE_GETOPT_LONG_ONLY
+#ifndef HAVE_GETOPT
   #include "gnu_getopt.h"
 #else
   #ifdef HAVE_GETOPT_H
@@ -463,6 +463,8 @@ usage() {
     "files), and will not have any function pointers available.\n\n"
 
     "Options:\n\n"
+    "  -p [path]\n"
+    "      Specify the search path for *.in files.  This option may be repeated.\n"
     "  -f  Give a detailed report of each function in the database, including\n"
     "      synthesized functions like upcasts and downcasts.\n"
     "  -t  Give a detailed report of every type in the database, including types\n"
@@ -473,9 +475,9 @@ usage() {
 
 int
 main(int argc, char *argv[]) {
-  //  extern char *optarg;
+  extern char *optarg;
   extern int optind;
-  const char *optstr = "ftqh";
+  const char *optstr = "p:ftqh";
 
   bool all_functions = false;
   bool all_types = false;
@@ -484,6 +486,10 @@ main(int argc, char *argv[]) {
 
   while (flag != EOF) {
     switch (flag) {
+    case 'p':
+      interrogate_add_search_path(optarg);
+      break;
+
     case 'f':
       all_functions = true;
       break;

+ 2 - 0
panda/src/express/config_express.N

@@ -8,9 +8,11 @@ forcetype NotifySeverity
 forcetype ConfigExpress
 renametype ConfigExpress ConfigExpress
 
+forcetype ConfigFlags
 forcetype ConfigPage
 forcetype ConfigPageManager
 forcetype ConfigVariable
+forcetype ConfigVariableBase
 forcetype ConfigVariableBool
 forcetype ConfigVariableDouble
 forcetype ConfigVariableInt

+ 2 - 0
panda/src/express/config_express.h

@@ -27,9 +27,11 @@
 // We include these files to force them to be instrumented by
 // interrogate.
 #include "globPattern.h"
+#include "configFlags.h"
 #include "configPage.h"
 #include "configPageManager.h"
 #include "configVariable.h"
+#include "configVariableBase.h"
 #include "configVariableBool.h"
 #include "configVariableDouble.h"
 #include "configVariableInt.h"

+ 28 - 33
panda/src/pstatclient/pStatProperties.cxx

@@ -20,6 +20,10 @@
 #include "pStatCollectorDef.h"
 #include "pStatClient.h"
 #include "config_pstats.h"
+#include "configVariableBool.h"
+#include "configVariableDouble.h"
+#include "configVariableInt.h"
+#include "configVariableString.h"
 
 #include <ctype.h>
 
@@ -268,44 +272,35 @@ initialize_collector_def(PStatClient *client, PStatCollectorDef *def) {
     }
   }
 
-  if (!config_pstats.GetString("pstats-active-" + config_name, "").empty()) {
-    def->_is_active =
-      config_pstats.GetBool("pstats-active-" + config_name, true);
+  ConfigVariableBool pstats_active
+    ("pstats-active-" + config_name, true, ConfigVariable::F_dynamic);
+  ConfigVariableInt pstats_sort
+    ("pstats-sort-" + config_name, def->_sort, ConfigVariable::F_dynamic);
+  ConfigVariableDouble pstats_scale
+    ("pstats-scale-" + config_name, def->_suggested_scale, ConfigVariable::F_dynamic);
+  ConfigVariableString pstats_units
+    ("pstats-units-" + config_name, def->_level_units, ConfigVariable::F_dynamic);
+  ConfigVariableDouble pstats_factor
+    ("pstats-factor-" + config_name, 1.0, ConfigVariable::F_dynamic);
+  ConfigVariableDouble pstats_color
+    ("pstats-color-" + config_name, 0.0, ConfigVariable::F_dynamic);
+  
+  if (pstats_active.has_value()) {
+    def->_is_active = pstats_active;
     def->_active_explicitly_set = true;
   }
 
-  def->_sort =
-    config_pstats.GetInt("pstats-sort-" + config_name, def->_sort);
-  def->_suggested_scale =
-    config_pstats.GetFloat("pstats-scale-" + config_name, def->_suggested_scale);
-  def->_level_units =
-    config_pstats.GetString("pstats-units-" + config_name, def->_level_units);
-  def->_level_units =
-    config_pstats.GetString("pstats-units-" + config_name, def->_level_units);
-  if (!config_pstats.GetString("pstats-factor-" + config_name, "").empty()) {
-    def->_factor =
-      1.0/config_pstats.GetFloat("pstats-factor-" + config_name, 1.0);
+  def->_sort = pstats_sort;
+  def->_suggested_scale = pstats_scale;
+  def->_level_units = pstats_units;
+  if (pstats_factor.has_value()) {
+    def->_factor = pstats_factor;
   }
 
-  // Get and decode the color string.  We allow any three
-  // floating-point numbers, with any kind of non-digit characters
-  // between them.
-  string color_str =
-    config_pstats.GetString("pstats-color-" + config_name, "");
-  if (!color_str.empty()) {
-    const char *cstr = color_str.c_str();
-    const char *p = cstr;
-
-    int i = 0;
-    while (i < 3 && *p != '\0') {
-      while (*p != '\0' && !(isdigit(*p) || *p == '.')) {
-        p++;
-      }
-      char *q;
-      def->_suggested_color[i] = strtod(p, &q);
-      p = q;
-      i++;
-    }
+  if (pstats_color.has_value()) {
+    def->_suggested_color[0] = pstats_color[0];
+    def->_suggested_color[1] = pstats_color[1];
+    def->_suggested_color[2] = pstats_color[2];
   }
 }
 

+ 5 - 1
panda/src/putil/Sources.pp

@@ -34,6 +34,7 @@
     ioPtaDatagramFloat.h ioPtaDatagramInt.h \
     ioPtaDatagramShort.h keyboardButton.h lineStream.I \
     lineStream.h lineStreamBuf.I lineStreamBuf.h \
+    load_prc_file.h \
     modifierButtons.I modifierButtons.h mouseButton.h \
     mouseData.I mouseData.h nameUniquifier.I nameUniquifier.h \
     pipeline.h pipeline.I \
@@ -64,6 +65,7 @@
     globalPointerRegistry.cxx ioPtaDatagramFloat.cxx \
     ioPtaDatagramInt.cxx ioPtaDatagramShort.cxx \
     keyboardButton.cxx lineStream.cxx lineStreamBuf.cxx \
+    load_prc_file.cxx \
     modifierButtons.cxx mouseButton.cxx mouseData.cxx \
     nameUniquifier.cxx \
     pipeline.cxx \
@@ -101,7 +103,9 @@
     indirectCompareTo.h \
     ioPtaDatagramFloat.h ioPtaDatagramInt.h \
     ioPtaDatagramShort.h iterator_types.h keyboardButton.h lineStream.I \
-    lineStream.h lineStreamBuf.I lineStreamBuf.h modifierButtons.I \
+    lineStream.h lineStreamBuf.I lineStreamBuf.h \
+    load_prc_file.h \
+    modifierButtons.I \
     modifierButtons.h mouseButton.h mouseData.I mouseData.h \
     nameUniquifier.I nameUniquifier.h \
     pipeline.h pipeline.I \

+ 1 - 0
panda/src/putil/putil_composite1.cxx

@@ -21,6 +21,7 @@
 #include "keyboardButton.cxx"
 #include "lineStream.cxx"
 #include "lineStreamBuf.cxx"
+#include "load_prc_file.cxx"
 #include "modifierButtons.cxx"
 #include "mouseButton.cxx"
 #include "mouseData.cxx"