mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-11 17:00:37 +00:00
LibC: Make getopt
modify argv
again
A POSIX-compatibility fix was introduced in 64740a0214
to make the
compilation of the `diffutils` port work, which expected a
`char* const* argv` signature.
And indeed, the POSIX spec does not mention permutation of `argv`:
https://pubs.opengroup.org/onlinepubs/9699919799/functions/getopt.html
However, most implementations do modify `argv` as evidenced by
documentation such as:
https://refspecs.linuxbase.org/LSB_5.0.0/LSB-Core-generic
/LSB-Core-generic/libutil-getopt-3.html
"The function prototype was aligned with POSIX 1003.1-2008 (ISO/IEC
9945-2009) despite the fact that it modifies argv, and the library
maintainers are unwilling to change this."
Change the behavior back to permutate `argc` to allow for the following
command line argument order to work again:
unzip ./file.zip -o target-dir
Without this change, `./file.zip` in the example above would have been
ignored completely.
This commit is contained in:
parent
d72aeb2e1a
commit
10e8b99038
Notes:
sideshowbarker
2024-07-18 12:18:59 +09:00
Author: https://github.com/gmta Commit: https://github.com/SerenityOS/serenity/commit/10e8b990384 Pull-request: https://github.com/SerenityOS/serenity/pull/8037
2 changed files with 13 additions and 14 deletions
|
@ -333,7 +333,7 @@ TEST_CASE(stop_on_first_non_option)
|
|||
EXPECT_EQ(positionals[0], "one");
|
||||
|
||||
// Do not stop on first non-option; arguments in wrong order
|
||||
// Expected: parser chokes on the positional argument
|
||||
// Expected: bool options are set and one positional argument is filled
|
||||
bool_opt1 = false;
|
||||
bool_opt2 = false;
|
||||
positionals = {};
|
||||
|
@ -343,7 +343,12 @@ TEST_CASE(stop_on_first_non_option)
|
|||
parser.add_option(bool_opt2, "bool_opt2", nullptr, 'c');
|
||||
parser.add_positional_argument(positionals, "pos", "pos", Core::ArgsParser::Required::Yes);
|
||||
});
|
||||
EXPECT_EQ(parser_result, false);
|
||||
EXPECT_EQ(parser_result, true);
|
||||
EXPECT_EQ(bool_opt1, true);
|
||||
EXPECT_EQ(bool_opt2, true);
|
||||
EXPECT_EQ(positionals.size(), 1u);
|
||||
if (positionals.size() == 1u)
|
||||
EXPECT_EQ(positionals[0], "one");
|
||||
|
||||
// Stop on first non-option; arguments in correct order
|
||||
// Expected: bool options are set and one positional argument is filled
|
||||
|
|
|
@ -42,7 +42,6 @@ namespace {
|
|||
class OptionParser {
|
||||
public:
|
||||
OptionParser(int argc, char* const* argv, const StringView& short_options, const option* long_options, int* out_long_option_index = nullptr);
|
||||
~OptionParser();
|
||||
int getopt();
|
||||
|
||||
private:
|
||||
|
@ -56,7 +55,7 @@ private:
|
|||
bool find_next_option();
|
||||
|
||||
size_t m_argc { 0 };
|
||||
char** m_argv { nullptr };
|
||||
char* const* m_argv { nullptr };
|
||||
StringView m_short_options;
|
||||
const option* m_long_options { nullptr };
|
||||
int* m_out_long_option_index { nullptr };
|
||||
|
@ -68,12 +67,11 @@ private:
|
|||
|
||||
OptionParser::OptionParser(int argc, char* const* argv, const StringView& short_options, const option* long_options, int* out_long_option_index)
|
||||
: m_argc(argc)
|
||||
, m_argv(argv)
|
||||
, m_short_options(short_options)
|
||||
, m_long_options(long_options)
|
||||
, m_out_long_option_index(out_long_option_index)
|
||||
{
|
||||
m_argv = new char*[m_argc + 1];
|
||||
memmove(m_argv, argv, sizeof(char*) * (m_argc + 1));
|
||||
// In the following case:
|
||||
// $ foo bar -o baz
|
||||
// we want to parse the option (-o baz) first, and leave the argument (bar)
|
||||
|
@ -94,11 +92,6 @@ OptionParser::OptionParser(int argc, char* const* argv, const StringView& short_
|
|||
optarg = nullptr;
|
||||
}
|
||||
|
||||
OptionParser::~OptionParser()
|
||||
{
|
||||
delete[] m_argv;
|
||||
}
|
||||
|
||||
int OptionParser::getopt()
|
||||
{
|
||||
bool should_reorder_argv = !m_stop_on_first_non_option;
|
||||
|
@ -308,10 +301,11 @@ void OptionParser::shift_argv()
|
|||
return;
|
||||
}
|
||||
|
||||
auto new_argv = const_cast<char**>(m_argv);
|
||||
char* buffer[m_consumed_args];
|
||||
memcpy(buffer, &m_argv[m_arg_index], sizeof(char*) * m_consumed_args);
|
||||
memmove(&m_argv[optind + m_consumed_args], &m_argv[optind], sizeof(char*) * (m_arg_index - optind));
|
||||
memcpy(&m_argv[optind], buffer, sizeof(char*) * m_consumed_args);
|
||||
memcpy(buffer, &new_argv[m_arg_index], sizeof(char*) * m_consumed_args);
|
||||
memmove(&new_argv[optind + m_consumed_args], &new_argv[optind], sizeof(char*) * (m_arg_index - optind));
|
||||
memcpy(&new_argv[optind], buffer, sizeof(char*) * m_consumed_args);
|
||||
}
|
||||
|
||||
bool OptionParser::find_next_option()
|
||||
|
|
Loading…
Reference in a new issue