mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
Merge pull request #6533 from ArjenS-LA/feat/guest-getopt-long-only
feat(libc): implement getopt_long_only
This commit is contained in:
2 files changed
+95
-8
No files matched your search
@@ -38,6 +38,7 @@ constexpr int OptionalArgument = 2;
|
||||
|
||||
constexpr int FlagPermute = 1;
|
||||
constexpr int FlagAllArguments = 2;
|
||||
constexpr int FlagLongOnly = 4;
|
||||
|
||||
constexpr int BadCharacter = '?';
|
||||
constexpr int InOrder = 1;
|
||||
@@ -112,7 +113,7 @@ void PermuteArguments(int nonOptionStart, int nonOptionEnd, int optionEnd, char*
|
||||
}
|
||||
}
|
||||
|
||||
int ParseLongOptions(char* const* arguments, const char* options, const GuestOption* longOptions, int* index, const char* dash) {
|
||||
int ParseLongOptions(char* const* arguments, const char* options, const GuestOption* longOptions, int* index, const char* dash, bool shortToo, int flags) {
|
||||
char* const current = g_longPlace;
|
||||
int match = -1;
|
||||
bool exactMatch = false;
|
||||
@@ -136,8 +137,9 @@ int ParseLongOptions(char* const* arguments, const char* options, const GuestOpt
|
||||
exactMatch = true;
|
||||
break;
|
||||
}
|
||||
if (shortToo && length == 1) continue;
|
||||
if (match == -1) match = i;
|
||||
else if (longOptions[i].hasArgument != longOptions[match].hasArgument ||
|
||||
else if ((flags & FlagLongOnly) || longOptions[i].hasArgument != longOptions[match].hasArgument ||
|
||||
longOptions[i].flag != longOptions[match].flag ||
|
||||
longOptions[i].value != longOptions[match].value)
|
||||
secondPartialMatch = true;
|
||||
@@ -149,6 +151,10 @@ int ParseLongOptions(char* const* arguments, const char* options, const GuestOpt
|
||||
return BadCharacter;
|
||||
}
|
||||
if (match == -1) {
|
||||
if (shortToo) {
|
||||
--optind_nid_postfix;
|
||||
return -1;
|
||||
}
|
||||
if (PrintError(options)) Warn(std::string("unrecognized option `") + dash + current + "'");
|
||||
optopt_nid_postfix = 0;
|
||||
return BadCharacter;
|
||||
@@ -237,11 +243,21 @@ int GetoptInternal(int count, char* const* arguments, const char* options, const
|
||||
break;
|
||||
}
|
||||
|
||||
if (longOptions && *g_longPlace == '-' && g_longPlace != arguments[optind_nid_postfix]) {
|
||||
++g_longPlace;
|
||||
const int result = ParseLongOptions(arguments, options, longOptions, index, "--");
|
||||
g_longPlace = g_emptyMessage;
|
||||
return result;
|
||||
if (longOptions && g_longPlace != arguments[optind_nid_postfix] &&
|
||||
(*g_longPlace == '-' || (flags & FlagLongOnly))) {
|
||||
bool shortToo = false;
|
||||
const char* dash = "-";
|
||||
if (*g_longPlace == '-') {
|
||||
++g_longPlace;
|
||||
dash = "--";
|
||||
} else if (*g_longPlace != ':' && std::strchr(options, *g_longPlace)) {
|
||||
shortToo = true;
|
||||
}
|
||||
const int result = ParseLongOptions(arguments, options, longOptions, index, dash, shortToo, flags);
|
||||
if (result != -1) {
|
||||
g_longPlace = g_emptyMessage;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
const int character = OptionCharacter(g_longPlace++);
|
||||
@@ -265,7 +281,7 @@ int GetoptInternal(int count, char* const* arguments, const char* options, const
|
||||
}
|
||||
g_longPlace = Argument(arguments, optind_nid_postfix, "getopt_long");
|
||||
}
|
||||
const int result = ParseLongOptions(arguments, options, longOptions, index, "-W ");
|
||||
const int result = ParseLongOptions(arguments, options, longOptions, index, "-W ", false, flags);
|
||||
g_longPlace = g_emptyMessage;
|
||||
return result;
|
||||
}
|
||||
@@ -355,4 +371,8 @@ int APS5_VABI getopt_long_nid_postfix(int count, char* const* arguments, const c
|
||||
return GetoptInternal(count, arguments, options, longOptions, index, FlagPermute);
|
||||
}
|
||||
|
||||
int APS5_VABI getopt_long_only_nid_postfix(int count, char* const* arguments, const char* options, const GuestOption* longOptions, int* index) {
|
||||
return GetoptInternal(count, arguments, options, longOptions, index, FlagPermute | FlagLongOnly);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,6 +17,7 @@ struct GuestOption {
|
||||
extern "C" {
|
||||
int APS5_VABI getopt_nid_postfix(int, char* const*, const char*);
|
||||
int APS5_VABI getopt_long_nid_postfix(int, char* const*, const char*, const GuestOption*, int*);
|
||||
int APS5_VABI getopt_long_only_nid_postfix(int, char* const*, const char*, const GuestOption*, int*);
|
||||
int APS5_VABI setenv_nid_postfix(const char*, const char*, int);
|
||||
int APS5_VABI unsetenv_nid_postfix(const char*);
|
||||
extern int opterr_nid_postfix;
|
||||
@@ -244,6 +245,71 @@ void ShortOptions() {
|
||||
ExpectText(RunGetopt("bc", permuted), "|3", "getopt does not permute");
|
||||
}
|
||||
|
||||
void LongOnlyOptions() {
|
||||
int flag = 0;
|
||||
const GuestOption options[] = {
|
||||
{"alpha", 0, nullptr, 100},
|
||||
{"alpine", 0, nullptr, 100},
|
||||
{"b", 0, nullptr, 101},
|
||||
{"required", 1, nullptr, 102},
|
||||
{"optional", 2, nullptr, 103},
|
||||
{"flag", 0, &flag, 7},
|
||||
{nullptr, 0, nullptr, 0},
|
||||
};
|
||||
struct Case {
|
||||
const char* arguments;
|
||||
const char* shortOptions;
|
||||
std::vector<int> results;
|
||||
std::vector<std::string> values;
|
||||
int finalIndex;
|
||||
};
|
||||
const Case cases[] = {
|
||||
{"foo -alpha --alpha -b", "ab", {100, 100, 101}, {"", "", ""}, 4},
|
||||
{"foo -a -acvalue", "ac:", {'a', 'a', 'c'}, {"", "", "value"}, 3},
|
||||
{"foo -required=one -req two -optional=three -optional four", "", {102, 102, 103, 103}, {"one", "two", "three", ""}, 6},
|
||||
{"foo operand -alpha tail -b", "ab", {100, 101}, {"", ""}, 3},
|
||||
{"foo -al --al", "a", {'?', '?'}, {"", ""}, 3},
|
||||
{"foo -unknown", "", {'?'}, {""}, 2},
|
||||
{"foo -required", ":", {':'}, {""}, 2},
|
||||
{"foo -alpha=yes", "", {'?'}, {""}, 2},
|
||||
{"foo -flag", "", {0}, {""}, 2},
|
||||
{"foo -- -alpha", "", {}, {}, 2},
|
||||
{"foo operand -alpha", "+", {}, {}, 1},
|
||||
{"foo operand -alpha", "-", {1, 100}, {"operand", ""}, 3},
|
||||
{"foo -W alpha", "W;", {100}, {""}, 3},
|
||||
};
|
||||
for (const auto& test : cases) {
|
||||
ArgumentVector arguments(test.arguments);
|
||||
Reset();
|
||||
opterr_nid_postfix = 0;
|
||||
for (std::size_t i = 0; i < test.results.size(); ++i) {
|
||||
const int result = getopt_long_only_nid_postfix(arguments.Count(), arguments.Values(), test.shortOptions, options, nullptr);
|
||||
Expect(result == test.results[i], std::string("getopt_long_only result: ") + test.arguments);
|
||||
ExpectText(optarg_nid_postfix ? optarg_nid_postfix : "", test.values[i], "getopt_long_only argument");
|
||||
}
|
||||
Expect(getopt_long_only_nid_postfix(arguments.Count(), arguments.Values(), test.shortOptions, options, nullptr) == -1,
|
||||
std::string("getopt_long_only termination: ") + test.arguments);
|
||||
Expect(optind_nid_postfix == test.finalIndex, std::string("getopt_long_only optind: ") + test.arguments);
|
||||
}
|
||||
Expect(flag == 7, "getopt_long_only flag pointer");
|
||||
{
|
||||
ArgumentVector arguments("foo -al");
|
||||
StderrCapture capture;
|
||||
Reset();
|
||||
int index = -1;
|
||||
Expect(getopt_long_only_nid_postfix(arguments.Count(), arguments.Values(), "a", options, &index) == '?' &&
|
||||
optopt_nid_postfix == 0 && index == -1, "ambiguous aliases keep index unchanged");
|
||||
ExpectText(capture.Text(), "eboot.bin: option `-al' is ambiguous\n", "single dash diagnostic");
|
||||
}
|
||||
ArgumentVector arguments("foo -alpha");
|
||||
Reset();
|
||||
int index = -1;
|
||||
Expect(getopt_long_only_nid_postfix(arguments.Count(), arguments.Values(), "a", options, &index) == 100 && index == 0,
|
||||
"long-only index");
|
||||
optind_nid_postfix = 0;
|
||||
Expect(getopt_long_only_nid_postfix(arguments.Count(), arguments.Values(), "a", options, nullptr) == 100, "long-only restart");
|
||||
}
|
||||
|
||||
void LongOptions() {
|
||||
int flag = 0;
|
||||
const GuestOption options[] = {
|
||||
@@ -364,4 +430,5 @@ int main() {
|
||||
FreeBsdGetoptLongCases();
|
||||
ShortOptions();
|
||||
LongOptions();
|
||||
LongOnlyOptions();
|
||||
}
|
||||
Reference in new issue
Block a user