How do I expand `~' in a filename like the shell does?

How do I expand `~' in a filename like the shell does?


The standard interpretation for `~' at the start of a filename is:
if alone or followed by a `/', then substitute the current user's
home directory; if followed by the name of a user, then substitute that
user's home directory. If no valid expansion can be found, then shells
will leave the filename unchanged.



Be wary, however, of filenames that actually start with the `~'
character. Indiscriminate tilde-expansion can make it very difficult to
specify such filenames to a program; while quoting will prevent the
shell from doing the expansion, the quotes will have been removed by the
time the program sees the filename. As a general rule, do not try and
perform tilde-expansion on filenames that have been passed to the
program on the command line or in environment variables. (Filenames
generated within the program, obtained by prompting the user, or
obtained from a configuration file, are good candidates for
tilde-expansion.)



Here's a piece of C++ code (using the standard string class) to do the
job:




string expand_path(const string& path)
{
if (path.length() == 0 || path[0] != '~')
return path;

const char *pfx = NULL;
string::size_type pos = path.find_first_of('/');

if (path.length() == 1 || pos == 1)
{
pfx = getenv("HOME");
if (!pfx)
{
// Punt. We're trying to expand ~/, but HOME isn't set
struct passwd *pw = getpwuid(getuid());
if (pw)
pfx = pw->pw_dir;
}
}
else
{
string user(path,1,(pos==string::npos) ? string::npos : pos-1);
struct passwd *pw = getpwnam(user.c_str());
if (pw)
pfx = pw->pw_dir;
}

// if we failed to find an expansion, return the path unchanged.

if (!pfx)
return path;

string result(pfx);

if (pos == string::npos)
return result;

if (result.length() == 0 || result[result.length()-1] != '/')
result += '/';

result += path.substr(pos+1);

return result;
}






Home FAQ