Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C

Another argument parsing function for C and C++

4.72/5 (9 votes)
18 Oct 2013MIT5 min read 30.6K   365  
Argument parsing function identifies both optional and positional arguments.

Introduction

The get_arguments function was written to provide argument parsing code for multiple platforms. Also, unlike some other common argument parsing functions, the get_arguments code can be used under the terms of the MIT license.

The get_arguments function allows both short and long optional switches, and will work with the ASCII, UTF-8, and Unicode character sets.

Both single character and long optional argument switch names are allowed.

Optional arguments and positional arguments can be interspersed. The benefit of allowing
interspersed optional and positional arguments comes at the cost of requiring that an optional argument either does, or does not, take an additional parameter, but not both.


Also, optional argument names cannot start with a digit character, a period character, or a plus sign. This simplified parsing as a dash followed by one of these characters could also be the start of a numeric positional argument.

Background 

The C, and C++, 'main' function is passed two argument parameters. One is an integer parameter named 'argc', and the other is an array of pointers to the string arguments. String arguments are supplied by the user on the command line when the program is run. The first string argument is the path and file name of the program being run.

The get_arguments function in this code accepts optional parameters and positional parameters. Optional parameters are specified using switches that start with a dash character. A single dash character accepts a single character switch name. A double dash character takes an optional switch name that is more than one character. An optional switch name might by the complete optional parameter, or it might be followed by a required string.

Example:

ProgramName -x --name Fred --age 57

The example sets a program value when the '-x' switch is specified and sets the name Fred and an age value.

Positional arguments are not usually preceded by a dash character. A positional argument is only preceded by a dash character, which is a minus sign, if the parameter is a number. To avoid the parsing ambiguity, switch names never start with a digit character. Positional parameters always must be specified in a specified order.

Adding two positional arguments to the previous program line leads to:

ProgramName positional1 someotherargument -x --name Fred --age 57

The code

The get_arguments.h header file shows the definitions and documents the arguments and use of the 'get_arguments' function. File platform_os.h, which is included in get_arguments.h to define 'TCHAR', is shown further below.

The get_arguments function arguments are in the get_arguments header file and are repeated here.

        Argument Name
        Description
argcThe number of arguments.

        
argv


An array of pointers to argument strings.

argument_option_array_ptr 

A pointer to an array of ArgOption_t structures that specifies that attributes of each optional argument.

An example declaration for the array might be:

static const ArgOption_t argument_option_array[] =
{
    { 'x', NULL, OPTION_NO_PARAMETER, },
    { 'f', NULL, OPTION_REQUIRES_PARAMETER, },
    { 'b', "build", OPTION_REQUIRES_PARAMETER, },
    { 'h', "help", OPTION_NO_PARAMETER, },
    {   0, NULL, OPTION_NO_PARAMETER }
};

This would allow optional arguments of the form:

-x
-f <somestring>
-b <somestring>
--build <somestring>
-h
--help

A string must be supplied after the -s parameter because OPTION_REQUIRES_PARAMETER is used.

The final line must always be supplied as written to terminate the data.

Either a short argument name, a long argument name, or both must be specified. If only a long name is specified, the first field of the ArgOption_t structure must be set to an out-of-band integer value, which for either ASCII or Unicode character sets can be any value above 0x011FFFF.
arg_index_ptr A pointer to an 'int' value that is used to index into the argv[] array. The value pointed to by arg_index_ptr specifies either the index of a positional argument or the index of the required parameter for an optional argument that has the OPTION_REQUIRES_PARAMETER attribute. 

C++
/* ********************************************************************
 * Header File: get_arguments.h
 * Author: Bill Hallahan
 * Date: September 26, 2013
 *
 * Copyright (C) 2013 William Hallahan
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ******************************************************************* */

#ifndef GET_ARGUMENTS_H
#define GET_ARGUMENTS_H

#include "platform_os.h"

#ifdef __cplusplus
extern "C"
{
#endif /* __cplusplus */

/* The get_arguments function either returns an option
 * character or one of these values. */
typedef enum
{
    ARG_ERROR_INVALID_SWITCH = -2,
    ARG_ERROR_MISSING_SWITCH_ARGUMENT = -1,
    ARG_NO_MORE_ARGUMENTS = 0,
    ARG_POSITIONAL_ARGUMENT = 0x7FFFFFFF
} ArgOptionChar_t;

/* Used to set whether an option requires a parameter. */
typedef enum
{
    OPTION_NO_PARAMETER,
    OPTION_REQUIRES_PARAMETER
} ArgOptionParameter_t;

/* The option structure. 
 * Element c stores the short option character, i.e. "b" for "-b".
 *   name is the long option name string, "build" for "--build".
 * requires_params is set to one of the ArgOptionParameter_t
 *   enum values to indicate whether the option requires a parameter. */
typedef struct
{
    int c;
    TCHAR * long_name;
    ArgOptionParameter_t requires_param;
} ArgOption_t;

 /* ********************************************************************
 * Function: get_arguments
 *
 * Abstract:
 *
 *  The get_arguments function was written to provide argument
 *  parsing code for multiple platforms.  Also, the code can
 *  be used under the terms of the MIT license.
 *
 *  The get_arguments function allows both short and long
 *  optional switches, and will work with the ASCII, UTF-8, and
 *  Unicode character sets.
 *
 *  Both single character and long optional argument switch
 *  named are allowed.
 *
 *  Optional arguments and positional arguments can be interspersed.
 *
 *  The benefit of allowing interspersed optional and positional
 *  arguments comes at the cost of requiring that an optional argument
 *  either does, or does not, take an additional parameter, but not both.
 *
 *  Also, optional argument names cannot start with a digit
 *  character.  This simplified parsing as a dash followed by
 *  a digit character could also be the start of a numeric
 *  positional argument.
 *
 *  Input:
 *
 *    The first two arguments are passed into the 'main' function of
 *    a C or C++ console program.
 *
 *    argc                      - The number of arguments.
 *
 *    argv                      - An array of pointers to argument strings.
 *
 *    argument_option_array_ptr - A pointer to an array of ArgOption_t
 *                                structures that specifies that attributes
 *                                of each optional argument.
 *
 *                                An example declaration for the array might be:
 *
 *                                static const ArgOption_t argument_option_array[] =
 *                                {
 *                                    { 'x', NULL, OPTION_NO_PARAMETER, },
 *                                    { 'f', NULL, OPTION_REQUIRES_PARAMETER, },
 *                                    { 'b', "build", OPTION_REQUIRES_PARAMETER, },
 *                                    { 'h', "help", OPTION_NO_PARAMETER, },
 *                                    {   0, NULL, OPTION_NO_PARAMETER }
 *                                };
 *
 *                                This would allow optional arguments of the form:
 *
 *                                -x
 *                                -f <somestring>
 *                                -b <somestring>
 *                                --build <somestring>
 *                                -h
 *                                --help
 *
 *                                A string must be supplied after the -s parameter
 *                                because OPTION_REQUIRES_PARAMETER is used.
 *                                
 *                                The final line must always be supplied as written
 *                                to terminate the data.
 *
 *                                Either a short argument name, a long
 *                                argument name, or both must be specified.
 *                                If only a long name is specified, the first
 *                                field of the ArgOption_t structure must be
 *                                set to an out-of-band integer value, which
 *                                for either ASCII or Unicode character sets
 *                                can be any value above 0x011FFFF.
 *                                 
 *
 *    arg_index_ptr               A pointer to an 'int' value that is used
 *                                to index into the argv[] array. The value
 *                                pointed to by arg_index_ptr specifies either
 *                                the index of a positional argument or the
 *                                index of the required parameter for an
 *                                optional argument that has the
 *                                OPTION_REQUIRES_PARAMETER attribute.
 *
 *  Returns:
 *
 *    An integer value that is either the option character for an
 *    optional argument, which is the first field in OptionsArg_t
 *    structure that matches the optional argument passed on the
 *    command line, or, one of the following values.
 *
 *    ARG_POSITIONAL_ARGUMENT  - Specified that argument in the argv
 *                               array, indexed by the index value
 *                               pointed to by arg_index_ptr, is a
 *                               positional argument.
 *
 *    ARG_NO_MORE_ARGUMENTS    - Specifies that there are no more
 *                               arguments to parse.
 *
 *    ARG_ERROR_INVALID_SWITCH - Invalid switch specified on the command
 *                               line.
 *
 *    ARG_ERROR_MISSING_SWITCH_ARGUMENT - A dash character for an
 *                                        optional argument was found
 *                                        but is missing required
 *                                        characters following the dash.
 *
 *  Any returned character value, represented as an integer, and
 *  the value of ARG_POSITIONAL_ARGUMENT, are always greater than
 *  zero.  ARG_NO_MORE_ARGUMENTS equals zero, and the error return
 *  values are negative numbers, so parsing should be done until
 *  the return value of this function is not greater than
 *  ARG_NO_MORE_ARGUMENTS, or zero.
 *
 ******************************************************************* */

int get_arguments(int argc,
                  TCHAR *argv[],
                  const ArgOption_t * argument_option_array_ptr,
                  int * arg_index_ptr);

#ifdef __cplusplus
}
#endif /* __cplusplus */

#endif /* GET_ARGUMENTS_H */

File get_arguments.c is:

C++
/* ********************************************************************
 * Header File: get_arguments.c
 * Author: Bill Hallahan
 * Date: September 26, 2013
 *
 * Copyright (C) 2013 William Hallahan
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ******************************************************************* */

#include "get_arguments.h"

int get_arguments(int argc,
                  TCHAR *argv[],
                  const ArgOption_t * argument_option_array_ptr,
                  int * arg_index_ptr)
{
    int arg_length = 0;
    int option_param_type = OPTION_NO_PARAMETER;
    const ArgOption_t * arg_option_ptr = argument_option_array_ptr;
    TCHAR * argument_ptr = NULL;
    int option_character = ARG_NO_MORE_ARGUMENTS;

    /* Increment the index to point to the next argument.
     * On the first call to this function, this increment
     * skips the program name. */
    ++(*arg_index_ptr);

    /* Are there more arguments? */
    if (*arg_index_ptr < argc)
    {
        /* There are more arguments.  Get the current argument string
         * and the number of characters in the argument string. */
        argument_ptr = argv[*arg_index_ptr];
        arg_length = _tcslen(argument_ptr);

        /* Check for the dash character.  The dash character starts either
         * an optional argument or a number. */
        if (argument_ptr[0] == _T('-'))
        {
            /* Optional arguments always have at least one non-digit character
             * after the dash character. */
            if (arg_length > 1)
            {
                /* A dash followed by a digit, period, or a plus sign is not a
                 * valid switch name and is considered to be a negative number. */
                if ((_istdigit(argument_ptr[1]))
                    || (argument_ptr[1] == _T('.'))
                    || (argument_ptr[1] == _T('+')))
                {
                    option_character = ARG_POSITIONAL_ARGUMENT;
                }
                else
                {
                    /* This is an optional argument.  Long optional arguments
                     * start with two dash characters followed by at least one
                     * character.  Check for a second dash character. */
                    if ((arg_length > 2) && (argument_ptr[1] == _T('-')))
                    {
                        /* This is a long optional argument of the form "--name".
                         * Skip the second '_' character. */
                        argument_ptr += 2;

                        /* Search for the argument long name in the argument options array */
                        while (arg_option_ptr->c != _T('\0'))
                        {
                            if ((arg_option_ptr->long_name != NULL)
                                && (_tcscmp(arg_option_ptr->long_name, argument_ptr) == 0))
                            {
                                option_character = arg_option_ptr->c;
                                option_param_type = arg_option_ptr->requires_param;
                                break;
                            }

                            /* Point to the next ArgOption_t instance in the array. */
                            ++arg_option_ptr;
                        }
                    }
                    else
                    {
                        /* This is a short optional argument of the form "-n".
                         * Skip the '_' character. */
                        ++argument_ptr;

                        /* This is a short optional argument of the form "-n".
                         * Search for the argument character in the argument options array */
                        while (arg_option_ptr->c != _T('\0'))
                        {
                            if (argument_ptr[0] == arg_option_ptr->c)
                            {
                                option_character = arg_option_ptr->c;
                                option_param_type = arg_option_ptr->requires_param;
                                break;
                            }

                            /* Point to the next ArgOption_t instance in the array. */
                            ++arg_option_ptr;
                        }
                    }

                    /* Check to see if the argument option matched any ArgOption_t entry
                     * in the array pointed to by 'argument_option_array_ptr'. */
                    if (option_character != ARG_NO_MORE_ARGUMENTS)
                    {
                        /* An option switch was found.  Does the switch require an argument? */
                        if (option_param_type == OPTION_REQUIRES_PARAMETER)
                        {
                            /* Increment the index to point to the switch argument. */
                            ++(*arg_index_ptr);

                            if (*arg_index_ptr >= argc)
                            {
                                /* The option parameter is missing.  Return an error. */
                                --(*arg_index_ptr);
                                option_character = ARG_ERROR_MISSING_SWITCH_ARGUMENT;
                            }
                        }
                    }
                    else
                    {
                        /* No option matched.  Return an error. */
                        option_character = ARG_ERROR_INVALID_SWITCH;
                    }
                }        
            }
            /* A single dash character is not a valid argument. */
            else if (arg_length == 1)
            {
                option_character = ARG_ERROR_MISSING_SWITCH_ARGUMENT;
            }
            else
            {
                option_character = ARG_POSITIONAL_ARGUMENT;
            }
        }
        else
        {
            option_character = ARG_POSITIONAL_ARGUMENT;
        }
    }
    else
    {
        option_character = ARG_NO_MORE_ARGUMENTS;
    }

    return option_character;
}

The platform_os.h header file.

The platform_os.h header file is included by file get_arguments.h, and allows running the code on Windows and Linux. I tested on Linux a while ago, but have not tested recently, so the header file '#include's for the C library files might need tweaking. I will update this article when I test on Linux again. This works fine on Windows with either ASCII builds or Unicode builds.

C++
/* ********************************************************************
 * Header File: platform_os.h
 * Author: Bill Hallahan
 * Date: September 26, 2013
 *
 * Platform and operating system specific definitions.
 *
 * Copyright (C) 2013 William Hallahan
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so,
 * subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 *
 ******************************************************************* */

#ifndef PLATFORM_OS_H
#define PLATFORM_OS_H

#ifdef WIN32
#include <tchar.h>
#ifdef UNICODE
#include <wctype.h>
#else
#include <ctype.h>

#endif /* UNICODE */
#endif /* WIN32 */

#ifdef __linux__
typedef char TCHAR;

#define SET_STDOUT_MODE
#define _T(X) X
#define _tmain main
#define _tprintf printf
#define _istdigit isdigit
#define _tcstol strtol
#define _tcstod strtod
#endif /* __linux__ */

#define FALSE (0)
#define TRUE (1)

typedef int BOOL;

#endif /* PLATFORM_OS_H */

Why I wrote the get_arguments function

I found myself writing a lot of C and C++ console programs, and I realized that most of the time the parsing code was similar to other programs. To save time, I wrote a code generator in Python. I found other parsing functions encumbered by their license or their behavior wasn't what I wanted. In particular, I wanted to be able to intersperse optional and positional arguments. I also wanted code that ran on multiple platforms with multiple character sets.

Unlike the example in the get_argument.h header file, program ParseExample.c defines the options array using the _T() macro for both characters and strings to allow compiling with different character sets.

About program ParseExample.c

File ParseExample.c demonstrates one possible use of the 'get_arguments' function.

ParseExample.c was designed to have a single return point, which greatly aids debugging as only a single breakpoint need to be set the first time the program is debugged.

To avoid either excessive indenting or using a 'goto' keyword for errors, while still allowing a single return, ParseExample uses the following useful construct. A non-zero status value indicates an error. An error results in breaking out of the do-while statement, which because of the "while (FALSE);" at the end is not a loop. This is a very useful construct.

C++
do
{
    [some code here]

    if (status != 0)
    {
        break;
    }

    [More code here]

    if (status != 0)
    {
        break;
    }

    [Even more code here]

    if (status != 0)
    {
        break;
    }
}
while (FALSE);

[More code here]

Program ParseExample.c source code

C++
/* Program: ParseExample.c */

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#ifdef __linux__
#include <unistd.h>
#endif
#include "get_arguments.h"
#include "platform_os.h"

/* Define the option character values for optional arguments
 * that only have a long option name. */
typedef enum
{
    OPTINT0 = 1114112
} OptChar_t;

/* Structure type used for program arguments. */
typedef struct
{
    TCHAR * stringVar;
    int intVar;
    float floatVar;
    double doubleVar;
    TCHAR * optstringVar;
    int optIntVar;
    float optFloatVar;
    double optDoubleVar;
    BOOL optBoolVar;
    BOOL optAnotherBoolVar;
} ProgramArgument_T;

/* Forward declarations. */
int executeParseExample(ProgramArgument_T * program_args_ptr);
void displayUsage();

/* Start of main program. */
int _tmain(int argc, TCHAR* argv[])
{
    int status = 0;
    int arg_index = 0;
    int positional_arg_index = 0;
    int arg_result = 0;
    TCHAR * stop_ptr = NULL;

    ProgramArgument_T program_args;

    static const ArgOption_t argument_option_array[] =
    {
        { _T('s'), NULL, OPTION_REQUIRES_PARAMETER, },
        { _T('i'), NULL, OPTION_REQUIRES_PARAMETER, },
        { _T('f'), NULL, OPTION_REQUIRES_PARAMETER, },
        { _T('d'), NULL, OPTION_REQUIRES_PARAMETER, },
        { _T('b'), _T("build"), OPTION_NO_PARAMETER, },
        { OPTINT0, _T("another"), OPTION_NO_PARAMETER, },
        { _T('h'), _T("help"), OPTION_NO_PARAMETER },
        { 0, NULL, OPTION_NO_PARAMETER }
    };

    do
    {
        /* If there are no arguments supplied then display the command to get help. */
        if (argc < 2)
        {
            _tprintf(_T("Program ParseExample [version 1.1 TODO:]\n"));
            _tprintf(_T("Copyright (C) 2013 William Hallahan.\n\n"));
            _tprintf(_T("For help, enter:\n\n"));
            _tprintf(_T("    ParseExample -h\n\n"));
            break;
        }

        /* Initialize the program argument structure. */
        program_args.stringVar = _T("");
        program_args.intVar = 0;
        program_args.floatVar = 0.0F;
        program_args.doubleVar = 0.0;
        program_args.optstringVar = _T("");
        program_args.optIntVar = 0;
        program_args.optFloatVar = 0.0F;
        program_args.optDoubleVar = 0.0;
        program_args.optBoolVar = FALSE;
        program_args.optAnotherBoolVar = TRUE;

        /* Call the get_arguments function to populate the argument variables. */
        while ((status == 0)
            && ((arg_result = get_arguments(argc,
                                            argv,
                                            &argument_option_array[0],
                                            &arg_index)) > ARG_NO_MORE_ARGUMENTS))
        {
            if (arg_result != ARG_POSITIONAL_ARGUMENT)
            {
                /* Process an optional argument. */
                switch (arg_result)
                {
                case 's':
                    {
                        program_args.optstringVar = argv[arg_index];
                    }
                    break;

                case 'i':
                    {
                        program_args.optIntVar = _tcstol(argv[arg_index], &stop_ptr, 10);
                    if (_tcslen(stop_ptr) > 0)
                    {
                        _tprintf(_T("Error in argument %s.\n"), argv[arg_index]);
                        status = -1;
                    }
                    }
                    break;

                case 'f':
                    {
                        program_args.optFloatVar = (float)_tcstod(argv[arg_index], &stop_ptr);
                    if (_tcslen(stop_ptr) > 0)
                    {
                        _tprintf(_T("Error in argument %s.\n"), argv[arg_index]);
                        status = -1;
                    }
                    }
                    break;

                case 'd':
                    {
                        program_args.optDoubleVar = _tcstod(argv[arg_index], &stop_ptr);
                    if (_tcslen(stop_ptr) > 0)
                    {
                        _tprintf(_T("Error in argument %s.\n"), argv[arg_index]);
                        status = -1;
                    }
                    }
                    break;

                case 'b':
                    {
                        program_args.optBoolVar = TRUE;
                    }
                    break;

                case OPTINT0:
                    {
                        program_args.optAnotherBoolVar = FALSE;
                    }
                    break;

                case 'h':
                    {
                        displayUsage();
                        status = 1;
                    }
                    break;

                default:
                    {
                        /* It should be impossible to reach here. */
                        _tprintf(_T("Program error.  Contact support.\n"));
                        status = 1;
                    }
                    break;
                }
            }
            else
            {
                /* Process a positional argument. */
                switch (positional_arg_index)
                {
                case 0:
                    {
                        program_args.stringVar = argv[arg_index];
                    }
                    break;

                case 1:
                    {
                        program_args.intVar = _tcstol(argv[arg_index], &stop_ptr, 10);
                    if (_tcslen(stop_ptr) > 0)
                    {
                        _tprintf(_T("Error in argument %s.\n"), argv[arg_index]);
                        status = -1;
                    }
                    }
                    break;

                case 2:
                    {
                        program_args.floatVar = (float)_tcstod(argv[arg_index], &stop_ptr);
                    if (_tcslen(stop_ptr) > 0)
                    {
                        _tprintf(_T("Error in argument %s.\n"), argv[arg_index]);
                        status = -1;
                    }
                    }
                    break;

                case 3:
                    {
                        program_args.doubleVar = _tcstod(argv[arg_index], &stop_ptr);
                    if (_tcslen(stop_ptr) > 0)
                    {
                        _tprintf(_T("Error in argument %s.\n"), argv[arg_index]);
                        status = -1;
                    }
                    }
                    break;

                default:
                   {
                        _tprintf(_T("Too many positional arguments atarting at %s.\n"), argv[arg_index]);
                        status = -1;
                         break;
                   }
                }

                /* Increment the positional argument index. */
                ++positional_arg_index;
            }
        }

        /* Check for a command line error. */
        if (status != 0)
        {
            break;
        }
        else if (arg_result == ARG_ERROR_MISSING_SWITCH_ARGUMENT)
        {
            _tprintf(_T("Error - missing switch argument for switch %s.\n"), argv[arg_index]);
            status = -1;
            break;
        }
        else if (arg_result == ARG_ERROR_INVALID_SWITCH)
        {
            _tprintf(_T("Invalid switch argument %s.\n"), argv[arg_index]);
            status = -1;
            break;
        }
        /* Were the required number of positional arguments supplied? */
        else if (positional_arg_index < 4)
        {
            _tprintf(_T("Too few arguments.\n"));
            status = -1;
            break;
        }
        else
        {
            /* Process the input data. */
            status = executeParseExample(&program_args);
        }
    }
    while (FALSE);

    return status;
}

/* Function: executeParseExample */
int executeParseExample(ProgramArgument_T * program_args_ptr)
{
    /* Display the input parameters. */
    _tprintf(_T("TCHAR * stringVar = %s\n"), program_args_ptr->stringVar);
    _tprintf(_T("int intVar = %d\n"), program_args_ptr->intVar);
    _tprintf(_T("float floatVar = %f\n"), program_args_ptr->floatVar);
    _tprintf(_T("double doubleVar = %f\n"), program_args_ptr->doubleVar);
    _tprintf(_T("TCHAR * optstringVar = %s\n"), program_args_ptr->optstringVar);
    _tprintf(_T("int optIntVar = %d\n"), program_args_ptr->optIntVar);
    _tprintf(_T("float optFloatVar = %f\n"), program_args_ptr->optFloatVar);
    _tprintf(_T("double optDoubleVar = %f\n"), program_args_ptr->optDoubleVar);
    _tprintf(_T("BOOL optBoolVar = %d\n"), program_args_ptr->optBoolVar);
    _tprintf(_T("BOOL optAnotherBoolVar = %d\n"), program_args_ptr->optAnotherBoolVar);
    return 0;
}

/* Function: displayUsage */
void displayUsage()
{
    _tprintf(_T("\n"));
    _tprintf(_T("Program ParseExample\n"));
    _tprintf(_T("Copyright (c) 2013, William H.\n\n"));
    _tprintf(_T("This program demonstrates the use of the get_arguments function.\n\n"));
    _tprintf(_T("Usage:\n\n"));
    _tprintf(_T("    ParseExample <stringVar> <intVar> <floatVar> <doubleVar> [-s optstringVar] [-i optIntVar] [-f optFloatVar] [-d optDoubleVar] [-b, --build] [--another]\n\n"));
    _tprintf(_T("Positional arguments:\n\n"));
    _tprintf(_T("stringVar       String argument\n"));
    _tprintf(_T("intVar       Integer argument\n"));
    _tprintf(_T("floatVar       Floating point argument\n"));
    _tprintf(_T("doubleVar       Double precision floating point argument\n"));
    _tprintf(_T("\nOptional arguments:\n\n"));
    _tprintf(_T("-s optstringVar        String parameter optstringVar\n"));
    _tprintf(_T("-i optIntVar        Integer parameter optIntVar\n"));
    _tprintf(_T("-f optFloatVar        Floating point parameter optFloatVar\n"));
    _tprintf(_T("-d optDoubleVar        Double precision floating point parameter optDoubleVar TODO:\n"));
    _tprintf(_T("-b, --build        If specified, optBoolVar becomes TRUE.\n"));
    _tprintf(_T("--another        If specified, optAnotherBoolVar becomes FALSE.\n"));
    _tprintf(_T("-h, --help      Display program help.\n\n"));
}

History

Oct. 11, 2013 - Posted the first version of the code.

Oct. 11, 2013 - Updated article and code.

License

This article, along with any associated source code and files, is licensed under The MIT License