Skip to content

Commit

Permalink
getopt_longの実装
Browse files Browse the repository at this point in the history
no_argumentとrequired_argumentの動作を確認。
まだ試験は不十分。
  • Loading branch information
takamin committed Oct 17, 2015
1 parent 3d83b1a commit f829813
Show file tree
Hide file tree
Showing 3 changed files with 138 additions and 12 deletions.
2 changes: 1 addition & 1 deletion include/getopt.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
Expand Down
89 changes: 85 additions & 4 deletions source/getopt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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)
Expand Down
59 changes: 52 additions & 7 deletions test/test_getopt_long.cpp
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string>
#include <string.h>
Expand All @@ -21,6 +22,7 @@ using namespace std;
class Arg {
public:
Arg(char const* command_line) : argc(0), argv(0) {
cout << "*** " << command_line << endl;
vector<string> elements;
this->argc = Arg::split(command_line, elements);
if(this->argc == 0) {
Expand Down Expand Up @@ -123,35 +125,78 @@ int Arg::split(char const* in, vector<string>& 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<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', },
{"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;
}

0 comments on commit f829813

Please sign in to comment.