about summary refs log tree commit diff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@mozilla.com>2012-08-20 13:14:19 -0700
committerGraydon Hoare <graydon@mozilla.com>2012-08-20 13:59:47 -0700
commit08441fca76084b97c21ead917e54ce6c66d5d012 (patch)
treee25b4c236f9864a5e4657d3e0c3ae65e58849dcd
parenta14485b7fd1a8a268a456ee1b47d79b10ccac875 (diff)
downloadrust-08441fca76084b97c21ead917e54ce6c66d5d012.tar.gz
rust-08441fca76084b97c21ead917e54ce6c66d5d012.zip
Add PosixPath to path2. Add path2 to core build. Add dot/dotdot-normalizing.
-rw-r--r--src/libcore/core.rc1
-rw-r--r--src/libcore/path2.rs248
-rw-r--r--src/libcore/str.rs1
3 files changed, 241 insertions, 9 deletions
diff --git a/src/libcore/core.rc b/src/libcore/core.rc
index cd87313c696..f3f1e6e9839 100644
--- a/src/libcore/core.rc
+++ b/src/libcore/core.rc
@@ -252,6 +252,7 @@ mod libc;
 mod os;
 #[warn(non_camel_case_types)]
 mod path;
+mod path2;
 #[warn(non_camel_case_types)]
 mod rand;
 #[warn(non_camel_case_types)]
diff --git a/src/libcore/path2.rs b/src/libcore/path2.rs
index c6b25476b96..50996c7876b 100644
--- a/src/libcore/path2.rs
+++ b/src/libcore/path2.rs
@@ -1,4 +1,6 @@
-extern mod std;
+// NB: transitionary, de-mode-ing.
+#[forbid(deprecated_mode)];
+#[forbid(deprecated_pattern)];
 
 struct WindowsPath {
     host: option<~str>;
@@ -31,6 +33,148 @@ trait Path {
     fn pop_component() -> self;
 }
 
+// FIXME (#3227): when default methods in traits are working, de-duplicate
+// PosixPath and WindowsPath, most of their methods are common.
+
+impl PosixPath : Path {
+    fn to_str() -> ~str {
+        match self.filename() {
+          none => self.dirname(),
+          some(ref f) =>
+          if (self.components.len() == 1 &&
+              !self.is_absolute) {
+            copy *f
+          } else {
+            self.dirname() + "/" + *f
+          }
+        }
+    }
+
+    static fn from_str(s: &str) -> PosixPath {
+        let mut components = str::split_nonempty(s, |c| c == '/');
+        let is_absolute = (s.len() != 0 && s[0] == '/' as u8);
+        return PosixPath { is_absolute: is_absolute,
+                           components: normalize(components) }
+    }
+
+    fn dirname() -> ~str {
+        let mut s = ~"";
+        if self.is_absolute {
+            s += "/";
+        }
+        let mut d = copy self.components;
+        if d.len() != 0 {
+            vec::pop(d);
+        }
+        s += str::connect(d, "/");
+        if s.len() == 0 {
+            s = ~".";
+        }
+        return s;
+    }
+
+    fn filename() -> option<~str> {
+        match self.components.len() {
+          0 => none,
+          n => some(copy self.components[n - 1])
+        }
+    }
+
+    fn filestem() -> option<~str> {
+        match self.filename() {
+          none => none,
+          some(ref f) => {
+            match str::rfind_char(*f, '.') {
+              some(p) => some(f.slice(0, p)),
+              none => some(copy *f)
+            }
+          }
+        }
+    }
+
+    fn filetype() -> option<~str> {
+        match self.filename() {
+          none => none,
+          some(ref f) => {
+            match str::rfind_char(*f, '.') {
+              some(p) if p+1 < f.len() => some(f.slice(p+1, f.len())),
+              _ => none
+            }
+          }
+        }
+    }
+
+    fn with_dirname(d: &str) -> PosixPath {
+        let dpath = from_str::<PosixPath>(d);
+        match self.filename() {
+          some(ref f) => dpath.push_components(~[copy *f]),
+          none => dpath
+        }
+    }
+
+    fn with_filename(f: &str) -> PosixPath {
+        assert ! str::any(f, |c| windows::is_sep(c as u8));
+        self.dir_path().push_components(~[str::from_slice(f)])
+    }
+
+    fn with_filestem(s: &str) -> PosixPath {
+        match self.filetype() {
+          none => self.with_filename(s),
+          some(ref t) =>
+          self.with_filename(str::from_slice(s) + "." + *t)
+        }
+    }
+
+    fn with_filetype(t: &str) -> PosixPath {
+        if t.len() == 0 {
+            match self.filestem() {
+              none => copy self,
+              some(s) => self.with_filename(s)
+            }
+        } else {
+            let t = ~"." + str::from_slice(t);
+            match self.filestem() {
+              none => self.with_filename(t),
+              some(ref s) =>
+              self.with_filename(*s + t)
+            }
+        }
+    }
+
+    fn dir_path() -> PosixPath {
+        if self.components.len() != 0 {
+            self.pop_component()
+        } else {
+            copy self
+        }
+    }
+
+    fn file_path() -> PosixPath {
+        let cs = match self.filename() {
+          none => ~[],
+          some(ref f) => ~[copy *f]
+        };
+        return PosixPath { is_absolute: false,
+                           components: cs }
+    }
+
+    fn push_components(cs: &[~str]) -> PosixPath {
+        return PosixPath { components: normalize(self.components + cs),
+                           ..self }
+    }
+
+    fn pop_component() -> PosixPath {
+        let mut cs = copy self.components;
+        if cs.len() != 0 {
+            vec::pop(cs);
+        }
+        return PosixPath { components: cs, ..self }
+    }
+
+
+
+}
+
 
 impl WindowsPath : Path {
 
@@ -82,7 +226,7 @@ impl WindowsPath : Path {
         return WindowsPath { host: host,
                              device: device,
                              is_absolute: is_absolute,
-                            components: components }
+                             components: normalize(components) }
     }
 
     fn dirname() -> ~str {
@@ -112,7 +256,6 @@ impl WindowsPath : Path {
     fn filename() -> option<~str> {
         match self.components.len() {
           0 => none,
-          1 => some(copy self.components[0]),
           n => some(copy self.components[n - 1])
         }
     }
@@ -163,11 +306,18 @@ impl WindowsPath : Path {
     }
 
     fn with_filetype(t: &str) -> WindowsPath {
-        let t = ~"." + str::from_slice(t);
-        match self.filestem() {
-          none => self.with_filename(t),
-          some(ref s) =>
-          self.with_filename(*s + t)
+        if t.len() == 0 {
+            match self.filestem() {
+              none => copy self,
+              some(s) => self.with_filename(s)
+            }
+        } else {
+            let t = ~"." + str::from_slice(t);
+            match self.filestem() {
+              none => self.with_filename(t),
+              some(ref s) =>
+              self.with_filename(*s + t)
+            }
         }
     }
 
@@ -191,7 +341,8 @@ impl WindowsPath : Path {
     }
 
     fn push_components(cs: &[~str]) -> WindowsPath {
-        return WindowsPath { components: self.components + cs, ..self }
+        return WindowsPath { components: normalize(self.components + cs),
+                            ..self }
     }
 
     fn pop_component() -> WindowsPath {
@@ -203,6 +354,85 @@ impl WindowsPath : Path {
     }
 }
 
+
+fn normalize(components: &[~str]) -> ~[~str] {
+    let mut cs = ~[];
+    for components.each |c| {
+        if c == ~"." { again; }
+        if c == ~".." && cs.len() != 0 {
+            vec::pop(cs);
+            again;
+        }
+        vec::push(cs, copy c);
+    }
+    cs
+}
+
+mod posix {
+
+    #[test]
+    fn test_posix_paths() {
+        fn mk(s: &str) -> PosixPath { from_str::<PosixPath>(s) }
+        fn t(wp: &PosixPath, s: &str) {
+            let ss = wp.to_str();
+            let sss = str::from_slice(s);
+            if (ss != sss) {
+                debug!("got %s", ss);
+                debug!("expected %s", sss);
+                assert ss == sss;
+            }
+        }
+
+        t(&(mk("hi")), "hi");
+        t(&(mk("hi/there")), "hi/there");
+        t(&(mk("hi/there.txt")), "hi/there.txt");
+
+        t(&(mk("hi/there.txt")), "hi/there.txt");
+        t(&(mk("hi/there.txt")
+           .with_filetype("")), "hi/there");
+
+        t(&(mk("/a/b/c/there.txt")
+            .with_dirname("hi")), "hi/there.txt");
+
+        t(&(mk("hi/there.txt")
+            .with_dirname(".")), "there.txt");
+
+        t(&(mk("a/b/../c/././/../foo.txt/")),
+          "a/foo.txt");
+
+        t(&(mk("a/b/c")
+            .push_components([~".."])), "a/b");
+
+        t(&(mk("there.txt")
+            .with_filetype("o")), "there.o");
+
+        t(&(mk("hi/there.txt")
+            .with_filetype("o")), "hi/there.o");
+
+        t(&(mk("hi/there.txt")
+            .with_filetype("o")
+            .with_dirname("/usr/lib")),
+          "/usr/lib/there.o");
+
+        t(&(mk("hi/there.txt")
+            .with_filetype("o")
+            .with_dirname("/usr/lib/")),
+          "/usr/lib/there.o");
+
+        t(&(mk("hi/there.txt")
+            .with_filetype("o")
+            .with_dirname("/usr//lib//")),
+            "/usr/lib/there.o");
+
+        t(&(mk("/usr/bin/rust")
+            .push_components([~"lib", ~"thingy.so"])
+            .with_filestem("librustc")),
+          "/usr/bin/rust/lib/librustc.so");
+
+    }
+
+}
+
 // Various windows helpers, and tests for the impl.
 mod windows {
 
diff --git a/src/libcore/str.rs b/src/libcore/str.rs
index d73c71c510a..4d2c98077dd 100644
--- a/src/libcore/str.rs
+++ b/src/libcore/str.rs
@@ -14,6 +14,7 @@ export
    // Creating a string
    from_bytes,
    from_byte,
+   from_slice,
    from_char,
    from_chars,
    append,