Panda3D
Loading...
Searching...
No Matches
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"
18#include "configPage.h"
19#include "prcKeyRegistry.h"
20#include "dSearchPath.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
45using std::string;
46
47ConfigPageManager *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 */
54ConfigPageManager::
55ConfigPageManager() {
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 */
71ConfigPageManager::
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 */
510make_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 */
543void ConfigPageManager::
544output(std::ostream &out) const {
545 out << "ConfigPageManager, "
546 << _explicit_pages.size() + _implicit_pages.size()
547 << " pages.";
548}
549
550/**
551 *
552 */
553void ConfigPageManager::
554write(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 */
596ConfigPageManager *ConfigPageManager::
597get_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.
605class CompareConfigPages {
606public:
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 */
616void ConfigPageManager::
617sort_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 */
634bool ConfigPageManager::
635scan_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 */
672bool ConfigPageManager::
673scan_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 */
721void ConfigPageManager::
722config_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()."));
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 size_t extract_words(const std::string &str, vector_string &words)
Divides the string into a number of words according to whitespace.
A global object that maintains the set of ConfigPages everywhere in the world, and keeps them in sort...
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 std::string &name)
Creates and returns a new, empty ConfigPage.
void reload_implicit_pages()
Searches the PRC_DIR and/or PRC_PATH directories for *.prc files and loads them in as pages.
A page of ConfigDeclarations that may be loaded or unloaded.
Definition configPage.h:30
get_signature
Returns the raw binary signature that was found in the prc file, if any.
Definition configPage.h:60
bool read_encrypted_prc(std::istream &in, const std::string &password)
Automatically decrypts and reads the stream, given the indicated password.
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...
void output_brief_signature(std::ostream &out) const
Outputs the first few hex digits of the signature.
get_name
Returns the name of the page.
Definition configPage.h:43
This is a convenience class to specialize ConfigVariable as a boolean type.
This class specializes ConfigVariable as an enumerated type.
This is a convenience class to specialize ConfigVariable as a string type.
bool is_empty() const
Returns true if the search list is empty, false otherwise.
get_num_directories
Returns the number of directories on the search list.
Definition dSearchPath.h:76
void clear()
Removes all the directories from the search list.
void append_directory(const Filename &directory)
Adds a new directory to the end of the search list.
get_directory
Returns the nth directory on the search list.
Definition dSearchPath.h:76
get_dtool_name
Returns the name of the libdtool DLL that is used in this program, if it can be determined.
set_environment_variable
Changes the definition of the indicated environment variable.
get_environment_variable
Returns the definition of the indicated environment variable, or the empty string if the variable is ...
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
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...
bool is_executable() const
Returns true if the filename exists and is executable.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
bool open_read(std::ifstream &stream) const
Opens the indicated ifstream for reading the file, if possible.
void set_binary()
Indicates that the filename represents a binary file.
Definition filename.I:414
bool make_true_case()
On a case-insensitive operating system (e.g.
static void set_filesystem_encoding(TextEncoder::Encoding encoding)
Specifies the default encoding to be used for all subsequent Filenames.
Definition filename.I:630
void set_text()
Indicates that the filename represents a text file.
Definition filename.I:424
bool make_canonical()
Converts this filename to a canonical name by replacing the directory part with the fully-qualified d...
bool is_directory() const
Returns true if the filename exists on the physical disk and is a directory name, false otherwise.
std::string get_dirname() const
Returns the directory part of the filename.
Definition filename.I:358
This class can be used to test for string matches against standard Unix- shell filename globbing conv...
Definition globPattern.h:32
set_case_sensitive
Sets whether the match is case sensitive (true) or case insensitive (false).
Definition globPattern.h:48
static std::ostream & out()
A convenient way to get the ostream that should be written to for a Notify- type message.
Definition notify.cxx:265
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:428
static Notify * ptr()
Returns the pointer to the global Notify object.
Definition notify.cxx:293
This class is used as a namespace to group several global properties of Panda.
Definition pandaSystem.h:26
static PandaSystem * get_global_ptr()
Returns the global PandaSystem object.
static void set_notify_ptr(std::ostream *ptr)
Sets the ostream that is used to write error messages to.
set_default_encoding
Specifies the default encoding to be used for all subsequently created TextEncoder objects.
Definition textEncoder.h:54
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.