15 #include "configPageManager.h"
16 #include "configDeclaration.h"
17 #include "configVariableString.h"
18 #include "configPage.h"
19 #include "prcKeyRegistry.h"
20 #include "dSearchPath.h"
21 #include "executionEnvironment.h"
22 #include "config_prc.h"
24 #include "pandaSystem.h"
25 #include "textEncoder.h"
26 #include "stringDecoder.h"
29 #include "prc_parameters.h"
34 #ifdef PRC_PUBLIC_KEYS_INCLUDE
35 #include PRC_PUBLIC_KEYS_INCLUDE
54 _loaded_implicit =
false;
55 _currently_loading =
false;
58 #ifdef PRC_PUBLIC_KEYS_INCLUDE
60 PrcKeyRegistry::get_global_ptr()->record_keys(prc_pubkeys, num_prc_pubkeys);
61 #endif // PRC_PUBLIC_KEYS_INCLUDE
72 ~ConfigPageManager() {
74 <<
"Internal error--ConfigPageManager destructor called!\n";
88 if (_currently_loading) {
94 _currently_loading =
true;
98 for (pi = _implicit_pages.begin(); pi != _implicit_pages.end(); ++pi) {
101 _implicit_pages.clear();
105 _prc_patterns.clear();
107 string prc_patterns = PRC_PATTERNS;
108 if (!prc_patterns.empty()) {
109 vector_string pat_list;
111 _prc_patterns.reserve(pat_list.size());
112 for (
size_t i = 0; i < pat_list.size(); ++i) {
119 _prc_patterns.push_back(glob);
124 _prc_encrypted_patterns.clear();
126 string prc_encrypted_patterns = PRC_ENCRYPTED_PATTERNS;
127 if (!prc_encrypted_patterns.empty()) {
128 vector_string pat_list;
130 _prc_encrypted_patterns.reserve(pat_list.size());
131 for (
size_t i = 0; i < pat_list.size(); ++i) {
136 _prc_encrypted_patterns.push_back(glob);
141 _prc_executable_patterns.clear();
143 string prc_executable_patterns = PRC_EXECUTABLE_PATTERNS;
144 if (!prc_executable_patterns.empty()) {
145 vector_string pat_list;
147 _prc_executable_patterns.reserve(pat_list.size());
148 for (
size_t i = 0; i < pat_list.size(); ++i) {
153 _prc_executable_patterns.push_back(glob);
158 _search_path.
clear();
163 string prc_dir_envvars = PRC_DIR_ENVVARS;
164 if (!prc_dir_envvars.empty()) {
165 vector_string prc_dir_envvar_list;
167 for (
size_t i = 0; i < prc_dir_envvar_list.size(); ++i) {
169 if (!prc_dir.empty()) {
172 if (scan_auto_prc_dir(prc_dir_filename)) {
183 string prc_path_envvars = PRC_PATH_ENVVARS;
184 if (!prc_path_envvars.empty()) {
185 vector_string prc_path_envvar_list;
187 for (
size_t i = 0; i < prc_path_envvar_list.size(); ++i) {
190 while (p < path.length()) {
191 size_t q = path.find_first_of(DEFAULT_PATHSEP, p);
192 if (q == string::npos) {
197 if (scan_auto_prc_dir(prc_dir_filename)) {
213 string prc_path2_envvars = PRC_PATH2_ENVVARS;
214 if (!prc_path2_envvars.empty()) {
215 vector_string prc_path_envvar_list;
217 for (
size_t i = 0; i < prc_path_envvar_list.size(); ++i) {
220 while (p < path.length()) {
221 size_t q = path.find_first_of(
' ', p);
222 if (q == string::npos) {
225 Filename prc_dir_filename = path.substr(p, q - p);
226 if (scan_auto_prc_dir(prc_dir_filename)) {
237 string default_prc_dir = DEFAULT_PRC_DIR;
238 if (!default_prc_dir.empty()) {
240 Filename prc_dir_filename = default_prc_dir;
241 if (scan_auto_prc_dir(prc_dir_filename)) {
249 ConfigFiles config_files;
254 set<Filename> unique_dirnames;
263 if (unique_dirnames.insert(canonical).second) {
272 vector_string::reverse_iterator fi;
273 for (fi = files.rbegin(); fi != files.rend(); ++fi) {
275 Globs::const_iterator gi;
276 for (gi = _prc_patterns.begin();
277 gi != _prc_patterns.end();
279 if ((*gi).matches(*fi)) {
280 file_flags |= FF_read;
284 for (gi = _prc_encrypted_patterns.begin();
285 gi != _prc_encrypted_patterns.end();
287 if ((*gi).matches(*fi)) {
288 file_flags |= FF_read | FF_decrypt;
292 for (gi = _prc_executable_patterns.begin();
293 gi != _prc_executable_patterns.end();
295 if ((*gi).matches(*fi)) {
296 file_flags |= FF_execute;
300 if (file_flags != 0) {
302 file._file_flags = file_flags;
303 file._filename =
Filename(directory, (*fi));
304 config_files.push_back(file);
315 ConfigFiles::reverse_iterator ci;
317 for (ci = config_files.rbegin(); ci != config_files.rend(); ++ci) {
318 const ConfigFile &file = (*ci);
321 if ((file._file_flags & FF_execute) != 0 &&
326 string envvar = PRC_EXECUTABLE_ARGS_ENVVAR;
327 if (!envvar.empty()) {
338 _implicit_pages.push_back(page);
339 _pages_sorted =
false;
343 }
else if ((file._file_flags & FF_decrypt) != 0) {
350 <<
"Unable to read " << filename <<
"\n";
354 _implicit_pages.push_back(page);
355 _pages_sorted =
false;
360 }
else if ((file._file_flags & FF_read) != 0) {
367 <<
"Unable to read " << filename <<
"\n";
371 _implicit_pages.push_back(page);
372 _pages_sorted =
false;
379 if (!_loaded_implicit) {
380 config_initialized();
381 _loaded_implicit =
true;
384 _currently_loading =
false;
387 #ifdef USE_PANDAFILESTREAM
391 (
"newline-mode", PandaFileStreamBuf::NM_native,
392 PRC_DESC(
"Controls how newlines are written by Panda applications writing "
393 "to a text file. The default, \"native\", means to write newlines "
394 "appropriate to the current platform. You may also specify \"binary\", "
395 "to avoid molesting the file data, or one of \"msdos\", \"unix\", "
397 PandaFileStreamBuf::_newline_mode = newline_mode;
398 #endif // USE_PANDAFILESTREAM
404 (
"show-dll-error-dialog",
false,
405 PRC_DESC(
"Set this true to enable the Windows system dialog that pops "
406 "up when a DLL fails to load, or false to disable it. It is "
407 "normally false, but it may be useful to set it true to debug "
408 "why a DLL is not loading. (Note that this actually disables "
409 "*all* critical error messages, and that it's a global setting "
410 "that some other libraries might un-set.)"));
411 if (show_dll_error_dialog) {
414 SetErrorMode(SEM_FAILCRITICALERRORS);
432 _explicit_pages.push_back(page);
433 _pages_sorted =
false;
451 for (pi = _explicit_pages.begin(); pi != _explicit_pages.end(); ++pi) {
453 _explicit_pages.erase(pi);
467 void ConfigPageManager::
468 output(ostream &out)
const {
469 out <<
"ConfigPageManager, "
470 << _explicit_pages.size() + _implicit_pages.size()
479 void ConfigPageManager::
480 write(ostream &out)
const {
482 out << _explicit_pages.size() <<
" explicit pages:\n";
484 Pages::const_iterator pi;
485 for (pi = _explicit_pages.begin(); pi != _explicit_pages.end(); ++pi) {
493 out <<
" (invalid signature: ";
501 out <<
"\n" << _implicit_pages.size() <<
" implicit pages:\n";
502 for (pi = _implicit_pages.begin(); pi != _implicit_pages.end(); ++pi) {
510 out <<
" (invalid signature: ";
547 void ConfigPageManager::
552 _pages_sorted =
true;
570 bool ConfigPageManager::
571 scan_auto_prc_dir(
Filename &prc_dir)
const {
572 string prc_dir_string = prc_dir;
573 if (prc_dir_string.substr(0, 6) ==
"<auto>") {
574 Filename suffix = prc_dir_string.substr(6);
580 if (scan_up_from(prc_dir, dir, suffix)) {
586 if (scan_up_from(prc_dir, dir, suffix)) {
591 cerr <<
"Warning: unable to auto-locate config files in directory named by \""
592 << prc_dir <<
"\".\n";
611 bool ConfigPageManager::
617 if (consider.is_directory()) {
618 if (consider.scan_directory(files)) {
619 vector_string::const_iterator fi;
620 for (fi = files.begin(); fi != files.end(); ++fi) {
621 Globs::const_iterator gi;
622 for (gi = _prc_patterns.begin();
623 gi != _prc_patterns.end();
625 if ((*gi).matches(*fi)) {
631 for (gi = _prc_executable_patterns.begin();
632 gi != _prc_executable_patterns.end();
634 if ((*gi).matches(*fi)) {
651 return scan_up_from(result, parent, suffix);
663 void ConfigPageManager::
664 config_initialized() {
669 (
"panda-package-version",
"local_dev",
670 PRC_DESC(
"This can be used to specify the value returned by "
671 "PandaSystem::get_package_version_str(), in development mode only, "
672 "and only if another value has not already been compiled in. This "
673 "is intended for developer convenience, to masquerade a development "
674 "build of Panda as a different runtime version. Use with caution."));
676 (
"panda-package-host-url",
"",
677 PRC_DESC(
"This can be used to specify the value returned by "
678 "PandaSystem::get_package_host_url(), in development mode only, "
679 "and only if another value has not already been compiled in. This "
680 "is intended for developer convenience, to masquerade a development "
681 "build of Panda as a different runtime version. Use with caution."));
684 panda_sys->set_package_version_string(panda_package_version);
685 panda_sys->set_package_host_url(panda_package_host_url);
690 (
"text-encoding", TextEncoder::E_utf8,
691 PRC_DESC(
"Specifies how international characters are represented in strings "
692 "of 8-byte characters presented to Panda. See TextEncoder::set_encoding()."));
696 (
"filesystem-encoding", TextEncoder::E_utf8,
697 PRC_DESC(
"Specifies the default encoding used for wide-character filenames."));
const Filename & get_directory(int n) const
Returns the nth directory on the search list.
int get_trust_level() const
Returns the trust level associated with this page.
static PandaSystem * get_global_ptr()
Returns the global PandaSystem object.
bool read_encrypted_prc(istream &in, const string &password)
Automatically decrypts and reads the stream, given the indicated password.
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
bool is_empty() const
Returns true if the search list is empty, false otherwise.
This class is used as a namespace to group several global properties of Panda.
This is a convenience class to specialize ConfigVariable as a boolean type.
void clear()
Removes all the directories from the search list.
void output_brief_signature(ostream &out) const
Outputs the first few hex digits of the signature.
void set_binary()
Indicates that the filename represents a binary file.
void set_text()
Indicates that the filename represents a text file.
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
bool make_true_case()
On a case-insensitive operating system (e.g.
string get_dirname() const
Returns the directory part of the filename.
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
void set_case_sensitive(bool case_sensitive)
Sets whether the match is case sensitive (true) or case insensitive (false).
bool scan_directory(vector_string &contents) const
Attempts to open the named filename as if it were a directory and looks for the non-hidden files with...
static ostream & out()
A convenient way to get the ostream that should be written to for a Notify-type message.
int get_num_directories() const
Returns the number of directories on the search list.
static Notify * ptr()
Returns the pointer to the global Notify object.
float length() const
Returns the length of the vector, by the Pythagorean theorem.
A global object that maintains the set of ConfigPages everywhere in the world, and keeps them in sort...
static void set_filesystem_encoding(TextEncoder::Encoding encoding)
Specifies the default encoding to be used for all subsequent Filenames.
The name of a file, such as a texture file or an Egg file.
This is a convenience class to specialize ConfigVariable as a string type.
bool read_prc(istream &in)
Reads the contents of a complete prc file, as returned by the indicated istream, into the current pag...
static int extract_words(const string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
void reload_implicit_pages()
Searches the PRC_DIR and/or PRC_PATH directories for .prc files and loads them in as pages...
This class specializes ConfigVariable as an enumerated type.
static string get_dtool_name()
Returns the name of the libdtool DLL that is used in this program, if it can be determined.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
static string get_environment_variable(const string &var)
Returns the definition of the indicated environment variable, or the empty string if the variable is ...
A page of ConfigDeclarations that may be loaded or unloaded.
const string & get_name() const
Returns the name of the page.
bool is_executable() const
Returns true if the filename exists and is executable.
void config_initialized()
Intended to be called only by Config, this is a callback that indicates to Notify when Config has don...
static void set_notify_ptr(ostream *ptr)
Sets the ostream that is used to write error messages to.
bool delete_explicit_page(ConfigPage *page)
Removes a previously-constructed ConfigPage from the set of active pages, and deletes it...
ConfigPage * make_explicit_page(const string &name)
Creates and returns a new, empty ConfigPage.
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
static void set_default_encoding(Encoding encoding)
Specifies the default encoding to be used for all subsequently created TextEncoder objects...
static Filename from_os_specific(const string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes, and no drive letter) based on the supplied filename string that describes a filename in the local system conventions (for instance, on Windows, it may use backslashes or begin with a drive letter and a colon).
const string & get_signature() const
Returns the raw binary signature that was found in the prc file, if any.