3

I need to combine an absolute path A with path B, given that B may be relative as well as absolute, preferably using boost::filesystem.

In other words, I want to have:

  • /usr/home/ + abc = /usr/home/abc
  • /usr/home/ + ../abc = /usr/home/../abc (or, even better /usr/abc - this is not my question)
  • /usr/home/ + /abc = /abc

The first two are easy with the / operator but I can't get the third one to work.

I tried:

std::cout << boost::filesystem::path("/usr/home/") / "/abc";

Prints /usr/home//abc.

std::cout << boost::filesystem::path("/usr/home/") + "/abc";

Still prints /usr/home//abc.

Of course I can "see" when path B is absolute by looking at it and just use that, but I don't want to hardcode the check for the leading / because on Windows it can be different (e.g. C:\\ or \\).

rustyx
  • 80,671
  • 25
  • 200
  • 267
  • Check out boost::filesystem::canonical to get paths without the . and .. I believe it also removes the extra / – jodag Jul 09 '17 at 15:53
  • 2
    Possible duplicate of [How do I "normalize" a pathname using boost::filesystem?](https://stackoverflow.com/questions/1746136/how-do-i-normalize-a-pathname-using-boostfilesystem) – user0042 Jul 09 '17 at 16:00
  • Or even [remove trailing slash](https://stackoverflow.com/questions/36941934/parent-path-with-or-without-trailing-slash) – duong_dajgja Jul 09 '17 at 16:01
  • `/usr/home/ + /abc = /abc` -- That's rather unusual -- normalized, I'd expect this to become `/usr/home/abc`. – Dan Mašek Jul 09 '17 at 16:05
  • 1
    @DanMašek: Not unusual at all. This is basically what any program that accepts a filename does. Given an absolute path, it uses that path directly. And given a relative path, it appends it to the current working directory. – Benjamin Lindley Jul 09 '17 at 16:21
  • @BenjaminLindley In that case there has to be some more logic, than simple concatenation and possibly normalization -- like you show in your answer. – Dan Mašek Jul 09 '17 at 16:43

3 Answers3

5

boost::filesystem::path has a member function is_absolute(). So you can choose your operation (either concatenation or replacement) based on that.

path a = "/usr/home/";
path b = "/abc";
path c;

if (b.is_absolute())
    c = b;
else
    c = a / b;

There's also is_relative(), which does the opposite.

Benjamin Lindley
  • 101,917
  • 9
  • 204
  • 274
3

If you are looking to make a relative path absolute with respect to some directory (often the current working directory), there is a function to do this:

sehe
  • 374,641
  • 47
  • 450
  • 633
1

You can also use the C++17 std::filesystem::path. Its operator/ does exactly what you need.

// where "//host" is a root-name
path("//host")  / "foo" // the result is      "//host/foo" (appends with separator)
path("//host/") / "foo" // the result is also "//host/foo" (appends without separator)

// On POSIX,
path("foo") / ""      // the result is "foo/" (appends)
path("foo") / "/bar"; // the result is "/bar" (replaces)

// On Windows,
path("foo") / "C:/bar";  // the result is "C:/bar" (replaces)
path("foo") / "C:";      // the result is "C:"     (replaces)
path("C:") / "";         // the result is "C:"     (appends, without separator)
path("C:foo") / "/bar";  // yields "C:/bar"        (removes relative path, then appends)
path("C:foo") / "C:bar"; // yields "C:foo/bar"     (appends, omitting p's root-name)
wangqr
  • 11
  • 1
  • 5