Boost logo

Boost :

From: John Maddock (john_at_[hidden])
Date: 2004-08-21 05:36:31


> I propose the following design. The aim of boost::filesystem should be to
> support the following coding idiom:
>
> * The programmer should take care to only handle two types of paths
> in his application:
>
> 1) Complete paths
> 2) Relative paths

That is true now.

> * The programmer will have to specifically tell the libary when a
constructed
> path is 'native' and when not. A native path is accepted according to
native
> rules and never gives any problem (exceptions) further on.
> A non-native path is checked according to the existing rules, which
basically
> means that the programmer can set a default check routine that will in
effect
> determine how portable the application will be.

That is also true now, isn't it?

> I propose two design changes:
>
> 1) 'native' is now not only a representation, but an *internal state* of
fs::path.
> (this has no effect on the representation as returned by
fs::path::string()).
> 2) All 'complete' paths are automatically marked as 'native'.

If I understand you correctly, you are suggesting that error checking is
turned off for native paths, I would support that, but other than that I
don't see how it differs.

Actually, there is another case where error checking needs to be turned off:
when the path is obtained from a directory_iterator, but is none the less
relative (and *please* don't tell me that all such paths should be complete,
that would break a lot of code; actually it would make a lot of coding
idioms impossible).

> Examples, the following code is legal:
>
> fs::path p1("C:\\foo\\a.exe", native); // As one might do on windows.
> fs::path p2("/usr/src/a.out, native); // As one might do on linux.
> std::cout << p1.native_file_string(); // ok, p1 is native.
>
> fs::path p3("foo/bar"); // Relative path, always succeeds.
> std::cout << p.string(); // ok
> std::cout << p.native_directory_string(); // Useless, but ok.

Not useless at all. And works now.

> fs::path p4(complete(p3)); // p4 is now "native", because now it is
complete.
> std::cout << p4.native_directory_string(); // ok
>
> And the following will fail (assertion?):
>
> std::cout << p4.string() // Not allowed because p4 is native (complete).

One could add an assertion that the path is not complete, if you want that
behaviour.

Actually this change would break the bcp utility - there is a (slightly
hairy) use for this.

> Since there would be a default way defined of how a relative path is
> completed, all operation functions will accept both, relative
> and complete paths. For example:
>
> fs::path p1("C:\\cygwin\\usr/bin/ls", native); // Legal path on Cygwin.
> if (fs::exists(p1)) // Ok, access complete path.
>
> // For clarification
> fs::path p2("C:\\cygwin\\usr"); // Just an example
> fs::default_working_directory(p2); // fictuous function.
>
> fs::path p3("bin/ls"); // Portable representation (refers in fact to
"C:\cygwin\usr\bin\ls.exe").
> if (fs::exists(p3)) // Ok : exists() will make the path complete before
testing.
>
> And this throws:
>
> fs::path p4("/bin/ls"); // Not allowed: this path has a root but is not
marked 'native'.
>
> Setting the default_working_directory shall allways
> need to be done for each supported OS seperately.
> Of course you can set it to "/" on single root machines, and
> set it to "E:/" after extracting the 'E:' from the current
> path at application start up, in effect simulating a 'single root':

You should never need to set that explicitly unless you want to: each
aplication inherits a default working directory anyway from the host
environment.

BTW the behaviour you're asking for was required by bcp - all the paths are
relative to some root (the boost installation path) - that path may be
relative or absolute; and whenever you need a path relative to some root,
one can just use:

my_root / my_relative_path

so again, you can do what you want right now.

> The average application will work with relative
> paths, relative to some (native) base directory
> and next to that have some arbitrary, complete and thus native
> directories (ie, read from environment variables).
>
> But in case more than one 'working' directory seems needed
> then we can add support for that too by allowing to
> construct paths with a reference to the (complete/native)
> working directory. Ie,
>
> fs::path homedir(g_getenv("HOME"), native);
> fs::path rcdir(homedir / "edragon/rc", native);
> fs::path tmpdir(current_path().root_path() / "tmp");
> // ...
>
> fs::path runtime_rcfile(rcdir); // Set 'runtime_rcfile' to be relative
to 'rcdir'.
> // ...
>
> runtime_rcfile = "config/runtimerc";
>
> which is then relative to `rcdir' instead of
> a single, global 'working directory' (as now returned
> by fs::current_path()).

I'm sorry, but that looks way more complicated to me than the current
design: if you want a path to be relative to a specific base, then use
"my_base/my_path", it's easy to use, works, and it's clear what you mean as
well.

John.


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