Search code examples
cargv

Referencing global variables that are passed in using argv[]


I have some global variables of type int defined, and I want them to be matched with command line arguments to avoid endless chains of if statements with strcmp. For example, if I have defined the global variable myvar, and the user types myvar as a command line argument, I want to be able to reference myvar and perform operations on it using argv[]. Can this be done?

Editing my question just to make it a little more clear:

Currently, I'm having to do this:

int* A;
int* B;
int* C;

int set(void)
{
    if (strcmp((gargv[2]), "A") == 0)
    {
        *A = atoi(gargv[3]);
        return *A;
    }

    else if (strcmp((gargv[2]), "B") == 0)
    {
        *B = atoi(gargv[3]);
        return *B;
    }

    else if (strcmp((gargv[2]), "C") == 0)
    {
        *C = atoi(gargv[3]);
        return *C;
    }
    else 
    {
        errx(EX_USAGE, "Invalid");
    }
}


int main (int argc, char** argv) 
{
    gargv = argv;

    void* mem_chunk = calloc(5, sizeof(int));

    A = &mem_chunk[1];
    B = &mem_chunk[2];
    C = &mem_chunk[3];

    if (strcmp(argv[1], "set") == 0)
    {
        set();
    }
}

But it would be way less cumbersome to just do something like this, where I can set argv[2] to argv[3], referencing the global variables A, B, or C:

int* A;
int* B;
int* C;

int set(void)
{
    gargv[2] = gargv[3];
    // example, if A and 10 given by user then set A = 10 and return
}

int main (int argc, char** argv) 
{
    gargv = argv;

    void* mem_chunk = calloc(5, sizeof(int));

    A = &mem_chunk[1];
    B = &mem_chunk[2];
    C = &mem_chunk[3];

    if (strcmp(argv[1], "set") == 0)
    {
        set();
    }
}

Solution

  • Your question is pretty vague. Of course you can set a global variable based on the command line arguments passed, you do that by first examining/parsing argv setting all your configuration variables.

    This is in fact the typical structure of a command line program, the arguments are parsed first and later in the program, you only use configuration values and flags that were set during parsing.

    It's not entirely clear, but I assume you also look for tools to simplify parsing command line arguments. Well, there are many. On *nix systems, there's typically getopt() in the standard library (it's specified in POSIX). Note this manpage also describes getopt_long(), a GNU extension only available with GNUs C library (glibc).

    If getopt() is to simple for what you need or you want to use it on systems like windows, have a look at an old and well-known library for command line parsing: popt. You will probably find popt implementations for nearly any system with google.

    Then there's always the possibility to once write your own and reuse it yourself. I have my own because I needed a command line interface that's statefully parsed, like a scripting language -- just to give you an idea.


    Your question gives me the idea that with a commandline like that:

    > yourprogram foo=nanana bar=frobnicate
    

    you would like to set the variables foo and bar in your program. This is not the typical command line interface using switches with optional arguments and positional arguments, so getopt() will not give you exactly that. But it's quite easy to write a parser for that, as this little demo shows:

    #include <stdio.h>
    
    // configuration for the parser:
    struct argvVar
    {
        const char *name;    // the name of the variable to look for
        const char **value;  // the address of the variable to set the value
    };
    
    void parseArgvVars(int argc, char **argv, const struct argvVar *vars)
    {
        // loop over argv:
        for (int i = 1; i < argc; ++i)
        {
            // loop over configuration items:
            const struct argvVar *var = vars;
            while (var->name)
            {
                // compare variable name with current argument:
                const char *vname = var->name;
                const char *arg = argv[i];
                while (*arg && *vname)
                {
                    // when different, try the next configured variable:
                    if (*arg != *vname) goto nextVar;
                    ++arg;
                    ++vname;
                }
                if (*arg == '=')
                {
                    // when matching and the following sign is an equals sign,
                    // assign to the variable:
                    *var->value = arg + 1;
                }
    nextVar:
                ++var;
            }
        }
    }
    
    int main(int argc, char **argv)
    {
        const char *foo = 0;
        const char *bar = 0;
        const char *baz = 0;
    
        // list of variables we want to assign from argv values:
        const struct argvVar vars[] = {
            {"foo", &foo},
            {"bar", &bar},
            {"baz", &baz},
            {0, 0} // end of list
        };
    
        parseArgvVars(argc, argv, vars);
    
        if (foo) printf("foo: %s\n", foo);
        if (bar) printf("bar: %s\n", bar);
        if (baz) printf("baz: %s\n", baz);
    
        return 0;
    }
    

    Try to understand the usage of a configuration structure and the generic nature of the parsing function, so you can learn how to solve a problem once and reuse the code often.