ENH: Add SystemTools::SplitPathRootComponent and re-implement SplitPath to use it. Add better treatment of user home directory paths.

This commit is contained in:
Brad King 2008-01-11 08:33:48 -05:00
parent d7c7ab0927
commit a6d32b96ed
2 changed files with 123 additions and 44 deletions

View File

@ -2975,80 +2975,143 @@ kwsys_stl::string SystemTools::GetActualCaseForPath(const char* p)
} }
//---------------------------------------------------------------------------- //----------------------------------------------------------------------------
void SystemTools::SplitPath(const char* p, const char* SystemTools::SplitPathRootComponent(const char* p,
kwsys_stl::vector<kwsys_stl::string>& components) kwsys_stl::string* root)
{ {
components.clear();
// Identify the root component. // Identify the root component.
const char* c = p; const char* c = p;
if((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\')) if((c[0] == '/' && c[1] == '/') || (c[0] == '\\' && c[1] == '\\'))
{ {
// Network path. // Network path.
components.push_back("//"); if(root)
{
*root = "//";
}
c += 2; c += 2;
} }
else if(c[0] == '/') else if(c[0] == '/')
{ {
// Unix path. // Unix path.
components.push_back("/"); if(root)
{
*root = "/";
}
c += 1; c += 1;
} }
else if(c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\')) else if(c[0] && c[1] == ':' && (c[2] == '/' || c[2] == '\\'))
{ {
// Windows path. // Windows path.
kwsys_stl::string root = "_:/"; if(root)
root[0] = c[0]; {
components.push_back(root); (*root) = "_:/";
(*root)[0] = c[0];
}
c += 3; c += 3;
} }
else if(c[0] && c[1] == ':') else if(c[0] && c[1] == ':')
{ {
// Path relative to a windows drive working directory. // Path relative to a windows drive working directory.
kwsys_stl::string root = "_:"; if(root)
root[0] = c[0]; {
components.push_back(root); (*root) = "_:";
(*root)[0] = c[0];
}
c += 2; c += 2;
} }
#ifdef HAVE_GETPWNAM
else if(c[0] == '~') else if(c[0] == '~')
{ {
int numChars = 1; // Home directory. The returned root should always have a
while(c[numChars] && c[numChars] != '/') // 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(root)
if(numChars == 1)
{ {
homedir = getenv("HOME"); root->assign(c, n);
*root += '/';
} }
else if(c[n] == '/')
{ {
char user[PATH_MAX]; ++n;
strncpy(user, c+1, numChars-1);
user[numChars] = '\0';
passwd* pw = getpwnam(user);
if(p)
{
homedir = pw->pw_dir;
} }
else c += n;
{
homedir = "";
} }
}
kwsys_stl::vector<kwsys_stl::string> home_components;
SystemTools::SplitPath(homedir, home_components);
components.insert(components.end(),
home_components.begin(),
home_components.end());
c += numChars;
}
#endif
else else
{ {
// Relative path. // Relative path.
components.push_back(""); if(root)
{
*root = "";
}
}
// Return the remaining path.
return c;
}
//----------------------------------------------------------------------------
void SystemTools::SplitPath(const char* p,
kwsys_stl::vector<kwsys_stl::string>& 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 = h;
}
else
#endif
if(const char* h = getenv("HOME"))
{
homedir = h;
}
}
#ifdef HAVE_GETPWNAM
else if(passwd* pw = getpwnam(root.c_str()+1))
{
if(pw->pw_dir)
{
homedir = pw->pw_dir;
}
}
#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
{
components.push_back(root);
}
} }
// Parse the remaining components. // Parse the remaining components.

View File

@ -351,20 +351,36 @@ public:
const char* in_base); const char* in_base);
/** /**
* Split a path name into its basic components. The first component * Split a path name into its root component and the rest of the
* is one of the following roots: * path. The root component is one of the following:
* "/" = UNIX * "/" = UNIX full path
* "c:/" = Windows full path (can be any drive letter) * "c:/" = Windows full path (can be any drive letter)
* "c:" = Windows drive-letter relative path (can be any drive letter) * "c:" = Windows drive-letter relative path (can be any drive letter)
* "//" = Network path * "//" = Network path
* "~" = Home path for current user
* "~u" = Home path for user 'u'
* "" = Relative path * "" = 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 * The remaining components form the path. If there is a trailing
* slash then the last component is the empty string. The * slash then the last component is the empty string. The
* components can be recombined as "c[0]c[1]/c[2]/.../c[n]" to * 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, static void SplitPath(const char* p,
kwsys_stl::vector<kwsys_stl::string>& components); kwsys_stl::vector<kwsys_stl::string>& components,
bool expand_home_dir = true);
/** /**
* Join components of a path name into a single string. See * Join components of a path name into a single string. See