1

on input: two paths like

  • inFrom: /usr/share/lib
  • inTo: /usr/bin

on output: a path like

  • oRelPath == ../../bin

Are there any standard or near standard functions ? OSes of interests are: windows, mac, linux It looks weird that for such standard trivial task it seems there is no any standard function (or they called in an non-obvious way)

dev_null
  • 1,907
  • 1
  • 16
  • 25
  • 1
    [This question is a duplicate](http://stackoverflow.com/q/275689/440558), but in C#. Should not be impossible to port the code to C. – Some programmer dude Dec 01 '14 at 12:50
  • thanks, from there it seems I found a WinAPI function: PathRelativePathTo – dev_null Dec 01 '14 at 13:03
  • Providing a standard interface to file systems is anything but trivial. The closest to a standard implementation you will get is [boost::filesystem](http://www.boost.org/doc/libs/1_53_0/libs/filesystem/doc/index.htm). – IInspectable Dec 01 '14 at 13:28
  • Yes, but he said c not c++. – Iharob Al Asimi Dec 01 '14 at 13:49
  • @dev_null PathRelativePathTo is no use to you because you need support for linux as well as windows – David Heffernan Dec 01 '14 at 16:12
  • I have an OS dependent shim. So it's ok. Surely I'll write my own if I can't find. I just don't want to reinvent the wheel. I found it's time to time very hard to find an obvious for others thing. – dev_null Dec 01 '14 at 17:55
  • 1
    @Armali What did you do with your comment ? – Stargateur Jun 14 '17 at 21:53
  • 1
    @Stargateur - I did not make a comment; some fool "converted" (moved) an answer post to a comment, with the outcome we are seeing. – Armali Jun 19 '17 at 09:12

2 Answers2

0

I converted the C# code that @Armali posted to C++:

#include <vector>
#include <string>
#include <algorithm>

std::vector<std::string> str_split(const std::string& in,  const std::string& delim=" \t\r\n") {
    std::vector<std::string> out;
    auto firstPos = in.find_first_not_of(delim);
    auto secondPos = in.find_first_of(delim, firstPos);
    out.clear();
    if(firstPos != std::string::npos)
    { out.push_back( in.substr( firstPos, secondPos - firstPos ) ); }
    while( secondPos != std::string::npos ) {
        firstPos = in.find_first_not_of(delim, secondPos);
        if(firstPos == std::string::npos)
        { break; }
        secondPos = in.find_first_of( delim, firstPos );
        out.push_back( in.substr( firstPos, secondPos - firstPos ) );
    }
    return out;
}

int str_compare_no_case(std::string a, std::string b) {
    std::transform(a.begin(), a.end(), a.begin(), ::tolower);
    std::transform(b.begin(), b.end(), b.begin(), ::tolower);
    return a.compare(b);
}

static std::string MakeRelativePath(std::string absPath, std::string relTo) {
#ifdef _WIN32
    const char directorySeparator = '\\';
#else
    const char directorySeparator = '/';
#endif
    std::string DirectorySeparatorChars = {directorySeparator, '\0'};
    auto absParts = str_split(absPath, DirectorySeparatorChars);
    auto relParts = str_split(relTo, DirectorySeparatorChars);

    // Get the shortest of the two paths
    size_t len = std::min(absParts.size(), relParts.size());

    // Use to determine where in the loop we exited
    int lastCommonRoot = -1;
    int index;

    // Find common root
    for (size_t index = 0; index < len; index++) {
        if (str_compare_no_case(absParts[index], relParts[index])==0) {
            lastCommonRoot = index;
        } else {
            break;
        }
    }

    // If we didn't find a common prefix "c:\xx", "D:\"
    if (lastCommonRoot == -1) {
        // The path of the two files doesn't have any common base.
        return absPath;
    }

    // Build up the relative path
    std::string relativePath;

    // Add on the ..
    for (size_t index = lastCommonRoot + 1; index < relParts.size(); index++) {
        relativePath += "..";
        relativePath += directorySeparator;
    }

    // Add on the folders
    for (size_t index = lastCommonRoot + 1; index+1 < absParts.size(); index++) {
        relativePath += absParts[index];
        relativePath += directorySeparator;
    }
    if(!absParts.empty()) {
        relativePath += absParts[absParts.size() - 1];
    }
    return relativePath;
}
KungPhoo
  • 516
  • 4
  • 18
-1

This question is a duplicate, but in C#. Should not be impossible to port the code to C. – Some programmer dude

thanks, from there it seems I found a WinAPI function: PathRelativePathTo – dev_null

Armali
  • 18,255
  • 14
  • 57
  • 171