Panda3D
configPageManager.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file configPageManager.cxx
10  * @author drose
11  * @date 2004-10-15
12  */
13 
14 #include "configPageManager.h"
15 #include "configDeclaration.h"
16 #include "configVariableBool.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 #ifndef _MSC_VER
42 #include <dlfcn.h>
43 #endif
44 
45 using std::string;
46 
47 ConfigPageManager *ConfigPageManager::_global_ptr = nullptr;
48 
49 /**
50  * The constructor is private (actually, just protected, but only to avoid a
51  * gcc compiler warning) because it should not be explicitly constructed.
52  * There is only one ConfigPageManager, and it constructs itself.
53  */
54 ConfigPageManager::
55 ConfigPageManager() {
56  _next_page_seq = 1;
57  _loaded_implicit = false;
58  _currently_loading = false;
59  _pages_sorted = true;
60 
61 #ifdef PRC_PUBLIC_KEYS_INCLUDE
62  // Record the public keys in the registry at startup time.
63  PrcKeyRegistry::get_global_ptr()->record_keys(prc_pubkeys, num_prc_pubkeys);
64 #endif // PRC_PUBLIC_KEYS_INCLUDE
65 }
66 
67 /**
68  * The ConfigPageManager destructor should never be called, because this is a
69  * global object that is never freed.
70  */
71 ConfigPageManager::
72 ~ConfigPageManager() {
73  prc_cat->error()
74  << "Internal error--ConfigPageManager destructor called!\n";
75 }
76 
77 /**
78  * Searches the PRC_DIR and/or PRC_PATH directories for *.prc files and loads
79  * them in as pages.
80  *
81  * This may be called after startup, to force the system to re-read all of the
82  * implicit prc files.
83  */
86  if (_currently_loading) {
87  // This is a recursion protector. We can get recursion feedback between
88  // config and notify, as each tries to use the other at construction.
89  return;
90  }
91  _currently_loading = true;
92 
93  // First, remove all the previously-loaded pages.
94  Pages::iterator pi;
95  for (pi = _implicit_pages.begin(); pi != _implicit_pages.end(); ++pi) {
96  delete (*pi);
97  }
98  _implicit_pages.clear();
99 
100  // If we are running inside a deployed application, see if it exposes
101  // information about how the PRC data should be initialized.
102  struct BlobInfo {
103  uint64_t blob_offset;
104  uint64_t blob_size;
105  uint16_t version;
106  uint16_t num_pointers;
107  uint16_t codepage;
108  uint16_t flags;
109  uint64_t reserved;
110  const void *module_table;
111  const char *prc_data;
112  const char *default_prc_dir;
113  const char *prc_dir_envvars;
114  const char *prc_path_envvars;
115  const char *prc_patterns;
116  const char *prc_encrypted_patterns;
117  const char *prc_encryption_key;
118  const char *prc_executable_patterns;
119  const char *prc_executable_args_envvar;
120  const char *main_dir;
121  const char *log_filename;
122  };
123 #ifdef _MSC_VER
124  const BlobInfo *blobinfo = (const BlobInfo *)GetProcAddress(GetModuleHandle(NULL), "blobinfo");
125 #elif defined(RTLD_MAIN_ONLY)
126  const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_MAIN_ONLY, "blobinfo");
127 //#elif defined(RTLD_SELF)
128 // const BlobInfo *blobinfo = (const BlobInfo *)dlsym(RTLD_SELF, "blobinfo");
129 #else
130  const BlobInfo *blobinfo = (const BlobInfo *)dlsym(dlopen(NULL, RTLD_NOW), "blobinfo");
131 #endif
132  if (blobinfo == nullptr) {
133 #ifndef _MSC_VER
134  // Clear the error flag.
135  dlerror();
136 #endif
137  } else if (blobinfo->version == 0 || blobinfo->num_pointers < 10) {
138  blobinfo = nullptr;
139  }
140 
141  if (blobinfo != nullptr) {
142  if (blobinfo->num_pointers >= 11 && blobinfo->main_dir != nullptr) {
143  ExecutionEnvironment::set_environment_variable("MAIN_DIR", blobinfo->main_dir);
144  } else {
145  // Make sure that py_panda.cxx won't override MAIN_DIR.
148  }
149  }
150 
151  // PRC_PATTERNS lists one or more filename templates separated by spaces.
152  // Pull them out and store them in _prc_patterns.
153  _prc_patterns.clear();
154 
155  string prc_patterns = PRC_PATTERNS;
156  if (blobinfo != nullptr && blobinfo->prc_patterns != nullptr) {
157  prc_patterns = blobinfo->prc_patterns;
158  }
159  if (!prc_patterns.empty()) {
160  vector_string pat_list;
161  ConfigDeclaration::extract_words(prc_patterns, pat_list);
162  _prc_patterns.reserve(pat_list.size());
163  for (size_t i = 0; i < pat_list.size(); ++i) {
164  GlobPattern glob(pat_list[i]);
165 #ifdef WIN32
166  // On windows, the file system is case-insensitive, so the pattern
167  // should be too.
168  glob.set_case_sensitive(false);
169 #endif // WIN32
170  _prc_patterns.push_back(glob);
171  }
172  }
173 
174  // Similarly for PRC_ENCRYPTED_PATTERNS.
175  _prc_encrypted_patterns.clear();
176 
177  string prc_encrypted_patterns = PRC_ENCRYPTED_PATTERNS;
178  if (blobinfo != nullptr && blobinfo->prc_encrypted_patterns != nullptr) {
179  prc_encrypted_patterns = blobinfo->prc_encrypted_patterns;
180  }
181  if (!prc_encrypted_patterns.empty()) {
182  vector_string pat_list;
183  ConfigDeclaration::extract_words(prc_encrypted_patterns, pat_list);
184  _prc_encrypted_patterns.reserve(pat_list.size());
185  for (size_t i = 0; i < pat_list.size(); ++i) {
186  GlobPattern glob(pat_list[i]);
187 #ifdef WIN32
188  glob.set_case_sensitive(false);
189 #endif // WIN32
190  _prc_encrypted_patterns.push_back(glob);
191  }
192  }
193 
194  // And again for PRC_EXECUTABLE_PATTERNS.
195  _prc_executable_patterns.clear();
196 
197  string prc_executable_patterns = PRC_EXECUTABLE_PATTERNS;
198  if (blobinfo != nullptr && blobinfo->prc_executable_patterns != nullptr) {
199  prc_executable_patterns = blobinfo->prc_executable_patterns;
200  }
201  if (!prc_executable_patterns.empty()) {
202  vector_string pat_list;
203  ConfigDeclaration::extract_words(prc_executable_patterns, pat_list);
204  _prc_executable_patterns.reserve(pat_list.size());
205  for (size_t i = 0; i < pat_list.size(); ++i) {
206  GlobPattern glob(pat_list[i]);
207 #ifdef WIN32
208  glob.set_case_sensitive(false);
209 #endif // WIN32
210  _prc_executable_patterns.push_back(glob);
211  }
212  }
213 
214  // Now build up the search path for .prc files.
215  _search_path.clear();
216 
217  // PRC_DIR_ENVVARS lists one or more environment variables separated by
218  // spaces. Pull them out, and each of those contains the name of a single
219  // directory to search. Add it to the search path.
220  string prc_dir_envvars = PRC_DIR_ENVVARS;
221  if (blobinfo != nullptr && blobinfo->prc_dir_envvars != nullptr) {
222  prc_dir_envvars = blobinfo->prc_dir_envvars;
223  }
224  if (!prc_dir_envvars.empty()) {
225  vector_string prc_dir_envvar_list;
226  ConfigDeclaration::extract_words(prc_dir_envvars, prc_dir_envvar_list);
227  for (size_t i = 0; i < prc_dir_envvar_list.size(); ++i) {
228  string prc_dir = ExecutionEnvironment::get_environment_variable(prc_dir_envvar_list[i]);
229  if (!prc_dir.empty()) {
230  Filename prc_dir_filename = Filename::from_os_specific(prc_dir);
231  prc_dir_filename.make_true_case();
232  if (scan_auto_prc_dir(prc_dir_filename)) {
233  _search_path.append_directory(prc_dir_filename);
234  }
235  }
236  }
237  }
238 
239  // PRC_PATH_ENVVARS lists one or more environment variables separated by
240  // spaces. Pull them out, and then each one of those contains a list of
241  // directories to search. Add each of those to the search path.
242  string prc_path_envvars = PRC_PATH_ENVVARS;
243  if (blobinfo != nullptr && blobinfo->prc_path_envvars != nullptr) {
244  prc_path_envvars = blobinfo->prc_path_envvars;
245  }
246  if (!prc_path_envvars.empty()) {
247  vector_string prc_path_envvar_list;
248  ConfigDeclaration::extract_words(prc_path_envvars, prc_path_envvar_list);
249  for (size_t i = 0; i < prc_path_envvar_list.size(); ++i) {
250  string path = ExecutionEnvironment::get_environment_variable(prc_path_envvar_list[i]);
251  size_t p = 0;
252  while (p < path.length()) {
253  size_t q = path.find_first_of(DEFAULT_PATHSEP, p);
254  if (q == string::npos) {
255  q = path.length();
256  }
257  Filename prc_dir_filename = Filename::from_os_specific(path.substr(p, q - p));
258  prc_dir_filename.make_true_case();
259  if (scan_auto_prc_dir(prc_dir_filename)) {
260  _search_path.append_directory(prc_dir_filename);
261  }
262  p = q + 1;
263  }
264  }
265  }
266 
267 /*
268  * PRC_PATH2_ENVVARS is a special variable that is rarely used; it exists
269  * primarily to support the Cygwin-based "ctattach" tools used by the Walt
270  * Disney VR Studio. This defines a set of environment variable(s) that
271  * define a search path, as above; except that the directory names on these
272  * search paths are Panda-style filenames, not Windows-style filenames; and
273  * the path separator is always a space character, regardless of
274  * DEFAULT_PATHSEP.
275  */
276  string prc_path2_envvars = PRC_PATH2_ENVVARS;
277  if (!prc_path2_envvars.empty() && blobinfo == nullptr) {
278  vector_string prc_path_envvar_list;
279  ConfigDeclaration::extract_words(prc_path2_envvars, prc_path_envvar_list);
280  for (size_t i = 0; i < prc_path_envvar_list.size(); ++i) {
281  string path = ExecutionEnvironment::get_environment_variable(prc_path_envvar_list[i]);
282  size_t p = 0;
283  while (p < path.length()) {
284  size_t q = path.find_first_of(' ', p);
285  if (q == string::npos) {
286  q = path.length();
287  }
288  Filename prc_dir_filename = path.substr(p, q - p);
289  if (scan_auto_prc_dir(prc_dir_filename)) {
290  _search_path.append_directory(prc_dir_filename);
291  }
292  p = q + 1;
293  }
294  }
295  }
296 
297  if (_search_path.is_empty()) {
298  // If nothing's on the search path (PRC_DIR and PRC_PATH were not
299  // defined), then use the DEFAULT_PRC_DIR.
300  string default_prc_dir = DEFAULT_PRC_DIR;
301  if (blobinfo != nullptr && blobinfo->default_prc_dir != nullptr) {
302  default_prc_dir = blobinfo->default_prc_dir;
303  }
304  if (!default_prc_dir.empty()) {
305  // It's already from-os-specific by ppremake.
306  Filename prc_dir_filename = default_prc_dir;
307  if (scan_auto_prc_dir(prc_dir_filename)) {
308  _search_path.append_directory(prc_dir_filename);
309  }
310  }
311  }
312 
313  // Now find all of the *.prc files (or whatever matches PRC_PATTERNS) on the
314  // path.
315  ConfigFiles config_files;
316 
317  // Use a set to ensure that we only visit each directory once, even if it
318  // appears multiple times (under different aliases!) in the path.
319  std::set<Filename> unique_dirnames;
320 
321  // We walk through the list of directories in forward order, so that the
322  // most important directories are visited first.
323  for (size_t di = 0; di < _search_path.get_num_directories(); ++di) {
324  const Filename &directory = _search_path.get_directory(di);
325  if (directory.is_directory()) {
326  Filename canonical(directory, ".");
327  canonical.make_canonical();
328  if (unique_dirnames.insert(canonical).second) {
329  vector_string files;
330  directory.scan_directory(files);
331 
332  // We walk through the directory's list of files in reverse
333  // alphabetical order, because for historical reasons, the most
334  // important file within a directory is the alphabetically last file
335  // of that directory, and we still want to visit the most important
336  // files first.
337  vector_string::reverse_iterator fi;
338  for (fi = files.rbegin(); fi != files.rend(); ++fi) {
339  int file_flags = 0;
340  Globs::const_iterator gi;
341  for (gi = _prc_patterns.begin();
342  gi != _prc_patterns.end();
343  ++gi) {
344  if ((*gi).matches(*fi)) {
345  file_flags |= FF_read;
346  break;
347  }
348  }
349  for (gi = _prc_encrypted_patterns.begin();
350  gi != _prc_encrypted_patterns.end();
351  ++gi) {
352  if ((*gi).matches(*fi)) {
353  file_flags |= FF_read | FF_decrypt;
354  break;
355  }
356  }
357  for (gi = _prc_executable_patterns.begin();
358  gi != _prc_executable_patterns.end();
359  ++gi) {
360  if ((*gi).matches(*fi)) {
361  file_flags |= FF_execute;
362  break;
363  }
364  }
365  if (file_flags != 0) {
366  ConfigFile file;
367  file._file_flags = file_flags;
368  file._filename = Filename(directory, (*fi));
369  config_files.push_back(file);
370  }
371  }
372  }
373  }
374  }
375 
376  int i = 1;
377 
378  // If prc_data is predefined, we load it as an implicit page.
379  if (blobinfo != nullptr && blobinfo->prc_data != nullptr) {
380  ConfigPage *page = new ConfigPage("builtin", true, i);
381  ++i;
382  _implicit_pages.push_back(page);
383  _pages_sorted = false;
384 
385  std::istringstream in(blobinfo->prc_data);
386  page->read_prc(in);
387  }
388 
389  // Now we have a list of filenames in order from most important to least
390  // important. Walk through the list in reverse order to load their
391  // contents, because we want the first file in the list (the most important)
392  // to be on the top of the stack.
393  ConfigFiles::reverse_iterator ci;
394  for (ci = config_files.rbegin(); ci != config_files.rend(); ++ci) {
395  const ConfigFile &file = (*ci);
396  Filename filename = file._filename;
397 
398  if ((file._file_flags & FF_execute) != 0 &&
399  filename.is_executable()) {
400  // Attempt to execute the file as a command.
401  string command = filename.to_os_specific();
402 
403  string envvar = PRC_EXECUTABLE_ARGS_ENVVAR;
404  if (blobinfo != nullptr && blobinfo->prc_executable_args_envvar != nullptr) {
405  envvar = blobinfo->prc_executable_args_envvar;
406  }
407  if (!envvar.empty()) {
409  if (!args.empty()) {
410  command += " ";
411  command += args;
412  }
413  }
414  IPipeStream ifs(command);
415 
416  ConfigPage *page = new ConfigPage(filename, true, i);
417  ++i;
418  _implicit_pages.push_back(page);
419  _pages_sorted = false;
420 
421  page->read_prc(ifs);
422 
423  } else if ((file._file_flags & FF_decrypt) != 0) {
424  // Read and decrypt the file.
425  filename.set_binary();
426 
427  pifstream in;
428  if (!filename.open_read(in)) {
429  prc_cat.error()
430  << "Unable to read " << filename << "\n";
431  } else {
432  ConfigPage *page = new ConfigPage(filename, true, i);
433  ++i;
434  _implicit_pages.push_back(page);
435  _pages_sorted = false;
436 
437  if (blobinfo != nullptr && blobinfo->prc_encryption_key != nullptr) {
438  page->read_encrypted_prc(in, blobinfo->prc_encryption_key);
439  } else {
440  page->read_encrypted_prc(in, PRC_ENCRYPTION_KEY);
441  }
442  }
443 
444  } else if ((file._file_flags & FF_read) != 0) {
445  // Just read the file.
446  filename.set_text();
447 
448  pifstream in;
449  if (!filename.open_read(in)) {
450  prc_cat.error()
451  << "Unable to read " << filename << "\n";
452  } else {
453  ConfigPage *page = new ConfigPage(filename, true, i);
454  ++i;
455  _implicit_pages.push_back(page);
456  _pages_sorted = false;
457 
458  page->read_prc(in);
459  }
460  }
461  }
462 
463  if (!_loaded_implicit) {
464  config_initialized();
465  _loaded_implicit = true;
466  }
467 
468  _currently_loading = false;
469  invalidate_cache();
470 
471 #ifdef USE_PANDAFILESTREAM
472  // Update this very low-level config variable here, for lack of any better
473  // place.
475  ("newline-mode", PandaFileStreamBuf::NM_native,
476  PRC_DESC("Controls how newlines are written by Panda applications writing "
477  "to a text file. The default, \"native\", means to write newlines "
478  "appropriate to the current platform. You may also specify \"binary\", "
479  "to avoid molesting the file data, or one of \"msdos\", \"unix\", "
480  "or \"mac\"."));
481  PandaFileStreamBuf::_newline_mode = newline_mode;
482 #endif // USE_PANDAFILESTREAM
483 
484 #ifdef WIN32
485  // We don't necessarily want an error dialog when we fail to load a .dll
486  // file. But sometimes it is useful for debugging.
487  ConfigVariableBool show_dll_error_dialog
488  ("show-dll-error-dialog", false,
489  PRC_DESC("Set this true to enable the Windows system dialog that pops "
490  "up when a DLL fails to load, or false to disable it. It is "
491  "normally false, but it may be useful to set it true to debug "
492  "why a DLL is not loading. (Note that this actually disables "
493  "*all* critical error messages, and that it's a global setting "
494  "that some other libraries might un-set.)"));
495  if (show_dll_error_dialog) {
496  SetErrorMode(0);
497  } else {
498  SetErrorMode(SEM_FAILCRITICALERRORS);
499  }
500 #endif
501 
502 }
503 
504 /**
505  * Creates and returns a new, empty ConfigPage. This page will be stacked on
506  * top of any pages that were created before; it may shadow variable
507  * declarations that are defined in previous pages.
508  */
510 make_explicit_page(const string &name) {
511  ConfigPage *page = new ConfigPage(name, false, _next_page_seq);
512  ++_next_page_seq;
513  _explicit_pages.push_back(page);
514  _pages_sorted = false;
515  invalidate_cache();
516  return page;
517 }
518 
519 /**
520  * Removes a previously-constructed ConfigPage from the set of active pages,
521  * and deletes it. The ConfigPage object is no longer valid after this call.
522  * Returns true if the page is successfully deleted, or false if it was
523  * unknown (which should never happen if the page was legitimately
524  * constructed).
525  */
528  Pages::iterator pi;
529  for (pi = _explicit_pages.begin(); pi != _explicit_pages.end(); ++pi) {
530  if ((*pi) == page) {
531  _explicit_pages.erase(pi);
532  delete page;
533  invalidate_cache();
534  return true;
535  }
536  }
537  return false;
538 }
539 
540 /**
541  *
542  */
543 void ConfigPageManager::
544 output(std::ostream &out) const {
545  out << "ConfigPageManager, "
546  << _explicit_pages.size() + _implicit_pages.size()
547  << " pages.";
548 }
549 
550 /**
551  *
552  */
553 void ConfigPageManager::
554 write(std::ostream &out) const {
555  check_sort_pages();
556  out << _explicit_pages.size() << " explicit pages:\n";
557 
558  Pages::const_iterator pi;
559  for (pi = _explicit_pages.begin(); pi != _explicit_pages.end(); ++pi) {
560  const ConfigPage *page = (*pi);
561  out << " " << page->get_name();
562  if (page->get_trust_level() > 0) {
563  out << " (signed " << page->get_trust_level() << ": ";
564  page->output_brief_signature(out);
565  out << ")\n";
566  } else if (!page->get_signature().empty()) {
567  out << " (invalid signature: ";
568  page->output_brief_signature(out);
569  out << ")\n";
570  } else {
571  out << "\n";
572  }
573  }
574 
575  out << "\n" << _implicit_pages.size() << " implicit pages:\n";
576  for (pi = _implicit_pages.begin(); pi != _implicit_pages.end(); ++pi) {
577  const ConfigPage *page = (*pi);
578  out << " " << page->get_name();
579  if (page->get_trust_level() > 0) {
580  out << " (signed " << page->get_trust_level() << ": ";
581  page->output_brief_signature(out);
582  out << ")\n";
583  } else if (!page->get_signature().empty()) {
584  out << " (invalid signature: ";
585  page->output_brief_signature(out);
586  out << ")\n";
587  } else {
588  out << "\n";
589  }
590  }
591 }
592 
593 /**
594  *
595  */
596 ConfigPageManager *ConfigPageManager::
597 get_global_ptr() {
598  if (_global_ptr == nullptr) {
599  _global_ptr = new ConfigPageManager;
600  }
601  return _global_ptr;
602 }
603 
604 // This class is used in sort_pages, below.
605 class CompareConfigPages {
606 public:
607  bool operator () (const ConfigPage *a, const ConfigPage *b) const {
608  return (*a) < (*b);
609  }
610 };
611 
612 /**
613  * Sorts the list of pages into priority order, so that the page at the front
614  * of the list is the one that shadows all following pages.
615  */
616 void ConfigPageManager::
617 sort_pages() {
618  sort(_implicit_pages.begin(), _implicit_pages.end(), CompareConfigPages());
619  sort(_explicit_pages.begin(), _explicit_pages.end(), CompareConfigPages());
620 
621  _pages_sorted = true;
622 }
623 
624 /**
625  * Checks for the prefix "<auto>" in the value of the $PRC_DIR environment
626  * variable (or in the compiled-in DEFAULT_PRC_DIR value). If it is found,
627  * then the actual directory is determined by searching upward from the
628  * executable's starting directory, or from the current working directory,
629  * until at least one .prc file is found.
630  *
631  * Returns true if the prc_dir has been filled with a valid directory name,
632  * false if no good directory name was found.
633  */
634 bool ConfigPageManager::
635 scan_auto_prc_dir(Filename &prc_dir) const {
636  string prc_dir_string = prc_dir;
637  if (prc_dir_string.substr(0, 6) == "<auto>") {
638  Filename suffix = prc_dir_string.substr(6);
639 
640  // Start at the dtool directory.
642  Filename dir = dtool.get_dirname();
643 
644  if (scan_up_from(prc_dir, dir, suffix)) {
645  return true;
646  }
647 
648  // Try the program's directory.
650  if (scan_up_from(prc_dir, dir, suffix)) {
651  return true;
652  }
653 
654  // Didn't find it; too bad.
655  std::cerr << "Warning: unable to auto-locate config files in directory named by \""
656  << prc_dir << "\".\n";
657  return false;
658  }
659 
660  // The filename did not begin with "<auto>", so it stands unchanged.
661  return true;
662 }
663 
664 /**
665  * Used to implement scan_auto_prc_dir(), above, this scans upward from the
666  * indicated directory name until a directory is found that includes at least
667  * one .prc file, or the root directory is reached.
668  *
669  * If a match is found, puts it result and returns true; otherwise, returns
670  * false.
671  */
672 bool ConfigPageManager::
673 scan_up_from(Filename &result, const Filename &dir,
674  const Filename &suffix) const {
675  Filename consider(dir, suffix);
676 
677  vector_string files;
678  if (consider.is_directory()) {
679  if (consider.scan_directory(files)) {
680  vector_string::const_iterator fi;
681  for (fi = files.begin(); fi != files.end(); ++fi) {
682  Globs::const_iterator gi;
683  for (gi = _prc_patterns.begin();
684  gi != _prc_patterns.end();
685  ++gi) {
686  if ((*gi).matches(*fi)) {
687  result = consider;
688  return true;
689  }
690  }
691 
692  for (gi = _prc_executable_patterns.begin();
693  gi != _prc_executable_patterns.end();
694  ++gi) {
695  if ((*gi).matches(*fi)) {
696  result = consider;
697  return true;
698  }
699  }
700  }
701  }
702  }
703 
704  Filename parent = dir.get_dirname();
705 
706  if (dir == parent) {
707  // Too bad; couldn't find a match.
708  return false;
709  }
710 
711  // Recursively try again on the parent.
712  return scan_up_from(result, parent, suffix);
713 }
714 
715 /**
716  * This is called once, at startup, the first time that the config system has
717  * been initialized and is ready to read config variables. It's intended to
718  * be a place to initialize values that are defined at a lower level than the
719  * config system itself.
720  */
721 void ConfigPageManager::
722 config_initialized() {
724 
725 #ifndef NDEBUG
726  ConfigVariableString panda_package_version
727  ("panda-package-version", "local_dev",
728  PRC_DESC("This can be used to specify the value returned by "
729  "PandaSystem::get_package_version_str(), in development mode only, "
730  "and only if another value has not already been compiled in. This "
731  "is intended for developer convenience, to masquerade a development "
732  "build of Panda as a different runtime version. Use with caution."));
733  ConfigVariableString panda_package_host_url
734  ("panda-package-host-url", "",
735  PRC_DESC("This can be used to specify the value returned by "
736  "PandaSystem::get_package_host_url(), in development mode only, "
737  "and only if another value has not already been compiled in. This "
738  "is intended for developer convenience, to masquerade a development "
739  "build of Panda as a different runtime version. Use with caution."));
740 
742  panda_sys->set_package_version_string(panda_package_version);
743  panda_sys->set_package_host_url(panda_package_host_url);
744 #endif // NDEBUG
745 
746  // Also set up some other low-level things.
748  ("text-encoding", TextEncoder::E_utf8,
749  PRC_DESC("Specifies how international characters are represented in strings "
750  "of 8-byte characters presented to Panda. See TextEncoder::set_encoding()."));
751  TextEncoder::set_default_encoding(text_encoding);
752 
754  ("filesystem-encoding", TextEncoder::E_utf8,
755  PRC_DESC("Specifies the default encoding used for wide-character filenames."));
756  Filename::set_filesystem_encoding(filesystem_encoding);
757 
759 }
static PandaSystem * get_global_ptr()
Returns the global PandaSystem object.
std::string get_dirname() const
Returns the directory part of the filename.
Definition: filename.I:358
get_name
Returns the name of the page.
Definition: configPage.h:43
static size_t extract_words(const std::string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
This class is used as a namespace to group several global properties of Panda.
Definition: pandaSystem.h:26
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
set_case_sensitive
Sets whether the match is case sensitive (true) or case insensitive (false).
Definition: globPattern.h:48
This is a convenience class to specialize ConfigVariable as a boolean type.
void clear()
Removes all the directories from the search list.
void set_binary()
Indicates that the filename represents a binary file.
Definition: filename.I:414
void set_text()
Indicates that the filename represents a text file.
Definition: filename.I:424
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
Definition: filename.cxx:1863
bool read_encrypted_prc(std::istream &in, const std::string &password)
Automatically decrypts and reads the stream, given the indicated password.
Definition: configPage.cxx:224
bool is_empty() const
Returns true if the search list is empty, false otherwise.
get_signature
Returns the raw binary signature that was found in the prc file, if any.
Definition: configPage.h:60
set_default_encoding
Specifies the default encoding to be used for all subsequently created TextEncoder objects.
Definition: textEncoder.h:54
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
Definition: filename.cxx:1011
bool make_true_case()
On a case-insensitive operating system (e.g.
Definition: filename.cxx:1053
get_dtool_name
Returns the name of the libdtool DLL that is used in this program, if it can be determined.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
static std::ostream & out()
A convenient way to get the ostream that should be written to for a Notify- type message.
Definition: notify.cxx:261
get_trust_level
Returns the trust level associated with this page.
Definition: configPage.h:59
bool read_prc(std::istream &in)
Reads the contents of a complete prc file, as returned by the indicated istream, into the current pag...
Definition: configPage.cxx:124
static Notify * ptr()
Returns the pointer to the global Notify object.
Definition: notify.cxx:289
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A global object that maintains the set of ConfigPages everywhere in the world, and keeps them in sort...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
static void set_filesystem_encoding(TextEncoder::Encoding encoding)
Specifies the default encoding to be used for all subsequent Filenames.
Definition: filename.I:630
get_num_directories
Returns the number of directories on the search list.
Definition: dSearchPath.h:76
bool is_executable() const
Returns true if the filename exists and is executable.
Definition: filename.cxx:1387
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of a file, such as a texture file or an Egg file.
Definition: filename.h:39
This is a convenience class to specialize ConfigVariable as a string type.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void reload_implicit_pages()
Searches the PRC_DIR and/or PRC_PATH directories for *.prc files and loads them in as pages.
ConfigPage * make_explicit_page(const std::string &name)
Creates and returns a new, empty ConfigPage.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This class specializes ConfigVariable as an enumerated type.
A page of ConfigDeclarations that may be loaded or unloaded.
Definition: configPage.h:30
bool is_directory() const
Returns true if the filename exists and is a directory name, false otherwise.
Definition: filename.cxx:1359
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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:424
get_directory
Returns the nth directory on the search list.
Definition: dSearchPath.h:76
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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:1718
static void set_notify_ptr(std::ostream *ptr)
Sets the ostream that is used to write error messages to.
set_environment_variable
Changes the definition of the indicated environment variable.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
bool delete_explicit_page(ConfigPage *page)
Removes a previously-constructed ConfigPage from the set of active pages, and deletes it.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
Definition: filename.cxx:1123
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void output_brief_signature(std::ostream &out) const
Outputs the first few hex digits of the signature.
Definition: configPage.cxx:346
static Filename from_os_specific(const std::string &os_specific, Type type=T_general)
This named constructor returns a Panda-style filename (that is, using forward slashes,...
Definition: filename.cxx:328
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition: globPattern.h:32
get_environment_variable
Returns the definition of the indicated environment variable, or the empty string if the variable is ...