mirror of
https://github.com/morgan9e/systemd
synced 2026-04-14 00:14:32 +09:00
musl: introduce wrappers for getopt() and getopt_long()
musl's getopt_long() behaves something different in handling optional arguments: ``` $ journalctl _PID=1 _COMM=systemd --since 19:19:01 -n all --follow Failed to add match 'all': Invalid argument ``` This introduces getopt_long_fix() that reorders the passed arguments to make getopt_long() provided by musl works as what we expect. Also, musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string found. Let's always use getopt_long().
This commit is contained in:
committed by
Zbigniew Jędrzejewski-Szmek
parent
26b2085d54
commit
53f5aa3fd2
29
src/include/musl/getopt.h
Normal file
29
src/include/musl/getopt.h
Normal file
@@ -0,0 +1,29 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/* getopt() is provided both in getopt.h and unistd.h. Hence, we need to tentatively undefine it. */
|
||||
#undef getopt
|
||||
|
||||
#include_next <getopt.h>
|
||||
|
||||
/* musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string
|
||||
* found. Let's always use getopt_long(). */
|
||||
int getopt_fix(int argc, char * const *argv, const char *optstring);
|
||||
#define getopt(argc, argv, optstring) getopt_fix(argc, argv, optstring)
|
||||
|
||||
/* musl's getopt_long() behaves something different in handling optional arguments.
|
||||
* ========
|
||||
* $ journalctl _PID=1 _COMM=systemd --since 19:19:01 -n all --follow
|
||||
* Failed to add match 'all': Invalid argument
|
||||
* ========
|
||||
* Here, we introduce getopt_long_fix() that reorders the passed arguments to make getopt_long() provided by
|
||||
* musl works as what we expect. */
|
||||
int getopt_long_fix(
|
||||
int argc,
|
||||
char * const *argv,
|
||||
const char *optstring,
|
||||
const struct option *longopts,
|
||||
int *longindex);
|
||||
|
||||
#define getopt_long(argc, argv, optstring, longopts, longindex) \
|
||||
getopt_long_fix(argc, argv, optstring, longopts, longindex)
|
||||
12
src/include/musl/unistd.h
Normal file
12
src/include/musl/unistd.h
Normal file
@@ -0,0 +1,12 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
#pragma once
|
||||
|
||||
/* getopt() is provided both in getopt.h and unistd.h. Hence, we need to tentatively undefine it. */
|
||||
#undef getopt
|
||||
|
||||
#include_next <unistd.h>
|
||||
|
||||
/* musl's getopt() always behaves POSIXLY_CORRECT mode, and stops parsing arguments when a non-option string
|
||||
* found. Let's always use getopt_long(). */
|
||||
int getopt_fix(int argc, char * const *argv, const char *optstring);
|
||||
#define getopt(argc, argv, optstring) getopt_fix(argc, argv, optstring)
|
||||
100
src/libc/musl/getopt.c
Normal file
100
src/libc/musl/getopt.c
Normal file
@@ -0,0 +1,100 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
static int first_non_opt = 0, last_non_opt = 0;
|
||||
static bool non_opt_found = false, dash_dash = false;
|
||||
|
||||
static void shift(char * const *argv, int start, int end) {
|
||||
char **av = (char**) argv;
|
||||
char *saved = av[end];
|
||||
|
||||
for (int i = end; i > start; i--)
|
||||
av[i] = av[i - 1];
|
||||
|
||||
av[start] = saved;
|
||||
}
|
||||
|
||||
static void exchange(int argc, char * const *argv) {
|
||||
/* input:
|
||||
*
|
||||
* first_non_opt last_non_opt optind
|
||||
* | | |
|
||||
* v v v
|
||||
* aaaaa bbbbb ccccc --prev-opt prev-opt-arg ddddd --next-opt
|
||||
*
|
||||
* output:
|
||||
* first_non_opt last_non_opt optind
|
||||
* | | |
|
||||
* v v v
|
||||
* --prev-opt prev-opt-arg aaaaa bbbbb ccccc ddddd --next-opt
|
||||
*/
|
||||
|
||||
/* First, move previous arguments. */
|
||||
int c = optind - 1 - last_non_opt;
|
||||
if (c > 0) {
|
||||
for (int i = 0; i < c; i++)
|
||||
shift(argv, first_non_opt, optind - 1);
|
||||
first_non_opt += c;
|
||||
last_non_opt += c;
|
||||
}
|
||||
|
||||
/* Then, skip entries that do not start with '-'. */
|
||||
while (optind < argc && (argv[optind][0] != '-' || argv[optind][1] == '\0')) {
|
||||
if (!non_opt_found) {
|
||||
first_non_opt = optind;
|
||||
non_opt_found = true;
|
||||
}
|
||||
last_non_opt = optind;
|
||||
optind++;
|
||||
}
|
||||
}
|
||||
|
||||
int getopt_long_fix(
|
||||
int argc,
|
||||
char * const *argv,
|
||||
const char *optstring,
|
||||
const struct option *longopts,
|
||||
int *longindex) {
|
||||
|
||||
int r;
|
||||
|
||||
if (optind == 0 || first_non_opt == 0 || last_non_opt == 0) {
|
||||
/* initialize musl's internal variables. */
|
||||
(void) (getopt_long)(/* argc= */ -1, /* argv= */ NULL, /* optstring= */ NULL, /* longopts= */ NULL, /* longindex= */ NULL);
|
||||
first_non_opt = last_non_opt = 1;
|
||||
non_opt_found = dash_dash = false;
|
||||
}
|
||||
|
||||
if (first_non_opt >= argc || last_non_opt >= argc || optind > argc || dash_dash)
|
||||
return -1;
|
||||
|
||||
/* Do not shuffle arguments when optstring starts with '+' or '-'. */
|
||||
if (!optstring || optstring[0] == '+' || optstring[0] == '-')
|
||||
return (getopt_long)(argc, argv, optstring, longopts, longindex);
|
||||
|
||||
exchange(argc, argv);
|
||||
|
||||
if (optind < argc && strcmp(argv[optind], "--") == 0) {
|
||||
if (first_non_opt < optind)
|
||||
shift(argv, first_non_opt, optind);
|
||||
first_non_opt++;
|
||||
optind++;
|
||||
dash_dash = true;
|
||||
if (non_opt_found)
|
||||
optind = first_non_opt;
|
||||
return -1;
|
||||
}
|
||||
|
||||
r = (getopt_long)(argc, argv, optstring, longopts, longindex);
|
||||
if (r < 0 && non_opt_found)
|
||||
optind = first_non_opt;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int getopt_fix(int argc, char * const *argv, const char *optstring) {
|
||||
return getopt_long_fix(argc, argv, optstring, /* longopts= */ NULL, /* longindex= */ NULL);
|
||||
}
|
||||
@@ -5,6 +5,7 @@ if get_option('libc') != 'musl'
|
||||
endif
|
||||
|
||||
libc_wrapper_sources += files(
|
||||
'getopt.c',
|
||||
'printf.c',
|
||||
'stdio.c',
|
||||
'stdlib.c',
|
||||
|
||||
@@ -111,6 +111,7 @@ simple_tests += files(
|
||||
'test-format-util.c',
|
||||
'test-fs-util.c',
|
||||
'test-fstab-util.c',
|
||||
'test-getopt.c',
|
||||
'test-glob-util.c',
|
||||
'test-gpt.c',
|
||||
'test-gunicode.c',
|
||||
|
||||
516
src/test/test-getopt.c
Normal file
516
src/test/test-getopt.c
Normal file
@@ -0,0 +1,516 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
|
||||
#include <getopt.h>
|
||||
|
||||
#include "strv.h"
|
||||
#include "tests.h"
|
||||
|
||||
typedef struct Entry {
|
||||
int opt;
|
||||
const char *argument;
|
||||
const char *nextarg;
|
||||
} Entry;
|
||||
|
||||
static void test_getopt_long_one(
|
||||
char **argv,
|
||||
const char *optstring,
|
||||
const struct option *longopts,
|
||||
const Entry *entries,
|
||||
char **remaining) {
|
||||
|
||||
_cleanup_free_ char *joined = strv_join(argv, ", ");
|
||||
log_debug("/* %s(%s) */", __func__, joined);
|
||||
|
||||
_cleanup_free_ char *saved_argv0 = NULL;
|
||||
ASSERT_NOT_NULL(saved_argv0 = strdup(argv[0]));
|
||||
|
||||
int c, argc = strv_length(argv);
|
||||
size_t i = 0, n_entries = 0;
|
||||
|
||||
for (const Entry *e = entries; e && e->opt != 0; e++)
|
||||
n_entries++;
|
||||
|
||||
optind = 0;
|
||||
while ((c = getopt_long(argc, argv, optstring, longopts, NULL)) >= 0) {
|
||||
if (c < 0x100)
|
||||
log_debug("%c: %s", c, strna(optarg));
|
||||
else
|
||||
log_debug("0x%x: %s", (unsigned) c, strna(optarg));
|
||||
|
||||
ASSERT_LT(i, n_entries);
|
||||
ASSERT_EQ(c, entries[i].opt);
|
||||
ASSERT_STREQ(optarg, entries[i].argument);
|
||||
if (entries[i].nextarg)
|
||||
ASSERT_STREQ(argv[optind], entries[i].nextarg);
|
||||
i++;
|
||||
}
|
||||
|
||||
ASSERT_EQ(i, n_entries);
|
||||
ASSERT_LE(optind, argc);
|
||||
ASSERT_EQ(argc - optind, (int) strv_length(remaining));
|
||||
for (int j = optind; j < argc; j++)
|
||||
ASSERT_STREQ(argv[j], remaining[j - optind]);
|
||||
ASSERT_STREQ(argv[0], saved_argv0);
|
||||
}
|
||||
|
||||
TEST(getopt_long) {
|
||||
enum {
|
||||
ARG_VERSION = 0x100,
|
||||
ARG_REQUIRED,
|
||||
ARG_OPTIONAL,
|
||||
};
|
||||
|
||||
static const struct option options[] = {
|
||||
{ "help", no_argument, NULL, 'h' },
|
||||
{ "version" , no_argument, NULL, ARG_VERSION },
|
||||
{ "required1", required_argument, NULL, 'r' },
|
||||
{ "required2", required_argument, NULL, ARG_REQUIRED },
|
||||
{ "optional1", optional_argument, NULL, 'o' },
|
||||
{ "optional2", optional_argument, NULL, ARG_OPTIONAL },
|
||||
{},
|
||||
};
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0"),
|
||||
"hr:o::", options,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
NULL,
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"--",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
NULL,
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"--",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
NULL,
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4",
|
||||
"--"),
|
||||
"hr:o::", options,
|
||||
NULL,
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"--help"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"-h"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"--help",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"-h",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"--help",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"-h",
|
||||
"string3",
|
||||
"string4"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4",
|
||||
"--help"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4",
|
||||
"-h"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"--required1", "reqarg1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'r', "reqarg1" },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"-r", "reqarg1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'r', "reqarg1" },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"-r", "reqarg1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'r', "reqarg1" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"--optional1=optarg1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'o', "optarg1" },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"--optional1", "string1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'o', NULL, "string1" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"-ooptarg1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'o', "optarg1" },
|
||||
{}
|
||||
}, NULL);
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"-o", "string1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'o', NULL, "string1" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1"));
|
||||
|
||||
test_getopt_long_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"--help",
|
||||
"--version",
|
||||
"string2",
|
||||
"--required1", "reqarg1",
|
||||
"--required2", "reqarg2",
|
||||
"--required1=reqarg3",
|
||||
"--required2=reqarg4",
|
||||
"string3",
|
||||
"--optional1", "string4",
|
||||
"--optional2", "string5",
|
||||
"--optional1=optarg1",
|
||||
"--optional2=optarg2",
|
||||
"-h",
|
||||
"-r", "reqarg5",
|
||||
"-rreqarg6",
|
||||
"-ooptarg3",
|
||||
"-o",
|
||||
"string6",
|
||||
"-o",
|
||||
"-h",
|
||||
"-o",
|
||||
"--help",
|
||||
"string7",
|
||||
"-hooptarg4",
|
||||
"-hrreqarg6",
|
||||
"--",
|
||||
"--help",
|
||||
"--required1",
|
||||
"--optional1"),
|
||||
"hr:o::", options,
|
||||
(Entry[]) {
|
||||
{ 'h' },
|
||||
{ ARG_VERSION },
|
||||
{ 'r', "reqarg1" },
|
||||
{ ARG_REQUIRED, "reqarg2" },
|
||||
{ 'r', "reqarg3" },
|
||||
{ ARG_REQUIRED, "reqarg4" },
|
||||
{ 'o', NULL, "string4" },
|
||||
{ ARG_OPTIONAL, NULL, "string5" },
|
||||
{ 'o', "optarg1" },
|
||||
{ ARG_OPTIONAL, "optarg2" },
|
||||
{ 'h' },
|
||||
{ 'r', "reqarg5" },
|
||||
{ 'r', "reqarg6" },
|
||||
{ 'o', "optarg3" },
|
||||
{ 'o', NULL, "string6" },
|
||||
{ 'o', NULL, "-h" },
|
||||
{ 'h' },
|
||||
{ 'o', NULL, "--help" },
|
||||
{ 'h' },
|
||||
{ 'h' },
|
||||
{ 'o', "optarg4" },
|
||||
{ 'h' },
|
||||
{ 'r', "reqarg6" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string4",
|
||||
"string5",
|
||||
"string6",
|
||||
"string7",
|
||||
"--help",
|
||||
"--required1",
|
||||
"--optional1"));
|
||||
}
|
||||
static void test_getopt_one(
|
||||
char **argv,
|
||||
const char *optstring,
|
||||
const Entry *entries,
|
||||
char **remaining) {
|
||||
|
||||
_cleanup_free_ char *joined = strv_join(argv, ", ");
|
||||
log_debug("/* %s(%s) */", __func__, joined);
|
||||
|
||||
_cleanup_free_ char *saved_argv0 = NULL;
|
||||
ASSERT_NOT_NULL(saved_argv0 = strdup(argv[0]));
|
||||
|
||||
int c, argc = strv_length(argv);
|
||||
size_t i = 0, n_entries = 0;
|
||||
|
||||
for (const Entry *e = entries; e && e->opt != 0; e++)
|
||||
n_entries++;
|
||||
|
||||
optind = 0;
|
||||
while ((c = getopt(argc, argv, optstring)) >= 0) {
|
||||
log_debug("%c: %s", c, strna(optarg));
|
||||
|
||||
ASSERT_LT(i, n_entries);
|
||||
ASSERT_EQ(c, entries[i].opt);
|
||||
ASSERT_STREQ(optarg, entries[i].argument);
|
||||
if (entries[i].nextarg)
|
||||
ASSERT_STREQ(argv[optind], entries[i].nextarg);
|
||||
i++;
|
||||
}
|
||||
|
||||
ASSERT_EQ(i, n_entries);
|
||||
ASSERT_LE(optind, argc);
|
||||
ASSERT_EQ(argc - optind, (int) strv_length(remaining));
|
||||
for (int j = optind; j < argc; j++)
|
||||
ASSERT_STREQ(argv[j], remaining[j - optind]);
|
||||
ASSERT_STREQ(argv[0], saved_argv0);
|
||||
}
|
||||
|
||||
TEST(getopt) {
|
||||
test_getopt_one(STRV_MAKE("arg0"),
|
||||
"hr:o::",
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2"),
|
||||
"hr:o::",
|
||||
NULL,
|
||||
STRV_MAKE("string1",
|
||||
"string2"));
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"-h"),
|
||||
"hr:o::",
|
||||
(Entry[]) {
|
||||
{ 'h', NULL },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"-r", "reqarg1"),
|
||||
"hr:o::",
|
||||
(Entry[]) {
|
||||
{ 'r', "reqarg1" },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"-r", "reqarg1"),
|
||||
"hr:o::",
|
||||
(Entry[]) {
|
||||
{ 'r', "reqarg1" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2"));
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"-ooptarg1"),
|
||||
"hr:o::",
|
||||
(Entry[]) {
|
||||
{ 'o', "optarg1" },
|
||||
{}
|
||||
},
|
||||
NULL);
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"-o", "string1"),
|
||||
"hr:o::",
|
||||
(Entry[]) {
|
||||
{ 'o', NULL, "string1" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1"));
|
||||
|
||||
test_getopt_one(STRV_MAKE("arg0",
|
||||
"string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"-h",
|
||||
"-r", "reqarg5",
|
||||
"-rreqarg6",
|
||||
"-ooptarg3",
|
||||
"-o",
|
||||
"string6",
|
||||
"-o",
|
||||
"-h",
|
||||
"-o",
|
||||
"string7",
|
||||
"-hooptarg4",
|
||||
"-hrreqarg6"),
|
||||
"hr:o::",
|
||||
(Entry[]) {
|
||||
{ 'h' },
|
||||
{ 'r', "reqarg5" },
|
||||
{ 'r', "reqarg6" },
|
||||
{ 'o', "optarg3" },
|
||||
{ 'o', NULL, "string6" },
|
||||
{ 'o', NULL, "-h" },
|
||||
{ 'h' },
|
||||
{ 'o', NULL, "string7" },
|
||||
{ 'h' },
|
||||
{ 'o', "optarg4" },
|
||||
{ 'h' },
|
||||
{ 'r', "reqarg6" },
|
||||
{}
|
||||
},
|
||||
STRV_MAKE("string1",
|
||||
"string2",
|
||||
"string3",
|
||||
"string6",
|
||||
"string7"));
|
||||
}
|
||||
|
||||
DEFINE_TEST_MAIN(LOG_DEBUG);
|
||||
Reference in New Issue
Block a user