From a7b71a311d7f081626c7872254c47a4fa2ad0b17 Mon Sep 17 00:00:00 2001 From: Michal Z <michal.zwonek@gmail.com> Date: Sun, 4 Nov 2018 22:40:01 +0100 Subject: [PATCH] Implement libgen.h Implemented the following calls according to http://pubs.opengroup.org/onlinepubs/7908799/xsh/libgen.h.html - char* basename(char*) - char* dirname(char*) Added test suit for the implemented calls. Issue: https://gitlab.redox-os.org/redox-os/relibc/issues/134 --- src/header/libgen/cbindgen.toml | 7 +++ src/header/libgen/mod.rs | 49 ++++++++++++++++++++ src/header/mod.rs | 1 + tests/Makefile | 1 + tests/expected/libgen.stderr | 0 tests/expected/libgen.stdout | 18 ++++++++ tests/libgen.c | 81 +++++++++++++++++++++++++++++++++ 7 files changed, 157 insertions(+) create mode 100644 src/header/libgen/cbindgen.toml create mode 100644 src/header/libgen/mod.rs create mode 100644 tests/expected/libgen.stderr create mode 100644 tests/expected/libgen.stdout create mode 100644 tests/libgen.c diff --git a/src/header/libgen/cbindgen.toml b/src/header/libgen/cbindgen.toml new file mode 100644 index 000000000..b3c8f6bd3 --- /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 000000000..8128df98c --- /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 08cf34c82..fc6201556 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 bdc7168fe..2a8cb5aef 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 000000000..e69de29bb diff --git a/tests/expected/libgen.stdout b/tests/expected/libgen.stdout new file mode 100644 index 000000000..c19d73cc8 --- /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 000000000..f38f70f0f --- /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; +} -- GitLab