Selaa lähdekoodia

LibC: Implement the getsubopt function

This is a LibC function that POSIX defines to help userspace programs
to get suboptions. An example of a suboption is the token "pixclk" from
a Shell command running "edid-decode --gtf w=1024,h=768,pixclk=48".
The function should be run in a while loop to acquire all suboptions
until the last one.
Liav A 3 vuotta sitten
vanhempi
commit
e02da2ed41

+ 1 - 0
Userland/Libraries/LibC/CMakeLists.txt

@@ -11,6 +11,7 @@ set(LIBC_SOURCES
     fnmatch.cpp
     fnmatch.cpp
     ifaddrs.cpp
     ifaddrs.cpp
     getopt.cpp
     getopt.cpp
+    getsubopt.cpp
     grp.cpp
     grp.cpp
     inttypes.cpp
     inttypes.cpp
     ioctl.cpp
     ioctl.cpp

+ 51 - 0
Userland/Libraries/LibC/getsubopt.cpp

@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2022, Liav A. <liavalb@hotmail.co.il>
+ *
+ * SPDX-License-Identifier: BSD-2-Clause
+ */
+
+#include <AK/ScopeGuard.h>
+#include <AK/StringView.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+// 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<char*>(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<char*>(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;
+}

+ 1 - 0
Userland/Libraries/LibC/unistd.h

@@ -167,5 +167,6 @@ extern int optreset;
 extern char* optarg;
 extern char* optarg;
 
 
 int getopt(int argc, char* const* argv, char const* short_options);
 int getopt(int argc, char* const* argv, char const* short_options);
+int getsubopt(char** optionp, char* const* tokens, char** valuep);
 
 
 __END_DECLS
 __END_DECLS