diff --git a/Userland/Libraries/LibC/CMakeLists.txt b/Userland/Libraries/LibC/CMakeLists.txt index 885bbcbb3d..0389a04c8b 100644 --- a/Userland/Libraries/LibC/CMakeLists.txt +++ b/Userland/Libraries/LibC/CMakeLists.txt @@ -11,6 +11,7 @@ set(LIBC_SOURCES fnmatch.cpp ifaddrs.cpp getopt.cpp + getsubopt.cpp grp.cpp inttypes.cpp ioctl.cpp diff --git a/Userland/Libraries/LibC/getsubopt.cpp b/Userland/Libraries/LibC/getsubopt.cpp new file mode 100644 index 0000000000..1bf78efc42 --- /dev/null +++ b/Userland/Libraries/LibC/getsubopt.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022, Liav A. + * + * SPDX-License-Identifier: BSD-2-Clause + */ + +#include +#include +#include +#include +#include + +// https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsubopt.html +int getsubopt(char** option_array, char* const* tokens, char** option_value) +{ + if (**option_array == '\0') + return -1; + + auto option_string = StringView(*option_array); + + auto possible_comma_location = option_string.find(','); + char* option_end = const_cast(option_string.characters_without_null_termination()) + possible_comma_location.value_or(option_string.length()); + + auto possible_equals_char_location = option_string.find('='); + char* value_start = option_end; + if (possible_equals_char_location.has_value()) { + value_start = const_cast(option_string.characters_without_null_termination()) + possible_equals_char_location.value(); + } + + ScopeGuard ensure_end_array_contains_null_char([&]() { + if (*option_end != '\0') + *option_end++ = '\0'; + *option_array = option_end; + }); + + for (int count = 0; tokens[count] != NULL; ++count) { + auto token_stringview = StringView(tokens[count]); + if (!option_string.starts_with(token_stringview)) + continue; + if (tokens[count][value_start - *option_array] != '\0') + continue; + + *option_value = value_start != option_end ? value_start + 1 : nullptr; + return count; + } + + // Note: The current sub-option does not match any option, so prepare to tell this + // to the application. + *option_value = *option_array; + return -1; +} diff --git a/Userland/Libraries/LibC/unistd.h b/Userland/Libraries/LibC/unistd.h index 1d1e1b99da..6707a5bbab 100644 --- a/Userland/Libraries/LibC/unistd.h +++ b/Userland/Libraries/LibC/unistd.h @@ -167,5 +167,6 @@ extern int optreset; extern char* optarg; int getopt(int argc, char* const* argv, char const* short_options); +int getsubopt(char** optionp, char* const* tokens, char** valuep); __END_DECLS