Browse Source

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
Michal Z 6 years ago
parent
commit
a7b71a311d

+ 7 - 0
src/header/libgen/cbindgen.toml

@@ -0,0 +1,7 @@
+sys_includes = []
+include_guard = "_LIBGEN_H"
+language = "C"
+style = "Tag"
+
+[enum]
+prefix_with_name = true

+ 49 - 0
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;
+}

+ 1 - 0
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;

+ 1 - 0
tests/Makefile

@@ -11,6 +11,7 @@ EXPECT_BINS=\
 	fcntl/create \
 	fcntl/fcntl \
 	fnmatch \
+	libgen \
 	locale \
 	math \
 	netdb \

+ 0 - 0
tests/expected/libgen.stderr


+ 18 - 0
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: '.'

+ 81 - 0
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;
+}