Passing Hard Arguments - c++

I am trying to hardcode arguments that are passed to the OpenCV Command Line Parser. In the object_detection file, I have added the code as such, so that I do not have to enter the file name via command-line:
Line 40-48:
void drawPred(int classId, float conf, int left, int top, int right, int bottom, Mat& frame);
void callback(int pos, void* userdata);
int main(int argc, char** argv)
{
// This line added below:
argv[1]="-input /home/Videos/test.mp4";
CommandLineParser parser(argc, argv, keys);
parser.about("Use this script to run object detection deep learning networks using OpenCV.");
if (argc == 1 || parser.has("help"))
OpenCV skips using this file, and switches to camera instead. How can I hardcode the arguments, before they are passed to the Command Line Parser ?

and what is argc? if it's 0, it'll be ignored, and pointer in argv will be NULL, so you get UB. Also, modifying system storage supplied to main is a bad idea, it's likely an UB because you don't have proper storage available to store string.
The only proper way about this is create intermediate variables. Note that array should be NULL-terminated.

The problem is that argc,argv are an old-style C mechanism. You can't simply insert a value in the C array char**. Instead, you must create a new array with one extra element. (Your existing code overwrites argv[1])
Now there's more unusual stuff. argv is an array with argc+1 elements, the last one of which is nullptr. Since you're inserting a new element, you must create an char*[argc+2]*, copy all argc elements, append the pointer to your string, and then terminate the new array with nullptr.
You can now pass the new array and argc+1 to CommandLineParser.

The goal of argc and is to pass argument t"-input /home/Videos/test.mp4");
argv[2] = NULL;hrough the main, if you are using a GNU / UNIX distribution, just pass argument like it:
argc = 2
argv[1] = strdup("-input /home/Videos/test.mp4");
argv[2] = NULL;
CommandLineParser parser(argc, argv, keys);
parser.about("Use this script to run object detection deep learning networks using OpenCV.");
if (argc == 1 || parser.has("help"))
or just use "normal" way and pass argument through our binary, like
./a.out "-input /home/Videos/test.mp4"

Related

C++ Emulating int main(int argc, char *argv[]) from node

Basically I am working on integrating an existing C++ file with our javascript / node using their NAPI, functionality. I have it working on a test C++ file so I know I have the setup working. However on the actual C++ file it is designed to run from the command line with argc and argv from the command line. Basically I just need to invoke the main method in C++ from inside of my other function, which means there is no command line. So I have to pass in values for argc and argv. argc is just an int, that is easy enough, but argc is a char ** type, which from my research looks like it is an array of character arrays aka strings?
This is my current code at the bottom of my c++ file
void Init(Env env, Object exports, Object module) {
exports.Set("main", Function::New(env, main(2,{"test","test2"})));
}
NODE_API_MODULE(addon, Init)
The argc value is working fine
I am trying to create a temporary / test value for argv to pass in but I am having an issue figuring out how to make an array of type char ** with my values.
argv is an array of pointers to strings (actually, NUL-terminated character arrays), where element 0 is the name of the program, elements 1 ... argc-1 are the program arguments, and element argc must be NULL1.
There's no array literal in C++, so you have to create explicitly an array variable to pass it to a function. Even worse, main is allowed to modify the passed arguments, so you cannot even build an array of string literals, as they are read only; thus, you have to explicitly allocate read/write space for each argument. A barebones solution can be to have single buffers for each argument and build the pointer array out of them:
char argv0[] = "test_program";
char argv1[] = "arg1";
char argv2[] = "arg2";
char *argv[] = {argv0, argv1, argv2, NULL};
main(3, argv);
A more flexible one (especially if you have to build your arguments dynamically) can be to use an std::vector<std::string>:
std::vector<std::string> args = { "test_program", "arg1", "arg2" };
// ... here you may add other arguments dynamically...
args.push_back("arg3"); // whatever
// build the pointers array
std::vector<char *> argv;
for(std::string &s: args) argv.push_back(&s[0]);
argv.push_back(NULL);
main(argv.size()-1, argv.data());
Now, coming to your code:
void Init(Env env, Object exports, Object module) {
exports.Set("main", Function::New(env, main(2,{"test","test2"})));
}
NODE_API_MODULE(addon, Init)
besides the fact that you cannot build argv to pass to main like that, you are trying to invoke main and pass its result as second argument to Function::New, while Function::New wants some callable type (e.g. a function pointer) to register as handler for the export named main! Copying from the Function::New documentation:
/// Callable must implement operator() accepting a const CallbackInfo&
/// and return either void or Value.
So, as a simple example, you could export your main as a parameterless JS function that returns nothing (undefined, I guess?) by registering a callback like this:
void MainCallback(const CallbackInfo& info) {
char argv0[] = "test_program";
char argv1[] = "arg1";
char argv2[] = "arg2";
char *argv[] = {argv0, argv1, argv2, NULL};
main(3, argv);
}
void Init(Env env, Object exports, Object module) {
exports.Set("main", Function::New(env, MainCallback));
}
NODE_API_MODULE(addon, Init)
Finally, as others said, technically in C++ main is somewhat magic - it's undefined behavior to invoke it from inside the program; in practice, on any platform that I know of that can also run node.js, main is a perfectly regular function that happens to be invoked by the C runtime at startup, so I don't think that this will cause you any problem.
Notes
So, you could say it's a NULL-terminated array of NUL-terminated character arrays. Notice that here NULL = null pointer; NUL = string terminator, i.e. '\0'.

where does the arguments of execl() passed to?

Under the context of system programming in UNIX environment, while using the programming language C++, in my understanding, execl() will pass in the path of the program it will run, and a vector. When that vector is being passed in, I understand it as being passed into the entry point, which is usually the main function. In a main function, I understand that my parameters can be written as:
int main(int argc, int* argv[]){ return 0; }
With the above context in mind, when arguments are being passed into the execl(), it seems to me that it doesn't get directly passed into the main function.
Is there a "processing" stage where arguments of execl() are changed to integer data type and an array?
At the same time, if there's any faults in my understanding, please, feel free to correct them.
The signature you give for the main function is incorrect. It should be:
int main(int argc, char *argv[]);
Or:
int main(void);
As for the arguments, the arguments passed to execl should match what the called program receives.
For example, if program A execs program B like this:
execl("/path/to/progB", "progB", "-a", "1", "-x", "hello", "command", (char *)NULL);
Then in program B, argc will be 6 and argv will essentially be:
{ "progB", "-a", "1", "-x", "hello", "command" }
Your understanding is wrong. From this documentation the argument list is always a number of null-terminated char* pointers (emphasis mine):
execl(<shell path>, arg0, file, arg1, ..., (char *)0);
where is an unspecified pathname for the sh utility, file is the >> process image file, and for execvp(), where arg0, arg1, and so on correspond to the values passed to execvp() in argv[0], argv[1], and so on.
The arguments represented by arg0,... are pointers to null-terminated character strings. These strings shall constitute the argument list available to the new process image. The list is terminated by a null pointer. The argument arg0 should point to a filename string that is associated with the process being started by one of the exec functions.
So that doesn't match what you're claiming:
int main(int argc, int* argv[]){ return 0; }
// ^^^^
main takes a char*argv[] argument (not int *argv[]) just like the usual core exec sysccall usually does. On Linux, the system call is execve (requires a char*[])and all other exec* functions are implemented in terms of that.
As for execl, the argument list is required to be NULL-terminated, which allows you to count the arguments and then copy them into an array that gets passed down to execve.
The musl libc library does that rather straightforwardly: https://git.musl-libc.org/cgit/musl/tree/src/process/execl.c

Alternative way to obtain argc and argv of a process

I'm looking for alternative ways to obtain the command line parameters argc and argv provided to a process without having direct access to the variables passed into main().
I want to make a class that is independent of main() so that argc and argv don't have to be passed explicitly to the code that uses them.
EDIT: Some clarification seems to be in order. I have this class.
class Application
{
int const argc_;
char const** const argv_;
public:
explicit Application(int, char const*[]);
};
Application::Application(int const argc, char const* argv[]) :
argc_(argc),
argv_(argv)
{
}
But I'd like a default constructor Application::Application(), with some (most probably) C code, that pulls argc and argv from somewhere.
On Linux, you can get this information from the process's proc file system, namely /proc/$$/cmdline:
int pid = getpid();
char fname[PATH_MAX];
char cmdline[ARG_MAX];
snprintf(fname, sizeof fname, "/proc/%d/cmdline", pid);
FILE *fp = fopen(fname);
fgets(cmdline, sizeof cmdline, fp);
// the arguments are in cmdline
The arguments to main are defined by the C runtime, and the only standard/portable way to obtain the command line arguments. Don't fight the system. :)
If all you want to do is to provide access to command line parameters in other parts of the program with your own API, there are many ways to do so. Just initialise your custom class using argv/argc in main and from that point onward you can ignore them and use your own API. The singleton pattern is great for this sort of thing.
To illustrate, one of the most popular C++ frameworks, Qt uses this mechanism:
int main(int argc, char* argv[])
{
QCoreApplication app(argc, argv);
std::cout << app.arguments().at(0) << std::endl;
return app.exec();
}
The arguments are captured by the app and copied into a QStringList. See QCoreApplication::arguments() for more details.
Similarly, Cocoa on the Mac has a special function which captures the command line arguments and makes them available to the framework:
#import <Cocoa/Cocoa.h>
int main(int argc, char *argv[])
{
return NSApplicationMain(argc, (const char **)argv);
}
The arguments are then available anywhere in the app using the NSProcessInfo.arguments property.
I notice in your updated question that your class directly stores a copy of argc/argv verbatim in its instance:
int const argc_;
char const** const argv_;
While this should be safe (the lifetime of the argv pointers should be valid for the full lifetime of the process), it is not very C++-like. Consider creating a vector of strings (std::vector<std::string>) as a container and copy the strings in. Then they can even be safely mutable (if you want!).
I want to make a class that is independent of main() so that argc and argv don't have to be passed explicitly to the code that uses them.
It is not clear why passing this info from main is somehow a bad thing that is to be avoided. This is just how the major frameworks do it.
I suggest you look at using a singleton to ensure there is only one instance of your Application class. The arguments can be passed in via main but no other code need know or care that this is where they came from.
And if you really want to hide the fact that main's arguments are being passed to your Application constructor, you can hide them with a macro.
To answer the question in part, concerning Windows, the command line can be obtained as the return of the GetCommandLine function, which is documented here, without explicit access to the arguments of the main function.
I totally agree with #gavinb and others. You really should use the arguments from main and store them or pass them where you need them. That's the only portable way.
However, for educational purposes only, the following works for me with clang on OS X and gcc on Linux:
#include <stdio.h>
__attribute__((constructor)) void stuff(int argc, char **argv)
{
for (int i=0; i<argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
}
int main(int argc, char **argv)
{
for (int i=0; i<argc; i++) {
printf("%s: argv[%d] = '%s'\n", __FUNCTION__, i, argv[i]);
}
return 0;
}
which will output:
$ gcc -std=c99 -o test test.c && ./test this will also get you the arguments
stuff: argv[0] = './test'
stuff: argv[1] = 'this'
stuff: argv[2] = 'will'
stuff: argv[3] = 'also'
stuff: argv[4] = 'get'
stuff: argv[5] = 'you'
stuff: argv[6] = 'the'
stuff: argv[7] = 'arguments'
main: argv[0] = './test'
main: argv[1] = 'this'
main: argv[2] = 'will'
main: argv[3] = 'also'
main: argv[4] = 'get'
main: argv[5] = 'you'
main: argv[6] = 'the'
main: argv[7] = 'arguments'
The reason is because the stuff function is marked as __attribute__((constructor)) which will run it when the current library is loaded by the dynamic linker. That means in the main program it will run even before main and have a similar environment. Therefore, you're able to get the arguments.
But let me repeat: This is for educational purposes only and shouldn't be used in any production code. It won't be portable and might break at any point in time without warning.
In Windows, if you need to get the arguments as wchar_t *, you can use CommandLineToArgvW():
int main()
{
LPWSTR *sz_arglist;
int n_args;
int result;
sz_arglist = CommandLineToArgvW(GetCommandLineW(), &n_args);
if (sz_arglist == NULL)
{
fprintf(stderr, _("CommandLineToArgvW() failed.\n"));
return 1;
}
else
{
result = wmain(n_args, sz_arglist);
}
LocalFree(sz_arglist);
return result;
}
This is very convenient when using MinGW because gcc does not recognize int _wmain(int, wchar_t *) as a valid main prototype.
Passing values doesn't constitute creating a dependency. Your class doesn't care about where those argc or argv values come out of - it just wants them passed. You may want to copy the values somewhere, though - there's no guarantee that they are not changed (the same applies to alternate methods like GetCommandLine).
Quite the opposite, in fact - you're creating a hidden dependency when you use something like GetCommandLine. Suddenly, instead of a simple "pass a value" semantics, you have "magically take their inputs from elsewhere" - combined with the aforementioned "the values can change at any time", this makes your code a lot more brittle, not to mention impossible to test. And parsing command line arguments is definitely one of the cases where automated testing is quite beneficial. It's a global variable vs. a method argument approach, if you will.
In C/C++, if main() doesn't export them, then there isn't a direct way to access them; however, that doesn't mean there isn't an indirect way. Many Posix-like systems use the elf format which passes argc, argv and envp on the stack in order to be initialized by _start() and passed into main() via normal calling convention. This is typically done in assembly (because there is still no portable way to get the stack pointer) and put in a "start file", typically with some variation of the name crt.o.
If you don't have access to main() so that you can just export the symbols, you probably aren't going to have access to _start(). So why then, do I even mention it? Because of that 3rd parameter envp. Since environ is a standard exported variable that does get set during _start() using envp. On many ELF systems, if you take the base address of environ and walk it backwards using negative array indices you can deduce the argc and argv parameters. The first one should be NULL followed by the last argv parameter until you get to the first. When the pointed to value cast to long is equal to the negative of your negative index, you have argc and the next (one more than your negative index) is argv/argv[0].
There are few common scenarios with functions requiring arguments of type int argc, char *argv[] known to me. One such obvious example is GLUT, where its initializing function is taking over these arguments from main(), which is kind of "nested main" scenario. This may or may not be your desired behavior. If not, as there is no convention for naming these arguments, as long as your function has its argument parser, and you know what you're doing, you can do whatever you need, hardcoded:
int foo = 1;
char * bar[1] = {" "};
or read from user input or generated otherwise, AFAIK.
int myFunc( int foo, char *bar[]){
//argument parser
{… …}
return 0;
}
Please, see this SO post.
The most portable way would be to use a global variable for storing the parameters. You can make this less ugly by using a Singleton (like your class in the question, but a singleton initialized by main) or similar a Service Locator which is basically just the same: Create an object in main, pass and store params statically, and have another or the same class access them.
Non-Portable ways are using GetCommandLine in Windows, accessing /proc/<pid>/cmdline or (/proc/self/cmdline), or using compiler-specific extensions like __attribute__((constructor))
Note that getting the command line in function via an equivalent of GetCommandLine is not possible (TLDR: Commandline is not passed to the Linux kernel, but already parsed and split by the invoking process (e.g. shell))
Here is a proper c++ way of doing so:
#include <iostream>
#include <fstream>
#include <unistd.h>
#include <sstream>
#include <vector>
using namespace std;
template <typename T>
string to_str(T value ){
ostringstream ss;
ss << value;
return ss.str();
}
int main(int argc, char** argv){
ifstream reader("/proc/" + to_str(getpid()) + "/cmdline", ios::binary);
vector<unsigned char> buffer(istreambuf_iterator<char>(reader), {});
int length = buffer.size();
for(int i = 0; i < length; i++){
if(!buffer[i]){
cout << endl;
}else{cout << buffer[i];}
}
return 0;
}
It sounds like what you want is a global variable; what you should do is just pass argc and argv as parameters.
An instructor had a challenge to use the gcc option nostartfiles and then try to access argc and argv. The nostartfiles option causes argc and argv to not be populated. This was my best solution for 64 bit Linux as it accesses argc and argv directly using the base pointer:
// Compile with gcc -nostartfiles -e main args.c -o args
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char *argv[]) // argc and argv are not available when compiled with -nostartfiles
{
register void *rbp asm ("rbp");
printf("argc is %ld\n", *(unsigned long *)(rbp + 8));
for(int count = 0 ; count < *(unsigned long *)(rbp + 8) ; count++)
{
printf("argv[%d] is %s\n", count, *(char **)(rbp + 16 + count * 8));
}
exit(0);
}

Get pointer to argv element Boost Program Options

I'm making the assumption that the array of strings passed into the main function as argv in void main( int argc, char* argv[] ) remains in scope for the duration of the application.
My question is therefore whether it is possible, using boost::program_options to get a pointer to the actual element in argv which represents a particular option.
That is, rather than allocating a std::string when parsing, it is possible to just get a pointer to the start of a string option value.

Convert std::vector<char*> to a c-style argument vector arv

I would like to prepare an old-school argument vector (argv) to use within the function
int execve(const char *filename, char
*const argv[],char *const envp[]);
I tried it with the stl::vector class:
std::string arguments = std::string("arg1");
std::vector<char*> argv;
char argument[128];
strcpy(argument, arguments.c_str());
argv.push_back(argument);
argv.push_back('\0'); // finish argv with zero
Finally I pass the vector to execve()
execve("bashscriptXY", &argv[0], NULL)
The code compiles but ArgV gets "ignored" by execve(). So it seems to be wrong, what I'm trying. How should I build an argV in a efficient way with c++?
I think the char[128] is redundant as the string local will have the same lifetime, also, try adding the program as argv[0] like rossoft said in his answer:
const std::string arguments("arg1");
std::vector<const char*> argv;
argv.push_back("bashscriptXY");
// The string will live as long as a locally allocated char*
argv.push_back(arguments.c_str());
argv.push_back(NULL); // finish argv with zero
execve(argv[0], &argv[0], NULL);
Beware that argv[0] is always the name of the command itself. So if you want to pass 1 parameter to a program, you have to fill two elements:
argv[0] should be "bashscriptXY" (or whatever you want...)
argv[1] = "your_argument"
A few issues:
the first element of the argv array is supposed to be the program name
the argv vector can take char const* types as execve() doesn't modify the args (though the process that gets invoked might - but those will be copies in its own address space). So you can push c_str() strings onto it. (See comments)
Try this out:
// unfortunately, execve() wants an array of `char*`, not
// am array of `char const*`.
// So we we need to make sure the string data is
// actually null terminated
inline
std::string& null_terminate( std::string& s)
{
s.append( 1, 0);
return s;
}
// ...
std::string program = std::string( "bashscriptXY");
std::string arg1("arg1");
std::string arg2("arg2");
null_terminate(program);
null_terminate(arg1);
null_terminate(arg2);
std::vector<char *> argv;
argv.push_back( &program[0]);
argv.push_back( &arg1[0]);
argv.push_back( &arg2[0]);
argv.push_back( NULL); // finish argv with zero
intptr_t result = execve( program.c_str(), &argv[0], NULL);
Unless the arguments are hard-coded, you'll have to do some dynamic memory allocation. First, create an array of character pointers for the number of arguments, then allocate memory for each argument and copy the data in.
This question is very similar and includes some code solutions.