ENH: Add SystemTools::SplitPathRootComponent and re-implement SplitPath to use it. Add better treatment of user home directory paths.
This commit is contained in:
parent
d7c7ab0927
commit
a6d32b96ed
|
@ -2975,80 +2975,143 @@ kwsys_stl::string SystemTools::GetActualCaseForPath(const char* p)
|
|||
}
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
void SystemTools::SplitPath(const char* p,
|
||||
kwsys_stl::vector<kwsys_stl::string>& 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] == '/')
|
||||
{
|
||||
char user[PATH_MAX];
|
||||
strncpy(user, c+1, numChars-1);
|
||||
user[numChars] = '\0';
|
||||
passwd* pw = getpwnam(user);
|
||||
if(p)
|
||||
{
|
||||
homedir = pw->pw_dir;
|
||||
++n;
|
||||
}
|
||||
else
|
||||
{
|
||||
homedir = "";
|
||||
c += n;
|
||||
}
|
||||
}
|
||||
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
|
||||
{
|
||||
// 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.
|
||||
|
|
|
@ -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<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
|
||||
|
|
Loading…
Reference in New Issue