| Roger Leigh 2006-07-04, 7:24 am |
| Ian Zimmerman <nobrowser@gmail.com> writes:
> thus http://www.opengroup.org/onlinepubs...s/dirname.html:
>
>
> Great, it's a MAY. How in the world do I know how to dispose with the
> result pointer? It can be the same as the argument (nothing seems to
> preclude that), a newly malloced one, or a static one.
>
> :-(
It will be a pointer to the original string if no modifications are
necessary, or else it will be copied into a buffer managed by dirname,
modified, and a pointer to that returned. Either way, you don't need
to worry about the returned pointer: it's either already managed by
you (the original path pointer), or it's managed by dirname. You can
just lose the pointer, and nothing bad will happen. However, it's not
thread-safe.
I wrote some thread-safe and nicer version in C++, below. It's GPL,
so feel free to reuse it under those terms.
Regards,
Roger
/* Copyright © 2005-2006 Roger Leigh <rleigh@debian.org>
*
* schroot is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* schroot is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*
****************************************
*****************************/
/**
* Strip the directory path from a filename. This is similar to
* basename(3).
*
* @param name the filename to strip of its path.
* @param separator the separation delimiting directories.
* @returns the base name.
*/
std::string
basename (std::string name,
char separator = '/');
/**
* Strip the fileame from a pathname. This is similar to
* dirname(3).
*
* @param name the path to strip of its filename.
* @param separator the separation delimiting directories.
* @returns the directory name.
*/
std::string
dirname (std::string name,
char separator = '/');
/**
* Normalise a pathname. This strips all trailing separators, and
* duplicate separators within a path.
*
* @param name the path to normalise.
* @param separator the separation delimiting directories.
* @returns the normalised name.
*/
std::string
normalname (std::string name,
char separator = '/');
namespace
{
/**
* Remove duplicate adjacent characters from a string.
*
* @param str the string to check.
* @param dup the duplicate character to check for.
* @returns a string with any duplicates removed.
*/
std::string remove_duplicates (std::string const& str,
char dup)
{
std::string ret;
for (std::string::size_type pos = 0;
pos < str.length();
++pos)
{
ret += str[pos];
if (str[pos] == dup)
{
while (pos + 1 < str.length() &&
str[pos + 1] == dup)
++pos;
}
}
return ret;
}
}
std::string
basename (std::string name,
char separator)
{
// Remove trailing separators
std::string::size_type cur = name.length();
while (cur - 1 != 0 && name[cur - 1] == separator)
--cur;
name.resize(cur);
// Find last separator
std::string::size_type pos = name.rfind(separator);
std::string ret;
if (pos == std::string::npos)
ret = name; // No separators
else if (pos == 0 && name.length() == 1 && name[0] == separator)
ret = separator; // Only separators
else
ret = name.substr(pos + 1); // Basename only
return remove_duplicates(ret, separator);
}
std::string
dirname (std::string name,
char separator)
{
// Remove trailing separators
std::string::size_type cur = name.length();
while (cur - 1 != 0 && name[cur - 1] == separator)
--cur;
name.resize(cur);
// Find last separator
std::string::size_type pos = name.rfind(separator);
std::string ret;
if (pos == std::string::npos)
ret = "."; // No directory components
else if (pos == 0)
ret = separator;
else
ret = name.substr(0, pos); // Dirname part
return remove_duplicates(ret, separator);
}
std::string
normalname (std::string name,
char separator)
{
// Remove trailing separators
std::string::size_type cur = name.length();
while (cur - 1 != 0 && name[cur - 1] == separator)
--cur;
name.resize(cur);
return remove_duplicates(name, separator);
}
--
Roger Leigh
Printing on GNU/Linux? http://gutenprint.sourceforge.net/
Debian GNU/Linux http://www.debian.org/
GPG Public Key: 0x25BFB848. Please sign and encrypt your mail.
|