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 #ifdef PREREAD_ENVIRONMENT
221 return _variables.count(var) != 0;
223 return getenv(var.c_str()) !=
nullptr;
231 string ExecutionEnvironment::
232 ns_get_environment_variable(
const string &var)
const {
233 EnvironmentVariables::const_iterator evi;
234 evi = _variables.find(var);
235 if (evi != _variables.end()) {
236 return (*evi).second;
244 }
else if (var ==
"TEMP") {
246 }
else if (var ==
"USER_APPDATA") {
248 }
else if (var ==
"COMMON_APPDATA") {
250 }
else if (var ==
"MAIN_DIR") {
254 if (!_binary_name.empty()) {
256 main_dir.make_absolute();
261 #ifndef PREREAD_ENVIRONMENT
262 const char *def = getenv(var.c_str());
263 if (def !=
nullptr) {
275 static struct {
int id;
const char *name; } csidl_table[] = {
276 { CSIDL_ADMINTOOLS,
"ADMINTOOLS" },
277 { CSIDL_ALTSTARTUP,
"ALTSTARTUP" },
278 { CSIDL_APPDATA,
"APPDATA" },
279 { CSIDL_BITBUCKET,
"BITBUCKET" },
280 { CSIDL_CDBURN_AREA,
"CDBURN_AREA" },
281 { CSIDL_COMMON_ADMINTOOLS,
"COMMON_ADMINTOOLS" },
282 { CSIDL_COMMON_ALTSTARTUP,
"COMMON_ALTSTARTUP" },
283 { CSIDL_COMMON_APPDATA,
"COMMON_APPDATA" },
284 { CSIDL_COMMON_DESKTOPDIRECTORY,
"COMMON_DESKTOPDIRECTORY" },
285 { CSIDL_COMMON_DOCUMENTS,
"COMMON_DOCUMENTS" },
286 { CSIDL_COMMON_FAVORITES,
"COMMON_FAVORITES" },
287 { CSIDL_COMMON_MUSIC,
"COMMON_MUSIC" },
288 { CSIDL_COMMON_OEM_LINKS,
"COMMON_OEM_LINKS" },
289 { CSIDL_COMMON_PICTURES,
"COMMON_PICTURES" },
290 { CSIDL_COMMON_PROGRAMS,
"COMMON_PROGRAMS" },
291 { CSIDL_COMMON_STARTMENU,
"COMMON_STARTMENU" },
292 { CSIDL_COMMON_STARTUP,
"COMMON_STARTUP" },
293 { CSIDL_COMMON_TEMPLATES,
"COMMON_TEMPLATES" },
294 { CSIDL_COMMON_VIDEO,
"COMMON_VIDEO" },
295 { CSIDL_COMPUTERSNEARME,
"COMPUTERSNEARME" },
296 { CSIDL_CONNECTIONS,
"CONNECTIONS" },
297 { CSIDL_CONTROLS,
"CONTROLS" },
298 { CSIDL_COOKIES,
"COOKIES" },
299 { CSIDL_DESKTOP,
"DESKTOP" },
300 { CSIDL_DESKTOPDIRECTORY,
"DESKTOPDIRECTORY" },
301 { CSIDL_DRIVES,
"DRIVES" },
302 { CSIDL_FAVORITES,
"FAVORITES" },
303 { CSIDL_FONTS,
"FONTS" },
304 { CSIDL_HISTORY,
"HISTORY" },
305 { CSIDL_INTERNET,
"INTERNET" },
306 { CSIDL_INTERNET_CACHE,
"INTERNET_CACHE" },
307 { CSIDL_LOCAL_APPDATA,
"LOCAL_APPDATA" },
308 { CSIDL_MYDOCUMENTS,
"MYDOCUMENTS" },
309 { CSIDL_MYMUSIC,
"MYMUSIC" },
310 { CSIDL_MYPICTURES,
"MYPICTURES" },
311 { CSIDL_MYVIDEO,
"MYVIDEO" },
312 { CSIDL_NETHOOD,
"NETHOOD" },
313 { CSIDL_NETWORK,
"NETWORK" },
314 { CSIDL_PERSONAL,
"PERSONAL" },
315 { CSIDL_PRINTERS,
"PRINTERS" },
316 { CSIDL_PRINTHOOD,
"PRINTHOOD" },
317 { CSIDL_PROFILE,
"PROFILE" },
318 { CSIDL_PROGRAM_FILES,
"PROGRAM_FILES" },
319 { CSIDL_PROGRAM_FILESX86,
"PROGRAM_FILESX86" },
320 { CSIDL_PROGRAM_FILES_COMMON,
"PROGRAM_FILES_COMMON" },
321 { CSIDL_PROGRAM_FILES_COMMONX86,
"PROGRAM_FILES_COMMONX86" },
322 { CSIDL_PROGRAMS,
"PROGRAMS" },
323 { CSIDL_RECENT,
"RECENT" },
324 { CSIDL_RESOURCES,
"RESOURCES" },
325 { CSIDL_RESOURCES_LOCALIZED,
"RESOURCES_LOCALIZED" },
326 { CSIDL_SENDTO,
"SENDTO" },
327 { CSIDL_STARTMENU,
"STARTMENU" },
328 { CSIDL_STARTUP,
"STARTUP" },
329 { CSIDL_SYSTEM,
"SYSTEM" },
330 { CSIDL_SYSTEMX86,
"SYSTEMX86" },
331 { CSIDL_TEMPLATES,
"TEMPLATES" },
332 { CSIDL_WINDOWS,
"WINDOWS" },
336 for (
int i = 0; csidl_table[i].name !=
nullptr; ++i) {
337 if (strcmp(var.c_str(), csidl_table[i].name) == 0) {
338 wchar_t buffer[MAX_PATH];
339 if (SHGetSpecialFolderPathW(
nullptr, buffer, csidl_table[i].
id,
true)) {
347 #elif !defined(__APPLE__)
351 if (var ==
"XDG_CONFIG_HOME") {
355 }
else if (var ==
"XDG_CACHE_HOME") {
359 }
else if (var ==
"XDG_DATA_HOME") {
372 void ExecutionEnvironment::
373 ns_set_environment_variable(
const string &var,
const string &value) {
374 _variables[var] = value;
375 string putstr = var +
"=" + value;
378 char *put = (
char *)malloc(putstr.length() + 1);
379 strcpy(put, putstr.c_str());
386 void ExecutionEnvironment::
387 ns_shadow_environment_variable(
const string &var,
const string &value) {
388 _variables[var] = value;
389 string putstr = var +
"=" + value;
395 void ExecutionEnvironment::
396 ns_clear_shadow(
const string &var) {
397 EnvironmentVariables::iterator vi = _variables.find(var);
398 if (vi == _variables.end()) {
402 #ifdef PREREAD_ENVIRONMENT
404 const char *def = getenv(var.c_str());
405 if (def !=
nullptr) {
408 _variables.erase(vi);
410 #endif // PREREAD_ENVIRONMENT
417 size_t ExecutionEnvironment::
418 ns_get_num_args()
const {
427 string ExecutionEnvironment::
428 ns_get_arg(
size_t n)
const {
429 assert(n < ns_get_num_args());
437 string ExecutionEnvironment::
438 ns_get_binary_name()
const {
439 if (_binary_name.empty()) {
449 string ExecutionEnvironment::
450 ns_get_dtool_name()
const {
451 if (_dtool_name.empty()) {
463 if (_global_ptr ==
nullptr) {
474 void ExecutionEnvironment::
475 read_environment_variables() {
476 #ifdef PREREAD_ENVIRONMENT
477 #if defined(IS_OSX) || defined(IS_FREEBSD) || defined(IS_LINUX)
482 for (envp = environ; envp && *envp; envp++) {
487 for (envc = *envp; envc && *envc && strncmp(envc,
"=", 1) != 0; envc++) {
488 variable += (char) *envc;
491 if (strncmp(envc,
"=", 1) == 0) {
492 for (envc++; envc && *envc; envc++) {
493 value += (char) *envc;
497 if (!variable.empty()) {
498 _variables[variable] = value;
501 #elif defined(HAVE_PROC_SELF_ENVIRON)
505 pifstream proc(
"/proc/self/environ");
507 cerr <<
"Cannot read /proc/self/environ; environment variables unavailable.\n";
512 while (!proc.eof() && !proc.fail()) {
516 while (!proc.eof() && !proc.fail() && ch !=
'=' && ch !=
'\0') {
517 variable += (char)ch;
523 while (!proc.eof() && !proc.fail() && ch !=
'\0') {
529 if (!variable.empty()) {
530 _variables[variable] = value;
535 cerr <<
"Warning: environment variables unavailable to dconfig.\n";
537 #endif // PREREAD_ENVIRONMENT
544 void ExecutionEnvironment::
551 HMODULE dllhandle = GetModuleHandle(
"libp3dtool_d.dll");
553 HMODULE dllhandle = GetModuleHandle(
"libp3dtool.dll");
555 if (dllhandle != 0) {
556 static const DWORD buffer_size = 1024;
557 wchar_t buffer[buffer_size];
558 DWORD size = GetModuleFileNameW(dllhandle, buffer, buffer_size);
567 #if defined(__APPLE__)
570 if (_dtool_name.empty()) {
571 uint32_t ic = _dyld_image_count();
572 for (uint32_t i = 0; i < ic; ++i) {
573 const char *buffer = _dyld_get_image_name(i);
574 const char *tail = strrchr(buffer,
'/');
575 if (tail && (strcmp(tail,
"/libp3dtool." PANDA_ABI_VERSION_STR
".dylib") == 0
576 || strcmp(tail,
"/libp3dtool.dylib") == 0)) {
577 _dtool_name = buffer;
583 #if defined(RTLD_DI_ORIGIN)
586 char origin[PATH_MAX + 1];
588 if (_dtool_name.empty()) {
589 void *dtool_handle = dlopen(
"libp3dtool.so." PANDA_ABI_VERSION_STR, RTLD_NOW | RTLD_NOLOAD);
590 if (dtool_handle !=
nullptr && dlinfo(dtool_handle, RTLD_DI_ORIGIN, origin) != -1) {
591 _dtool_name = origin;
592 _dtool_name +=
"/libp3dtool.so." PANDA_ABI_VERSION_STR;
595 dtool_handle = dlopen(
"libp3dtool.so", RTLD_NOW | RTLD_NOLOAD);
596 if (dtool_handle !=
nullptr && dlinfo(dtool_handle, RTLD_DI_ORIGIN, origin) != -1) {
597 _dtool_name = origin;
598 _dtool_name +=
"/libp3dtool.so";
604 #if !defined(RTLD_DI_ORIGIN) && defined(RTLD_DI_LINKMAP)
606 if (_dtool_name.empty()) {
607 struct link_map *map;
609 void *
self = RTLD_SELF;
611 void *
self = dlopen(NULL, RTLD_NOW | RTLD_NOLOAD);
613 if (dlinfo(
self, RTLD_DI_LINKMAP, &map)) {
614 while (map !=
nullptr) {
615 const char *tail = strrchr(map->l_name,
'/');
616 const char *head = strchr(map->l_name,
'/');
617 if (tail && head && (strcmp(tail,
"/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
618 || strcmp(tail,
"/libp3dtool.so") == 0)) {
627 #if defined(HAVE_PROC_SELF_MAPS) || defined(HAVE_PROC_CURPROC_MAP)
630 if (_dtool_name.empty()) {
631 #ifdef HAVE_PROC_CURPROC_MAP
632 pifstream maps(
"/proc/curproc/map");
634 pifstream maps(
"/proc/self/maps");
636 while (!maps.fail() && !maps.eof()) {
637 char buffer[PATH_MAX];
639 maps.getline(buffer, PATH_MAX);
640 const char *tail = strrchr(buffer,
'/');
641 const char *head = strchr(buffer,
'/');
642 if (tail && head && (strcmp(tail,
"/libp3dtool.so." PANDA_ABI_VERSION_STR) == 0
643 || strcmp(tail,
"/libp3dtool.so") == 0)) {
655 if (_binary_name.empty()) {
656 static const DWORD buffer_size = 1024;
657 wchar_t buffer[buffer_size];
658 DWORD size = GetModuleFileNameW(
nullptr, buffer, buffer_size);
667 #if defined(__APPLE__)
669 if (_binary_name.empty()) {
670 char *pathbuf =
new char[PATH_MAX];
671 uint32_t bufsize = PATH_MAX;
672 if (_NSGetExecutablePath(pathbuf, &bufsize) == 0) {
673 _binary_name = pathbuf;
679 #if defined(IS_FREEBSD)
682 if (_binary_name.empty()) {
683 size_t bufsize = 4096;
685 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1};
687 if (sysctl(mib, 4, (
void*) buffer, &bufsize,
nullptr, 0) == -1) {
690 _binary_name = buffer;
695 #if defined(HAVE_PROC_SELF_EXE) || defined(HAVE_PROC_CURPROC_FILE)
699 if (_binary_name.empty()) {
700 char readlinkbuf [PATH_MAX];
701 #ifdef HAVE_PROC_CURPROC_FILE
702 ssize_t pathlen = readlink(
"/proc/curproc/file", readlinkbuf, PATH_MAX - 1);
704 ssize_t pathlen = readlink(
"/proc/self/exe", readlinkbuf, PATH_MAX - 1);
707 readlinkbuf[pathlen] = 0;
708 _binary_name = readlinkbuf;
716 #if defined(WIN32_VC)
721 LPWSTR cmdline = GetCommandLineW();
723 LPWSTR *wargv = CommandLineToArgvW(cmdline, &argc);
725 if (wargv ==
nullptr) {
726 cerr <<
"CommandLineToArgvW failed; command-line arguments unavailable to config.\n";
732 for (
int i = 0; i < argc; ++i) {
733 std::wstring wtext(wargv[i]);
737 if (_binary_name.empty()) {
741 _args.push_back(encoder.
get_text());
748 #elif defined(IS_FREEBSD)
751 size_t bufsize = 4096;
753 int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_ARGS, 0};
755 if (sysctl(mib, 4, (
void*) buffer, &bufsize,
nullptr, 0) == -1) {
758 if (_binary_name.empty()) {
759 _binary_name = buffer;
761 size_t idx = strlen(buffer) + 1;
762 while (idx < bufsize) {
763 _args.push_back((
char*)(buffer + idx));
764 size_t newidx = strlen(buffer + idx);
769 #elif defined(HAVE_GLOBAL_ARGV)
770 int argc = GLOBAL_ARGC;
774 if (GLOBAL_ARGV !=
nullptr) {
775 if (_binary_name.empty() && argc > 0) {
776 _binary_name = GLOBAL_ARGV[0];
780 for (
int i = 1; i < argc; i++) {
781 _args.push_back(GLOBAL_ARGV[i]);
785 #elif defined(HAVE_PROC_SELF_CMDLINE) || defined(HAVE_PROC_CURPROC_CMDLINE)
791 #ifdef HAVE_PROC_CURPROC_CMDLINE
792 pifstream proc(
"/proc/curproc/cmdline");
794 cerr <<
"Cannot read /proc/curproc/cmdline; command-line arguments unavailable to config.\n";
796 pifstream proc(
"/proc/self/cmdline");
798 cerr <<
"Cannot read /proc/self/cmdline; command-line arguments unavailable to config.\n";
803 while (!proc.eof() && !proc.fail()) {
806 while (!proc.eof() && !proc.fail() && ch !=
'\0') {
812 if (_binary_name.empty())
815 _args.push_back(arg);
827 if (!_binary_name.empty()) {
828 char newpath [PATH_MAX + 1];
829 if (realpath(_binary_name.c_str(), newpath) !=
nullptr) {
830 _binary_name = newpath;
834 if (!_dtool_name.empty()) {
835 char newpath [PATH_MAX + 1];
836 if (realpath(_dtool_name.c_str(), newpath) !=
nullptr) {
837 _dtool_name = newpath;
842 if (_dtool_name.empty()) {
843 _dtool_name = _binary_name;