views:

163

answers:

4

I am writing a program in c++ that accepts a filename as an argument on the command line:

>> ./myprogram ../path/to/file.txt

I know I can simply open an fstream using argv[1], but the program needs more information about the exact location (ie. full pathname) of the file.

I thought about appending argv[1] to getcwd(), however obviously in the example above you'd end up with /path/../path/to/file.txt. Not sure whether fstream would resolve that path automatically, but even if it did, I still don't have the full path without a lot of string processing.

Of course, that method wouldn't work at all if the path provided was already absolute. And since this program may be run on Linux/Windows/etc, simply detecting a starting '/' character won't work to determine whether the argument was a full path or not.

I would think this is a fairly common issue to deal with path names across multiple OSs. So how does one retreive the full path name of a command line argument and how is this handled between operating systems?

+1  A: 

...you'd end up with /path/../path/to/file.txt. Not sure whether fstream would resolve that path automatically, but even if it did, I still don't have the full path without a lot of string processing.

It does, and you can use /path/../path/ for everything you want without problems.

Anyway there is no standard function in C++ to do what you want. You would have to do it manually, and it wouldn't be trivial.. I suggest you keep the path as it is, it shouldn't cause any problems.

Andreas Bonini
In a perfect world, that would be a good solution, however the program's purpose is to collect some information about a file, which includes its location in the filesystem. I am okay with doing the string processing, the real problem is determining whether you typed a relative path or an absolute path in order to know to append it to the cwd.
Alex B
@Alex B, absolute path is _very_ likely to start with '/', otherwise it's relative isn't it?
Dmitry
Not if you're in Windows.
Alex B
Sorry, didn't realize that you might care about that after reading your example of '/path/../path/stuff'.
Dmitry
+3  A: 

Pathname handling is highly OS-specific: some OS have a hierarchy with just one root (e.g. / on Unix ), some have several roots a la MS-DOS' drive letters; some may have symbolic links, hard links or other kinds of links, which can make traversal tricky. Some may not even have the concept of a "canonical" path to a file (e.g. if a file has hard links, it has multiple names, none of which is more "canonical").

If you've ever tried to do path-name manipulation across multiple OS in Java, you know what I mean :-).

In short, pathname handling is system-specific, so you'll have to do it separately for each OS (family), or use a suitable library.

Edit:

You could look at Apache Portable Runtime, or at Boost (C++ though), both have pathname handling functions.

sleske
Platform-specific code it is then. Thanks!
Alex B
If you're cross-platform, you should really use boost instead of platform specific functions.
Klaim
+1  A: 

It is OS-dependent. If you are using linux you can look at realpath(). No doubt Windows has something comparable.

Duck
Thanks, realpath() works perfectly on linux. Still looking around for a Windows equivalent though...
Alex B
+1  A: 

AFAIK there is no standard way.

however you could try this approach (written in pseudocode):

string raw_dirname=get_directory_part(argv[1])
string basename=get_filename_part(argv[1])
string cwd=getcwd()
chdir(relative_dirname)
string absolute_dirname=getcwd()
chdir(cwd)
string absolute_filename=absulute_dirname + separator + basename

but note: I am not quite sure if there are issues when symbolic links come into play.

I just found this article - http://insanecoding.blogspot.com/2007/11/implementing-realpath-in-c.html - It has some c++ code for this exact approach. Although realpath() seems to work quite well (if it's available on the platform - doesn't seem to be for Windows), the article shows a good do-it-yourself version.
Alex B
Nice idea. I'd be worried however if `getcwd` really returns a canonical path. I read its documentation, and it seems it might simply return something like /a/b/../c , if it feels like it.
sleske