about summary refs log tree commit diff
diff options
context:
space:
mode:
authorBrian Anderson <banderson@mozilla.com>2011-10-28 23:23:51 -0700
committerBrian Anderson <banderson@mozilla.com>2011-10-28 23:34:01 -0700
commit802deac3233d91bcd6ba5a87c6a4de8b3e12425e (patch)
tree29843187afb551550e9804df7408a0028ee97b03
parenta2377ccf91158ce5c9da2e5d0cc1f56fa562b2fe (diff)
downloadrust-802deac3233d91bcd6ba5a87c6a4de8b3e12425e.tar.gz
rust-802deac3233d91bcd6ba5a87c6a4de8b3e12425e.zip
stdlib: Add fs::splitext
Splits a path into the filename + extension
-rw-r--r--src/lib/fs.rs49
-rw-r--r--src/test/stdtest/fs.rs56
2 files changed, 105 insertions, 0 deletions
diff --git a/src/lib/fs.rs b/src/lib/fs.rs
index 5787e9c510c..057f933d0a5 100644
--- a/src/lib/fs.rs
+++ b/src/lib/fs.rs
@@ -177,6 +177,55 @@ fn split(p: path) -> [path] {
 }
 
 /*
+Function: splitext
+
+Split a path into a pair of strings with the first element being the filename
+without the extension and the second being either empty or the file extension
+including the period. Leading periods in the basename are ignored.  If the
+path includes directory components then they are included in the filename part
+of the result pair.
+*/
+fn splitext(p: path) -> (str, str) {
+    if str::is_empty(p) { ("", "") }
+    else {
+        let parts = str::split(p, '.' as u8);
+        if vec::len(parts) > 1u {
+            let base = str::connect(vec::init(parts), ".");
+            let ext = "." + option::get(vec::last(parts));
+
+            fn is_dotfile(base: str) -> bool {
+                str::is_empty(base)
+                    || str::ends_with(
+                        base, str::from_char(os_fs::path_sep))
+                    || str::ends_with(
+                        base, str::from_char(os_fs::alt_path_sep))
+            }
+
+            fn ext_contains_sep(ext: str) -> bool {
+                vec::len(split(ext)) > 1u
+            }
+
+            fn no_basename(ext: str) -> bool {
+                str::ends_with(
+                    ext, str::from_char(os_fs::path_sep))
+                    || str::ends_with(
+                        ext, str::from_char(os_fs::alt_path_sep))
+            }
+
+            if is_dotfile(base)
+                || ext_contains_sep(ext)
+                || no_basename(ext) {
+                (p, "")
+            } else {
+                (base, ext)
+            }
+        } else {
+            (p, "")
+        }
+    }
+}
+
+/*
 Function: normalize
 
 Removes extra "." and ".." entries from paths.
diff --git a/src/test/stdtest/fs.rs b/src/test/stdtest/fs.rs
index 14467ea59a6..66cec07c795 100644
--- a/src/test/stdtest/fs.rs
+++ b/src/test/stdtest/fs.rs
@@ -156,4 +156,60 @@ fn normalize12() {
 #[cfg(target_os = "win32")]
 fn path_is_absolute_win32() {
    assert fs::path_is_absolute("C:/whatever");
+}
+
+#[test]
+fn splitext_empty() {
+    let (base, ext) = fs::splitext("");
+    assert base == "";
+    assert ext == "";
+}
+
+#[test]
+fn splitext_ext() {
+    let (base, ext) = fs::splitext("grum.exe");
+    assert base == "grum";
+    assert ext == ".exe";
+}
+
+#[test]
+fn splitext_noext() {
+    let (base, ext) = fs::splitext("grum");
+    assert base == "grum";
+    assert ext == "";
+}
+
+#[test]
+fn splitext_dotfile() {
+    let (base, ext) = fs::splitext(".grum");
+    assert base == ".grum";
+    assert ext == "";
+}
+
+#[test]
+fn splitext_path_ext() {
+    let (base, ext) = fs::splitext("oh/grum.exe");
+    assert base == "oh/grum";
+    assert ext == ".exe";
+}
+
+#[test]
+fn splitext_path_noext() {
+    let (base, ext) = fs::splitext("oh/grum");
+    assert base == "oh/grum";
+    assert ext == "";
+}
+
+#[test]
+fn splitext_dot_in_path() {
+    let (base, ext) = fs::splitext("oh.my/grum");
+    assert base == "oh.my/grum";
+    assert ext == "";
+}
+
+#[test]
+fn splitext_nobasename() {
+    let (base, ext) = fs::splitext("oh.my/");
+    assert base == "oh.my/";
+    assert ext == "";
 }
\ No newline at end of file