15 #include "pandaVersion.h"
25 #include <sys/param.h>
31 #define getcwd _getcwd
45 #include <mach-o/dyld.h>
47 #include <crt_externs.h>
49 #define environ (*_NSGetEnviron())
58 extern char **environ;
61 #include <sys/types.h>
62 #include <sys/sysctl.h>
65 #if defined(IS_LINUX) || defined(IS_FREEBSD)
75 #ifndef STATIC_INIT_GETENV
76 #define PREREAD_ENVIRONMENT
83 #if !defined(WIN32_VC) && defined(HAVE_GLOBAL_ARGV) && defined(PROTOTYPE_GLOBAL_ARGV)
84 extern char **GLOBAL_ARGV;
85 extern int GLOBAL_ARGC;
98 ExecutionEnvironment::
99 ExecutionEnvironment() {
100 read_environment_variables();
116 size_t dollar = str.find(
'$');
117 while (dollar != string::npos && dollar + 1 < str.length()) {
118 size_t start = dollar + 1;
120 if (str[start] ==
'$') {
122 result += str.substr(last, start - last);
129 if (str[start] ==
'{') {
131 end = str.find(
'}', start + 1);
132 if (end != string::npos) {
133 varname = str.substr(start + 1, end - (start + 1));
140 while (end < str.length() && (isalnum(str[end]) || str[end] ==
'_')) {
143 varname = str.substr(start, end - start);
147 result += str.substr(last, dollar - last);
152 dollar = str.find(
'$', last);
155 result += str.substr(last);
167 static size_t bufsize = 1024;
168 static wchar_t *buffer =
nullptr;
170 if (buffer ==
nullptr) {
171 buffer =
new wchar_t[bufsize];
174 while (_wgetcwd(buffer, bufsize) ==
nullptr) {
175 if (errno != ERANGE) {
180 bufsize = bufsize * 2;
181 buffer =
new wchar_t[bufsize];
182 assert(buffer !=
nullptr);
190 static size_t bufsize = 1024;
191 static char *buffer =
nullptr;
193 if (buffer ==
nullptr) {
194 buffer =
new char[bufsize];
197 while (getcwd(buffer, bufsize) ==
nullptr) {
198 if (errno != ERANGE) {
203 bufsize = bufsize * 2;
204 buffer =
new char[bufsize];
205 assert(buffer !=
nullptr);
218 bool ExecutionEnvironment::
219 ns_has_environment_variable(
const string &var)
const {
220 if (_variables.count(var) != 0) {
224 #ifndef PREREAD_ENVIRONMENT
225 return getenv(var.c_str()) !=
nullptr;
235 string ExecutionEnvironment::
236 ns_get_environment_variable(
const string &var)
const {
237 EnvironmentVariables::const_iterator evi;
238 evi = _variables.find(var);
239 if (evi != _variables.end()) {
240 return (*evi).second;
248 }
else if (var ==
"TEMP") {
250 }
else if (var ==
"USER_APPDATA") {
252 }
else if (var ==
"COMMON_APPDATA") {
254 }
else if (var ==
"MAIN_DIR") {
258 if (!_binary_name.empty()) {
260 main_dir.make_absolute();
265 #ifndef PREREAD_ENVIRONMENT
266 const char *def = getenv(var.c_str());
267 if (def !=
nullptr) {
279 static struct {
int id;
const char *name; } csidl_table[] = {
280 { CSIDL_ADMINTOOLS,
"ADMINTOOLS" },
281 { CSIDL_ALTSTARTUP,
"ALTSTARTUP" },
282 { CSIDL_APPDATA,
"APPDATA" },
283 { CSIDL_BITBUCKET,
"BITBUCKET" },
284 { CSIDL_CDBURN_AREA,
"CDBURN_AREA" },
285 { CSIDL_COMMON_ADMINTOOLS,
"COMMON_ADMINTOOLS" },
286 { CSIDL_COMMON_ALTSTARTUP,
"COMMON_ALTSTARTUP" },
287 { CSIDL_COMMON_APPDATA,
"COMMON_APPDATA" },
288 { CSIDL_COMMON_DESKTOPDIRECTORY,
"COMMON_DESKTOPDIRECTORY" },
289 { CSIDL_COMMON_DOCUMENTS,
"COMMON_DOCUMENTS" },
290 { CSIDL_COMMON_FAVORITES,
"COMMON_FAVORITES" },
291 { CSIDL_COMMON_MUSIC,
"COMMON_MUSIC" },
292 { CSIDL_COMMON_OEM_LINKS,
"COMMON_OEM_LINKS" },
293 { CSIDL_COMMON_PICTURES,
"COMMON_PICTURES" },
294 { CSIDL_COMMON_PROGRAMS,
"COMMON_PROGRAMS" },
295 { CSIDL_COMMON_STARTMENU,
"COMMON_STARTMENU" },
296 { CSIDL_COMMON_STARTUP,
"COMMON_STARTUP" },
297 { CSIDL_COMMON_TEMPLATES,
"COMMON_TEMPLATES" },
298 { CSIDL_COMMON_VIDEO,
"COMMON_VIDEO" },
299 { CSIDL_COMPUTERSNEARME,
"COMPUTERSNEARME" },
300 { CSIDL_CONNECTIONS,
"CONNECTIONS" },
301 { CSIDL_CONTROLS,
"CONTROLS" },
302 { CSIDL_COOKIES,
"COOKIES" },
303 { CSIDL_DESKTOP,
"DESKTOP" },
304 { CSIDL_DESKTOPDIRECTORY,
"DESKTOPDIRECTORY" },
305 { CSIDL_DRIVES,
"DRIVES" },
306 { CSIDL_FAVORITES,
"FAVORITES" },
307 { CSIDL_FONTS,
"FONTS" },
308 { CSIDL_HISTORY,
"HISTORY" },
309 { CSIDL_INTERNET,
"INTERNET" },
310 { CSIDL_INTERNET_CACHE,
"INTERNET_CACHE" },
311 { CSIDL_LOCAL_APPDATA,
"LOCAL_APPDATA" },
312 { CSIDL_MYDOCUMENTS,
"MYDOCUMENTS" },
313 { CSIDL_MYMUSIC,
"MYMUSIC" },
314 { CSIDL_MYPICTURES,
"MYPICTURES" },
315 { CSIDL_MYVIDEO,
"MYVIDEO" },
316 { CSIDL_NETHOOD,
"NETHOOD" },
317 { CSIDL_NETWORK,
"NETWORK" },
318 { CSIDL_PERSONAL,
"PERSONAL" },
319 { CSIDL_PRINTERS,
"PRINTERS" },
320 { CSIDL_PRINTHOOD,
"PRINTHOOD" },
321 { CSIDL_PROFILE,
"PROFILE" },
322 { CSIDL_PROGRAM_FILES,
"PROGRAM_FILES" },
323 { CSIDL_PROGRAM_FILESX86,
"PROGRAM_FILESX86" },
324 { CSIDL_PROGRAM_FILES_COMMON,
"PROGRAM_FILES_COMMON" },
325 { CSIDL_PROGRAM_FILES_COMMONX86,
"PROGRAM_FILES_COMMONX86" },
326 { CSIDL_PROGRAMS,
"PROGRAMS" },
327 { CSIDL_RECENT,
"RECENT" },
328 { CSIDL_RESOURCES,
"RESOURCES" },
329 { CSIDL_RESOURCES_LOCALIZED,
"RESOURCES_LOCALIZED" },
330 { CSIDL_SENDTO,
"SENDTO" },
331 { CSIDL_STARTMENU,
"STARTMENU" },
332 { CSIDL_STARTUP,
"STARTUP" },
333 { CSIDL_SYSTEM,
"SYSTEM" },
334 { CSIDL_SYSTEMX86,
"SYSTEMX86" },
335 { CSIDL_TEMPLATES,
"TEMPLATES" },
336 { CSIDL_WINDOWS,
"WINDOWS" },
340 for (
int i = 0; csidl_table[i].name !=
nullptr; ++i) {
341 if (strcmp(var.c_str(), csidl_table[i].name) == 0) {
342 wchar_t buffer[MAX_PATH];
343 if (SHGetSpecialFolderPathW(
nullptr, buffer, csidl_table[i].
id,
true)) {
351 #elif !defined(__APPLE__)
355 if (var ==
"XDG_CONFIG_HOME") {
359 }
else if (var ==
"XDG_CACHE_HOME") {
363 }
else if (var ==
"XDG_DATA_HOME") {
376 void ExecutionEnvironment::
377 ns_set_environment_variable(
const string &var,
const string &value) {
378 _variables[var] = value;
379 string putstr = var +
"=" + value;
382 char *put = (
char *)malloc(putstr.length() + 1);
383 strcpy(put, putstr.c_str());
390 void ExecutionEnvironment::
391 ns_shadow_environment_variable(
const string &var,
const string &value) {
392 _variables[var] = value;
393 string putstr = var +
"=" + value;
399 void ExecutionEnvironment::
400 ns_clear_shadow(
const string &var) {
401 EnvironmentVariables::iterator vi = _variables.find(var);
402 if (vi == _variables.end()) {
406 #ifdef PREREAD_ENVIRONMENT
408 const char *def = getenv(var.c_str());
409 if (def !=
nullptr) {
412 _variables.erase(vi);
421 size_t ExecutionEnvironment::
422 ns_get_num_args()
const {
431 string ExecutionEnvironment::
432 ns_get_arg(
size_t n)
const {
433 assert(n < ns_get_num_args());
441 string ExecutionEnvironment::
442 ns_get_binary_name()
const {
443 if (_binary_name.empty()) {
453 string ExecutionEnvironment::
454 ns_get_dtool_name()
const {
455 if (_dtool_name.empty()) {
467 if (_global_ptr ==
nullptr) {
478 void ExecutionEnvironment::
479 read_environment_variables() {
480 #ifdef PREREAD_ENVIRONMENT
481 #if defined(IS_OSX) || defined(IS_FREEBSD) || defined(IS_LINUX)
486 for (envp = environ; envp && *envp; envp++) {
491 for (envc = *envp; envc && *envc && strncmp(envc,
"=", 1) != 0; envc++) {
492 variable += (char) *envc;
495 if (strncmp(envc,
"=", 1) == 0) {
496 for (envc++; envc && *envc; envc++) {
497 value += (char) *envc;
501 if (!variable.empty()) {
502 _variables[variable] = value;
505 #elif defined(HAVE_PROC_SELF_ENVIRON)
509 pifstream proc(
"/proc/self/environ");
511 cerr <<
"Cannot read /proc/self/environ; environment variables unavailable.\n";
516 while (!proc.eof() && !proc.fail()) {
520 while (!proc.eof() && !proc.fail() && ch !=
'=' && ch !=
'\0') {
521 variable += (char)ch;
527 while (!proc.eof() && !proc.fail() && ch !=
'\0') {
533 if (!variable.empty()) {
534 _variables[variable] = value;
539 cerr <<
"Warning: environment variables unavailable to dconfig.\n";
548 void ExecutionEnvironment::
555 HMODULE dllhandle = GetModuleHandle(
"libp3dtool_d.dll");
557 HMODULE dllhandle = GetModuleHandle(
"libp3dtool.dll");
559 if (dllhandle != 0) {
560 static const DWORD buffer_size = 1024;
561 wchar_t buffer[buffer_size];
562 DWORD size = GetModuleFileNameW(dllhandle, buffer, buffer_size);
571 #if defined(__APPLE__)
574 if (_dtool_name.empty()) {
575 uint32_t ic = _dyld_image_count();
576 for (uint32_t i = 0; i < ic; ++i) {
577 const char *buffer = _dyld_get_image_name(i);
578 const char *tail = strrchr(buffer,
'/');
579 if (tail && (strcmp(tail,
"/libp3dtool." PANDA_ABI_VERSION_STR
".dylib") == 0
580 || strcmp(tail,
"/libp3dtool.dylib") == 0)) {
581 _dtool_name = buffer;
587 #if defined(RTLD_DI_ORIGIN)
590 char origin[PATH_MAX + 1];
592 if (_dtool_name.empty()) {
593 void *dtool_handle = dlopen(
"libp3dtool.so." PANDA_ABI_VERSION_STR, RTLD_NOW | RTLD_NOLOAD);
594 if (dtool_handle !=
nullptr && dlinfo(dtool_handle, RTLD_DI_ORIGIN, origin) != -1) {
595 _dtool_name = origin;
596 _dtool_name +=
"/libp3dtool.so." PANDA_ABI_VERSION_STR;
599 dtool_handle = dlopen(
"libp3dtool.so", RTLD_NOW | RTLD_NOLOAD);
600 if (dtool_handle !=
nullptr && dlinfo(dtool_handle, RTLD_DI_ORIGIN, origin) != -1) {
601 _dtool_name = origin;
602 _dtool_name +=
"/libp3dtool.so";
608 #if !defined(RTLD_DI_ORIGIN) && defined(RTLD_DI_LINKMAP)
610 if (_dtool_name.empty()) {
611 struct link_map *map;
613 void *
self = RTLD_SELF;
615 void *
self = dlopen(NULL, RTLD_NOW | RTLD_NOLOAD);
617 if (dlinfo(
self, RTLD_DI_LINKMAP, &map)) {
618 while (map !=
nullptr) {
619 const char *tail = strrchr(map->l_name,
'/');
620 const char *head = strchr(map->l_name,
'/');
621 if (tail && head && (strcmp(tail,
"/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
622 || strcmp(tail,
"/libp3dtool.so") == 0)) {
631 #if defined(HAVE_PROC_SELF_MAPS) || defined(HAVE_PROC_CURPROC_MAP)
634 if (_dtool_name.empty()) {
635 #ifdef HAVE_PROC_CURPROC_MAP
636 pifstream maps(
"/proc/curproc/map");
638 pifstream maps(
"/proc/self/maps");
640 while (!maps.fail() && !maps.eof()) {
641 char buffer[PATH_MAX];
643 maps.getline(buffer, PATH_MAX);
644 const char *tail = strrchr(buffer,
'/');
645 const char *head = strchr(buffer,
'/');
646 if (tail && head && (strcmp(tail,
"/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
647 || strcmp(tail,
"/libp3dtool.so") == 0)) {
659 if (_binary_name.empty()) {
660 static const DWORD buffer_size = 1024;
661 wchar_t buffer[buffer_size];
662 DWORD size = GetModuleFileNameW(
nullptr, buffer, buffer_size);
671 #if defined(__APPLE__)
673 if (_binary_name.empty()) {
674 char *pathbuf =
new char[PATH_MAX];
675 uint32_t bufsize = PATH_MAX;
676 if (_NSGetExecutablePath(pathbuf, &bufsize) == 0) {
677 _binary_name = pathbuf;
683 #if defined(IS_FREEBSD)
686 if (_binary_name.empty()) {
687 size_t bufsize = 4096;
689 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
691 if (sysctl(mib, 4, (
void*) buffer, &bufsize,
nullptr, 0) == -1) {
694 _binary_name = buffer;
699 #if defined(HAVE_PROC_SELF_EXE) || defined(HAVE_PROC_CURPROC_FILE)
703 if (_binary_name.empty()) {
704 char readlinkbuf [PATH_MAX];
705 #ifdef HAVE_PROC_CURPROC_FILE
706 ssize_t pathlen = readlink(
"/proc/curproc/file", readlinkbuf, PATH_MAX - 1);
708 ssize_t pathlen = readlink(
"/proc/self/exe", readlinkbuf, PATH_MAX - 1);
711 readlinkbuf[pathlen] = 0;
712 _binary_name = readlinkbuf;
720 #if defined(WIN32_VC)
725 LPWSTR cmdline = GetCommandLineW();
727 LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc);
729 if (wargv ==
nullptr) {
730 cerr <<
"CommandLineToArgvW failed; command-line arguments unavailable to config.\n";
736 for (
int i = 0; i < argc; ++i) {
737 std::wstring wtext(wargv[i]);
741 if (_binary_name.empty()) {
745 _args.push_back(encoder.
get_text());
752 #elif defined(IS_FREEBSD)
756 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0};
758 if (sysctl(mib, 4,
nullptr, &bufsize,
nullptr, 0) == -1) {
761 char *buffer = (
char *)alloca(bufsize);
762 if (sysctl(mib, 4, buffer, &bufsize,
nullptr, 0) == -1) {
765 if (_binary_name.empty()) {
766 _binary_name = buffer;
768 size_t idx = strlen(buffer) + 1;
769 while (idx < bufsize) {
770 _args.push_back((
char*)(buffer + idx));
771 size_t newidx = strlen(buffer + idx);
777 #elif defined(HAVE_GLOBAL_ARGV)
778 int argc = GLOBAL_ARGC;
782 if (GLOBAL_ARGV !=
nullptr) {
783 if (_binary_name.empty() && argc > 0) {
784 _binary_name = GLOBAL_ARGV[0];
788 for (
int i = 1; i < argc; i++) {
789 _args.push_back(GLOBAL_ARGV[i]);
793 #elif defined(HAVE_PROC_SELF_CMDLINE) || defined(HAVE_PROC_CURPROC_CMDLINE)
799 #ifdef HAVE_PROC_CURPROC_CMDLINE
800 pifstream proc(
"/proc/curproc/cmdline");
802 cerr <<
"Cannot read /proc/curproc/cmdline; command-line arguments unavailable to config.\n";
804 pifstream proc(
"/proc/self/cmdline");
806 cerr <<
"Cannot read /proc/self/cmdline; command-line arguments unavailable to config.\n";
811 while (!proc.eof() && !proc.fail()) {
814 while (!proc.eof() && !proc.fail() && ch !=
'\0') {
820 if (_binary_name.empty())
823 _args.push_back(arg);
835 if (!_binary_name.empty()) {
836 char newpath [PATH_MAX + 1];
837 if (realpath(_binary_name.c_str(), newpath) !=
nullptr) {
838 _binary_name = newpath;
842 if (!_dtool_name.empty()) {
843 char newpath [PATH_MAX + 1];
844 if (realpath(_dtool_name.c_str(), newpath) !=
nullptr) {
845 _dtool_name = newpath;
850 if (_dtool_name.empty()) {
851 _dtool_name = _binary_name;
Encapsulates access to the environment variables and command-line arguments at the time of execution.
static std::string expand_string(const std::string &str)
Reads the string, looking for environment variable names marked by a $.
get_environment_variable
Returns the definition of the indicated environment variable, or the empty string if the variable is ...
get_cwd
Returns the name of the current working directory.
The name of a file, such as a texture file or an Egg file.
std::string to_os_specific() const
Converts the filename from our generic Unix-like convention (forward slashes starting with the root a...
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 const Filename & get_common_appdata_directory()
Returns a path to a system-defined directory appropriate for creating a subdirectory for storing appl...
static Filename from_os_specific_w(const std::wstring &os_specific, Type type=T_general)
The wide-string variant of from_os_specific().
static TextEncoder::Encoding get_filesystem_encoding()
Specifies the default encoding to be used for all subsequent Filenames objects.
static const Filename & get_temp_directory()
Returns a path to a system-defined temporary directory.
static const Filename & get_user_appdata_directory()
Returns a path to a system-defined directory appropriate for creating a subdirectory for storing appl...
bool make_true_case()
On a case-insensitive operating system (e.g.
std::string get_fullpath() const
Returns the entire filename: directory, basename, extension.
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,...
This class can be used to convert text between multiple representations, e.g.
void set_encoding(Encoding encoding)
Specifies how the string set via set_text() is to be interpreted.
get_text
Returns the current text, as encoded via the current encoding system.
void set_wtext(const std::wstring &wtext)
Changes the text that is stored in the encoder.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.