1

Because in Windows, with Visual Studio, the __FILE__ macro can give lower-case strings, and because I need to know the correctly-cased filename (as perceived by users), I am trying to work out how to convert an all lower-case path on windows to the correctly cased one.

It looks like using stat to get info about the file may be a good starting point.

But how, given a stat object, can I get the filename?

#include <sys/stat.h>
#include <string>

void test()
{
    std::string file_name = "C:\\WiNdoWs";
    struct stat statbuf;
    int stat_ok = stat(file_name.c_str(), &statbuf);
    auto file_serial_number = statbuf.st_ino;
    std::string full_file_name = ???;
}

Or is there any other C++11 way of achieving this? It only needs to work on Windows, so Windows-specific solutions (with code) are fine.

We would like to do this without adding a dependency on either boost filesystem or Qt, or moving to C++17.

Update 1

For context, the code is in a header-only testing framework, that intends to create some output files based on the name of the source file containing the test - so a test file called DemoTest.cpp would generate an output file whose name begins DemoTest....

The problem we trying to solve is that, for some Visual Studio compiler settings, the output file name begins demotest....

So this means that the stat call is running on the same source file where __FILE__ was generated at compile time.

Update 2

It turns out that the statbuf.st_ino value is zero when debugging in Visual Studio 2017 - presumably because the value represents a Unix inode, and there's no such thing on Windows.

So this whole approach won't work.

Are there any other options?

Deduplicator
  • 44,692
  • 7
  • 66
  • 118
Clare Macrae
  • 3,670
  • 2
  • 31
  • 45
  • I'd look into things like [`GetLongPathName`](https://msdn.microsoft.com/en-us/library/aa364980(v=vs.85).aspx) and [`GetFinalPathNameByHandle`](https://msdn.microsoft.com/en-us/library/windows/desktop/aa364962.aspx) (from a random search on msdn). – melpomene Mar 02 '18 at 19:28
  • Also `GetFullPathName`. I'm not exactly sure about the difference between that and `GetLongPathName`. – Igor Tandetnik Mar 02 '18 at 19:31
  • Thank you, I should have said I was aware of those, and was having trouble finding modern examples of them working with C++11. – Clare Macrae Mar 02 '18 at 22:40

1 Answers1

0

I'm afraid you can get stuck again, because that depends on how the user has invoked the compiler.... If you say (e.g. in one Makefile)

A.o: A.c
    $(CC) A.c -o a.o

Windows will not complaint about the case of the output file, because both cases refer to the same object output. But the case of A.c is different. If you try cc A.c and the source file is stored in the filesystem as a.c, you have only one way of knowing the actual name the file is stored in the filesystem... namely, to search the directory for files and stop when you find the file that matches the one you are searching. So, that's a complex (and expensive) way and so, the compiler will not normally follow it, so it will act upon the name you passed to it. That's also true for #include files, which are somewhat named in your source code... I you mangle the case of the character names, the compiler won't complain, except if the mangling gives you a nonexistent file, and in that case you'll get a file not found complaint from it.

The conclusion is: use the proper names, and the compiler will have the exact way to spell the filenames.... if you don't the compiler is not going to help on that... _If you told me to compile a.c I shall tell you __FILE__ matches a.c, even if the actual file name is A.C.

Probably the compiler will give you different case for a file because you gave different case to the compiler (by means of a mispelled command line or a mispelled #include directive) Use case with care, and you'll receive proper case in names.

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31