Panda3D
configPageManager.cxx
1 // Filename: configPageManager.cxx
2 // Created by: drose (15Oct04)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "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"
23 #include "pfstream.h"
24 #include "pandaSystem.h"
25 #include "textEncoder.h"
26 #include "stringDecoder.h"
27 
28 // This file is generated by ppremake.
29 #include "prc_parameters.h"
30 
31 #include <set>
32 
33 // Pick up the public key definitions.
34 #ifdef PRC_PUBLIC_KEYS_INCLUDE
35 #include PRC_PUBLIC_KEYS_INCLUDE
36 #endif
37 
38 #include <algorithm>
39 #include <ctype.h>
40 
41 ConfigPageManager *ConfigPageManager::_global_ptr = NULL;
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: ConfigPageManager::Constructor
45 // Access: Protected
46 // Description: The constructor is private (actually, just protected,
47 // but only to avoid a gcc compiler warning) because it
48 // should not be explicitly constructed. There is only
49 // one ConfigPageManager, and it constructs itself.
50 ////////////////////////////////////////////////////////////////////
51 ConfigPageManager::
52 ConfigPageManager() {
53  _next_page_seq = 1;
54  _loaded_implicit = false;
55  _currently_loading = false;
56  _pages_sorted = true;
57 
58 #ifdef PRC_PUBLIC_KEYS_INCLUDE
59  // Record the public keys in the registry at startup time.
60  PrcKeyRegistry::get_global_ptr()->record_keys(prc_pubkeys, num_prc_pubkeys);
61 #endif // PRC_PUBLIC_KEYS_INCLUDE
62 }
63 
64 ////////////////////////////////////////////////////////////////////
65 // Function: ConfigPageManager::Destructor
66 // Access: Protected
67 // Description: The ConfigPageManager destructor should never be
68 // called, because this is a global object that is never
69 // freed.
70 ////////////////////////////////////////////////////////////////////
71 ConfigPageManager::
72 ~ConfigPageManager() {
73  prc_cat->error()
74  << "Internal error--ConfigPageManager destructor called!\n";
75 }
76 
77 ////////////////////////////////////////////////////////////////////
78 // Function: ConfigPageManager::reload_implicit_pages
79 // Access: Published
80 // Description: Searches the PRC_DIR and/or PRC_PATH directories for
81 // *.prc files and loads them in as pages.
82 //
83 // This may be called after startup, to force the system
84 // to re-read all of the implicit prc files.
85 ////////////////////////////////////////////////////////////////////
88  if (_currently_loading) {
89  // This is a recursion protector. We can get recursion feedback
90  // between config and notify, as each tries to use the other at
91  // construction.
92  return;
93  }
94  _currently_loading = true;
95 
96  // First, remove all the previously-loaded pages.
97  Pages::iterator pi;
98  for (pi = _implicit_pages.begin(); pi != _implicit_pages.end(); ++pi) {
99  delete (*pi);
100  }
101  _implicit_pages.clear();
102 
103  // PRC_PATTERNS lists one or more filename templates separated by
104  // spaces. Pull them out and store them in _prc_patterns.
105  _prc_patterns.clear();
106 
107  string prc_patterns = PRC_PATTERNS;
108  if (!prc_patterns.empty()) {
109  vector_string pat_list;
110  ConfigDeclaration::extract_words(prc_patterns, pat_list);
111  _prc_patterns.reserve(pat_list.size());
112  for (size_t i = 0; i < pat_list.size(); ++i) {
113  GlobPattern glob(pat_list[i]);
114 #ifdef WIN32
115  // On windows, the file system is case-insensitive, so the
116  // pattern should be too.
117  glob.set_case_sensitive(false);
118 #endif // WIN32
119  _prc_patterns.push_back(glob);
120  }
121  }
122 
123  // Similarly for PRC_ENCRYPTED_PATTERNS.
124  _prc_encrypted_patterns.clear();
125 
126  string prc_encrypted_patterns = PRC_ENCRYPTED_PATTERNS;
127  if (!prc_encrypted_patterns.empty()) {
128  vector_string pat_list;
129  ConfigDeclaration::extract_words(prc_encrypted_patterns, pat_list);
130  _prc_encrypted_patterns.reserve(pat_list.size());
131  for (size_t i = 0; i < pat_list.size(); ++i) {
132  GlobPattern glob(pat_list[i]);
133 #ifdef WIN32
134  glob.set_case_sensitive(false);
135 #endif // WIN32
136  _prc_encrypted_patterns.push_back(glob);
137  }
138  }
139 
140  // And again for PRC_EXECUTABLE_PATTERNS.
141  _prc_executable_patterns.clear();
142 
143  string prc_executable_patterns = PRC_EXECUTABLE_PATTERNS;
144  if (!prc_executable_patterns.empty()) {
145  vector_string pat_list;
146  ConfigDeclaration::extract_words(prc_executable_patterns, pat_list);
147  _prc_executable_patterns.reserve(pat_list.size());
148  for (size_t i = 0; i < pat_list.size(); ++i) {
149  GlobPattern glob(pat_list[i]);
150 #ifdef WIN32
151  glob.set_case_sensitive(false);
152 #endif // WIN32
153  _prc_executable_patterns.push_back(glob);
154  }
155  }
156 
157  // Now build up the search path for .prc files.
158  _search_path.clear();
159 
160  // PRC_DIR_ENVVARS lists one or more environment variables separated
161  // by spaces. Pull them out, and each of those contains the name of
162  // a single directory to search. Add it to the search path.
163  string prc_dir_envvars = PRC_DIR_ENVVARS;
164  if (!prc_dir_envvars.empty()) {
165  vector_string prc_dir_envvar_list;
166  ConfigDeclaration::extract_words(prc_dir_envvars, prc_dir_envvar_list);
167  for (size_t i = 0; i < prc_dir_envvar_list.size(); ++i) {
168  string prc_dir = ExecutionEnvironment::get_environment_variable(prc_dir_envvar_list[i]);
169  if (!prc_dir.empty()) {
170  Filename prc_dir_filename = Filename::from_os_specific(prc_dir);
171  prc_dir_filename.make_true_case();
172  if (scan_auto_prc_dir(prc_dir_filename)) {
173  _search_path.append_directory(prc_dir_filename);
174  }
175  }
176  }
177  }
178 
179  // PRC_PATH_ENVVARS lists one or more environment variables separated
180  // by spaces. Pull them out, and then each one of those contains a
181  // list of directories to search. Add each of those to the search
182  // path.
183  string prc_path_envvars = PRC_PATH_ENVVARS;
184  if (!prc_path_envvars.empty()) {
185  vector_string prc_path_envvar_list;
186  ConfigDeclaration::extract_words(prc_path_envvars, prc_path_envvar_list);
187  for (size_t i = 0; i < prc_path_envvar_list.size(); ++i) {
188  string path = ExecutionEnvironment::get_environment_variable(prc_path_envvar_list[i]);
189  size_t p = 0;
190  while (p < path.length()) {
191  size_t q = path.find_first_of(DEFAULT_PATHSEP, p);
192  if (q == string::npos) {
193  q = path.length();
194  }
195  Filename prc_dir_filename = Filename::from_os_specific(path.substr(p, q - p));
196  prc_dir_filename.make_true_case();
197  if (scan_auto_prc_dir(prc_dir_filename)) {
198  _search_path.append_directory(prc_dir_filename);
199  }
200  p = q + 1;
201  }
202  }
203  }
204 
205  // PRC_PATH2_ENVVARS is a special variable that is rarely used; it
206  // exists primarily to support the Cygwin-based "ctattach" tools
207  // used by the Walt Disney VR Studio. This defines a set of
208  // environment variable(s) that define a search path, as above;
209  // except that the directory names on these search paths are
210  // Panda-style filenames, not Windows-style filenames; and the path
211  // separator is always a space character, regardless of
212  // DEFAULT_PATHSEP.
213  string prc_path2_envvars = PRC_PATH2_ENVVARS;
214  if (!prc_path2_envvars.empty()) {
215  vector_string prc_path_envvar_list;
216  ConfigDeclaration::extract_words(prc_path2_envvars, prc_path_envvar_list);
217  for (size_t i = 0; i < prc_path_envvar_list.size(); ++i) {
218  string path = ExecutionEnvironment::get_environment_variable(prc_path_envvar_list[i]);
219  size_t p = 0;
220  while (p < path.length()) {
221  size_t q = path.find_first_of(' ', p);
222  if (q == string::npos) {
223  q = path.length();
224  }
225  Filename prc_dir_filename = path.substr(p, q - p);
226  if (scan_auto_prc_dir(prc_dir_filename)) {
227  _search_path.append_directory(prc_dir_filename);
228  }
229  p = q + 1;
230  }
231  }
232  }
233 
234  if (_search_path.is_empty()) {
235  // If nothing's on the search path (PRC_DIR and PRC_PATH were not
236  // defined), then use the DEFAULT_PRC_DIR.
237  string default_prc_dir = DEFAULT_PRC_DIR;
238  if (!default_prc_dir.empty()) {
239  // It's already from-os-specific by ppremake.
240  Filename prc_dir_filename = default_prc_dir;
241  if (scan_auto_prc_dir(prc_dir_filename)) {
242  _search_path.append_directory(prc_dir_filename);
243  }
244  }
245  }
246 
247  // Now find all of the *.prc files (or whatever matches
248  // PRC_PATTERNS) on the path.
249  ConfigFiles config_files;
250 
251  // Use a set to ensure that we only visit each directory once, even
252  // if it appears multiple times (under different aliases!) in the
253  // path.
254  set<Filename> unique_dirnames;
255 
256  // We walk through the list of directories in forward order, so that
257  // the most important directories are visited first.
258  for (int di = 0; di < _search_path.get_num_directories(); ++di) {
259  const Filename &directory = _search_path.get_directory(di);
260  if (directory.is_directory()) {
261  Filename canonical(directory, ".");
262  canonical.make_canonical();
263  if (unique_dirnames.insert(canonical).second) {
264  vector_string files;
265  directory.scan_directory(files);
266 
267  // We walk through the directory's list of files in reverse
268  // alphabetical order, because for historical reasons, the
269  // most important file within a directory is the
270  // alphabetically last file of that directory, and we still
271  // want to visit the most important files first.
272  vector_string::reverse_iterator fi;
273  for (fi = files.rbegin(); fi != files.rend(); ++fi) {
274  int file_flags = 0;
275  Globs::const_iterator gi;
276  for (gi = _prc_patterns.begin();
277  gi != _prc_patterns.end();
278  ++gi) {
279  if ((*gi).matches(*fi)) {
280  file_flags |= FF_read;
281  break;
282  }
283  }
284  for (gi = _prc_encrypted_patterns.begin();
285  gi != _prc_encrypted_patterns.end();
286  ++gi) {
287  if ((*gi).matches(*fi)) {
288  file_flags |= FF_read | FF_decrypt;
289  break;
290  }
291  }
292  for (gi = _prc_executable_patterns.begin();
293  gi != _prc_executable_patterns.end();
294  ++gi) {
295  if ((*gi).matches(*fi)) {
296  file_flags |= FF_execute;
297  break;
298  }
299  }
300  if (file_flags != 0) {
301  ConfigFile file;
302  file._file_flags = file_flags;
303  file._filename = Filename(directory, (*fi));
304  config_files.push_back(file);
305  }
306  }
307  }
308  }
309  }
310 
311  // Now we have a list of filenames in order from most important to
312  // least important. Walk through the list in reverse order to load
313  // their contents, because we want the first file in the list (the
314  // most important) to be on the top of the stack.
315  ConfigFiles::reverse_iterator ci;
316  int i = 1;
317  for (ci = config_files.rbegin(); ci != config_files.rend(); ++ci) {
318  const ConfigFile &file = (*ci);
319  Filename filename = file._filename;
320 
321  if ((file._file_flags & FF_execute) != 0 &&
322  filename.is_executable()) {
323  // Attempt to execute the file as a command.
324  string command = filename.to_os_specific();
325 
326  string envvar = PRC_EXECUTABLE_ARGS_ENVVAR;
327  if (!envvar.empty()) {
329  if (!args.empty()) {
330  command += " ";
331  command += args;
332  }
333  }
334  IPipeStream ifs(command);
335 
336  ConfigPage *page = new ConfigPage(filename, true, i);
337  ++i;
338  _implicit_pages.push_back(page);
339  _pages_sorted = false;
340 
341  page->read_prc(ifs);
342 
343  } else if ((file._file_flags & FF_decrypt) != 0) {
344  // Read and decrypt the file.
345  filename.set_binary();
346 
347  pifstream in;
348  if (!filename.open_read(in)) {
349  prc_cat.error()
350  << "Unable to read " << filename << "\n";
351  } else {
352  ConfigPage *page = new ConfigPage(filename, true, i);
353  ++i;
354  _implicit_pages.push_back(page);
355  _pages_sorted = false;
356 
357  page->read_encrypted_prc(in, PRC_ENCRYPTION_KEY);
358  }
359 
360  } else if ((file._file_flags & FF_read) != 0) {
361  // Just read the file.
362  filename.set_text();
363 
364  pifstream in;
365  if (!filename.open_read(in)) {
366  prc_cat.error()
367  << "Unable to read " << filename << "\n";
368  } else {
369  ConfigPage *page = new ConfigPage(filename, true, i);
370  ++i;
371  _implicit_pages.push_back(page);
372  _pages_sorted = false;
373 
374  page->read_prc(in);
375  }
376  }
377  }
378 
379  if (!_loaded_implicit) {
380  config_initialized();
381  _loaded_implicit = true;
382  }
383 
384  _currently_loading = false;
385  invalidate_cache();
386 
387 #ifdef USE_PANDAFILESTREAM
388  // Update this very low-level config variable here, for lack of any
389  // better place.
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\", "
396  "or \"mac\"."));
397  PandaFileStreamBuf::_newline_mode = newline_mode;
398 #endif // USE_PANDAFILESTREAM
399 
400 #ifdef WIN32
401  // We don't necessarily want an error dialog when we fail to load a
402  // .dll file. But sometimes it is useful for debugging.
403  ConfigVariableBool show_dll_error_dialog
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) {
412  SetErrorMode(0);
413  } else {
414  SetErrorMode(SEM_FAILCRITICALERRORS);
415  }
416 #endif
417 
418 }
419 
420 ////////////////////////////////////////////////////////////////////
421 // Function: ConfigPageManager::make_explicit_page
422 // Access: Published
423 // Description: Creates and returns a new, empty ConfigPage. This
424 // page will be stacked on top of any pages that were
425 // created before; it may shadow variable declarations
426 // that are defined in previous pages.
427 ////////////////////////////////////////////////////////////////////
429 make_explicit_page(const string &name) {
430  ConfigPage *page = new ConfigPage(name, false, _next_page_seq);
431  ++_next_page_seq;
432  _explicit_pages.push_back(page);
433  _pages_sorted = false;
434  invalidate_cache();
435  return page;
436 }
437 
438 ////////////////////////////////////////////////////////////////////
439 // Function: ConfigPageManager::delete_explicit_page
440 // Access: Published
441 // Description: Removes a previously-constructed ConfigPage from the
442 // set of active pages, and deletes it. The ConfigPage
443 // object is no longer valid after this call. Returns
444 // true if the page is successfully deleted, or false if
445 // it was unknown (which should never happen if the page
446 // was legitimately constructed).
447 ////////////////////////////////////////////////////////////////////
450  Pages::iterator pi;
451  for (pi = _explicit_pages.begin(); pi != _explicit_pages.end(); ++pi) {
452  if ((*pi) == page) {
453  _explicit_pages.erase(pi);
454  delete page;
455  invalidate_cache();
456  return true;
457  }
458  }
459  return false;
460 }
461 
462 ////////////////////////////////////////////////////////////////////
463 // Function: ConfigPageManager::output
464 // Access: Published
465 // Description:
466 ////////////////////////////////////////////////////////////////////
467 void ConfigPageManager::
468 output(ostream &out) const {
469  out << "ConfigPageManager, "
470  << _explicit_pages.size() + _implicit_pages.size()
471  << " pages.";
472 }
473 
474 ////////////////////////////////////////////////////////////////////
475 // Function: ConfigPageManager::write
476 // Access: Published
477 // Description:
478 ////////////////////////////////////////////////////////////////////
479 void ConfigPageManager::
480 write(ostream &out) const {
481  check_sort_pages();
482  out << _explicit_pages.size() << " explicit pages:\n";
483 
484  Pages::const_iterator pi;
485  for (pi = _explicit_pages.begin(); pi != _explicit_pages.end(); ++pi) {
486  const ConfigPage *page = (*pi);
487  out << " " << page->get_name();
488  if (page->get_trust_level() > 0) {
489  out << " (signed " << page->get_trust_level() << ": ";
490  page->output_brief_signature(out);
491  out << ")\n";
492  } else if (!page->get_signature().empty()) {
493  out << " (invalid signature: ";
494  page->output_brief_signature(out);
495  out << ")\n";
496  } else {
497  out << "\n";
498  }
499  }
500 
501  out << "\n" << _implicit_pages.size() << " implicit pages:\n";
502  for (pi = _implicit_pages.begin(); pi != _implicit_pages.end(); ++pi) {
503  const ConfigPage *page = (*pi);
504  out << " " << page->get_name();
505  if (page->get_trust_level() > 0) {
506  out << " (signed " << page->get_trust_level() << ": ";
507  page->output_brief_signature(out);
508  out << ")\n";
509  } else if (!page->get_signature().empty()) {
510  out << " (invalid signature: ";
511  page->output_brief_signature(out);
512  out << ")\n";
513  } else {
514  out << "\n";
515  }
516  }
517 }
518 
519 ////////////////////////////////////////////////////////////////////
520 // Function: ConfigPageManager::get_global_ptr
521 // Access: Published
522 // Description:
523 ////////////////////////////////////////////////////////////////////
524 ConfigPageManager *ConfigPageManager::
525 get_global_ptr() {
526  if (_global_ptr == (ConfigPageManager *)NULL) {
527  _global_ptr = new ConfigPageManager;
528  }
529  return _global_ptr;
530 }
531 
532 // This class is used in sort_pages, below.
534 public:
535  bool operator () (const ConfigPage *a, const ConfigPage *b) const {
536  return (*a) < (*b);
537  }
538 };
539 
540 ////////////////////////////////////////////////////////////////////
541 // Function: ConfigPageManager::sort_pages
542 // Access: Private
543 // Description: Sorts the list of pages into priority order,
544 // so that the page at the front of the list is
545 // the one that shadows all following pages.
546 ////////////////////////////////////////////////////////////////////
547 void ConfigPageManager::
548 sort_pages() {
549  sort(_implicit_pages.begin(), _implicit_pages.end(), CompareConfigPages());
550  sort(_explicit_pages.begin(), _explicit_pages.end(), CompareConfigPages());
551 
552  _pages_sorted = true;
553 }
554 
555 ////////////////////////////////////////////////////////////////////
556 // Function: ConfigPageManager::scan_auto_prc_dir
557 // Access: Private
558 // Description: Checks for the prefix "<auto>" in the value of the
559 // $PRC_DIR environment variable (or in the compiled-in
560 // DEFAULT_PRC_DIR value). If it is found, then the
561 // actual directory is determined by searching upward
562 // from the executable's starting directory, or from the
563 // current working directory, until at least one .prc
564 // file is found.
565 //
566 // Returns true if the prc_dir has been filled with a
567 // valid directory name, false if no good directory name
568 // was found.
569 ////////////////////////////////////////////////////////////////////
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);
575 
576  // Start at the dtool directory.
578  Filename dir = dtool.get_dirname();
579 
580  if (scan_up_from(prc_dir, dir, suffix)) {
581  return true;
582  }
583 
584  // Try the program's directory.
586  if (scan_up_from(prc_dir, dir, suffix)) {
587  return true;
588  }
589 
590  // Didn't find it; too bad.
591  cerr << "Warning: unable to auto-locate config files in directory named by \""
592  << prc_dir << "\".\n";
593  return false;
594  }
595 
596  // The filename did not begin with "<auto>", so it stands unchanged.
597  return true;
598 }
599 
600 ////////////////////////////////////////////////////////////////////
601 // Function: ConfigPageManager::scan_up_from
602 // Access: Private
603 // Description: Used to implement scan_auto_prc_dir(), above, this
604 // scans upward from the indicated directory name until
605 // a directory is found that includes at least one .prc
606 // file, or the root directory is reached.
607 //
608 // If a match is found, puts it result and returns true;
609 // otherwise, returns false.
610 ////////////////////////////////////////////////////////////////////
611 bool ConfigPageManager::
612 scan_up_from(Filename &result, const Filename &dir,
613  const Filename &suffix) const {
614  Filename consider(dir, suffix);
615 
616  vector_string files;
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();
624  ++gi) {
625  if ((*gi).matches(*fi)) {
626  result = consider;
627  return true;
628  }
629  }
630 
631  for (gi = _prc_executable_patterns.begin();
632  gi != _prc_executable_patterns.end();
633  ++gi) {
634  if ((*gi).matches(*fi)) {
635  result = consider;
636  return true;
637  }
638  }
639  }
640  }
641  }
642 
643  Filename parent = dir.get_dirname();
644 
645  if (dir == parent) {
646  // Too bad; couldn't find a match.
647  return false;
648  }
649 
650  // Recursively try again on the parent.
651  return scan_up_from(result, parent, suffix);
652 }
653 
654 ////////////////////////////////////////////////////////////////////
655 // Function: ConfigPageManager::config_initialized
656 // Access: Private
657 // Description: This is called once, at startup, the first time that
658 // the config system has been initialized and is ready
659 // to read config variables. It's intended to be a
660 // place to initialize values that are defined at a
661 // lower level than the config system itself.
662 ////////////////////////////////////////////////////////////////////
663 void ConfigPageManager::
664 config_initialized() {
666 
667 #ifndef NDEBUG
668  ConfigVariableString panda_package_version
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."));
675  ConfigVariableString panda_package_host_url
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."));
682 
684  panda_sys->set_package_version_string(panda_package_version);
685  panda_sys->set_package_host_url(panda_package_host_url);
686 #endif // NDEBUG
687 
688  // Also set up some other low-level things.
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()."));
693  TextEncoder::set_default_encoding(text_encoding);
694 
696  ("filesystem-encoding", TextEncoder::E_utf8,
697  PRC_DESC("Specifies the default encoding used for wide-character filenames."));
698  Filename::set_filesystem_encoding(filesystem_encoding);
699 
701 }
string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:424
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.
Definition: configPage.cxx:257
This class is used as a namespace to group several global properties of Panda.
Definition: pandaSystem.h:29
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.
Definition: configPage.cxx:407
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:494
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:507
bool is_empty() const
Returns true if the search list is empty, false otherwise.
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
Definition: filename.cxx:1072
bool make_true_case()
On a case-insensitive operating system (e.g.
Definition: filename.cxx:1120
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).
Definition: globPattern.I:112
static ostream & out()
A convenient way to get the ostream that should be written to for a Notify-type message.
Definition: notify.cxx:301
bool open_read(ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:2003
static Notify * ptr()
Returns the pointer to the global Notify object.
Definition: notify.cxx:337
int get_num_directories() const
Returns the number of directories on the search list.
A global object that maintains the set of ConfigPages everywhere in the world, and keeps them in sort...
const Filename & get_directory(int n) const
Returns the nth directory on the search list.
static void set_filesystem_encoding(TextEncoder::Encoding encoding)
Specifies the default encoding to be used for all subsequent Filenames.
Definition: filename.I:766
const string & get_name() const
Returns the name of the page.
Definition: configPage.I:44
bool is_executable() const
Returns true if the filename exists and is executable.
Definition: filename.cxx:1487
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:44
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...
Definition: configPage.cxx:144
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.
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.
Definition: configPage.h:33
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
Definition: filename.cxx:1456
void config_initialized()
Intended to be called only by Config, this is a callback that indicates to Notify when Config has don...
Definition: notify.cxx:489
const string & get_signature() const
Returns the raw binary signature that was found in the prc file, if any.
Definition: configPage.I:141
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...
Definition: filename.cxx:1854
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.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1196
This class can be used to test for string matches against standard Unix-shell filename globbing conve...
Definition: globPattern.h:37
static void set_default_encoding(Encoding encoding)
Specifies the default encoding to be used for all subsequently created TextEncoder objects...
Definition: textEncoder.I:85
int get_trust_level() const
Returns the trust level associated with this page.
Definition: configPage.I:116
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).
Definition: filename.cxx:332