Merge branch 'getsubopt' into 'master'

Fix getsubopt and add test

See merge request redox-os/relibc!765
This commit is contained in:
Jeremy Soller
2025-11-28 08:14:44 -07:00
5 changed files with 96 additions and 24 deletions
+40 -24
View File
@@ -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
}
+1
View File
@@ -80,6 +80,7 @@ EXPECT_NAMES=\
stdlib/atoi \
stdlib/div \
stdlib/env \
stdlib/getsubopt \
stdlib/mkostemps \
stdlib/qsort \
stdlib/rand \
+55
View File
@@ -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);
}