From f82981342c4dd83f90aca2607b5cdc1f7bcb37cd Mon Sep 17 00:00:00 2001 From: Koji Takami Date: Sat, 17 Oct 2015 17:35:52 +0900 Subject: [PATCH] =?UTF-8?q?getopt=5Flong=E3=81=AE=E5=AE=9F=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit no_argumentとrequired_argumentの動作を確認。 まだ試験は不十分。 --- include/getopt.h | 2 +- source/getopt.c | 89 +++++++++++++++++++++++++++++++++++++-- test/test_getopt_long.cpp | 59 +++++++++++++++++++++++--- 3 files changed, 138 insertions(+), 12 deletions(-) diff --git a/include/getopt.h b/include/getopt.h index a8e0963..8111e04 100644 --- a/include/getopt.h +++ b/include/getopt.h @@ -19,7 +19,6 @@ extern "C" { extern char *optarg; extern int optind, opterr, optopt; -/**************************************************************************** #define no_argument 0 #define required_argument 1 #define optional_argument 2 @@ -34,6 +33,7 @@ extern "C" { int getopt_long(int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex); +/**************************************************************************** int getopt_long_only(int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex); diff --git a/source/getopt.c b/source/getopt.c index e28848c..9c770b3 100644 --- a/source/getopt.c +++ b/source/getopt.c @@ -34,8 +34,9 @@ static int postpone_noopt(int argc, char* const argv[], int index) { } return 0; } -int getopt(int argc, char* const argv[], - const char* optstring) +static int _getopt_(int argc, char* const argv[], + const char* optstring, + const struct option* longopts, int* longindex) { static int postpone_count = 0; static int nextchar = 0; @@ -76,6 +77,81 @@ int getopt(int argc, char* const argv[], break; } ++nextchar; + if(longopts != 0 && *(argv[optind] + nextchar) == '-') { + char const* spec_long = argv[optind] + nextchar + 1; + int spec_len = 0; + char const* pos_eq = strchr(spec_long, '='); + if(pos_eq == NULL) { + spec_len = strlen(spec_long); + } else { + spec_len = pos_eq - spec_long; + } + int index_search = 0; + int index_found = -1; + const struct option* optdef = 0; + while(longopts->name != 0) { + if(strncmp(spec_long, longopts->name, spec_len) == 0) { + if(optdef != 0) { + break; + } + optdef = longopts; + index_found = index_search; + } + longopts++; + index_search++; + } + if(longopts->name != 0) { + if(opterr) { + fprintf(stderr, "ambiguous option: %s\n", spec_long); + } + return '?'; + } + if(optdef == 0) { + if(opterr) { + fprintf(stderr, "no such a option: %s\n", spec_long); + } + return '?'; + } + if(optdef->has_arg == no_argument && pos_eq > 0) { + if(opterr) { + fprintf(stderr, "no such a option: %s\n", spec_long); + } + return '?'; + } + switch(optdef->has_arg) { + case no_argument: + optarg = 0; + break; + case required_argument: + if(pos_eq == NULL) { + ++optind; + if(strcmp(argv[optind], "=") == 0) { + optarg = argv[++optind]; + } else if(strncmp(argv[optind], "=", 1) == 0) { + optarg = argv[optind] + 1; + } else { + optarg = argv[optind]; + } + } else { + if(*(argv[optind] + spec_len + 1) == '\0') { + optarg = argv[++optind]; + } else { + optarg = argv[optind] + spec_len + 1; + } + } + break; + } + ++optind; + nextchar = 0; + if(longindex != 0) { + *longindex = index_found; + } + if(optdef->flag != 0) { + *optdef->flag = optdef->val; + return 0; + } + return optdef->val; + } continue; } } @@ -141,13 +217,18 @@ int getopt(int argc, char* const argv[], return -1; } -/******************************************************** +int getopt(int argc, char* const argv[], + const char* optstring) +{ + return _getopt_(argc, argv, optstring, 0, 0); +} int getopt_long(int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex) { - return -1; + return _getopt_(argc, argv, optstring, longopts, longindex); } +/******************************************************** int getopt_long_only(int argc, char* const argv[], const char* optstring, const struct option* longopts, int* longindex) diff --git a/test/test_getopt_long.cpp b/test/test_getopt_long.cpp index 85c741d..19bf19e 100644 --- a/test/test_getopt_long.cpp +++ b/test/test_getopt_long.cpp @@ -1,3 +1,4 @@ +#define _CRT_SECURE_NO_WARNINGS #include #include #include @@ -21,6 +22,7 @@ using namespace std; class Arg { public: Arg(char const* command_line) : argc(0), argv(0) { + cout << "*** " << command_line << endl; vector elements; this->argc = Arg::split(command_line, elements); if(this->argc == 0) { @@ -123,35 +125,78 @@ int Arg::split(char const* in, vector& argv) } return argc; } -static void test_equal(char const* name, int A, int B, bool condition) { - if(condition) { +static void test_equal(char const* name, char const* A, char const* B) { + if(A == B || A != 0 && string(A) == string(B)) { + cout << "PASS ( " << name << " )" << endl; + } else { + cout << "PASS ( " << name << " )" << endl; + } +} +static void test_equal(char const* name, int A, int B) { + if(A == B) { cout << "PASS ( " << name << " )" << A << "==" << B << endl; } else { cout << "FAIL ( " << name << " )" << A << "!=" << B << endl; } } -#define TEST_EQUAL(A,B) test_equal("" #A " == " #B, A, B, A==B) +#define TEST_EQUAL(A,B) test_equal("" #A " == " #B, A, B) int main(int argc, char* argv[]) { vector elements; Arg test_arg("A\\'B\\'C \"D\\\"E\\\"F\" 'G\\H\\I' "); struct option opt01[] = { {"aaa", no_argument, NULL, 'a', }, + {"ddd", required_argument, NULL, 'd', }, {"bbb", no_argument, NULL, 'b', }, + {"fff", required_argument, NULL, 'f', }, {"ccc", no_argument, NULL, 'c', }, + {"eee", required_argument, NULL, 'e', }, { NULL, 0, NULL, 0, }, }; int longindex = 0; int opt = 0; Arg test01arg("a.out --aa --bbb --c"); - opt = getopt_long(test01arg.count(), test01arg.values(), "abc", opt01, &longindex); + opt = getopt_long(test01arg.count(), test01arg.values(), "abcdef", opt01, &longindex); TEST_EQUAL(opt, 'a'); TEST_EQUAL(longindex, 0); - opt = getopt_long(test01arg.count(), test01arg.values(), "abc", opt01, &longindex); + TEST_EQUAL(optarg, 0); + opt = getopt_long(test01arg.count(), test01arg.values(), "abcdef", opt01, &longindex); TEST_EQUAL(opt, 'b'); - TEST_EQUAL(longindex, 1); - opt = getopt_long(test01arg.count(), test01arg.values(), "abc", opt01, &longindex); + TEST_EQUAL(longindex, 2); + TEST_EQUAL(optarg, 0); + opt = getopt_long(test01arg.count(), test01arg.values(), "abcdef", opt01, &longindex); TEST_EQUAL(opt, 'c'); + TEST_EQUAL(longindex, 4); + TEST_EQUAL(optarg, 0); + + optarg = 0; + optind = 1; + opterr = 1; + optopt = 0; + Arg test02arg("a.out --ee --aa --f=XXX --f= XYZ --bbb --ddd =YYY --ddd = ZZZ"); + opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex); + TEST_EQUAL(opt, 'e'); + TEST_EQUAL(longindex, 5); + TEST_EQUAL(optarg, "-aa"); + opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex); + TEST_EQUAL(opt, 'f'); + TEST_EQUAL(longindex, 3); + TEST_EQUAL(optarg, "XXX"); + opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex); + TEST_EQUAL(opt, 'f'); + TEST_EQUAL(longindex, 3); + TEST_EQUAL(optarg, "XYZ"); + opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex); + TEST_EQUAL(opt, 'b'); TEST_EQUAL(longindex, 2); + TEST_EQUAL(optarg, "YYY"); + opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex); + TEST_EQUAL(opt, 'd'); + TEST_EQUAL(longindex, 1); + TEST_EQUAL(optarg, "YYY"); + opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex); + TEST_EQUAL(opt, 'd'); + TEST_EQUAL(longindex, 1); + TEST_EQUAL(optarg, "ZZZ"); return 0; }