Boost logo

Boost :

From: Carlo Wood (carlo_at_[hidden])
Date: 2004-08-21 03:26:48


On Sat, Aug 21, 2004 at 08:30:43AM +0100, Keith Burton wrote:
> > And the following will fail (assertion?):
> > std::cout << p4.string() // Not allowed because
> p4 is native (complete).
>
> Why should this fail ? It seems an unnecessary restriction

Perhaps more extension of the API is needed. There is a mixup
up of two different types of 'native'.

'native' means "works only on the OS that the application is
currently running on".

But still, there two distinct ways that a path can fail to be
portable:

1) It can contain characters that are not portable, or use
   a format that is not portable.

2) The root base (an explicit, complete, directory) is well,
   explicit.

The internal 'native' state that I introduced marks the latter,
assuming that any complete path is automatically not portable
because the 'root' part of any path is simply not portable.
But, as I said before, this 'native' wouldn't change the format
of the string returned by 'string()'.

And now, as you noted, I suddenly propose to also trip on
the *usage* of 'string()' when this 'native' flags (with the
second meaning) is set!

I agree that this is a duality and some refinement might be
better.

However, just plain allowing it seems wrong. If a programmer
uses a complete path, then it is per definition not portable
(point 2) and therefore marked internally as a 'native' path
of the second kind. Then when a programmer converts the path
to a std::string, he should show somehow that he is aware of
the fact that this is not portable. The idea was to reserve
path::string() for portable strings, that can be used regardless
of the OS. But well, you are right if you say that it might
be needed, because there is also this thing 'representation'.
A programmer might need the 'canonical' representation of
a path - having nothing else then that path.

The current boost::filesystem just allows one to 'store' all
kind of paths that are out there, and gards point 1), only.
If a path contains a "c:/Program Files/My Documents", then
string() will return that, and native_directory_string()
will return "C:\Program Files\My Documents". I can imagine
that that is not wanted in some cases.

The most clean, logical, way to improve this would be to
have a way to convert complete paths back to relative paths,
and then use string(). But there are inprinciple many relative
paths (one for each directory it contains) so I don't like
the conversion (removing an explicit root base should be
possible though).

A straight forward shortcircuit of this problem would be
to introduce the same function but with a different name.
Like fs::path::complete_string, which would be allowed on
complete paths and return then what string() returns now.

That brings me to a new idea: why not have two different
_types_? fs::relative_path and fs::native_path.

Then, a program that uses code that you considered
problematic turns into something like this:

#ifdef __CYGWIN__
fs::native_path rootbase(get_cygwin_root());
#else
// ...
#endif

fs::relative_path tmpdir(rootbase);

tmpdir = "tmp";

fs::relative_path session_socket(tmpdir);

session_socket = fs::relative_path("screen") / username() / "s0";

std::cout << session_socket.string() << std::endl; // Prints "screen/carlo/s0".
std::cout << session_socket.native_file_string() << std::endl; // Prints "[screen/carlo]:s0" on VMS.

fs::native_path completed_session_socket(session_socket);

std::cout << completed_session_socket.string() << std::endl; // Prints "c:/cygwin/tmp/screen/carlo/s0" on cygwin.
std::cout << completed_session_socket.native_directory_string() << std::endl; // Prints "C:\cygwin\tmp\screen\carlo\s0" on cygwin.

In this senario I do not have a problem with allowing 'string()'
to be called, because having a separate type for complete path's
is enough clarity for me.

Note that in this case:

fs::relative_path foo; // Uses fs::current_path() as root base.

fs::complete(foo) // returns fs::current_path() / foo.
fs::complete(foo, tmp) // returns tmp / foo.

The first parameter of fs::complete must be a relative_path
and the second a native_path.


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