Printing boost path on windows with escaped backslashes - c++

I need to print out a path (stored as boost filesystem path) to file, to be parsed back to path later.
The parser expects paths in windows platform to be escaped, so a path like
c:\path\to\file
will appear in the file as
c:\\path\\to\\file
Is there a method in boost path to do this? or do i need to process the output of string() method to add the escapes?

Did you hear about std::quoted?
It can be handy for things like this. Alternatively, use the power of your shell (e.g. Escape FileNames Using The Same Way Bash Do It)
Live On Coliru
#include <iomanip>
#include <iostream>
int main() {
std::cout << std::quoted(R"(c:\path\to\file)") << std::endl;
std::cout << std::quoted("c:\\path\\to\\file") << std::endl;
}
Prints
"c:\\path\\to\\file"
"c:\\path\\to\\file"
Note: also shows raw string literal

Related

Is there a simple way to get the filename from a path in c++?

Currently I am getting a file's path with GetModuleFileName and storing it in szExeFilePath by doing:
TCHAR szExeFilePath[MAX_PATH];
GetModuleFileName(NULL, szExeFilePath, MAX_PATH);
And that returns C:\\dev\\program\\Debug\\program.exe
However I also want to store just the program.exe. I looked around and saw _splitpath_s might be the easiest way of doing this. The only problem is that I didn't see any explanation on how to actually use _splitpath_s and I can't get it to work at all.
So basically I am asking how to use _splitpath_s or if there is a simpler/easier method of getting the filename of the executable.
However I also want to store just the program.exe
With C++17 you could simple use std::filesystem
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
std::cout << fs::path("C:/dev/program/Debug/program.exe").filename() << '\n' ;
}
Demo here

C/C++ equivalent to Bash "readlink -f"

I'm coding a Linux tool in C/C++ and receive a full path to a directory as input, this will always be rooted at "/" but elements of the path may be symlinks rather than real directories. For example:
/tools/sometool/latest
where "latest" is a symlink to "1.0".
The path is then used to filter a list of other files. My problem is that the other files can use either form:
/tools/sometool/latest/foo.txt
/tools/sometool/1.0/foo.txt
and I need to treat both as matching the criteria of being contained inside /tools/sometool/latest. I therefore need a way to fully resolve all the symlinks in the path.
In Bash, "readlink -f /tools/sometool/latest" returns "/tools/sometool/1.0" which is perfect, but when I try "readlink()" in C, it just gives me "1.0".
I've searched but can't find any existing solution to this in C.
Is there a simple solution that I've missed, or do I need to build the equivalent of the bash command in C to make this work?
Thanks!
P.S. The tool doesn't need to be portable, so a Linux-only solution would be fine.
If you're using C++17, you can try std::filesystem::canonical.
Converts path p to a canonical absolute path, i.e. an absolute path that has no dot, dot-dot elements or symbolic links in its generic format representation.
#include <iostream>
#include <filesystem>
namespace fs = std::filesystem;
int main()
{
fs::path p = fs::path("/tools/sometool/latest");
std::cout << "Canonical path for " << p << " is " << fs::canonical(p) << '\n';
}
Try realpath() (see its man page). This does basically the same as readlink -f.

boost locale c++ - understanding the basics

First of all How do i make the following example work (from boost website):
#include <boost/locale.hpp>
#include <iostream>
using namespace std;
using namespace boost::locale;
int main()
{
generator gen;
// Specify location of dictionaries
gen.add_messages_path(".");
gen.add_messages_domain("hello");
// Generate locales and imbue them to iostream
locale::global(gen(""));
cout.imbue(locale());
// Display a message using current system locale
cout << translate("Hello World") << endl;
}
(tried creating an hello.mo file but still didn't work).
Basically what i am trying to do is to be able to cout a string like: "operation",
and then according to file1 / file2 it will print the string value under id:operation for that specific file.
how can i do that?
Thanks.
boost translate: po file not work might help.
The most confusing step is:
2. Put the .mo file into the correct file structure, for example if your trying to translate to spanish this would be ./es_ES/LC_MESSAGES/hello.mo
It's a wraper of GNU 'gettext' utilities. The manual is useful too.

Executing Batch File From C++ with Spaces in the Path

I want to execute a batch file using system() and the path to the file will be passed to the function so it will look like this:
void executeBatch(char* BatchFile){
system(BatchFile);
}
Now the issue is that the path passed in will not have the escape quotes to ignore spaces for example the user would input:
"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat"
How do I add escape quotes to the path passed in?
So I essentually change:
"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat"
to
"\"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat\""
Try
system("\"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat\"");
As for your additional question from your comment, you have to use:
char* it = "\"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat\"";
system(it);
then.
As for your edited question, since you've marked the question to use c++, here's a c++ solution how to implement your function correctly:
#include <sstream>
int executeBatch(const char* fullBatchFileName)
{
std::ostringstream oss;
oss << '\"' << fullBatchFileName << '\"';
return system(oss.str().c_str());
}
Don't make this an XY problem now! I think you should have understood the principle from these samples: Just wrap your batch file name within a pair of double-quote characters ('\"'), that the shell can interpret it correctly.
There are also pure c library methods available to achieve this (see <cstring>) but I wouldn't recommend these, if you can use the c++ standard library.
Try adding escaped double-quotes around your command line, i.e.
system("\"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat\"");
You need to escape the quotes:
system("\"C:\\Users\\500543\\Documents\\Batch File Project\\Testing.bat\"");

How to redirect stdout and stderr streams (Multiplatform)?

I'm writing GL application that uses external libs, which print errors to the console. I want to catch that and print in the in-game console.
PS: Sorry, for my bad english....
There are two basic approaches you could take to this:
If the libraries all use std::cout for the IO you want to capture you can write your own basic_streambuf. You can then just call std::cout.rdbuf(mybufinst); to replace the streambuffer, for example using the std::basic_stringbuf:
#include <sstream>
#include <iostream>
int main() {
static std::basic_stringbuf<std::ostream::char_type> buf;
std::cout.rdbuf(&buf);
std::cout << "Hello captured world!\n";
std::cerr << "Stole: " << buf.str() << std::endl;
}
You can use a platform specific approach, e.g. on POSIX systems dup2() will allow you to replace a file descriptor with another one, or on Windows with SetStdHandle(). You'd want to use pipes rather than just another file probably and you'd need to be really careful about blocking (so probably want a dedicated thread)