Add PosixPath to path2. Add path2 to core build. Add dot/dotdot-normalizing.

This commit is contained in:
Graydon Hoare 2012-08-20 13:14:19 -07:00
parent a14485b7fd
commit 08441fca76
3 changed files with 241 additions and 9 deletions

View File

@ -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)]

View File

@ -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 {

View File

@ -14,6 +14,7 @@ export
// Creating a string
from_bytes,
from_byte,
from_slice,
from_char,
from_chars,
append,