diff options
-rw-r--r-- | libsimple-arg.c | 212 | ||||
-rw-r--r-- | libsimple-arg.h | 10 |
2 files changed, 217 insertions, 5 deletions
diff --git a/libsimple-arg.c b/libsimple-arg.c index a802c55..95581bf 100644 --- a/libsimple-arg.c +++ b/libsimple-arg.c @@ -88,6 +88,50 @@ } while (0) +#define LONG_WITHOUT_ARG(LONG_FLAG)\ + do {\ + assert(nparsed < sizeof(parsed) / sizeof(*parsed));\ + assert(FLAG() == LONG_FLAG[1]);\ + assert(!strcmp(LFLAG(), LONG_FLAG));\ + parsed[nparsed].short_used = 0;\ + parsed[nparsed].long_used = 1;\ + parsed[nparsed].have_arg = 0;\ + parsed[nparsed].short_flag[0] = '\0';\ + parsed[nparsed].short_flag[1] = '\0';\ + parsed[nparsed].short_flag[2] = '\0';\ + stpcpy(parsed[nparsed].long_flag, LONG_FLAG);\ + parsed[nparsed].argument[0] = '\0';\ + nparsed += 1;\ + } while (0) + + +#define LONG_WITH_ARG(LONG_FLAG)\ + do {\ + char *arg__;\ + assert(nparsed < sizeof(parsed) / sizeof(*parsed));\ + assert(FLAG() == LONG_FLAG[1]);\ + assert(!strcmp(LFLAG(), LONG_FLAG) || !strncmp(LFLAG(), LONG_FLAG"=", sizeof(LONG_FLAG"=")));\ + parsed[nparsed].short_used = 0;\ + parsed[nparsed].long_used = 1;\ + parsed[nparsed].have_arg = 1;\ + parsed[nparsed].short_flag[0] = '\0';\ + parsed[nparsed].short_flag[1] = '\0';\ + parsed[nparsed].short_flag[2] = '\0';\ + stpcpy(parsed[nparsed].long_flag, LONG_FLAG);\ + assert(strlen(ARG()) < sizeof(parsed[nparsed].argument));\ + assert((arg__ = ARG()));\ + assert(arg__ == ARGNULL());\ + stpcpy(parsed[nparsed].argument, ARG());\ + nparsed += 1;\ + } while (0) + + +#define LONG_WITH_MISSING_ARG(LONG_FLAG)\ + do {\ + assert_unreached();\ + } while (0) + + #define ASSERT_ENTRY(SHORT_FLAG, LONG_FLAG, ARGUMENT)\ do {\ const char *volatile short_flag__ = (SHORT_FLAG);\ @@ -363,6 +407,102 @@ stop: } +static int +parser7(int argc, char *argv[]) +{ + PARSER_BEGIN; + ARGBEGIN { + case '-': + if (TESTLONG("--alpha", 0)) + LONG_WITHOUT_ARG("--alpha"); + else if (TESTLONG("--alpha=", 0)) + LONG_WITHOUT_ARG("--alpha="); + else if (TESTLONG("--beta", 1)) + LONG_WITH_ARG("--beta"); + else if (TESTLONG("--gamma=", 1)) + LONG_WITH_ARG("--gamma"); + else if (TESTLONG("--gamma", 0)) + LONG_WITHOUT_ARG("--gamma"); + else if (TESTLONG("--missing", 1)) + LONG_WITH_MISSING_ARG("--missing"); + else + usage(); + break; + default: + usage(); + } ARGALT('+') { + case '+': + if (TESTLONG("++alpha", 0)) + LONG_WITHOUT_ARG("++alpha"); + else if (TESTLONG("++alpha=", 0)) + LONG_WITHOUT_ARG("++alpha="); + else if (TESTLONG("++beta", 1)) + LONG_WITH_ARG("++beta"); + else if (TESTLONG("++gamma=", 1)) + LONG_WITH_ARG("++gamma"); + else if (TESTLONG("++gamma", 0)) + LONG_WITHOUT_ARG("++gamma"); + else if (TESTLONG("++missing", 1)) + LONG_WITH_MISSING_ARG("++missing"); + else + usage(); + break; + default: + usage(); + } ARGEND; + PARSER_END; +} + + +static int +parser8(int argc, char *argv[]) +{ + PARSER_BEGIN; + ARGBEGIN { + case 'a': SHORT_WITHOUT_ARG("-a"); break; + case 'A': SHORT_WITHOUT_ARG("-A"); break; + case 'b': SHORT_WITH_ARG("-b"); break; + case 'g': SHORT_WITH_ARG("-g"); break; + case 'G': SHORT_WITHOUT_ARG("-G"); break; + case 'm': SHORT_WITH_MISSING_ARG("-m"); break; + case '-': + ARGMAPLONG(((struct longopt []){ + {"--alpha", 'a', 0}, + {"--alpha=", 'A', 0}, + {"--beta", 'b', 1}, + {"--gamma=", 'g', 1}, + {"--gamma", 'G', 0}, + {"--missing", 'm', 1}, + {NULL, '\0', 0}, + })); + /* fall through */ + default: + usage(); + } ARGALT('+') { + case 'a': SHORT_WITHOUT_ARG("+a"); break; + case 'A': SHORT_WITHOUT_ARG("+A"); break; + case 'b': SHORT_WITH_ARG("+b"); break; + case 'g': SHORT_WITH_ARG("+g"); break; + case 'G': SHORT_WITHOUT_ARG("+G"); break; + case 'm': SHORT_WITH_MISSING_ARG("+m"); break; + case '+': + ARGMAPLONG(((struct longopt []){ + {"++alpha", 'a', 0}, + {"++alpha=", 'A', 0}, + {"++beta", 'b', 1}, + {"++gamma=", 'g', 1}, + {"++gamma", 'G', 0}, + {"++missing", 'm', 1}, + {NULL, '\0', 0}, + })); + /* fall through */ + default: + usage(); + } ARGEND; + PARSER_END; +} + + int main(void) { @@ -484,6 +624,78 @@ main(void) ASSERT_END(); } + assert(apply(parser7, "", "--alpha", "++alpha", "--alpha=", "++alpha=", "--missing") == -1); + ASSERT_ENTRY(NULL, "--alpha", NULL); + ASSERT_ENTRY(NULL, "++alpha", NULL); + ASSERT_ENTRY(NULL, "--alpha=", NULL); + ASSERT_ENTRY(NULL, "++alpha=", NULL); + ASSERT_END(); + + assert(apply(parser7, "", "++alpha", "--alpha", "++alpha=", "--alpha=", "++missing") == -1); + ASSERT_ENTRY(NULL, "++alpha", NULL); + ASSERT_ENTRY(NULL, "--alpha", NULL); + ASSERT_ENTRY(NULL, "++alpha=", NULL); + ASSERT_ENTRY(NULL, "--alpha=", NULL); + ASSERT_END(); + + assert(apply(parser7, "", "--beta", "abc", "--beta=xyz", "--betax") == -1); + ASSERT_ENTRY(NULL, "--beta", "abc"); + ASSERT_ENTRY(NULL, "--beta", "xyz"); + ASSERT_END(); + + assert(apply(parser7, "", "++beta", "abc", "++beta=xyz", "++betax") == -1); + ASSERT_ENTRY(NULL, "++beta", "abc"); + ASSERT_ENTRY(NULL, "++beta", "xyz"); + ASSERT_END(); + + assert(apply(parser7, "", "--gamma=123", "--gamma=", "--gamma", "789") == 1); + ASSERT_ENTRY(NULL, "--gamma", "123"); + ASSERT_ENTRY(NULL, "--gamma", ""); + ASSERT_ENTRY(NULL, "--gamma", NULL); + ASSERT_END(); + + assert(apply(parser7, "", "++gamma=123", "++gamma=", "++gamma", "789") == 1); + ASSERT_ENTRY(NULL, "++gamma", "123"); + ASSERT_ENTRY(NULL, "++gamma", ""); + ASSERT_ENTRY(NULL, "++gamma", NULL); + ASSERT_END(); + + assert(apply(parser8, "", "--alpha", "++alpha", "--alpha=", "++alpha=", "--missing") == -1); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_ENTRY("+a", NULL, NULL); + ASSERT_ENTRY("-A", NULL, NULL); + ASSERT_ENTRY("+A", NULL, NULL); + ASSERT_END(); + + assert(apply(parser8, "", "++alpha", "--alpha", "++alpha=", "--alpha=", "++missing") == -1); + ASSERT_ENTRY("+a", NULL, NULL); + ASSERT_ENTRY("-a", NULL, NULL); + ASSERT_ENTRY("+A", NULL, NULL); + ASSERT_ENTRY("-A", NULL, NULL); + ASSERT_END(); + + assert(apply(parser8, "", "--beta", "abc", "--beta=xyz", "--betax") == -1); + ASSERT_ENTRY("-b", NULL, "abc"); + ASSERT_ENTRY("-b", NULL, "xyz"); + ASSERT_END(); + + assert(apply(parser8, "", "++beta", "abc", "++beta=xyz", "++betax") == -1); + ASSERT_ENTRY("+b", NULL, "abc"); + ASSERT_ENTRY("+b", NULL, "xyz"); + ASSERT_END(); + + assert(apply(parser8, "", "--gamma=123", "--gamma=", "--gamma", "789") == 1); + ASSERT_ENTRY("-g", NULL, "123"); + ASSERT_ENTRY("-g", NULL, ""); + ASSERT_ENTRY("-G", NULL, NULL); + ASSERT_END(); + + assert(apply(parser8, "", "++gamma=123", "++gamma=", "++gamma", "789") == 1); + ASSERT_ENTRY("+g", NULL, "123"); + ASSERT_ENTRY("+g", NULL, ""); + ASSERT_ENTRY("+G", NULL, NULL); + ASSERT_END(); + argv0_1 = "[1]"; assert_exit(usage1()); assert(exit_status == 1); diff --git a/libsimple-arg.h b/libsimple-arg.h index 0ba316a..1f4291c 100644 --- a/libsimple-arg.h +++ b/libsimple-arg.h @@ -147,7 +147,7 @@ struct longopt { * @param LONGOPTS:struct longopt * The options, list shall end * with `NULL` as `.long_flag` */ -#define ARGMAPLONG(LONGOPTS)/* TODO test */\ +#define ARGMAPLONG(LONGOPTS)\ for (i_ = 0; (LONGOPTS)[i_].long_flag; i_++) {\ if (TESTLONG((LONGOPTS)[i_].long_flag, (LONGOPTS)[i_].with_arg)) {\ flag_ = (LONGOPTS)[i_].short_flag;\ @@ -338,7 +338,7 @@ struct longopt { * @param WARG:int Whether the option takes an argument, * should not have side-effects */ -#define TESTLONG(FLG, WARG)/* TODO test */\ +#define TESTLONG(FLG, WARG)\ ((WARG)\ ? ((!strncmp(lflag_, (FLG), (n_ = strlen(FLG), n_ -= ((FLG)[n_ - !!n_] == '='))) && lflag_[n_] == '=')\ ? (lflag_[n_] = '\0',\ @@ -393,7 +393,7 @@ struct longopt { * * This macro also defines `char *argv0` * - * @param SYNOPSIS Description of the command line argument syntax + * @param SYNOPSIS:const char * Description of the command line argument syntax */ #define USAGE(SYNOPSIS)\ NUSAGE(1, SYNOPSIS) @@ -409,8 +409,8 @@ struct longopt { * * This macro also defines `char *argv0` * - * @param SYNOPSIS Description of the command line argument syntax - * @parma STATUS The exit value for the process + * @param SYNOPSIS:const char * Description of the command line argument syntax + * @parma STATUS:int The exit value for the process */ #if defined(__GNUC__) || defined(__clang__) # define NUSAGE(STATUS, SYNOPSIS)\ |