解析 C 中的命令行参数

我正在尝试编写一个程序,可以比较两个文件逐行,逐字,或字符的字符在 C。它必须能够读取命令行选项 -l-w-i--..。

  • 如果选项是 -l,它将逐行比较文件。
  • 如果选项是 -w,则逐字比较文件。
  • 如果该选项是 --,它会自动假设下一个参数是第一个文件名。
  • 如果选项是 -i,则以不区分大小写的方式对它们进行比较。
  • 默认值为逐字符比较文件。

只要 -w-l不是同时输入的,并且不多于或少于两个文件,输入选项的次数并不重要。

我甚至不知道从哪里开始解析命令行参数。

这就是我想出来的所有代码。我还没有完全检查错误,但是我是否以过于复杂的方式写东西?

/*
* Functions to compare files.
*/
int compare_line();
int compare_word();
int compare_char();
int case_insens();


/*
* Program to compare the information in two files and print message saying
* whether or not this was successful.
*/
int main(int argc, char* argv[])
{
/* Loop counter */
size_t i = 0;


/* Variables for functions */
int caseIns = 0;
int line = 0;
int word = 0;


/* File pointers */
FILE *fp1, *fp2;


/*
* Read through command-line arguments for options.
*/
for (i = 1; i < argc; i++)
{
printf("argv[%u] = %s\n", i, argv[i]);
if (argv[i][0] == '-')
{
if (argv[i][1] == 'i')
{
caseIns = 1;
}
if (argv[i][1] == 'l')
{
line = 1;
}
if (argv[i][1] == 'w')
{
word = 1;
}
if (argv[i][1] == '-')
{
fp1 = argv[i][2];
fp2 = argv[i][3];
}
else
{
printf("Invalid option.");
return 2;
}
}
else
{
fp1(argv[i]);
fp2(argv[i][1]);
}
}


/*
* Check that files can be opened.
*/
if(((fp1 = fopen(fp1, "rb")) ==  NULL) || ((fp2 = fopen(fp2, "rb")) == NULL))
{
perror("fopen()");
return 3;
}
else
{
if (caseIns == 1)
{
if(line == 1 && word == 1)
{
printf("That is invalid.");
return 2;
}
if(line == 1 && word == 0)
{
if(compare_line(case_insens(fp1, fp2)) == 0)
return 0;
}
if(line == 0 && word == 1)
{
if(compare_word(case_insens(fp1, fp2)) == 0)
return 0;
}
else
{
if(compare_char(case_insens(fp1,fp2)) == 0)
return 0;
}
}
else
{
if(line == 1 && word == 1)
{
printf("That is invalid.");
return 2;
}
if(line == 1 && word == 0)
{
if(compare_line(fp1, fp2) == 0)
return 0;
}
if(line == 0 && word == 1)
{
if(compare_word(fp1, fp2) == 0)
return 0;
}
else
{
if(compare_char(fp1, fp2) == 0)
return 0;
}
}
}
return 1;


if(((fp1 = fclose(fp1)) == NULL) || (((fp2 = fclose(fp2)) == NULL)))
{
perror("fclose()");
return 3;
}
else
{
fp1 = fclose(fp1);
fp2 = fclose(fp2);
}
}


/*
* Function to compare two files line-by-line.
*/
int compare_line(FILE *fp1, FILE *fp2)
{
/* Buffer variables to store the lines in the file */
char buff1 [LINESIZE];
char buff2 [LINESIZE];


/* Check that neither is the end of file */
while((!feof(fp1)) && (!feof(fp2)))
{
/* Go through files line by line */
fgets(buff1, LINESIZE, fp1);
fgets(buff2, LINESIZE, fp2);
}


/* Compare files line by line */
if(strcmp(buff1, buff2) == 0)
{
printf("Files are equal.\n");
return 0;
}
printf("Files are not equal.\n");
return 1;
}


/*
* Function to compare two files word-by-word.
*/
int compare_word(FILE *fp1, FILE *fp2)
{
/* File pointers */
FILE *fp1, *fp2;


/* Arrays to store words */
char fp1words[LINESIZE];
char fp2words[LINESIZE];


if(strtok(fp1, " ") == NULL || strtok(fp2, " ") == NULL)
{
printf("File is empty. Cannot compare.\n");
return 0;
}
else
{
fp1words = strtok(fp1, " ");
fp2words = strtok(fp2, " ");


if(fp1words == fp2words)
{
fputs(fp1words);
fputs(fp2words);
printf("Files are equal.\n");
return 0;
}
}
return 1;
}


/*
* Function to compare two files character by character.
*/
int compare_char(FILE *fp1,FILE *fp2)
{
/* Variables to store the characters from both files */
int c;
int d;


/* Buffer variables to store chars */
char buff1 [LINESIZE];
char buff2 [LINESIZE];


while(((c = fgetc(fp1))!= EOF) && (((d = fgetc(fp2))!=EOF)))
{
if(c == d)
{
if((fscanf(fp1, "%c", buff1)) == (fscanf(fp2, "%c", buff2)))
{
printf("Files have equivalent characters.\n");
return 1;
break;
}
}


}
return 0;
}


/*
* Function to compare two files in a case-insensitive manner.
*/
int case_insens(FILE *fp1, FILE *fp2, size_t n)
{
/* Pointers for files. */
FILE *fp1, *fp2;


/* Variable to go through files. */
size_t i = 0;


/* Arrays to store file information. */
char fp1store[LINESIZE];
char fp2store[LINESIZE];


while(!feof(fp1) && !feof(fp2))
{
for(i = 0; i < n; i++)
{
fscanf(fp1, "%s", fp1store);
fscanf(fp2, "%s", fp2store);


fp1store = tolower(fp1store);
fp2store = tolower(fp2store);


return 1;
}
}
return 0;
}
241635 次浏览
#include <stdio.h>


int main(int argc, char **argv)
{
size_t i;
size_t filename_i = -1;


for (i = 0; i < argc; i++)
{
char const *option =  argv[i];
if (option[0] == '-')
{
printf("I am a flagged option");
switch (option[1])
{
case 'a':
/*someting*/
break;
case 'b':
break;
case '-':
/* "--" -- the next argument will be a file.*/
filename_i = i;
i = i + 1;
break;
default:
printf("flag not recognised %s", option);
break;
}
}
else
{
printf("I am a positional argument");
}


/* At this point, if -- was specified, then filename_i contains the index
into argv that contains the filename. If -- was not specified, then filename_i will be -1*/
}
return 0;
}

使用 getopt(),或者 getopt_long()

int iflag = 0;
enum { WORD_MODE, LINE_MODE } op_mode = WORD_MODE;  // Default set
int opt;


while ((opt = getopt(argc, argv, "ilw") != -1)
{
switch (opt)
{
case 'i':
iflag = 1;
break;
case 'l':
op_mode = LINE_MODE;
break;
case 'w':
op_mode = WORD_MODE;
break;
default:
fprintf(stderr, "Usage: %s [-ilw] [file ...]\n", argv[0]);
exit(EXIT_FAILURE);
}
}


/* Process file names or stdin */
if (optind >= argc)
process(stdin, "(standard input)", op_mode);
else
{
int i;
for (i = optind; i < argc; i++)
{
FILE *fp = fopen(argv[i], "r");
if (fp == 0)
fprintf(stderr, "%s: failed to open %s (%d %s)\n",
argv[0], argv[i], errno, strerror(errno));
else
{
process(fp, argv[i], op_mode);
fclose(fp);
}
}
}

请注意,您需要确定包含哪些头(我将其设置为4个必需的头) ,而且我编写 op_mode类型的方式意味着函数 process()中存在问题——您无法访问下面的枚举。最好将枚举移到函数之外; 您甚至可以使 op_mode成为一个没有外部链接的文件范围变量(一种说 static的花哨方式) ,以避免将其传递给函数。这段代码不将 -作为标准输入的同义词处理,这是读者的另一个练习。请注意,getopt()会自动处理 --以标记您的选项的结束。

我没有通过编译器运行上面的任何版本的类型; 它可能有错误。


为了获得额外的学分,编写一个(库)函数:

int filter(int argc, char **argv, int idx, int (*function)(FILE *fp, const char *fn));

它封装了在 getopt()循环之后处理文件名选项的逻辑。它应该将 -作为标准输入处理。请注意,使用这个属性将表明 op_mode应该是一个静态文件范围变量。filter()函数接受 argcargvoptind和一个指向处理函数的指针。如果它能够打开函数的所有文件和所有调用,则返回0(EXIT _ SUCCESS) ,否则返回1(或 EXIT _ FAILURE)。使用这样的函数可以简化编写 Unix 风格的“过滤器”程序,这些程序可以读取命令行或标准输入中指定的文件。

用 C 语言解析命令行参数的教学模板。

C: > program Name-w —— fileOne.txt fileTwo.txt

BOOL argLine = FALSE;
BOOL argWord = FALSE;
BOOL argChar = FALSE;
char * fileName1 = NULL;
char * fileName2 = NULL;


int main(int argc, char * argv[]) {
int i;
printf("Argument count=%d\n",argc);
for (i = 0; i < argc; i++) {
printf("Argument %s\n",argv[i]);
if (strcmp(argv[i],"-l")==0) {
argLine = TRUE;
printf("    argLine=TRUE\n");
}
else if (strcmp(argv[i],"-w")==0) {
argWord = TRUE;
printf("    argWord=TRUE\n");
}
else if (strcmp(argv[i],"-c")==0) {
argChar = TRUE;
printf("    argChar=TRUE\n");
}
else if (strcmp(argv[i],"--")==0) {
if (i+1 <= argc) {
fileName1 = argv[++i];
printf("    fileName1=%s\n",fileName1);
}
if (i+1 <= argc) {
fileName2 = argv[++i];
printf("    fileName2=%s\n",fileName2);
}
}
}
return 0;
}

据我所知,如何在 C 语言中解析命令行参数的三种最流行的方法是:

  • 获取 (来自 POSIX C 库的 #include <unistd.h>) ,它可以解决 简单参数解析简单参数解析任务。如果您对 bash 比较熟悉,那么 bash 的 Getopt 内置是基于 GNU libc 中的 Getopt 的。
  • Argp (来自 GNU C Library 的 #include <argp.h>) ,它可以解决更多的 复杂的任务并处理诸如下面这样的事情:
    • -?--help帮助信息,包括 电邮地址
    • -V --version代表 版本资料
    • --usage呼叫 使用信息
  • 自己做 ,我不推荐给别人的程序这样做,因为有太多可能出错或质量低下的地方。忘记“——”而停止选项解析这一常见错误只是一个例子。

GNU C Library 文档中有一些很好的 Getopt 和 Argp 示例。

使用 接电话的示例

#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>


int main(int argc, char *argv[])
{
bool isCaseInsensitive = false;
int opt;
enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;


while ((opt = getopt(argc, argv, "ilw")) != -1) {
switch (opt) {
case 'i': isCaseInsensitive = true; break;
case 'l': mode = LINE_MODE; break;
case 'w': mode = WORD_MODE; break;
default:
fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
exit(EXIT_FAILURE);
}
}


// Now optind (declared extern int by <unistd.h>) is the index of the first non-option argument.
// If it is >= argc, there were no non-option arguments.


// ...
}

使用 Argp的示例

#include <argp.h>
#include <stdbool.h>


const char *argp_program_version = "programname programversion";
const char *argp_program_bug_address = "<your@email.address>";
static char doc[] = "Your program description.";
static char args_doc[] = "[FILENAME]...";
static struct argp_option options[] = {
{ "line", 'l', 0, 0, "Compare lines instead of characters."},
{ "word", 'w', 0, 0, "Compare words instead of characters."},
{ "nocase", 'i', 0, 0, "Compare case insensitive instead of case sensitive."},
{ 0 }
};


struct arguments {
enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode;
bool isCaseInsensitive;
};


static error_t parse_opt(int key, char *arg, struct argp_state *state) {
struct arguments *arguments = state->input;
switch (key) {
case 'l': arguments->mode = LINE_MODE; break;
case 'w': arguments->mode = WORD_MODE; break;
case 'i': arguments->isCaseInsensitive = true; break;
case ARGP_KEY_ARG: return 0;
default: return ARGP_ERR_UNKNOWN;
}
return 0;
}


static struct argp argp = { options, parse_opt, args_doc, doc, 0, 0, 0 };


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


arguments.mode = CHARACTER_MODE;
arguments.isCaseInsensitive = false;


argp_parse(&argp, argc, argv, 0, 0, &arguments);


// ...
}

例如 自己动手

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


int main(int argc, char *argv[])
{
bool isCaseInsensitive = false;
enum { CHARACTER_MODE, WORD_MODE, LINE_MODE } mode = CHARACTER_MODE;
size_t optind;
for (optind = 1; optind < argc && argv[optind][0] == '-'; optind++) {
switch (argv[optind][1]) {
case 'i': isCaseInsensitive = true; break;
case 'l': mode = LINE_MODE; break;
case 'w': mode = WORD_MODE; break;
default:
fprintf(stderr, "Usage: %s [-ilw] [file...]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
argv += optind;


// *argv points to the remaining non-option arguments.
// If *argv is NULL, there were no non-option arguments.


// ...
}

免责声明: 我是新的 Argp,示例可能包含错误。

    /*
Here's a rough one not relying on any libraries.
Example:
-wi | -iw //word case insensitive
-li | -il //line case insensitive
-- file  //specify the first filename (you could just get the files
as positional arguments in the else statement instead)
PS: don't mind the #define's, they're just pasting code :D
*/
#ifndef OPT_H
#define OPT_H


//specify option requires argument
#define require \
optarg = opt_pointer + 1; \
if (*optarg == '\0') \
{ \
if (++optind == argc) \
goto opt_err_arg; \
else \
optarg = argv[optind]; \
} \
opt_pointer = opt_null_terminator;


//start processing argv
#define opt \
int   optind                 = 1; \
char *opt_pointer            = argv[1]; \
char *optarg                 = NULL; \
char  opt_null_terminator[2] = {'\0','\0'}; \
if (0) \
{ \
opt_err_arg: \
fprintf(stderr,"option %c requires argument.\n",*opt_pointer); \
return 1; \
opt_err_opt: \
fprintf(stderr,"option %c is invalid.\n",*opt_pointer); \
return 1; \
} \
for (; optind < argc; opt_pointer = argv[++optind]) \
if (*opt_pointer++ == '-') \
{ \
for (;;++opt_pointer) \
switch (*opt_pointer) \
{


//stop processing argv
#define done \
default: \
if (*opt_pointer != '\0') \
goto opt_err_opt; \
else \
goto opt_next; \
break; \
} \
opt_next:; \
}
#endif //opt.h


#include <stdio.h>
#include "opt.h"
int
main (int argc, char **argv)
{
#define by_character 0
#define by_word      1
#define by_line      2
int cmp = by_character;
int case_insensitive = 0;
opt
case 'h':
puts ("HELP!");
break;
case 'v':
puts ("fileCMP Version 1.0");
break;
case 'i':
case_insensitive = 1;
break;
case 'w':
cmp = by_word;
break;
case 'l':
cmp = by_line;
break;
case '-':required
printf("first filename: %s\n", optarg);
break;
done
else printf ("Positional Argument %s\n", argv[optind]);
return 0;
}

我发现 Gengetopt非常有用——您可以用一个简单的配置文件指定所需的选项,然后它会生成一个。转交。H 对,只需包含并链接到应用程序即可。生成的代码使用 getopt _ long,似乎可以处理最常见的命令行参数类型,并且可以节省大量时间。

Gengetopt 输入文件可能是这样的:

version "0.1"
package "myApp"
purpose "Does something useful."


# Options
option "filename" f "Input filename" string required
option "verbose" v "Increase program verbosity" flag off
option "id" i "Data ID" int required
option "value" r "Data value" multiple(1-) int optional

生成代码很简单,只需要输出 cmdline.hcmdline.c:

$ gengetopt --input=myApp.cmdline --include-getopt

生成的代码很容易集成:

#include <stdio.h>
#include "cmdline.h"


int main(int argc, char ** argv) {
struct gengetopt_args_info ai;
if (cmdline_parser(argc, argv, &ai) != 0) {
exit(1);
}
printf("ai.filename_arg: %s\n", ai.filename_arg);
printf("ai.verbose_flag: %d\n", ai.verbose_flag);
printf("ai.id_arg: %d\n", ai.id_arg);
int i;
for (i = 0; i < ai.value_given; ++i) {
printf("ai.value_arg[%d]: %d\n", i, ai.value_arg[i]);
}
}

如果需要进行任何额外的检查(比如确保标志是相互排斥的) ,那么使用存储在 gengetopt_args_info结构中的数据可以很容易地完成这项工作。

你可以用詹姆斯 · 泰勒的 “选择”方案

下面是一篇讨人喜欢的文章,其中举了一些例子,说明这种方法比其他方法简单得多:

选择3.19审查和升级

有一个很棒的通用 C 库,LibUCW,它包含了简洁的 命令行选项解析配置文件加载

该库还提供了很好的文档,并包括一些其他有用的东西(快速 I/O、数据结构、分配器等) ,但是这可以单独使用。

示例 libUCW 选项解析器(来自库文档)

#include <ucw/lib.h>
#include <ucw/opt.h>


int english;
int sugar;
int verbose;
char *tea_name;


static struct opt_section options = {
OPT_ITEMS {
OPT_HELP("A simple tea boiling console."),
OPT_HELP("Usage: teapot [options] name-of-the-tea"),
OPT_HELP(""),
OPT_HELP("Options:"),
OPT_HELP_OPTION,
OPT_BOOL('e', "english-style", english, 0, "\tEnglish style (with milk)"),
OPT_INT('s', "sugar", sugar, OPT_REQUIRED_VALUE, "<spoons>\tAmount of sugar (in teaspoons)"),
OPT_INC('v', "verbose", verbose, 0, "\tVerbose (the more -v, the more verbose)"),
OPT_STRING(OPT_POSITIONAL(1), NULL, tea_name, OPT_REQUIRED, ""),
OPT_END
}
};


int main(int argc, char **argv)
{
opt_parse(&options, argv+1);
return 0;
}

如果可以的话,我还想自吹自擂一下,建议看看我写的一个选项解析库: 掉了

  • 它是一个 C 库(如果需要,可以使用 C + + 包装器)。
  • 这是轻量级的。
  • 它是可扩展的(自定义参数类型可以很容易地添加,并且与内置参数类型具有相同的基础)。
  • 它应该是非常可移植的(它是用标准 C 编写的) ,没有依赖关系(除了 C 标准库之外)。
  • 它有一个非常不受限制的许可证(zlib/libpng)。

它提供的一个特性是可以覆盖以前的选项,而其他许多软件都没有这个特性。例如,如果您有一个 shell 别名:

alias bar="foo --flag1 --flag2 --flag3"

你想使用 bar,但是禁用了 --flag1,它允许你做:

bar --flag1=0

我编写了一个小型库,用于解析类似于 POPT 的参数,这个库名为 XOpt,我在使用它时遇到了一些问题。它使用 GNU 风格的参数解析,并具有与 POPT 非常相似的接口。

我时不时地使用它,获得了巨大的成功,它几乎在任何地方都可以工作。

Docopt 有一个 C 实现,我认为它相当不错 不错:

从描述命令行选项的手册页标准化格式,docopt 推断并创建一个参数解析器。这是在 Python 中开始的; Python 版本实际上只是解析 docstring 并返回一个 dict。要在 C 中完成这项工作需要多做一些工作,但是可以很干净地使用,而且没有外部依赖关系。

好了,这就是长话短说的开始 中止解析 C 语言中的命令行..。

/**
* Helper function to parse the command line
* @param argc Argument Counter
* @param argv Argument Vector
* @param prog Program Instance Reference to fill with options
*/
bool parseCommandLine(int argc, char* argv[], DuplicateFileHardLinker* prog) {
bool pathAdded = false;


// Iterate over all arguments...
for (int i = 1; i<argc; i++) {


// Is argv a command line option?
if (argv[i][0] == '-' || argv[i][0] == '/') {


// ~~~~~~ Optionally Cut that part vvvvvvvvvvvvv for sake of simplicity ~~~~~~~
// Check for longer options
if (stricmp( &argv[i][1], "NoFileName") == 0  ||
strcmp( &argv[i][1], "q1"         ) == 0 ) {


boNoFileNameLog = true;


} else if (strcmp( &argv[i][1], "HowAreYou?") == 0 ) {
logInfo( "SECRET FOUND: Well - wow I'm glad ya ask me.");
} else {




// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Now here comes the main thing:
//


// Check for one-character options
while (char option = *++argv[i]) {


switch (option) {
case '?':
// Show program usage


logInfo(L"Options:");
logInfo(L"  /q\t>Quite mode");
logInfo(L"  /v\t>Verbose mode");
logInfo(L"  /d\t>Debug mode");
return false;


// Log options
case 'q':
setLogLevel(LOG_ERROR);
break;


case 'v':
setLogLevel(LOG_VERBOSE);
break;


case 'd':
setLogLevel(LOG_DEBUG);
break;


default:
logError(L"'%s' is an illegal command line option!"
"  Use /? to see valid options!", option);
return false;
} // switch one-char-option
} // while one-char-options
}  // else one vs longer options
} // if isArgAnOption


//
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^  So that's it! ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
// What follows now is are some useful extras...
//
else {


// The command line options seems to be a path...
WCHAR tmpPath[MAX_PATH_LENGTH];
mbstowcs(tmpPath, argv[i], sizeof(tmpPath));


// Check if the path is existing!
//...


prog->addPath(tmpPath); // Comment or remove to get a working example
pathAdded = true;
}
}


// Check for parameters
if (!pathAdded) {
logError("You need to specify at least one folder to process!\n"
"Use /? to see valid options!");
return false;
}


return true;
}




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


try {
// Parse the command line
if ( !parseCommandLine(argc, argv, prog) ) {
return 1;
}


// I know that sample is just to show how the nicely parse command-line arguments
// So Please excuse more nice useful C-glatter that follows now...


}
catch ( LPCWSTR err ) {
DWORD dwError = GetLastError();
if ( wcslen(err) > 0 ) {
if ( dwError != 0 ) {
logError(dwError, err);
}
else {
logError(err);
}
}
return 2;
}
}


#define LOG_ERROR                1
#define LOG_INFO                 0
#define LOG_VERBOSE             -1
#define LOG_DEBUG               -2


/** Logging level for the console output */
int logLevel = LOG_INFO;


void logError(LPCWSTR message, ...) {
va_list argp;
fwprintf(stderr, L"ERROR: ");
va_start(argp, message);
vfwprintf(stderr, message, argp);
va_end(argp);
fwprintf(stderr, L"\n");
}




void logInfo(LPCWSTR message, ...) {
if ( logLevel <= LOG_INFO ) {
va_list argp;
va_start(argp, message);
vwprintf(message, argp);
va_end(argp);
wprintf(L"\n");
}
}

注意,这个版本还支持组合参数: 所以不写 /h/s-> /hs也可以。

很抱歉我是第 N 个在这里发帖的人-但是我并不是真的满意所有的独立版本,我在这里看到。 图书馆的书不错。所以我更喜欢 LibUCW选项解析器,接电话超过一个自制的。

注意:

- > (++argv*)[0]

它更长,不那么神秘,但仍然神秘。

好吧,我们来分析一下:

  1. 在 argv-char 指针字段中访问 i-th 元素

  2. + + * ...-> 将把 argv 指针转发一个字符

  3. ... [0]-> 将跟随指针读取字符

  4. + + (...)-> 括号,所以我们将增加指针,而不是字符值本身。

在 C # 中,指针“死了”——指针万岁! !

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




int is_arg(int ac, char **argv, char *arg) {
if (ac < 2) {
return 0;
}
for(int x=1; x < ac; x++) {
if (0 == strcmp(argv[x], arg)) {
return x;  // return position of arg
}
}
return 0;  // arg not present
}




int main (int argc, char *argv[]) {
int z = 0;


if (argc < 2) {
printf("no args present, aborting.\n");
exit(1);
}


(z=is_arg(argc, argv, "bar")) ?     printf("TRUE %d\n", z) : printf("FALSE\n");
(z=is_arg(argc, argv, "one bar")) ? printf("TRUE %d\n", z) : printf("FALSE\n");
(z=is_arg(argc, argv, "foo")) ?     printf("TRUE %d\n", z) : printf("FALSE\n");


/* testing:


run: ./getopt two bar "one bar" foo
TRUE 2
TRUE 3
TRUE 4


run: ./getopt two bar one bar foo
TRUE 2
FALSE
TRUE 5


*/
return 0;
}

我编写了一个名为 Cmdparser的命令行解析器库

Https://github.com/xujinkai/cmdparser/

它经过了充分的测试,并支持嵌套的子命令。

问题的一个例子:

static cmdp_action_t callback(cmdp_process_param_st *params);
static bool g_line_by_line = false;
static bool g_word_by_word = false;
static bool g_case_insensitive = false;


static cmdp_command_st cmdp = {
.options = {
{'l', NULL, "line by line", CMDP_TYPE_BOOL, &g_line_by_line },
{'w', NULL, "word by word", CMDP_TYPE_BOOL, &g_word_by_word },
{'i', NULL, "case insensitive", CMDP_TYPE_BOOL, &g_case_insensitive },
{0},
},
.fn_process = callback,
};


int main(int argc, char **argv) {
return cmdp_run(argc - 1, argv + 1, &cmdp);
}


static cmdp_action_t callback(cmdp_process_param_st *params) {
if (g_line_by_line && g_word_by_word) {
return CMDP_ACT_FAIL | CMDP_ACT_SHOW_HELP;
}


// your code here...


return CMDP_ACT_OVER;
}