Boost logo

Boost :

From: Martin Lutken (mlu_at_[hidden])
Date: 2007-10-02 05:20:56


Suggestion (and implementation) of 3 filesystem functions wich we have used a
lot on the C++ documentation tool DoxyS (Doxygen spin off, www.doxys.dk).

Well, enough intro. The functions are:

[intersection_from_start ( path1, path2)]:
        Get common part of the two from the start. Returs the
         intersection/common-part (from the root and forward)
        of the two paths.

[remove_from_start (inPath, remPath) ]:
        Remove part of path from beginning. Returns inPath with the
        intersection of inPath and remPath removed.

[relative_path ( pathFrom, fileTo ) ]:
        Returns relative path from dir to file/dir.

Implementation:
-----------------------------------------------------------------------------------------
/**
Get common part of the two from the start. Finds the intersection of two parts
from the beginning of the paths. See the example below.
\return The intersection/common-part (from the root and forward) of the two
paths.
\example
    namespace fs = boost::filesystem;
    fs::path path1("z:/hello/horse/goat/pig/cow/sheep", fs::native);
    fs::path path2("z:/hello/horse/whale/dolphin", fs::native);
    intersection_from_start(inPath, remPath) == fs::path("z:/hello/horse");
\endexample
*/
boost::filesystem::path
intersection_from_start(
    const boost::filesystem::path& path1, ///< [in] Path 1
    const boost::filesystem::path& path2 ///< [in] Path 2
                        )
{
    namespace fs = boost::filesystem;
    fs::path::iterator it1 = path1.begin();
    fs::path::iterator it2 = path2.begin();

    if ( *it1 != *it2 )
    {
        assert(*it1 == *it2 );
        return fs::path(); // If path do not have same root, return an
empty path !!!
    }
    fs::path intersectionPath;
    while ( (it1 != path1.end()) && (it2 != path2.end()) && (*it1 == *it2))
    {
        intersectionPath /= fs::path(*it1, fs::native);
        ++it1;
        ++it2;
    }
    return intersectionPath;
}

/**
Remove part of path from beginning. See the example below. If paths does
not have the same root then inPath is returned.
\return inPath with the intersection of inPath and remPath removed.
\example
    namespace fs = boost::filesystem;
    fs::path inPath("z:/hello/horse/goat/pig/cow/sheep", fs::native);
    fs::path remPath("z:/hello/horse", fs::native);
    remove_from_start(inPath, remPath) == fs::path("goat/pig/cow/sheep");
\endexample
*/

boost::filesystem::path
remove_from_start(
    const boost::filesystem::path& inPath, ///< [in] Path to remove start of
path from
    const boost::filesystem::path& remPath ///< [in] Path to remove from
inPath
                  )
{
    namespace fs = boost::filesystem;
        
    fs::path::iterator itIn = inPath.begin();
    fs::path::iterator itRem = remPath.begin();

    if ( *itIn != *itRem )
    {
        // assert(*itIn == *itRem );
        return inPath; // If path do not have same root, just return
inPath !!!
    }
    while ((itIn != inPath.end()) && (itRem != remPath.end()) && (*itIn ==
*itRem) )
    {
        ++itIn;
        ++itRem;
    }
    fs::path outPath;
    for ( ;itIn != inPath.end(); ++itIn )
    {
        outPath /= fs::path(*itIn, fs::native); // fs::native so we can cope
with spaces in file names
    }
    return outPath;
}

/**
Make relative path from dir to file/dir. Use this function to make a relative
link to a file in one directory, from a given directory. Typically one has
an absolute from path (no filename only path) and an absolute path to the
file to link to (path and filename). See examples.
\return Relative path from pathFrom to fileTo.
\example
    namespace fs = boost::filesystem;
    fs::path linkFrom("z:/hello/horse/goat/pig/cow/sheep", fs::native);
    fs::path linkTo("z:/hello/horse/whale/dolphin/seal.txt", fs::native);
    relative_path(linkFrom, linkTo) ==
fs::path("../../../../whale/dolphin/seal.txt");
\endexample
*/
boost::filesystem::path
relative_path (
    const boost::filesystem::path& pathFrom, ///< [in] Path to link from. No
file name only path.
    const boost::filesystem::path& fileTo ///< [in] Path/filename to link
to. Path including the filename to link to.
              )
{
    namespace fs = boost::filesystem;
    fs::path::iterator itFrom = pathFrom.begin();
    fs::path::iterator itTo = fileTo.begin();

    if ( *itFrom != *itTo )
    {
        assert(*itFrom == *itTo );
        return fileTo; // If path do not have same root, just return "to
path"!!!
    }
    while ( (itFrom != pathFrom.end()) && (itTo != fileTo.end()) && (*itFrom
== *itTo) )
    {
        ++itFrom;
        ++itTo;
    }
    fs::path relPath;
    for ( ;itFrom != pathFrom.end(); ++itFrom )
    {
        relPath /= "..";
    }
    for ( ;itTo != fileTo.end(); ++itTo)
    {
        relPath /= *itTo;
    }
    return relPath;
}

-----------------------------------------------------------------------------------------

-Martin Lutken


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk