From ThirdMartini

I never much liked the way getopt/getopt_long worked. It forces you to do everything in one giant loop, and add sometimes confusing logic when dealing with multilevel arguments. In many cases multilevel arguments can simplify the command line of a tool you are working on. Say for instance you want to have the tool be able to do 2 different things and each of those actions require unique parameters.

This article and code samples show another and ,in my opinion, simpler approach to dealing with command line parameter parsing.

[edit] Code

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define ASSERT assert

typedef struct{
   char *key;
   char *value;
}ArgTableEntry;

ArgTableEntry *argTable;

int argsParse(int argc, char *argv[])
{
    unsigned optCount = 0;
    unsigned argIndex;

    argTable = (ArgTableEntry*) calloc(argc+1,sizeof(ArgTableEntry));
    if( !argTable )
        return -1;

    for(argIndex=0; argIndex<argc;argIndex++){
        if( strstr(argv[argIndex],"--") == argv[argIndex] ){
            char *pKey   = argv[argIndex]+2;
            char *pValue = index(argv[argIndex],'=');
            if( pValue ){
                pValue[0] = '\0';
                pValue++;
                argTable[optCount].value = pValue;
            }
            argTable[optCount].key = pKey;
            optCount++;
        }
    }
   
    argTable[optCount].key = NULL;
    return 0;
}

int argsGetOptValue(const char * optName, void *value, char * format)
{
    int index;
    for( index=0; argTable[index].key != NULL; index++ ){
        if( strcasecmp(optName,argTable[index].key) == 0 ){
            if( argTable[index].value ){
                if( sscanf(argTable[index].value,format,value) == 1 ){
                return 0;
                }
            }
            return -1;
        }
    }
    return -1;
} 

int argsGetOptValueRequired(const char * optName, void *value, char * format)
{
    if( argsGetOptValue(optName,value,format) != 0 ){
        printf("Missing required argument: --%s\n",optName);
        exit(-1);
    }
    return 0;
} 

int argsHasArg(const char * arg)
{
    int index;
    for( index=0; argTable[index].key != NULL; index++ ){
        if( strcasecmp(arg,argTable[index].key) == 0 ){
            return 1;
        }
    } 
    return 0;
}

int main( int argc, char *argv[] )
{
    argsParse(argc,argv);

    if( argsHasArg("foo") ){
        unsigned arg1;
        unsigned arg2 = 0;

        /** Must have arg1 */
        argsGetOptValueRequired("foo_arg_one",&arg1,"%u");
        /** arg 2 is optional */
        argsGetOptValue("foo_arg_two",&arg2,"%u");
    }else if( argsHasArg("bar" ) ){
        unsigned arg1;
        unsigned arg2 = 0;

        /** Must have arg1 */
        argsGetOptValueRequired("bar_arg_one",&arg1,"%u");
        /** arg 2 is optional */
        argsGetOptValue("bar_arg_two",&arg2,"%u");
    }
    return 0;
}
Personal tools