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

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\"");

Related

Is it possible to read and write to a header file?

So I'm trying to overwrite a macro I have on a header file but I can't seem to open it by using std::ifstream. Is it even possible to read/write to an existing header file or are there default permissions that don't allow programs to modify header file contents?
std::ifstream versionH;
char temp[100];
versionH.open("..\temp.h");
if (!versionH.is_open()) {
std::cout << "Didn't open" << std::endl;
return 1;
}
while (!versionH.eof()) {
versionH >> temp;
std::cout << temp << std::endl;
}
I would hope that I'd be able to read in the header file and display it's contents but 'versionH.is_open()' is returning false. Is there something I'm missing here?
Is it possible to read and write to a header file?
Headers are files. It is possible to read and write files (assuming the file exists, and the process has sufficient permissions etc.). Therefore we can infer that header files can be read and written to.
Note that modifying a header file that has been used to compile a program has no effect on the compiled program. It can only affect programs compiled using the modified file.
Furthermore, files in the context where the program is compiled are irrelevant to the program. Only the files in the file system where the program is executed can be read.
Is there something I'm missing here?
Probably the file doesn't exist. The filename is most suspicious. Does it really contain a tab character (\t), or did you intend to write a (windows) dir separator? The backslash is the escape character, so in order to write it in a string literal, you must escape it (with another backslash: \\).

Printing boost path on windows with escaped backslashes

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

System copy file with space

By using system command prompt copy in C++, I could not perform the command as my directory has space in between two character, the 'log' and 'file'. Maybe regular expression may help me solve this problem. But I had no ideas how to do this.
system("copy C:\users\person\log file C:\users\person\desktop")
system("copy \"C:\\users\\person\\log file\" C:\\users\\person\\desktop")
I haven't tested that, but it should work.
I believe #tabstop was referring to "std::rename", which is one solution. The way that you are copying the file will only work if there is a command called "copy" on the operating system. If you were to run this program on, say, iOS, it would not work.
Here is a better way of doing this in a C++ way (solution grafted from here: Copy a file in a sane, safe and efficient way)....
#include <fstream>
int main(char** argv, int argc)
{
std::ifstream src("C:\\users\\person\\log file", std::ios::binary);
std::ofstream dst("C:\\users\\person\\desktop", std::ios::binary);
dst << src.rdbuf();
}
Don't forget the extra backslashes. You need them because the backslash is an escape character that will turn on or off functionality (like \n for the newline).

How to get directory of a file which is called from command line argument?

For example, I am calling my executable in ubuntu:
./foo temp/game1.txt temp/game2 txt
I am using realpath() to find the path to the game1.txt.
Using it however will give me the full path including the game1.txt name.
For example, it will come out as
/home/*/Download/temp/game1.txt
I want to erase game1.txt on that string so that I can use the string to use it to output other files in that folder.
Two questions.
Is realpath() alright to use for this kind of operation? Is there better way?
Can someone give me a quick way to erase "game1.txt" so that the string will be "/home/*/Download/temp/" save in a string format(not char)?
Thank you very much.
Don't really know Linux, but a general way for your second question:
#include <string>
#include <iostream>
int main(){
std::string fullpath("/home/*/Download/temp/game1.txt");
size_t last = fullpath.find_last_of('/');
std::string path = fullpath.substr(0,last+1);
std::cout << path;
}
See on Ideone.
You can use the dirname function for this: http://linux.die.net/man/3/dirname
Note that dirname will erase the trailing slash (except for the root directory); you'll have to append the slash back in when you append the filename.
Also, you don't actually need to use realpath for this purpose, you could simply use the argument as passed in, dirname will give you "temp" and you can append filenames to that.
man -S3 dirname
should do what you want
The cross-platform solution is
QFileInfo target_file_name(argv[1]);
QString absolute_path = target_file_name.absolutePath()
// e.g. /home/username/
QString some_other_file = QString("%1/another_file.txt").arg(absolute_path)
// => /home/username/another_file.txt
Boost.Filesystem can also do this easily. I just find the documentation of QFileInfo easily to navigate.
http://doc.qt.nokia.com/4.6/qfileinfo.html#absolutePath

Globbing in C++/C, on Windows

Is there a smooth way to glob in C or C++ in Windows?
E.g., myprogram.exe *.txt sends my program an ARGV list that has...ARGV[1]=*.txt in it.
I would like to be able to have a function (let's call it readglob) that takes a string and returns a vector of strings, each containing a filename.
This way, if I have files a.txt b.txt c.txt in my directory and readglob gets an argument *.txt, it returns the above filelist.
//Prototype of this hypothetical function.
vector<string> readglob(string);
Does such exist?
Link with setargv.obj (or wsetargv.obj) and argv[] will be globbed for you similar to how the Unix shells do it:
http://msdn.microsoft.com/en-us/library/8bch7bkk.aspx
I can't vouch for how well it does it though.
This is very Windows-specific. I don't know how you'd write this to be cross-platform. But I've used this in Windows programs and it works well for me.
// Change to the specified working directory
string path;
cout << "Enter the path to report: ";
cin >> path;
_chdir(path.c_str());
// Get the file description
string desc;
cout << "Enter the file description: ";
cin >> desc;
// List the files in the directory
intptr_t file;
_finddata_t filedata;
file = _findfirst(desc.c_str(),&filedata);
if (file != -1)
{
do
{
cout << filedata.name << endl;
// Or put the file name in a vector here
} while (_findnext(file,&filedata) == 0);
}
else
{
cout << "No described files found" << endl;
}
_findclose(file);
there was talk about having it in Boost::filesystem but it was dropped in favor of using the boost::regex.
For win32 specific (MFC) you can use the CFileFind class
There may be a better way now, but last time I had to deal with this problem I ended up including Henry Spencer's regex library statically linked into my program (his library is BSD licensed), and then I made a wrapper class that converted the user's glob-expressions into regular expressions to feed to the regex code. You can view/grab the wrapper class here if you like.
Once you have those parts in place, the final thing to do is actually read the directory, and pass each entry name into the matching function to see if it matches the expression or not. The filenames that match, you add to your vector; the ones that don't you discard. Reading the directory is fairly straightforward to do using the DOS _findfirst() and _findnext() functions, but if you want a nicer C++ interface I have a portable wrapper class for that also...
Ehw. I had to implement something like this in ANSI C about 15 years ago. Start with the ANSI opendir/readdir routines, I guess. Globs aren't exactly RegExs, so you will have to implement your own filtering.