diff --git a/dtool/src/dtoolutil/executionEnvironment.cxx b/dtool/src/dtoolutil/executionEnvironment.cxx index 4a19694343..584d3a35a1 100644 --- a/dtool/src/dtoolutil/executionEnvironment.cxx +++ b/dtool/src/dtoolutil/executionEnvironment.cxx @@ -6,6 +6,14 @@ #include "executionEnvironment.h" #include +#ifdef WIN32_VC +// Windows requires this for getcwd(). +#include +#define getcwd _getcwd +#endif + +#include + // We define the symbol PREREAD_ENVIRONMENT if we cannot rely on // getenv() to read environment variables at static init time. In // this case, we must read all of the environment variables directly @@ -44,6 +52,36 @@ ExecutionEnvironment() { read_args(); } +//////////////////////////////////////////////////////////////////// +// Function: ExecutionEnviroment::get_cwd +// Access: Public, Static +// Description: Returns the name of the current working directory. +//////////////////////////////////////////////////////////////////// +string ExecutionEnvironment:: +get_cwd() { + // getcwd() requires us to allocate a dynamic buffer and grow it on + // demand. + static size_t bufsize = 1024; + static char *buffer = NULL; + + if (buffer == (char *)NULL) { + buffer = new char[bufsize]; + } + + while (getcwd(buffer, bufsize) == (char *)NULL) { + if (errno != ERANGE) { + perror("getcwd"); + return string(); + } + delete[] buffer; + bufsize = bufsize * 2; + buffer = new char[bufsize]; + assert(buffer != (char *)NULL); + } + + return string(buffer); +} + //////////////////////////////////////////////////////////////////// // Function: ExecutionEnvironment::ns_has_environment_variable // Access: Private diff --git a/dtool/src/dtoolutil/executionEnvironment.h b/dtool/src/dtoolutil/executionEnvironment.h index ce4cb195ea..f55e460948 100644 --- a/dtool/src/dtoolutil/executionEnvironment.h +++ b/dtool/src/dtoolutil/executionEnvironment.h @@ -33,6 +33,8 @@ public: INLINE static string get_binary_name(); + static string get_cwd(); + private: bool ns_has_environment_variable(const string &var) const; string ns_get_environment_variable(const string &var) const; diff --git a/dtool/src/dtoolutil/filename.cxx b/dtool/src/dtoolutil/filename.cxx index 8ce0428892..93a3caf4a9 100644 --- a/dtool/src/dtoolutil/filename.cxx +++ b/dtool/src/dtoolutil/filename.cxx @@ -32,6 +32,31 @@ #include +static const string & +get_panda_root() { + static string panda_root; + static bool got_panda_root = false; + + if (!got_panda_root) { + const char *envvar = getenv("PANDA_ROOT"); + if (envvar == (const char *)NULL) { + envvar = getenv("CYGWIN_ROOT"); + } + + if (envvar != (const char *)NULL) { + panda_root = front_to_back_slash(envvar); + } + + if (!panda_root.empty() && panda_root[panda_root.length() - 1] != '\\') { + panda_root += '\\'; + } + + got_panda_root = true; + } + + return panda_root; +} + static string front_to_back_slash(const string &str) { string result = str; @@ -45,6 +70,19 @@ front_to_back_slash(const string &str) { return result; } +static string +back_to_front_slash(const string &str) { + string result = str; + string::iterator si; + for (si = result.begin(); si != result.end(); ++si) { + if ((*si) == '\\') { + (*si) = '/'; + } + } + + return result; +} + static string convert_pathname(const string &unix_style_pathname) { if (unix_style_pathname.empty()) { @@ -82,27 +120,9 @@ convert_pathname(const string &unix_style_pathname) { } else { // It does not begin with a single letter, so prefix "PANDA_ROOT". - static string panda_root; - static bool got_panda_root = false; - - if (!got_panda_root) { - const char *envvar = getenv("PANDA_ROOT"); - if (envvar == (const char *)NULL) { - envvar = getenv("CYGWIN_ROOT"); - } - - if (envvar != (const char *)NULL) { - panda_root = front_to_back_slash(envvar); - } - - if (!panda_root.empty() && panda_root[panda_root.length() - 1] != '\\') { - panda_root += '\\'; - } - - got_panda_root = true; - } - - windows_pathname = panda_root + front_to_back_slash(unix_style_pathname); + + windows_pathname = + get_panda_root() + front_to_back_slash(unix_style_pathname); } return windows_pathname; @@ -179,6 +199,78 @@ Filename(const Filename &dirname, const Filename &basename) { _flags = 0; } +//////////////////////////////////////////////////////////////////// +// Function: Filename::from_os_specific +// Access: Public, Static +// Description: 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). +// +// Use this function to create a Filename from an +// externally-given filename string. Use +// to_os_specific() again later to reconvert it back to +// the local operating system's conventions. +// +// This function will do the right thing even if the +// filename is partially local conventions and partially +// Panda conventions; e.g. some backslashes and some +// forward slashes. +//////////////////////////////////////////////////////////////////// +Filename Filename:: +from_os_specific(const string &os_specific, Filename::Type type) { +#if defined(WIN32) + string result = back_to_front_slash(os_specific); + const string &panda_root = get_panda_root(); + + // If the initial prefix is the same as panda_root, remove it. + if (!panda_root.empty() && panda_root.length() < result.length()) { + bool matches = true; + size_t p; + for (p = 0; p < panda_root.length() && matches; p++) { + char c = tolower(panda_root[p]); + if (c == '\\') { + c = '/'; + } + matches = (c == tolower(result[p])); + } + + if (matches) { + // The initial prefix matches! Replace the initial bit with a + // leading slash. + result = result.substr(panda_root.length()); + assert(!result.empty()); + if (result[0] != '/') { + result = '/' + result; + } + Filename filename(result); + filename.set_type(type); + return filename; + } + } + + // All right, the initial prefix was not under panda_root. But + // maybe it begins with a drive letter. + if (result.size() >= 3 && isalpha(result[0]) && + result[1] == ':' && result[2] == '/') { + result[1] = tolower(result[0]); + result[0] = '/'; + } + + Filename filename(result); + filename.set_type(type); + return filename; + +#else + // Generic Unix-style filenames--no conversion necessary. + Filename filename(os_specific); + filename.set_type(type); + return filename; +#endif +} + //////////////////////////////////////////////////////////////////// // Function: Filename::set_fullpath // Access: Public diff --git a/dtool/src/dtoolutil/filename.h b/dtool/src/dtoolutil/filename.h index f047f1277f..b92d9ec028 100644 --- a/dtool/src/dtoolutil/filename.h +++ b/dtool/src/dtoolutil/filename.h @@ -68,6 +68,9 @@ public: INLINE static Filename dso_filename(const string &filename); INLINE static Filename executable_filename(const string &filename); + static Filename from_os_specific(const string &os_specific, + Type type = T_general); + // Assignment is via the = operator. INLINE Filename &operator = (const string &filename); INLINE Filename &operator = (const char *filename);