Skip to content

Commit

Permalink
getopt_longの修正。
Browse files Browse the repository at this point in the history
1. 長いオプション形式の場合の'='位置判定部分を修正
2. オプション解析終了時に、変数を初期化
3. デバッグ用に関数内部のスタティック変数をモジュール内の変数へ移動
4. その他、冗長なコードを簡潔に記述
5. テスト内容をgccの動作に合わせた
6. g++でテストプログラムをビルドするスクリプトを追加
  • Loading branch information
takamin committed Oct 18, 2015
1 parent f829813 commit 2fafa8b
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 47 deletions.
55 changes: 20 additions & 35 deletions source/getopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ int optind = 1;
int opterr = 1;
int optopt = 0;

int postpone_count = 0;
int nextchar = 0;

static void postpone(int argc, char* const argv[], int index) {
char** nc_argv = (char**)argv;
char* p = nc_argv[index];
Expand All @@ -38,12 +41,12 @@ 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;
while(1) {
int c;
const char* optptr = 0;
if(optind >= argc - postpone_count) {
c = 0;
optarg = 0;
break;
}
c = *(argv[optind] + nextchar);
Expand Down Expand Up @@ -77,67 +80,49 @@ static 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;
if(longopts != 0 && *(argv[optind] + 1) == '-') {
char const* spec_long = argv[optind] + 2;
char const* pos_eq = strchr(spec_long, '=');
if(pos_eq == NULL) {
spec_len = strlen(spec_long);
} else {
spec_len = pos_eq - spec_long;
}
int spec_len = (pos_eq == NULL ? strlen(spec_long) : 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;
if(opterr) {
fprintf(stderr, "ambiguous option: %s\n", spec_long);
}
return '?';
}
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;
if(pos_eq != 0) {
if(opterr) {
fprintf(stderr, "no argument for %s\n", optdef->name);
}
return '?';
}
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];
}
optarg = argv[optind];
} else {
if(*(argv[optind] + spec_len + 1) == '\0') {
optarg = argv[++optind];
} else {
optarg = argv[optind] + spec_len + 1;
}
optarg = pos_eq + 1;
}
break;
}
Expand Down
1 change: 1 addition & 0 deletions test/test-g++.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
g++ -std=c++0x -o test_getopt_long test_getopt_long.cpp
40 changes: 28 additions & 12 deletions test/test_getopt_long.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,16 @@
#if defined(_MSC_VER)

#include "getopt.h"
extern "C" int postpone_count;
extern "C" int nextchar;

#elif defined(_GCC)
#else

#include <getopt.h>

#endif


using namespace std;

class Arg {
Expand Down Expand Up @@ -125,25 +128,28 @@ int Arg::split(char const* in, vector<string>& argv)
}
return argc;
}
int pass_count = 0;
int fail_count = 0;
static void test_equal(char const* name, char const* A, char const* B) {
if(A == B || A != 0 && string(A) == string(B)) {
if(A == B || A != 0 && B != 0 && string(A) == string(B)) {
pass_count++;
cout << "PASS ( " << name << " )" << endl;
} else {
cout << "PASS ( " << name << " )" << endl;
fail_count++;
cout << "FAIL ( " << name << " )" << endl;
}
}
static void test_equal(char const* name, int A, int B) {
if(A == B) {
pass_count++;
cout << "PASS ( " << name << " )" << A << "==" << B << endl;
} else {
fail_count++;
cout << "FAIL ( " << name << " )" << A << "!=" << B << endl;
}
}
#define TEST_EQUAL(A,B) test_equal("" #A " == " #B, A, B)
int main(int argc, char* argv[]) {
vector<string> 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', },
Expand Down Expand Up @@ -177,26 +183,36 @@ int main(int argc, char* argv[]) {
opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex);
TEST_EQUAL(opt, 'e');
TEST_EQUAL(longindex, 5);
TEST_EQUAL(optarg, "-aa");
TEST_EQUAL(optarg, "--aa");
TEST_EQUAL(test02arg.values()[optind], "--f=XXX");
opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex);
TEST_EQUAL(opt, 'f');
TEST_EQUAL(longindex, 3);
TEST_EQUAL(optarg, "XXX");
TEST_EQUAL(test02arg.values()[optind], "--f=");
opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex);
TEST_EQUAL(opt, 'f');
TEST_EQUAL(longindex, 3);
TEST_EQUAL(optarg, "XYZ");
TEST_EQUAL(optarg, "");
TEST_EQUAL(test02arg.values()[optind], "XYZ");
opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex);
TEST_EQUAL(opt, 'b');
TEST_EQUAL(longindex, 2);
TEST_EQUAL(optarg, "YYY");
TEST_EQUAL(optarg, 0);
TEST_EQUAL(test02arg.values()[optind], "--ddd");
opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex);
TEST_EQUAL(opt, 'd');
TEST_EQUAL(longindex, 1);
TEST_EQUAL(optarg, "YYY");
TEST_EQUAL(optarg, "=YYY");
TEST_EQUAL(test02arg.values()[optind], "--ddd");
opt = getopt_long(test02arg.count(), test02arg.values(), "abcdef", opt01, &longindex);
TEST_EQUAL(opt, 'd');
TEST_EQUAL(longindex, 1);
TEST_EQUAL(optarg, "ZZZ");
return 0;
TEST_EQUAL(optarg, "=");
TEST_EQUAL(test02arg.values()[optind], "ZZZ");

printf("TEST RESULT: PASS %d(%.2f%%), FAIL %d(%.2f%%)\n",
pass_count, 100.0 * pass_count/(pass_count + fail_count),
fail_count, 100.0 * fail_count/(pass_count + fail_count));
return 0;
}

0 comments on commit 2fafa8b

Please sign in to comment.