使用argp解析负数

时间:2015-11-29 23:57:50

标签: c command-line-arguments gnu command-line-parsing

是否可以将argp配置为将-1,-4,-99等解释为负数参数而不是开关?我的C程序目前只允许一个开关(-v)。如果我将程序-4作为命令行参数传递,则argp会显示错误消息

  

无效选项 - ' 4'

示例代码:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <argp.h>

static const char *argpErrors[] = { "OK.", \
                      /* 01 */ "Too few arguments provided", \
                      /* 02 */ "Too many argument provided", \
                      /* 03 */ "Argument 1 must be an integer.", \
                      /* 04 */ "Argument 2 must be an integer.", \
                      /* 05 */ "Argument 3 must be an integer.", \
                      /* 06 */ "Unable to parse command line arguments." };

static struct argp_option options[] = {
    // name, key, argname, flags, doc, group
    {"verbose", 'v', 0, 0, "Produce verbose output"},
    { 0 }
};

struct arguments
{
    int argCount;
    bool verbose;
    int num[3];
};

bool isInteger(char *str)
{
    bool digitFound = false;
    int i;
    int chars = (int)strlen((const char *)str);
    for (i = 0; i < chars; ++i)
    {
        if ((i == 0) && (str[0] == '-'))
        {
            continue;
        }
        if (isdigit(str[i]))
        {
            digitFound = true;
            continue;
        }
        return false;
    }
    return digitFound;
}

void reportArgpError(bool verbose, struct argp_state *state, int errorNumber)
{
    if (verbose)
    {
        argp_failure(state, 1, 0, argpErrors[errorNumber]);
    }
    else
    {
        printf("%d\n", errorNumber);
        exit(-1);
    }
}

static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
    struct arguments *arguments = state->input;
    switch (key)
    {
        case 'v':
            arguments->verbose = true;
            break;
        case ARGP_KEY_NO_ARGS:
            reportArgpError(arguments->verbose, state, 1);
            break;
        case ARGP_KEY_ARG:
            arguments->argCount++;
            if (arguments->argCount > 3)
            {
                reportArgpError(arguments->verbose, state, 2);
            }
            else
            {
                if (isInteger(arg))
                {                
                    arguments->num[arguments->argCount - 1] = atoi(arg);
                }
                else
                {
                    reportArgpError(arguments->verbose, state, 2 + arguments->argCount);
                }
            }
            break;
        case ARGP_KEY_END:
            if (arguments->argCount < 3)
            {
                reportArgpError(arguments->verbose, state, 1);
            }
            else if (arguments->argCount > 3)
            {
                reportArgpError(arguments->verbose, state, 2);
            }
            break;
        default:
            break;
    }

    return 0;
}

static char args_doc[] = "num1 num2 num3";
static char doc[] = "Example for StackOverflow";
static struct argp argp = { options, parse_opt, args_doc, doc };

int main(int argc, char *argv[])
{
    struct arguments arguments;
    arguments.argCount = 0;
    arguments.verbose = false;
    argp_parse (&argp, argc, argv, 0, 0, &arguments);
    if (arguments.verbose)
    {
        puts("Success");
        printf("num1 = %d\n", arguments.num[0]);
        printf("num2 = %d\n", arguments.num[1]);
        printf("num3 = %d\n", arguments.num[2]);
    }
    else
    {
        printf("0 %d %d %d\n", arguments.num[0], arguments.num[1], arguments.num[2]);
    }

    return 0;
}

示例命令:

./a.out -v 33 66 99

响应:

Success
num1 = 33
num2 = 66
num3 = 99

示例命令:

./a.out -v 33 -4 9

响应:

./a.out: invalid option -- '4'
Try `a.out --help' or `a.out --usage' for more information.

1 个答案:

答案 0 :(得分:1)

./a.out -v -- 33 -4 9工作了。谢谢nwellnhof。

更换&#39; - &#39;带有&#39; n&#39;的字符在调用argp_parse()并更改&#39; n&#39;之前回到&#39; - &#39;在ARGP_KEY_ARG切换键块中也有效。源代码如下:

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <argp.h>

static const char *argpErrors[] = { "OK.", \
                      /* 01 */ "Too few arguments provided", \
                      /* 02 */ "Too many argument provided", \
                      /* 03 */ "Argument 1 must be an integer.", \
                      /* 04 */ "Argument 2 must be an integer.", \
                      /* 05 */ "Argument 3 must be an integer.", \
                      /* 06 */ "Unable to parse command line arguments." };

static struct argp_option options[] = {
    // name, key, argname, flags, doc, group
    {"verbose", 'v', 0, 0, "Produce verbose output"},
    { 0 }
};

struct arguments
{
    int argCount;
    bool verbose;
    int num[3];
};

bool isInteger(char *str)
{
    bool digitFound = false;
    int i;
    int chars = (int)strlen((const char *)str);
    for (i = 0; i < chars; ++i)
    {
        if ((i == 0) && (str[0] == '-'))
        {
            continue;
        }
        if (isdigit(str[i]))
        {
            digitFound = true;
            continue;
        }
        return false;
    }
    return digitFound;
}

void reportArgpError(bool verbose, struct argp_state *state, int errorNumber)
{
    if (verbose)
    {
        argp_failure(state, 1, 0, argpErrors[errorNumber]);
    }
    else
    {
        printf("%d\n", errorNumber);
        exit(-1);
    }
}

void replaceIntegerPrefixChar(char *str, char originalChar, char newChar)
{
    int len = (int)strlen(str);
    if (len > 1)
    {
        if ((str[0] == originalChar) && (isInteger(str + 1)))
        {
            str[0] = newChar;
        }
    }

    return;
}

static error_t parse_opt(int key, char *arg, struct argp_state *state)
{
    struct arguments *arguments = state->input;
    switch (key)
    {
        case 'v':
            arguments->verbose = true;
            break;
        case ARGP_KEY_NO_ARGS:
            reportArgpError(arguments->verbose, state, 1);
            break;
        case ARGP_KEY_ARG:
            arguments->argCount++;
            if (arguments->argCount > 3)
            {
                reportArgpError(arguments->verbose, state, 2);
            }
            else
            {
                replaceIntegerPrefixChar(arg, 'n', '-');
                if (isInteger(arg))
                {                
                    arguments->num[arguments->argCount - 1] = atoi(arg);
                }
                else
                {
                    reportArgpError(arguments->verbose, state, 2 + arguments->argCount);
                }
            }
            break;
        case ARGP_KEY_END:
            if (arguments->argCount < 3)
            {
                reportArgpError(arguments->verbose, state, 1);
            }
            else if (arguments->argCount > 3)
            {
                reportArgpError(arguments->verbose, state, 2);
            }
            break;
        default:
            //reportArgpError(arguments->verbose, state, false, 13);
            break;
    }

    return 0;
}

static char args_doc[] = "num1 num2 num3";
static char doc[] = "Example for StackOverflow";
static struct argp argp = { options, parse_opt, args_doc, doc };

int main(int argc, char *argv[])
{
    struct arguments arguments;
    arguments.argCount = 0;
    arguments.verbose = false;

    int i;
    for (i = 0; i < argc; ++i)
    {
        replaceIntegerPrefixChar(argv[i], '-', 'n');
    }

    argp_parse (&argp, argc, argv, 0, 0, &arguments);
    if (arguments.verbose)
    {
        puts("Success");
        printf("num1 = %d\n", arguments.num[0]);
        printf("num2 = %d\n", arguments.num[1]);
        printf("num3 = %d\n", arguments.num[2]);
    }
    else
    {
        printf("0 %d %d %d\n", arguments.num[0], arguments.num[1], arguments.num[2]);
    }

    return 0;
}