【问题标题】:Parsing negative numbers with argp使用 argp 解析负数
【发布时间】:2015-12-02 18:32:53
【问题描述】:

是否可以将 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.

【问题讨论】:

  • 绝对有可能。解析 args 的责任是程序的。所以当你说它“只允许一个开关”或“......显示错误信息”时,你是在谈论你自己的程序以及它决定做什么。您需要发布您的代码或更具体。
  • 我正在考虑准备命令行参数以用“n”字符替换数字前面的“-”字符,然后在 ARGP_KEY_ARG 开关键块中进行适当处理。任何其他想法表示赞赏。
  • 以下可能有效:./a.out -v -- 33 -4 9

标签: c gnu command-line-arguments


【解决方案1】:

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

在调用 argp_parse() 之前将“-”字符替换为“n”并将 ARGP_KEY_ARG 开关键块中的“n”改回“-”也有效。源码如下:

#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;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-12-26
    • 2017-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-11-20
    • 1970-01-01
    • 2012-05-13
    相关资源
    最近更新 更多