15 #include "executionEnvironment.h" 16 #include "pandaVersion.h" 23 #include <sys/param.h> 29 #define getcwd _getcwd 43 #include <mach-o/dyld.h> 45 #include <crt_externs.h> 47 #define environ (*_NSGetEnviron()) 56 extern char **environ;
59 #include <sys/types.h> 60 #include <sys/sysctl.h> 63 #if defined(IS_LINUX) || defined(IS_FREEBSD) 78 #ifndef STATIC_INIT_GETENV 79 #define PREREAD_ENVIRONMENT 86 #if !defined(WIN32_VC) && defined(HAVE_GLOBAL_ARGV) && defined(PROTOTYPE_GLOBAL_ARGV) 87 extern char **GLOBAL_ARGV;
88 extern int GLOBAL_ARGC;
103 ExecutionEnvironment::
104 ExecutionEnvironment() {
105 read_environment_variables();
124 size_t dollar = str.find(
'$');
125 while (dollar != string::npos && dollar + 1 < str.length()) {
126 size_t start = dollar + 1;
128 if (str[start] ==
'$') {
130 result += str.substr(last, start - last);
137 if (str[start] ==
'{') {
139 end = str.find(
'}', start + 1);
140 if (end != string::npos) {
141 varname = str.substr(start + 1, end - (start + 1));
148 while (end < str.length() && (isalnum(str[end]) || str[end] ==
'_')) {
151 varname = str.substr(start, end - start);
155 result += str.substr(last, dollar - last);
160 dollar = str.find(
'$', last);
163 result += str.substr(last);
178 static size_t bufsize = 1024;
179 static wchar_t *buffer = NULL;
181 if (buffer == (
wchar_t *)NULL) {
182 buffer =
new wchar_t[bufsize];
185 while (_wgetcwd(buffer, bufsize) == (
wchar_t *)NULL) {
186 if (errno != ERANGE) {
191 bufsize = bufsize * 2;
192 buffer =
new wchar_t[bufsize];
193 assert(buffer != (
wchar_t *)NULL);
202 static size_t bufsize = 1024;
203 static char *buffer = NULL;
205 if (buffer == (
char *)NULL) {
206 buffer =
new char[bufsize];
209 while (getcwd(buffer, bufsize) == (
char *)NULL) {
210 if (errno != ERANGE) {
215 bufsize = bufsize * 2;
216 buffer =
new char[bufsize];
217 assert(buffer != (
char *)NULL);
232 bool ExecutionEnvironment::
233 ns_has_environment_variable(
const string &var)
const {
234 #ifdef PREREAD_ENVIRONMENT 235 return _variables.count(var) != 0;
237 return getenv(var.c_str()) != (
char *)NULL;
248 string ExecutionEnvironment::
249 ns_get_environment_variable(
const string &var)
const {
250 EnvironmentVariables::const_iterator evi;
251 evi = _variables.find(var);
252 if (evi != _variables.end()) {
253 return (*evi).second;
261 }
else if (var ==
"TEMP") {
263 }
else if (var ==
"USER_APPDATA") {
265 }
else if (var ==
"COMMON_APPDATA") {
267 }
else if (var ==
"MAIN_DIR") {
270 if (!ns_has_environment_variable(
"PANDA_INCOMPATIBLE_PYTHON") && Py_IsInitialized()) {
276 PyGILState_STATE state = PyGILState_Ensure();
280 PyObject *obj = PySys_GetObject((
char*)
"argv");
281 if (obj != NULL && PyList_Check(obj)) {
282 PyObject *item = PyList_GetItem(obj, 0);
284 if (PyUnicode_Check(item)) {
285 Py_ssize_t size = PyUnicode_GetSize(item);
286 wchar_t *data = (
wchar_t *)alloca(
sizeof(
wchar_t) * (size + 1));
287 #if PY_MAJOR_VERSION >= 3 288 if (PyUnicode_AsWideChar(item, data, size) != -1) {
290 if (PyUnicode_AsWideChar((PyUnicodeObject*) item, data, size) != -1) {
292 wstring wstr (data, size);
296 #if PY_MAJOR_VERSION < 3 297 else if (PyString_Check(item)) {
298 char *str = PyString_AsString(item);
299 if (str != (
char *)NULL) {
308 PyGILState_Release(state);
311 if (main_dir.empty()) {
321 if (!_binary_name.empty()) {
328 #ifndef PREREAD_ENVIRONMENT 329 const char *def = getenv(var.c_str());
330 if (def != (
char *)NULL) {
342 static struct {
int id;
const char *name; } csidl_table[] = {
343 { CSIDL_ADMINTOOLS,
"ADMINTOOLS" },
344 { CSIDL_ALTSTARTUP,
"ALTSTARTUP" },
345 { CSIDL_APPDATA,
"APPDATA" },
346 { CSIDL_BITBUCKET,
"BITBUCKET" },
347 { CSIDL_CDBURN_AREA,
"CDBURN_AREA" },
348 { CSIDL_COMMON_ADMINTOOLS,
"COMMON_ADMINTOOLS" },
349 { CSIDL_COMMON_ALTSTARTUP,
"COMMON_ALTSTARTUP" },
350 { CSIDL_COMMON_APPDATA,
"COMMON_APPDATA" },
351 { CSIDL_COMMON_DESKTOPDIRECTORY,
"COMMON_DESKTOPDIRECTORY" },
352 { CSIDL_COMMON_DOCUMENTS,
"COMMON_DOCUMENTS" },
353 { CSIDL_COMMON_FAVORITES,
"COMMON_FAVORITES" },
354 { CSIDL_COMMON_MUSIC,
"COMMON_MUSIC" },
355 { CSIDL_COMMON_OEM_LINKS,
"COMMON_OEM_LINKS" },
356 { CSIDL_COMMON_PICTURES,
"COMMON_PICTURES" },
357 { CSIDL_COMMON_PROGRAMS,
"COMMON_PROGRAMS" },
358 { CSIDL_COMMON_STARTMENU,
"COMMON_STARTMENU" },
359 { CSIDL_COMMON_STARTUP,
"COMMON_STARTUP" },
360 { CSIDL_COMMON_TEMPLATES,
"COMMON_TEMPLATES" },
361 { CSIDL_COMMON_VIDEO,
"COMMON_VIDEO" },
362 { CSIDL_COMPUTERSNEARME,
"COMPUTERSNEARME" },
363 { CSIDL_CONNECTIONS,
"CONNECTIONS" },
364 { CSIDL_CONTROLS,
"CONTROLS" },
365 { CSIDL_COOKIES,
"COOKIES" },
366 { CSIDL_DESKTOP,
"DESKTOP" },
367 { CSIDL_DESKTOPDIRECTORY,
"DESKTOPDIRECTORY" },
368 { CSIDL_DRIVES,
"DRIVES" },
369 { CSIDL_FAVORITES,
"FAVORITES" },
370 { CSIDL_FONTS,
"FONTS" },
371 { CSIDL_HISTORY,
"HISTORY" },
372 { CSIDL_INTERNET,
"INTERNET" },
373 { CSIDL_INTERNET_CACHE,
"INTERNET_CACHE" },
374 { CSIDL_LOCAL_APPDATA,
"LOCAL_APPDATA" },
375 { CSIDL_MYDOCUMENTS,
"MYDOCUMENTS" },
376 { CSIDL_MYMUSIC,
"MYMUSIC" },
377 { CSIDL_MYPICTURES,
"MYPICTURES" },
378 { CSIDL_MYVIDEO,
"MYVIDEO" },
379 { CSIDL_NETHOOD,
"NETHOOD" },
380 { CSIDL_NETWORK,
"NETWORK" },
381 { CSIDL_PERSONAL,
"PERSONAL" },
382 { CSIDL_PRINTERS,
"PRINTERS" },
383 { CSIDL_PRINTHOOD,
"PRINTHOOD" },
384 { CSIDL_PROFILE,
"PROFILE" },
385 { CSIDL_PROGRAM_FILES,
"PROGRAM_FILES" },
386 { CSIDL_PROGRAM_FILESX86,
"PROGRAM_FILESX86" },
387 { CSIDL_PROGRAM_FILES_COMMON,
"PROGRAM_FILES_COMMON" },
388 { CSIDL_PROGRAM_FILES_COMMONX86,
"PROGRAM_FILES_COMMONX86" },
389 { CSIDL_PROGRAMS,
"PROGRAMS" },
390 { CSIDL_RECENT,
"RECENT" },
391 { CSIDL_RESOURCES,
"RESOURCES" },
392 { CSIDL_RESOURCES_LOCALIZED,
"RESOURCES_LOCALIZED" },
393 { CSIDL_SENDTO,
"SENDTO" },
394 { CSIDL_STARTMENU,
"STARTMENU" },
395 { CSIDL_STARTUP,
"STARTUP" },
396 { CSIDL_SYSTEM,
"SYSTEM" },
397 { CSIDL_SYSTEMX86,
"SYSTEMX86" },
398 { CSIDL_TEMPLATES,
"TEMPLATES" },
399 { CSIDL_WINDOWS,
"WINDOWS" },
403 for (
int i = 0; csidl_table[i].name != NULL; ++i) {
404 if (strcmp(var.c_str(), csidl_table[i].name) == 0) {
405 wchar_t buffer[MAX_PATH];
406 if (SHGetSpecialFolderPathW(NULL, buffer, csidl_table[i].
id,
true)) {
425 void ExecutionEnvironment::
426 ns_set_environment_variable(
const string &var,
const string &value) {
427 _variables[var] = value;
428 string putstr = var +
"=" + value;
431 char *put = (
char *)malloc(putstr.length() + 1);
432 strcpy(put, putstr.c_str());
441 void ExecutionEnvironment::
442 ns_shadow_environment_variable(
const string &var,
const string &value) {
443 _variables[var] = value;
444 string putstr = var +
"=" + value;
452 void ExecutionEnvironment::
453 ns_clear_shadow(
const string &var) {
454 EnvironmentVariables::iterator vi = _variables.find(var);
455 if (vi == _variables.end()) {
459 #ifdef PREREAD_ENVIRONMENT 461 const char *def = getenv(var.c_str());
462 if (def != (
char *)NULL) {
465 _variables.erase(vi);
467 #endif // PREREAD_ENVIRONMENT 477 int ExecutionEnvironment::
478 ns_get_num_args()
const {
491 string ExecutionEnvironment::
492 ns_get_arg(
int n)
const {
493 assert(n >= 0 && n < ns_get_num_args());
504 string ExecutionEnvironment::
505 ns_get_binary_name()
const {
506 if (_binary_name.empty()) {
519 string ExecutionEnvironment::
520 ns_get_dtool_name()
const {
521 if (_dtool_name.empty()) {
549 void ExecutionEnvironment::
550 read_environment_variables() {
551 #ifdef PREREAD_ENVIRONMENT 552 #if defined(IS_OSX) || defined(IS_FREEBSD) || defined(IS_LINUX) 557 for (envp = environ; envp && *envp; envp++) {
562 for (envc = *envp; envc && *envc && strncmp(envc,
"=", 1) != 0; envc++) {
563 variable += (char) *envc;
566 if (strncmp(envc,
"=", 1) == 0) {
567 for (envc++; envc && *envc; envc++) {
568 value += (char) *envc;
572 if (!variable.empty()) {
573 _variables[variable] = value;
576 #elif defined(HAVE_PROC_SELF_ENVIRON) 580 pifstream proc(
"/proc/self/environ");
582 cerr <<
"Cannot read /proc/self/environ; environment variables unavailable.\n";
587 while (!proc.eof() && !proc.fail()) {
591 while (!proc.eof() && !proc.fail() && ch !=
'=' && ch !=
'\0') {
592 variable += (char)ch;
598 while (!proc.eof() && !proc.fail() && ch !=
'\0') {
604 if (!variable.empty()) {
605 _variables[variable] = value;
610 cerr <<
"Warning: environment variables unavailable to dconfig.\n";
612 #endif // PREREAD_ENVIRONMENT 621 void ExecutionEnvironment::
629 HMODULE dllhandle = GetModuleHandle(
"libp3dtool_d.dll");
631 HMODULE dllhandle = GetModuleHandle(
"libp3dtool.dll");
633 if (dllhandle != 0) {
634 static const DWORD buffer_size = 1024;
635 wchar_t buffer[buffer_size];
636 DWORD size = GetModuleFileNameW(dllhandle, buffer, buffer_size);
645 #if defined(__APPLE__) 648 if (_dtool_name.empty()) {
649 uint32_t ic = _dyld_image_count();
650 for (uint32_t i = 0; i < ic; ++i) {
651 const char *buffer = _dyld_get_image_name(i);
652 const char *tail = strrchr(buffer,
'/');
653 if (tail && (strcmp(tail,
"/libp3dtool." PANDA_ABI_VERSION_STR
".dylib") == 0
654 || strcmp(tail,
"/libp3dtool.dylib") == 0)) {
655 _dtool_name = buffer;
661 #if defined(IS_FREEBSD) || defined(IS_LINUX) 664 char origin[PATH_MAX + 1];
666 if (_dtool_name.empty()) {
667 void *dtool_handle = dlopen(
"libp3dtool.so." PANDA_ABI_VERSION_STR, RTLD_NOW | RTLD_NOLOAD);
668 if (dtool_handle != NULL && dlinfo(dtool_handle, RTLD_DI_ORIGIN, origin) != -1) {
669 _dtool_name = origin;
670 _dtool_name +=
"/libp3dtool.so." PANDA_ABI_VERSION_STR;
673 dtool_handle = dlopen(
"libp3dtool.so", RTLD_NOW | RTLD_NOLOAD);
674 if (dtool_handle != NULL && dlinfo(dtool_handle, RTLD_DI_ORIGIN, origin) != -1) {
675 _dtool_name = origin;
676 _dtool_name +=
"/libp3dtool.so";
682 #if defined(IS_FREEBSD) 685 if (_dtool_name.empty()) {
687 dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &map);
689 while (map != NULL) {
690 const char *tail = strrchr(map->l_name,
'/');
691 const char *head = strchr(map->l_name,
'/');
692 if (tail && head && (strcmp(tail,
"/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
693 || strcmp(tail,
"/libp3dtool.so") == 0)) {
701 #if defined(HAVE_PROC_SELF_MAPS) || defined(HAVE_PROC_CURPROC_MAP) 704 if (_dtool_name.empty()) {
705 #ifdef HAVE_PROC_CURPROC_MAP 706 pifstream maps(
"/proc/curproc/map");
708 pifstream maps(
"/proc/self/maps");
710 while (!maps.fail() && !maps.eof()) {
711 char buffer[PATH_MAX];
713 maps.getline(buffer, PATH_MAX);
714 const char *tail = strrchr(buffer,
'/');
715 const char *head = strchr(buffer,
'/');
716 if (tail && head && (strcmp(tail,
"/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
717 || strcmp(tail,
"/libp3dtool.so") == 0)) {
729 if (_binary_name.empty()) {
730 static const DWORD buffer_size = 1024;
731 wchar_t buffer[buffer_size];
732 DWORD size = GetModuleFileNameW(NULL, buffer, buffer_size);
741 #if defined(__APPLE__) 743 if (_binary_name.empty()) {
744 char *pathbuf =
new char[PATH_MAX];
745 uint32_t bufsize = PATH_MAX;
746 if (_NSGetExecutablePath(pathbuf, &bufsize) == 0) {
747 _binary_name = pathbuf;
753 #if defined(IS_FREEBSD) 756 if (_binary_name.empty()) {
757 size_t bufsize = 4096;
759 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
761 if (sysctl(mib, 4, (
void*) buffer, &bufsize, NULL, 0) == -1) {
764 _binary_name = buffer;
769 #if defined(HAVE_PROC_SELF_EXE) || defined(HAVE_PROC_CURPROC_FILE) 773 if (_binary_name.empty()) {
774 char readlinkbuf [PATH_MAX];
775 #ifdef HAVE_PROC_CURPROC_FILE 776 int pathlen = readlink(
"/proc/curproc/file", readlinkbuf, PATH_MAX - 1);
778 int pathlen = readlink(
"/proc/self/exe", readlinkbuf, PATH_MAX - 1);
781 readlinkbuf[pathlen] = 0;
782 _binary_name = readlinkbuf;
790 #if defined(WIN32_VC) 795 LPWSTR cmdline = GetCommandLineW();
797 LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc);
800 cerr <<
"CommandLineToArgvW failed; command-line arguments unavailable to config.\n";
806 for (
int i = 0; i < argc; ++i) {
807 wstring wtext(wargv[i]);
811 if (_binary_name.empty()) {
815 _args.push_back(encoder.
get_text());
822 #elif defined(IS_FREEBSD) 825 size_t bufsize = 4096;
827 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0};
829 if (sysctl(mib, 4, (
void*) buffer, &bufsize, NULL, 0) == -1) {
832 if (_binary_name.empty()) {
833 _binary_name = buffer;
835 int idx = strlen(buffer) + 1;
836 while (idx < bufsize) {
837 _args.push_back((
char*)(buffer + idx));
838 int newidx = strlen(buffer + idx);
843 #elif defined(HAVE_GLOBAL_ARGV) 844 int argc = GLOBAL_ARGC;
848 if (GLOBAL_ARGV != NULL) {
849 if (_binary_name.empty() && argc > 0) {
850 _binary_name = GLOBAL_ARGV[0];
854 for (
int i = 1; i < argc; i++) {
855 _args.push_back(GLOBAL_ARGV[i]);
859 #elif defined(HAVE_PROC_SELF_CMDLINE) || defined(HAVE_PROC_CURPROC_CMDLINE) 866 #ifdef HAVE_PROC_CURPROC_CMDLINE 867 pifstream proc(
"/proc/curproc/cmdline");
869 cerr <<
"Cannot read /proc/curproc/cmdline; command-line arguments unavailable to config.\n";
871 pifstream proc(
"/proc/self/cmdline");
873 cerr <<
"Cannot read /proc/self/cmdline; command-line arguments unavailable to config.\n";
878 while (!proc.eof() && !proc.fail()) {
881 while (!proc.eof() && !proc.fail() && ch !=
'\0') {
887 if (_binary_name.empty())
890 _args.push_back(arg);
902 if (!_binary_name.empty()) {
903 char newpath [PATH_MAX + 1];
904 if (realpath(_binary_name.c_str(), newpath) != NULL) {
905 _binary_name = newpath;
909 if (!_dtool_name.empty()) {
910 char newpath [PATH_MAX + 1];
911 if (realpath(_dtool_name.c_str(), newpath) != NULL) {
912 _dtool_name = newpath;
919 if (_dtool_name.empty()) {
920 _dtool_name = _binary_name;
string get_dirname() const
Returns the directory part of the filename.
This class can be used to convert text between multiple representations, e.g.
bool make_true_case()
On a case-insensitive operating system (e.g.
static const Filename & get_home_directory()
Returns a path to the user's home directory, if such a thing makes sense in the current OS...
static TextEncoder::Encoding get_filesystem_encoding()
Specifies the default encoding to be used for all subsequent Filenames objects.
The name of a file, such as a texture file or an Egg file.
static const Filename & get_user_appdata_directory()
Returns a path to a system-defined directory appropriate for creating a subdirectory for storing appl...
static const Filename & get_temp_directory()
Returns a path to a system-defined temporary directory.
static string get_environment_variable(const string &var)
Returns the definition of the indicated environment variable, or the empty string if the variable is ...
void make_absolute()
Converts the filename to a fully-qualified pathname from the root (if it is a relative pathname)...
void set_encoding(Encoding encoding)
Specifies how the string set via set_text() is to be interpreted.
static const Filename & get_common_appdata_directory()
Returns a path to a system-defined directory appropriate for creating a subdirectory for storing appl...
Encapsulates access to the environment variables and command-line arguments at the time of execution...
static Filename from_os_specific_w(const wstring &os_specific, Type type=T_general)
The wide-string variant of from_os_specific().
static Filename get_cwd()
Returns the name of the current working directory.
static string expand_string(const string &str)
Reads the string, looking for environment variable names marked by a $.
void set_wtext(const wstring &wtext)
Changes the text that is stored in the encoder.
string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
string get_text() const
Returns the current text, as encoded via the current encoding system.
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).