diff --git a/src/header/libgen/cbindgen.toml b/src/header/libgen/cbindgen.toml new file mode 100644 index 0000000000000000000000000000000000000000..b3c8f6bd3cae22acc59545626b33a73ab4f49c0b --- /dev/null +++ b/src/header/libgen/cbindgen.toml @@ -0,0 +1,7 @@ +sys_includes = [] +include_guard = "_LIBGEN_H" +language = "C" +style = "Tag" + +[enum] +prefix_with_name = true diff --git a/src/header/libgen/mod.rs b/src/header/libgen/mod.rs new file mode 100644 index 0000000000000000000000000000000000000000..8128df98cd41181dd36c5eba9f3cd9c08d7c5226 --- /dev/null +++ b/src/header/libgen/mod.rs @@ -0,0 +1,49 @@ +//! libgen implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/libgen.h.html + +use core::ptr; + +use platform::types::c_char; + +use header::string::strlen; + +#[no_mangle] +pub unsafe extern "C" fn basename(str: *mut c_char) -> *mut c_char { + if str == ptr::null_mut() || strlen(str) == 0 { + return ".\0".as_ptr() as *mut c_char; + } + let mut end = strlen(str) as isize - 1; + while end >= 0 && *str.offset(end) == b'/' as c_char { + end -= 1; + } + if end == -1 { + return "/\0".as_ptr() as *mut c_char; + } + let mut begin = end; + while begin >= 0 && *str.offset(begin) != b'/' as c_char { + begin -= 1; + } + *str.offset(end + 1) = 0; + return str.offset(begin + 1) as *mut c_char; +} + +#[no_mangle] +pub unsafe extern "C" fn dirname(str: *mut c_char) -> *mut c_char { + if str == ptr::null_mut() || strlen(str) == 0 { + return ".\0".as_ptr() as *mut c_char; + } + let mut end = strlen(str) as isize - 1; + while end > 0 && *str.offset(end) == b'/' as c_char { + end -= 1; + } + while end >= 0 && *str.offset(end) != b'/' as c_char { + end -= 1; + } + while end > 0 && *str.offset(end) == b'/' as c_char { + end -= 1; + } + if end == -1 { + return ".\0".as_ptr() as *mut c_char; + } + *str.offset(end + 1) = 0; + return str; +} diff --git a/src/header/mod.rs b/src/header/mod.rs index 08cf34c826c427bd42e78374aa5d2d592dde6986..fc6201556bc248fbb56fc56d200889be8d31db5c 100644 --- a/src/header/mod.rs +++ b/src/header/mod.rs @@ -12,6 +12,7 @@ pub mod getopt; pub mod grp; pub mod inttypes; pub mod limits; +pub mod libgen; pub mod locale; pub mod netdb; pub mod netinet_in; diff --git a/tests/Makefile b/tests/Makefile index bdc7168fe45d3a5d87d1d4ff8a7b393011406b1d..2a8cb5aefce53abd421bb08c786a9750218fd420 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -11,6 +11,7 @@ EXPECT_BINS=\ fcntl/create \ fcntl/fcntl \ fnmatch \ + libgen \ locale \ math \ netdb \ diff --git a/tests/expected/libgen.stderr b/tests/expected/libgen.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/libgen.stdout b/tests/expected/libgen.stdout new file mode 100644 index 0000000000000000000000000000000000000000..c19d73cc8b270fd10cb1da2115bf1549c9747498 --- /dev/null +++ b/tests/expected/libgen.stdout @@ -0,0 +1,18 @@ +Testing libgen.h +OK on basename(/usr/lib), expected: 'lib', got: 'lib' +OK on basename(//usr//lib//), expected: 'lib', got: 'lib' +OK on basename(/usr/), expected: 'usr', got: 'usr' +OK on basename(), expected: '.', got: '.' +OK on basename(/), expected: '/', got: '/' +OK on basename(///), expected: '/', got: '/' +OK on basename(NULL), expected: '.', got: '.' +OK on dirname(/usr/lib), expected: '/usr', got: '/usr' +OK on dirname(//usr//lib//), expected: '//usr', got: '//usr' +OK on dirname(/usr), expected: '/', got: '/' +OK on dirname(usr), expected: '.', got: '.' +OK on dirname(/), expected: '/', got: '/' +OK on dirname(///), expected: '/', got: '/' +OK on dirname(.), expected: '.', got: '.' +OK on dirname(..), expected: '.', got: '.' +OK on dirname(), expected: '.', got: '.' +OK on dirname(NULL), expected: '.', got: '.' diff --git a/tests/libgen.c b/tests/libgen.c new file mode 100644 index 0000000000000000000000000000000000000000..f38f70f0f01cdd36025482ca61169e1e5d1989c3 --- /dev/null +++ b/tests/libgen.c @@ -0,0 +1,81 @@ +#include <libgen.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +typedef struct { + char * in; + char * expected_out; +} test_case; + +// API for basename and dirname allow the passed in string to +// be modified. This means we have to pass a modifiable copy. +char * get_mutable_string(char *str) { + if (str == NULL) + return NULL; + char * copy = malloc(sizeof(char) * (strlen(str) + 1)); + copy = strcpy(copy, str); + return copy; +} + +void test_basename() { + test_case test_cases[] = + { {"/usr/lib", "lib"}, + {"//usr//lib//", "lib"}, + {"/usr/", "usr"}, + {"", "."}, + {"/", "/"}, + {"///","/"}, + {NULL, "."} + }; + for (int i = 0;i < sizeof(test_cases)/sizeof(test_case);i++) { + char * in = get_mutable_string(test_cases[i].in); + char * out = basename(in); + if (!out) { + printf("Error on basename(%s), expected: '%s', got NULL\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out); + } else if (strcmp(out, test_cases[i].expected_out) != 0) { + printf("Error on basename(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out); + } else { + printf("OK on basename(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out); + } + if (!in) + free(in); + } + return; +} + +void test_dirname() { + test_case test_cases[] = + { {"/usr/lib", "/usr"}, + {"//usr//lib//", "//usr"}, + {"/usr", "/"}, + {"usr", "."}, + {"/", "/"}, + {"///","/"}, + {".", "."}, + {"..", "."}, + {"", "."}, + {NULL, "."} + }; + for (int i = 0;i < sizeof(test_cases)/sizeof(test_case);i++) { + char * in = get_mutable_string(test_cases[i].in); + char * out = dirname(in); + if (!out) { + printf("Error on dirname(%s), expected: '%s', got NULL\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out); + } else if (strcmp(out, test_cases[i].expected_out) != 0) { + printf("Error on dirname(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out); + } else { + printf("OK on dirname(%s), expected: '%s', got: '%s'\n", test_cases[i].in != 0 ? test_cases[i].in : "NULL", test_cases[i].expected_out, out); + } + if (!in) + free(in); + } + return; +} + +int main() { + printf("Testing libgen.h\n"); + test_basename(); + test_dirname(); + return 0; +}