From a6d32b96ed3e6fec59d84e33eb08e7bf6642ffe9 Mon Sep 17 00:00:00 2001 From: Brad King Date: Fri, 11 Jan 2008 08:33:48 -0500 Subject: ENH: Add SystemTools::SplitPathRootComponent and re-implement SplitPath to use it. Add better treatment of user home directory paths. --- Source/kwsys/SystemTools.cxx | 133 +++++++++++++++++++++++++++++----------- Source/kwsys/SystemTools.hxx.in | 26 ++++++-- 2 files changed, 119 insertions(+), 40 deletions(-) diff --git a/Source/kwsys/SystemTools.cxx b/Source/kwsys/SystemTools.cxx index 977133f..dbcf230 100644 --- a/Source/kwsys/SystemTools.cxx +++ b/Source/kwsys/SystemTools.cxx @@ -2975,81 +2975,144 @@ kwsys_stl::string SystemTools::GetActualCaseForPath(const char* p) } //---------------------------------------------------------------------------- -void SystemTools::SplitPath(const char* p, - kwsys_stl::vector& components) +const char* SystemTools::SplitPathRootComponent(const char* p, + kwsys_stl::string* root) { - components.clear(); // Identify the root component. const char* c = p; if((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) { // Network path. - components.push_back("//"); + if(root) + { + *root = "//"; + } c += 2; } else if(c[0] == '/') { // Unix path. - components.push_back("/"); + if(root) + { + *root = "/"; + } c += 1; } else if(c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) { // Windows path. - kwsys_stl::string root = "_:/"; - root[0] = c[0]; - components.push_back(root); + if(root) + { + (*root) = "_:/"; + (*root)[0] = c[0]; + } c += 3; } else if(c[0] && c[1] == ':') { // Path relative to a windows drive working directory. - kwsys_stl::string root = "_:"; - root[0] = c[0]; - components.push_back(root); + if(root) + { + (*root) = "_:"; + (*root)[0] = c[0]; + } c += 2; } -#ifdef HAVE_GETPWNAM else if(c[0] == '~') { - int numChars = 1; - while(c[numChars] && c[numChars] != '/') + // Home directory. The returned root should always have a + // trailing slash so that appending components as + // c[0]c[1]/c[2]/... works. The remaining path returned should + // skip the first slash if it exists: + // + // "~" : root = "~/" , return "" + // "~/ : root = "~/" , return "" + // "~/x : root = "~/" , return "x" + // "~u" : root = "~u/", return "" + // "~u/" : root = "~u/", return "" + // "~u/x" : root = "~u/", return "x" + int n = 1; + while(c[n] && c[n] != '/') { - numChars++; + ++n; } - const char* homedir; - if(numChars == 1) + if(root) { - homedir = getenv("HOME"); + root->assign(c, n); + *root += '/'; } - else + if(c[n] == '/') + { + ++n; + } + c += n; + } + else + { + // Relative path. + if(root) { - char user[PATH_MAX]; - strncpy(user, c+1, numChars-1); - user[numChars] = '\0'; - passwd* pw = getpwnam(user); - if(p) + *root = ""; + } + } + + // Return the remaining path. + return c; +} + +//---------------------------------------------------------------------------- +void SystemTools::SplitPath(const char* p, + kwsys_stl::vector& components, + bool expand_home_dir) +{ + const char* c = p; + components.clear(); + + // Identify the root component. + { + kwsys_stl::string root; + c = SystemTools::SplitPathRootComponent(c, &root); + + // Expand home directory references if requested. + if(expand_home_dir && !root.empty() && root[0] == '~') + { + kwsys_stl::string homedir; + root = root.substr(0, root.size()-1); + if(root.size() == 1) + { +#if defined(_WIN32) && !defined(__CYGWIN__) + if(const char* h = getenv("USERPROFILE")) { - homedir = pw->pw_dir; + homedir = h; } else +#endif + if(const char* h = getenv("HOME")) { - homedir = ""; + homedir = h; + } + } +#ifdef HAVE_GETPWNAM + else if(passwd* pw = getpwnam(root.c_str()+1)) + { + if(pw->pw_dir) + { + homedir = pw->pw_dir; } } - kwsys_stl::vector home_components; - SystemTools::SplitPath(homedir, home_components); - components.insert(components.end(), - home_components.begin(), - home_components.end()); - c += numChars; - } #endif + if(!homedir.empty() && (homedir[homedir.size()-1] == '/' || + homedir[homedir.size()-1] == '\\')) + { + homedir = homedir.substr(0, homedir.size()-1); + } + SystemTools::SplitPath(homedir.c_str(), components); + } else { - // Relative path. - components.push_back(""); + components.push_back(root); } + } // Parse the remaining components. const char* first = c; diff --git a/Source/kwsys/SystemTools.hxx.in b/Source/kwsys/SystemTools.hxx.in index 4845851..fa8c7ad 100644 --- a/Source/kwsys/SystemTools.hxx.in +++ b/Source/kwsys/SystemTools.hxx.in @@ -351,20 +351,36 @@ public: const char* in_base); /** - * Split a path name into its basic components. The first component - * is one of the following roots: - * "/" = UNIX + * Split a path name into its root component and the rest of the + * path. The root component is one of the following: + * "/" = UNIX full path * "c:/" = Windows full path (can be any drive letter) * "c:" = Windows drive-letter relative path (can be any drive letter) * "//" = Network path + * "~" = Home path for current user + * "~u" = Home path for user 'u' * "" = Relative path + * + * A pointer to the rest of the path after the root component is + * returned. The root component is stored in the "root" string if + * given. + */ + static const char* SplitPathRootComponent(const char* p, + kwsys_stl::string* root=0); + + /** + * Split a path name into its basic components. The first component + * is one of the roots returned by SplitPathRootComponent. * The remaining components form the path. If there is a trailing * slash then the last component is the empty string. The * components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to - * produce the original path. + * produce the original path. Home directory references are + * automatically expanded if expand_home_dir is true and this + * platform supports them. */ static void SplitPath(const char* p, - kwsys_stl::vector& components); + kwsys_stl::vector& components, + bool expand_home_dir = true); /** * Join components of a path name into a single string. See -- cgit v0.12