diff --git a/src/header/stdlib/mod.rs b/src/header/stdlib/mod.rs index 3a4dbb1cb7..cef9cdcdd1 100644 --- a/src/header/stdlib/mod.rs +++ b/src/header/stdlib/mod.rs @@ -454,35 +454,51 @@ pub unsafe extern "C" fn getenv(name: *const c_char) -> *mut c_char { #[unsafe(no_mangle)] pub unsafe extern "C" fn getsubopt( optionp: *mut *mut c_char, - tokens: *const *mut c_char, + keylistp: *const *mut c_char, valuep: *mut *mut c_char, ) -> c_int { + if optionp.is_null() || (*optionp).is_null() || keylistp.is_null() || valuep.is_null() { + return -1; + } + let start = *optionp; - let max = strlen(start) as isize; - let mut i: usize = 0; - *valuep = ptr::null_mut(); - *optionp = strchr(start, b',' as i32); - if !(*optionp).is_null() { - *(*optionp).add(0) = 0; - *optionp = *optionp.add(1); - } else { - *(optionp) = start.add(max as usize); - } - while !tokens.offset(i as isize).is_null() { - let cur = tokens.offset(i as isize) as *const _; - let len = strlen(cur) as isize; - if strncmp(cur, start, len as usize) != 0 { - i = i + 1; - continue; + let mut cursor = start; + let mut found_comma = false; + + while *cursor != 0 { + if *cursor == b',' as c_char { + *cursor = 0; + *optionp = cursor.add(1); + found_comma = true; + break; } - if (*start.offset(len)) == b'=' as c_char { - *valuep = start.offset(len + 1); - } else if !start.offset(len).is_null() { - i = i + 1; - continue; - } - return i as c_int; + cursor = cursor.add(1); } + + if !found_comma { + *optionp = cursor; + } + + let mut i = 0; + while !(*keylistp.add(i)).is_null() { + let token = *keylistp.add(i); + let token_len = strlen(token); + + if strncmp(start, token, token_len) == 0 { + let suffix_char = *start.add(token_len); + + if suffix_char == b'=' as c_char { + *valuep = start.add(token_len + 1); + return i as c_int; + } else if suffix_char == 0 { + *valuep = ptr::null_mut(); + return i as c_int; + } + } + i += 1; + } + + *valuep = start; -1 } diff --git a/tests/Makefile b/tests/Makefile index 4e6e3e7e73..08ccf04764 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -80,6 +80,7 @@ EXPECT_NAMES=\ stdlib/atoi \ stdlib/div \ stdlib/env \ + stdlib/getsubopt \ stdlib/mkostemps \ stdlib/qsort \ stdlib/rand \ diff --git a/tests/expected/bins_static/stdlib/getsubopt.stderr b/tests/expected/bins_static/stdlib/getsubopt.stderr new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/expected/bins_static/stdlib/getsubopt.stdout b/tests/expected/bins_static/stdlib/getsubopt.stdout new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/stdlib/getsubopt.c b/tests/stdlib/getsubopt.c new file mode 100644 index 0000000000..4717f65fcd --- /dev/null +++ b/tests/stdlib/getsubopt.c @@ -0,0 +1,55 @@ +#include "test_helpers.h" + +int main(void) { + char *const tokens[] = { + "ro", + "rw", + "foo", + "baz", + NULL + }; + + // getsubopt modifies the string in-place + char opt_str[] = "ro,foo=bar,bool,baz=,rw"; + char *options = opt_str; + char *value = NULL; + int idx; + + idx = getsubopt(&options, tokens, &value); + UNEXP_IF(getsubopt, idx, != 0); + if (value != NULL) { + printf("getsubopt failed: expected NULL value for 'ro', got '%s'\n", value); + exit(EXIT_FAILURE); + } + + idx = getsubopt(&options, tokens, &value); + UNEXP_IF(getsubopt, idx, != 2); + if (value == NULL || strcmp(value, "bar") != 0) { + printf("getsubopt failed: expected 'bar', got '%s'\n", value ? value : "NULL"); + exit(EXIT_FAILURE); + } + + idx = getsubopt(&options, tokens, &value); + UNEXP_IF(getsubopt, idx, != -1); + if (value == NULL || strcmp(value, "bool") != 0) { + printf("getsubopt failed: expected 'bool' in value, got '%s'\n", value ? value : "NULL"); + exit(EXIT_FAILURE); + } + + idx = getsubopt(&options, tokens, &value); + UNEXP_IF(getsubopt, idx, != 3); + if (value == NULL || strcmp(value, "") != 0) { + printf("getsubopt failed: expected empty string value, got '%s'\n", value ? value : "NULL"); + exit(EXIT_FAILURE); + } + + idx = getsubopt(&options, tokens, &value); + UNEXP_IF(getsubopt, idx, != 1); + if (value != NULL) { + printf("getsubopt failed: expected NULL value for 'rw', got '%s'\n", value); + exit(EXIT_FAILURE); + } + + idx = getsubopt(&options, tokens, &value); + UNEXP_IF(getsubopt, idx, != -1); +}