diff --git a/ci/run-docker.sh b/ci/run-docker.sh
index 4247827f67ffcf7d216afcf746842d15b8e64942..c656f5904d684d4c269cf11687da24fbbbf00925 100755
--- a/ci/run-docker.sh
+++ b/ci/run-docker.sh
@@ -7,6 +7,7 @@ set -ex
 
 run() {
     echo "Building docker container for target ${1}"
+
     # use -f so we can use ci/ as build context
     docker build -t libc -f "ci/docker/${1}/Dockerfile" ci/
     mkdir -p target
diff --git a/libc-test/build.rs b/libc-test/build.rs
index ca0b7a2e001b44e3a0d6de588cb3957a31566d15..66cef4a2d29190d5602e8f6843a5c6fa2bd51c34 100644
--- a/libc-test/build.rs
+++ b/libc-test/build.rs
@@ -26,6 +26,8 @@ fn main() {
     let openbsd = target.contains("openbsd");
     let rumprun = target.contains("rumprun");
     let solaris = target.contains("solaris");
+    let cloudabi = target.contains("cloudabi");
+    let redox = target.contains("redox");
     let bsdlike = freebsd || apple || netbsd || openbsd || dragonfly;
     let mut cfg = ctest::TestGenerator::new();
 
@@ -42,6 +44,8 @@ fn main() {
         cfg.define("_XOPEN_SOURCE", Some("700"));
         cfg.define("__EXTENSIONS__", None);
         cfg.define("_LCONV_C99", None);
+    } else if freebsd {
+        cfg.define("_WITH_GETLINE", None);
     }
 
     // Android doesn't actually have in_port_t but it's much easier if we
@@ -351,6 +355,10 @@ fn main() {
         }
     }
 
+    if cloudabi || redox {
+        cfg.header("strings.h");
+    }
+
     cfg.type_name(move |ty, is_struct, is_union| {
         match ty {
             // Just pass all these through, no need for a "struct" prefix
diff --git a/src/cloudabi/mod.rs b/src/cloudabi/mod.rs
index f72eeb4d24afc177f2dfd7cd6f9b76c26bcffa71..02b7974ff482512648d5131bbfce91f03b043851 100644
--- a/src/cloudabi/mod.rs
+++ b/src/cloudabi/mod.rs
@@ -185,6 +185,8 @@ extern {
     pub fn atexit(cb: extern fn()) -> c_int;
     pub fn system(s: *const c_char) -> c_int;
     pub fn getenv(s: *const c_char) -> *mut c_char;
+    pub fn getline (lineptr: *mut *mut c_char, n: *mut size_t,
+        stream: *mut FILE) -> ssize_t;
 
     pub fn strcpy(dst: *mut c_char, src: *const c_char) -> *mut c_char;
     pub fn strncpy(dst: *mut c_char, src: *const c_char,
@@ -201,6 +203,9 @@ extern {
     pub fn strdup(cs: *const c_char) -> *mut c_char;
     pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
     pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
+    pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int;
+    pub fn strncasecmp(s1: *const c_char, s2: *const c_char,
+                       n: size_t) -> c_int;
     pub fn strlen(cs: *const c_char) -> size_t;
     pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t;
     pub fn strerror(n: c_int) -> *mut c_char;
diff --git a/src/redox/mod.rs b/src/redox/mod.rs
index 9870fa6dca0665db4b14f9565a173b7ebc20f5a8..9f68632a0fbfbc6aca0c2a32839caf9e3fa06743 100644
--- a/src/redox/mod.rs
+++ b/src/redox/mod.rs
@@ -231,6 +231,10 @@ extern {
     pub fn strdup(cs: *const c_char) -> *mut c_char;
     pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
     pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
+    pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
+    pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int;
+    pub fn strncasecmp(s1: *const c_char, s2: *const c_char,
+                       n: size_t) -> c_int;
     pub fn strlen(cs: *const c_char) -> size_t;
     pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t;
     pub fn strerror(n: c_int) -> *mut c_char;
diff --git a/src/unix/mod.rs b/src/unix/mod.rs
index b9201897036c8c7dc0417bcbc8bb696f4d5ebffc..ff9e1954bbf8897f5591e7ef3167636d86892659 100644
--- a/src/unix/mod.rs
+++ b/src/unix/mod.rs
@@ -476,6 +476,9 @@ extern {
     pub fn strdup(cs: *const c_char) -> *mut c_char;
     pub fn strpbrk(cs: *const c_char, ct: *const c_char) -> *mut c_char;
     pub fn strstr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
+    pub fn strcasecmp(s1: *const c_char, s2: *const c_char) -> c_int;
+    pub fn strncasecmp(s1: *const c_char, s2: *const c_char,
+                       n: size_t) -> c_int;
     pub fn strlen(cs: *const c_char) -> size_t;
     pub fn strnlen(cs: *const c_char, maxlen: size_t) -> size_t;
     #[cfg_attr(
@@ -1108,6 +1111,10 @@ extern {
     pub fn posix_openpt(flags: ::c_int) -> ::c_int;
     pub fn ptsname(fd: ::c_int) -> *mut ::c_char;
     pub fn unlockpt(fd: ::c_int) -> ::c_int;
+
+    pub fn strcasestr(cs: *const c_char, ct: *const c_char) -> *mut c_char;
+    pub fn getline (lineptr: *mut *mut c_char, n: *mut size_t,
+        stream: *mut FILE) -> ssize_t;
 }
 
 cfg_if! {
diff --git a/src/windows/gnu.rs b/src/windows/gnu.rs
new file mode 100644
index 0000000000000000000000000000000000000000..a67af15a8f01d6d5efd6e3a03a64b3186006dfaa
--- /dev/null
+++ b/src/windows/gnu.rs
@@ -0,0 +1,8 @@
+pub const L_tmpnam: ::c_uint = 14;
+pub const TMP_MAX: ::c_uint = 0x7fff;
+
+extern {
+    pub fn strcasecmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int;
+    pub fn strncasecmp(s1: *const ::c_char, s2: *const ::c_char,
+                    n: ::size_t) -> ::c_int;
+}
diff --git a/src/windows.rs b/src/windows/mod.rs
similarity index 98%
rename from src/windows.rs
rename to src/windows/mod.rs
index 9ed89925ceb0f71472f12dcd5350e04abad48c44..f46eb362d81b2cb7251a1b5cfde1ce5d293ac3f5 100644
--- a/src/windows.rs
+++ b/src/windows/mod.rs
@@ -111,18 +111,6 @@ pub const BUFSIZ: ::c_uint = 512;
 pub const FOPEN_MAX: ::c_uint = 20;
 pub const FILENAME_MAX: ::c_uint = 260;
 
-cfg_if! {
-    if #[cfg(all(target_env = "gnu"))] {
-        pub const L_tmpnam: ::c_uint = 14;
-        pub const TMP_MAX: ::c_uint = 0x7fff;
-    } else if #[cfg(all(target_env = "msvc"))] {
-        pub const L_tmpnam: ::c_uint = 260;
-        pub const TMP_MAX: ::c_uint = 0x7fff_ffff;
-    } else {
-        // Unknown target_env
-    }
-}
-
 pub const O_RDONLY: ::c_int = 0;
 pub const O_WRONLY: ::c_int = 1;
 pub const O_RDWR: ::c_int = 2;
@@ -398,3 +386,15 @@ cfg_if! {
         }
     }
 }
+
+cfg_if! {
+    if #[cfg(all(target_env = "gnu"))] {
+        mod gnu;
+        pub use self::gnu::*;
+    } else if #[cfg(all(target_env = "msvc"))] {
+        mod msvc;
+        pub use self::msvc::*;
+    } else {
+        // Unknown target_env
+    }
+}
\ No newline at end of file
diff --git a/src/windows/msvc.rs b/src/windows/msvc.rs
new file mode 100644
index 0000000000000000000000000000000000000000..9e2a9b9e5d46c1e47d6c7877d92076d531145d89
--- /dev/null
+++ b/src/windows/msvc.rs
@@ -0,0 +1,10 @@
+pub const L_tmpnam: ::c_uint = 260;
+pub const TMP_MAX: ::c_uint = 0x7fff_ffff;
+
+extern {
+    #[link_name = "_stricmp"]
+    pub fn stricmp(s1: *const ::c_char, s2: *const ::c_char) -> ::c_int;
+    #[link_name = "_strnicmp"]
+    pub fn strnicmp(s1: *const ::c_char, s2: *const ::c_char,
+                    n: ::size_t) -> ::c_int;
+}
\ No newline at end of file