How does one properly use the Unix exec C(++)-command? - c++

Specifically, I need to call a version of exec that maintains the current working directory and sends standard out to the same terminal as the program calling exec. I also have a vector of string arguments I need to pass somehow, and I'm wondering how I would go about doing all of this. I've been told that all of this is possible exclusively with fork and exec, and given the terrible lack of documentation on the google, I've been unable to get the exec part working.
What exec method am I looking for that can accomplish this, and how do I call it?

If you have a vector of strings then you need to convert it to an array of char* and call execvp
#include <cstdio>
#include <string>
#include <vector>
#include <sys/wait.h>
#include <unistd.h>
int main() {
using namespace std;
vector<string> args;
args.push_back("Hello");
args.push_back("World");
char **argv = new char*[args.size() + 2];
argv[0] = "echo";
argv[args.size() + 1] = NULL;
for(unsigned int c=0; c<args.size(); c++)
argv[c+1] = (char*)args[c].c_str();
switch (fork()) {
case -1:
perror("fork");
return 1;
case 0:
execvp(argv[0], argv);
// execvp only returns on error
perror("execvp");
return 1;
default:
wait(0);
}
return 0;
}

You may be looking for execv() or execvp().

You don't necessarily need google to find this out, you should have the man command available so you can man fork and man exec (or maybe man 2 fork and man 3 exec) to find out about how the parameters to these system and library functions should be formed.
In Debian and Ubuntu, these man pages are in the manpages-dev package which can be installed using synaptic or with:
sudo apt-get install manpages-dev

Related

Ifstream is failing to load a file and it won't open

Some of this code may seem foreign to you since I make 3ds homebrew programs for fun but it's essentially the same but with extra lines of code you can put in. I'm trying to read a file called about.txt in a separate folder. I made it work when I put it in the same folder but i lost that file and then my partner said he wanted it in Scratch3ds-master\assets\english\text and not in Scratch3ds-master\source I keep getting the error I coded in. I'm new to stack-overflow so this might be too much code but well here's the code:
#include <fstream>
#include <string>
#include <iostream>
int main()
{
// Initialize the services
gfxInitDefault();
consoleInit(GFX_TOP, NULL);
int version_major;
int version_minor;
int version_patch;
version_major = 0;
version_minor = 0;
version_patch = 2;
printf("This is the placeholder for Scratch3ds\n\n");
std::ifstream about_file;
about_file.open("../assets/english/text/about.txt");
if (about_file.fail())
{
std::cerr << "file has failed to load\n";
exit(1);
}
Chance are that you're using devkitpro packages. And chances are that the devkitpro team provide an equivalent of the NDS 'ARGV protocol' for 3DS programming. In which case, if you use
int main(int argc, char* argv[]);
you should have the full path to your executable in argv[0] if argc is non-zero.
https://devkitpro.org/wiki/Homebrew_Menu might help.
Your program has no a priori knowledge of what sort of arguments main() should receive, and in your question, you're using a main function that receives no argument at all.
Established standard for C/C++ programming is that main() will receive an array of constant C strings (typically named argv for arguments values) and the number of valid entries in that array (typically named argc for count). If you replace your original code with
#include <fstream>
#include <string>
#include <iostream>
int main(int argc, char* argv[])
{
// Initialize the services
// ... more code follows
then you're able to tell whether you received argument by testing argc > 0 and you'll be able to get these arguments values with argv[i].
With homebrew development, it is unlikely that you can pass arguments such as --force or --directory=/boot as on typical command-line tools, but there is one thing that is still useful: the very first entry in argv is supposed to be a full path for the running program. so you're welcome to try
std::cerr << ((argc > 0) ? argv[0] : "<no arguments>");
and see what you get.

Is there an equivalent to the clone() syscall on macOS?

As the one in Linux, in which I can pass as parameters the function I want to execute in the child, the memory to be used, etc. I attach an example, in which I'm trying to start a child process that would execute the chld_func function using the memory allocated within stack_memory().
#include <iostream>
#include <sched.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>
// ...
int main(int argc, char** argv)
{
printf("Hello, World! (parent)\n");
clone(chld_func, stack_memory(), SIGCHLD, 0);
wait(nullptr);
return EXIT_SUCCESS;
}
Maybe I could try to do something similar using fork(), but I don't know where to begin.
Thanks in advance!
As stated here and here clone is specific to Linux.
The macOS system calls you can do include fork and vfork, so you can use one of then.
See also this answer for some reasoning about clone and fork and read man pages:
http://man7.org/linux/man-pages/man2/clone.2.html
http://man7.org/linux/man-pages/man2/vfork.2.html
http://man7.org/linux/man-pages/man2/fork.2.html

Catch dynamically pass arguments to test cases

I have a C++ project which is being tested using Catch.cpp:
I compile and run the following file to run my tests:
#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "test1.h"
#include "test2.h"
In the near future I'll want to run more complex tests, that require command line arguments.
In Other words, I would like to apply some logic to my tests runs, being able to run them from inside loops or conditions and pass variables to them.
I found this page: Supply your own main.
which seems like a good direction but i could not find a more detailed explanation.
Can this be done by catch? or maybe there is a better way to implement what i described?
What I managed to do is to write my own main, parse the command line and store the needed parameter (in my case an IP) in a global variable. Not the most beautiful code, but does the job:
#define CATCH_CONFIG_RUNNER
#include "catch.hpp"
std::string IP;
int main(int argc, char* const argv[])
{
Catch::Session session;
int returnCode = session.applyCommandLine(argc, argv, Catch::Session::OnUnusedOptions::Ignore);
if (returnCode != 0)
return returnCode;
for (auto token : session.unusedTokens()) {
printf("Token: %s\n", token.data.c_str());
IP = token.data;
}
return session.run();
}
I then run this as TestRunner.exe [test-case-tag] --MY_IP_HERE. Note that without the "--" in front of the parameter, they don't appear in the unusedTokens.

How can I enumerate all the file in a directory in vfs c or c++? [duplicate]

This question already has answers here:
How do you get a directory listing in C?
(9 answers)
Recursive function for listing all files in sub directories
(10 answers)
Closed 10 years ago.
I need to enumerate all the file in a folder and then navigate to the subfolder and do the same (recursion? sure).
Ideally the algorithm should work in the same way on linux & macos
DISCLAIMER: I have asked a similar question on POSIX: I'm now aware of VFS but I'm puzzled to use VFS for enumerate dir. Any suggestion ? Should I open a dir as file ? The only way is to use a library cross platform like qt ?
UPDATE: so no VFS way to work on directory? "*V*irtual *F*ile *S*ystem provides a single API for accessing various different file systems" but no way to enumerate directory.
The "readdir" etc solution will do the trick on any type of *NIX ? And on windows nothing better than the huge MingW lib? or partial impletion working on only some win like:
https://github.com/xbmc/xbmc/blob/master/tools/TexturePacker/Win32/dirent.c
The BOOST seem to be a really cool solution but it's complex and academic. thnks in any case
LAST UPDATE:
I have found some more doc and now everything is a lot more clear.
This question is a duplicate!
opendir() and readdir() are the solution to enumerate and browse directory on linux. As shown on my example is quite easy to map them on windows (but the incoerent windowz fs make everything strange) and ntfw() is even more useful.
VFS (the virtual file switch) is a kernel feature that resolves this problem by creating an abstraction layer for file-system operations. closed doc here: linux programming interface
thnks!
You want to look at nftw. Here's an example that just recursively prints the contents of a directory in C (Untested):
#define _XOPEN_SOURCE 500
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>
#include <ftw.h>
int
print( const char *path, const struct stat *s, int flag, struct FTW *f )
{
puts( path );
return 0;
}
int
main( int argc, char **argv )
{
while( *++argv ) {
if( nftw( *argv, print, 1024, FTW_DEPTH )) {
perror( *argv );
return EXIT_FAILURE;
}
}
return EXIT_SUCCESS;
}
Here is how I do it using Boost.Filesystem:
#include "boost/filesystem.hpp"
#include <iostream>
int main () {
for ( boost::filesystem::recursive_directory_iterator end, dir("./");
dir != end; ++dir ) {
// std::cout << *dir << "\n"; // full path
std::cout << dir->path().filename() << "\n"; // just last bit
}
}
Or, more succinctly:
#include "boost/filesystem.hpp"
#include <iostream>
#include <iterator>
#include <algorithm>
int main () {
std::copy(
boost::filesystem::recursive_directory_iterator("./"),
boost::filesystem::recursive_directory_iterator(),
std::ostream_iterator<boost::filesystem::directory_entry>(std::cout, "\n"));
}
Unix/Linux/Windows all have versions of readdir(). You can use it to get what the file system knows about files.

Create a directory if it doesn't exist

In my app I want to copy a file to the other hard disk so this is my code:
#include <windows.h>
using namespace std;
int main(int argc, char* argv[] )
{
string Input = "C:\\Emploi NAm.docx";
string CopiedFile = "Emploi NAm.docx";
string OutputFolder = "D:\\test";
CopyFile(Input.c_str(), string(OutputFolder+CopiedFile).c_str(), TRUE);
return 0;
}
so after executing this, it shows me in the D:HDD a file testEmploi NAm.docx
but I want him to create the test folder if it doesn't exist.
I want to do that without using the Boost library.
Use the WINAPI CreateDirectory() function to create a folder.
You can use this function without checking if the directory already exists as it will fail but GetLastError() will return ERROR_ALREADY_EXISTS:
if (CreateDirectory(OutputFolder.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// CopyFile(...)
}
else
{
// Failed to create directory.
}
The code for constructing the target file is incorrect:
string(OutputFolder+CopiedFile).c_str()
this would produce "D:\testEmploi Nam.docx": there is a missing path separator between the directory and the filename. Example fix:
string(OutputFolder+"\\"+CopiedFile).c_str()
#include <experimental/filesystem> // or #include <filesystem> for C++17 and up
namespace fs = std::experimental::filesystem;
if (!fs::is_directory("src") || !fs::exists("src")) { // Check if src folder exists
fs::create_directory("src"); // create src folder
}
Probably the easiest and most efficient way is to use boost and the boost::filesystem functions. This way you can build a directory simply and ensure that it is platform independent.
const char* path = _filePath.c_str();
boost::filesystem::path dir(path);
if(boost::filesystem::create_directory(dir))
{
std::cerr<< "Directory Created: "<<_filePath<<std::endl;
}
boost::filesystem::create_directory - documentation
Here is the simple way to create a folder.......
#include <windows.h>
#include <stdio.h>
void CreateFolder(const char * path)
{
if(!CreateDirectory(path ,NULL))
{
return;
}
}
CreateFolder("C:\\folder_name\\")
This above code works well for me.
_mkdir will also do the job.
_mkdir("D:\\test");
https://msdn.microsoft.com/en-us/library/2fkk4dzw.aspx
OpenCV Specific
Opencv supports filesystem, probably through its dependency Boost.
#include <opencv2/core/utils/filesystem.hpp>
cv::utils::fs::createDirectory(outputDir);
Since c++17, you can easily do this cross-platform with:
#include <filesystem>
int main() {
auto created_new_directory
= std::filesystem::create_directory("directory_name");
if (not created_new_directory) {
// Either creation failed or the directory was already present.
}
}
Note, that this version is very useful, if you need to know, whether the directory is actually newly created.
And I find the documentation on cppreference slightly difficult to understand on this point: If the directory is already present, this function returns false.
This means, you can more or less atomically create a new directory with this method.
Use CreateDirectory (char *DirName, SECURITY_ATTRIBUTES Attribs);
If the function succeeds it returns non-zero otherwise NULL.
You can use cstdlib
Although- http://www.cplusplus.com/articles/j3wTURfi/
#include <cstdlib>
const int dir= system("mkdir -p foo");
if (dir< 0)
{
return;
}
you can also check if the directory exists already by using
#include <dirent.h>
This works in GCC:
Taken from:
Creating a new directory in C
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
struct stat st = {0};
if (stat("/some/directory", &st) == -1) {
mkdir("/some/directory", 0700);
}