Find Argc and Argv from a Library

Find argc and argv from a library

This response in your second link contains working source code which worked fine for me (Gnu/Linux elf-based system), including during LD_PRELOAD.

The code is very short; it consists of a function:

int foo(int argc, char **argv, char **env) {
// Do something with argc, argv (and env, if desired)
}

and a pointer to that function in the .init_array section:

__attribute__((section(".init_array"))) static void *foo_constructor = &foo;

Putting that into a shared library and then LD_PRELOADing the shared library certainly triggered the call to foo when I tried it, and it was clearly called with the argc and argv which would later be passed to main (and also the value of environ).

Argc and argv for external program calling C shared library

The cmd_args module only parses verbose, quiet, output and max-memory arguments. Assuming only output is relevant for you, you could set the values with PySys_SetArgv just after Py_Initialize().

char **argv = {"", "-o", "path/to/output/file"};
PySys_SetArgv(3, argv);

Parse string into argv/argc

If glib solution is overkill for your case you may consider coding one yourself.

Then you can:

  • scan the string and count how many arguments there are (and you get your argc)
  • allocate an array of char * (for your argv)
  • rescan the string, assign the pointers in the allocated array and replace spaces with '\0' (if you can't modify the string containing the arguments, you should duplicate it).
  • don't forget to free what you have allocated!

The diagram below should clarify (hopefully):

             aa bbb ccc "dd d" ee         <- original string

aa0bbb0ccc00dd d00ee0 <- transformed string
| | | | |
argv[0] __/ / / / /
argv[1] ____/ / / /
argv[2] _______/ / /
argv[3] ___________/ /
argv[4] ________________/

A possible API could be:

    char **parseargs(char *arguments, int *argc);
void freeparsedargs(char **argv);

You will need additional considerations to implement freeparsedargs() safely.

If your string is very long and you don't want to scan twice you may consider alteranatives like allocating more elements for the argv arrays (and reallocating if needed).

EDIT: Proposed solution (desn't handle quoted argument).

    #include <stdio.h>

static int setargs(char *args, char **argv)
{
int count = 0;

while (isspace(*args)) ++args;
while (*args) {
if (argv) argv[count] = args;
while (*args && !isspace(*args)) ++args;
if (argv && *args) *args++ = '\0';
while (isspace(*args)) ++args;
count++;
}
return count;
}

char **parsedargs(char *args, int *argc)
{
char **argv = NULL;
int argn = 0;

if (args && *args
&& (args = strdup(args))
&& (argn = setargs(args,NULL))
&& (argv = malloc((argn+1) * sizeof(char *)))) {
*argv++ = args;
argn = setargs(args,argv);
}

if (args && !argv) free(args);

*argc = argn;
return argv;
}

void freeparsedargs(char **argv)
{
if (argv) {
free(argv[-1]);
free(argv-1);
}
}

int main(int argc, char *argv[])
{
int i;
char **av;
int ac;
char *as = NULL;

if (argc > 1) as = argv[1];

av = parsedargs(as,&ac);
printf("== %d\n",ac);
for (i = 0; i < ac; i++)
printf("[%s]\n",av[i]);

freeparsedargs(av);
exit(0);
}

Parsing Command Line Arguments in C++?

Boost.Program_options should do the trick



Related Topics



Leave a reply



Submit