diff options
| author | bors <bors@rust-lang.org> | 2013-10-16 11:26:35 -0700 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2013-10-16 11:26:35 -0700 |
| commit | 40180cdbea708307ca66dc6debddbd5ecc1ea41c (patch) | |
| tree | 0d26ddfa020874dc3f665c2c1d3e836ee729408b /src/libstd/path.rs | |
| parent | fabec998e5667d651d3475c12ee25ab97d21105c (diff) | |
| parent | d108a22fd1b38c108e2b9b6cd7276d953524ffa2 (diff) | |
| download | rust-40180cdbea708307ca66dc6debddbd5ecc1ea41c.tar.gz rust-40180cdbea708307ca66dc6debddbd5ecc1ea41c.zip | |
auto merge of #9655 : kballard/rust/path-rewrite, r=alexcrichton
Rewrite the entire `std::path` module from scratch. `PosixPath` is now based on `~[u8]`, which fixes #7225. Unnecessary allocation has been eliminated. There are a lot of clients of `Path` that still assume utf-8 paths. This is covered in #9639.
Diffstat (limited to 'src/libstd/path.rs')
| -rw-r--r-- | src/libstd/path.rs | 1507 |
1 files changed, 0 insertions, 1507 deletions
diff --git a/src/libstd/path.rs b/src/libstd/path.rs deleted file mode 100644 index ea157c6eea6..00000000000 --- a/src/libstd/path.rs +++ /dev/null @@ -1,1507 +0,0 @@ -// Copyright 2012 The Rust Project Developers. See the COPYRIGHT -// file at the top-level directory of this distribution and at -// http://rust-lang.org/COPYRIGHT. -// -// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or -// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license -// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your -// option. This file may not be copied, modified, or distributed -// except according to those terms. - -/*! - -Cross-platform file path handling - -*/ - -#[allow(missing_doc)]; - -use c_str::ToCStr; -use c_str; -use clone::Clone; -use cmp::Eq; -use container::Container; -use iter::{Iterator, range}; -use libc; -use num; -use option::{None, Option, Some}; -use str::{OwnedStr, Str, StrSlice, StrVector}; -use to_str::ToStr; -use ascii::{AsciiCast, AsciiStr}; -use vec::{Vector, OwnedVector, ImmutableVector, OwnedCopyableVector}; - -#[cfg(windows)] -pub use Path = self::WindowsPath; -#[cfg(unix)] -pub use Path = self::PosixPath; - -#[deriving(Clone, Eq)] -pub struct WindowsPath { - host: Option<~str>, - device: Option<~str>, - is_absolute: bool, - components: ~[~str], -} - -pub fn WindowsPath(s: &str) -> WindowsPath { - GenericPath::from_str(s) -} - -#[deriving(Clone, Eq)] -pub struct PosixPath { - is_absolute: bool, - components: ~[~str], -} - -pub fn PosixPath(s: &str) -> PosixPath { - GenericPath::from_str(s) -} - -pub trait GenericPath : Clone + Eq + ToStr { - /// Converts a string to a path. - fn from_str(&str) -> Self; - - /// Returns the directory component of `self`, as a string. - fn dirname(&self) -> ~str { - let s = self.dir_path().to_str(); - match s.len() { - 0 => ~".", - _ => s, - } - } - - /// Returns the file component of `self`, as a string option. - /// Returns None if `self` names a directory. - fn filename<'a>(&'a self) -> Option<&'a str> { - match self.components().len() { - 0 => None, - n => Some(self.components()[n - 1].as_slice()), - } - } - - /// Returns the stem of the file component of `self`, as a string option. - /// The stem is the slice of a filename starting at 0 and ending just before - /// the last '.' in the name. - /// Returns None if `self` names a directory. - fn filestem<'a>(&'a self) -> Option<&'a str> { - match self.filename() { - None => None, - Some(ref f) => { - match f.rfind('.') { - Some(p) => Some(f.slice_to(p)), - None => Some((*f)), - } - } - } - } - - /// Returns the type of the file component of `self`, as a string option. - /// The file type is the slice of a filename starting just after the last - /// '.' in the name and ending at the last index in the filename. - /// Returns None if `self` names a directory. - fn filetype<'a>(&'a self) -> Option<&'a str> { - match self.filename() { - None => None, - Some(ref f) => { - match f.rfind('.') { - Some(p) if p < f.len() => Some(f.slice_from(p)), - _ => None, - } - } - } - } - - /// Returns a new path consisting of `self` with the parent directory component replaced - /// with the given string. - fn with_dirname(&self, (&str)) -> Self; - - /// Returns a new path consisting of `self` with the file component replaced - /// with the given string. - fn with_filename(&self, (&str)) -> Self; - - /// Returns a new path consisting of `self` with the file stem replaced - /// with the given string. - fn with_filestem(&self, s: &str) -> Self { - match self.filetype() { - None => self.with_filename(s), - Some(ref t) => self.with_filename(s.to_owned() + *t), - } - } - - /// Returns a new path consisting of `self` with the file type replaced - /// with the given string. - fn with_filetype(&self, t: &str) -> Self { - match (t.len(), self.filestem()) { - (0, None) => (*self).clone(), - (0, Some(ref s)) => self.with_filename(*s), - (_, None) => self.with_filename(format!(".{}", t)), - (_, Some(ref s)) => self.with_filename(format!("{}.{}", *s, t)), - } - } - - /// Returns the directory component of `self`, as a new path. - /// If `self` has no parent, returns `self`. - fn dir_path(&self) -> Self { - match self.components().len() { - 0 => (*self).clone(), - _ => self.pop(), - } - } - - /// Returns the file component of `self`, as a new path. - /// If `self` names a directory, returns the empty path. - fn file_path(&self) -> Self; - - /// Returns a new path whose parent directory is `self` and whose - /// file component is the given string. - fn push(&self, (&str)) -> Self; - - /// Returns a new path consisting of the given path, made relative to `self`. - fn push_rel(&self, other: &Self) -> Self { - assert!(!other.is_absolute()); - self.push_many(other.components()) - } - - /// Returns a new path consisting of the path given by the given vector - /// of strings, relative to `self`. - fn push_many<S: Str>(&self, (&[S])) -> Self; - - /// Identical to `dir_path` except in the case where `self` has only one - /// component. In this case, `pop` returns the empty path. - fn pop(&self) -> Self; - - /// The same as `push_rel`, except that the directory argument must not - /// contain directory separators in any of its components. - fn unsafe_join(&self, (&Self)) -> Self; - - /// On Unix, always returns `false`. On Windows, returns `true` iff `self`'s - /// file stem is one of: `con` `aux` `com1` `com2` `com3` `com4` - /// `lpt1` `lpt2` `lpt3` `prn` `nul`. - fn is_restricted(&self) -> bool; - - /// Returns a new path that names the same file as `self`, without containing - /// any '.', '..', or empty components. On Windows, uppercases the drive letter - /// as well. - fn normalize(&self) -> Self; - - /// Returns `true` if `self` is an absolute path. - fn is_absolute(&self) -> bool; - - /// True if `self` is an ancestor of `other`. - // See `test_is_ancestor_of` for examples. - fn is_ancestor_of(&self, other: &Self) -> bool { - debug2!("{} / {} {} {}", self.to_str(), other.to_str(), self.is_absolute(), - self.components().len()); - self == other || - (!other.components().is_empty() && - !(self.components().is_empty() && !self.is_absolute()) && - self.is_ancestor_of(&other.pop())) - } - - /// Finds the relative path from one file to another. - fn get_relative_to(&self, abs2: (&Self)) -> Self { - assert!(self.is_absolute()); - assert!(abs2.is_absolute()); - let abs1 = self.normalize(); - let abs2 = abs2.normalize(); - - let split1: &[~str] = abs1.components(); - let split2: &[~str] = abs2.components(); - let len1 = split1.len(); - let len2 = split2.len(); - assert!(len1 > 0); - assert!(len2 > 0); - - let max_common_path = num::min(len1, len2) - 1; - let mut start_idx = 0; - while start_idx < max_common_path - && split1[start_idx] == split2[start_idx] { - start_idx += 1; - } - - let mut path: ~[~str] = ~[]; - for _ in range(start_idx, len1 - 1) { path.push(~".."); }; - - path.push_all(split2.slice(start_idx, len2 - 1)); - - let mut result: Self = GenericPath::from_str("."); - if !path.is_empty() { - // Without this type hint, the typechecker doesn't seem to like it - let p: Self = GenericPath::from_str(""); - result = p.push_many(path); - }; - result - } - - - /// Returns `true` iff `child` is a suffix of `parent`. See the test - /// case for examples. - fn is_parent_of(&self, child: &Self) -> bool { - if !self.is_absolute() || child.is_absolute() - || self.components().len() < child.components().len() - || self.components().is_empty() { - return false; - } - let child_components = child.components().len(); - let parent_components = self.components().len(); - let to_drop = self.components().len() - child_components; - self.components().slice(to_drop, parent_components) == child.components() - } - - fn components<'a>(&'a self) -> &'a [~str]; -} - -#[cfg(target_os = "linux")] -#[cfg(target_os = "android")] -mod stat { - #[cfg(target_arch = "x86")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - __pad1: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - __pad2: 0, - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - __unused4: 0, - __unused5: 0, - } - } - } - - #[cfg(target_arch = "arm")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - __pad0: [0, ..4], - __st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - __pad3: [0, ..4], - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_ino: 0 - } - } - } - - #[cfg(target_arch = "mips")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_pad1: [0, ..3], - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_pad2: [0, ..2], - st_size: 0, - st_pad3: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_blksize: 0, - st_blocks: 0, - st_pad5: [0, ..14], - } - } - } - - #[cfg(target_arch = "x86_64")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_nlink: 0, - st_mode: 0, - st_uid: 0, - st_gid: 0, - __pad0: 0, - st_rdev: 0, - st_size: 0, - st_blksize: 0, - st_blocks: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - __unused: [0, 0, 0], - } - } - } -} - -#[cfg(target_os = "freebsd")] -mod stat { - #[cfg(target_arch = "x86_64")] - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_size: 0, - st_blocks: 0, - st_blksize: 0, - st_flags: 0, - st_gen: 0, - st_lspare: 0, - st_birthtime: 0, - st_birthtime_nsec: 0, - __unused: [0, 0], - } - } - } -} - -#[cfg(target_os = "macos")] -mod stat { - pub mod arch { - use libc; - - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_mode: 0, - st_nlink: 0, - st_ino: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_atime: 0, - st_atime_nsec: 0, - st_mtime: 0, - st_mtime_nsec: 0, - st_ctime: 0, - st_ctime_nsec: 0, - st_birthtime: 0, - st_birthtime_nsec: 0, - st_size: 0, - st_blocks: 0, - st_blksize: 0, - st_flags: 0, - st_gen: 0, - st_lspare: 0, - st_qspare: [0, 0], - } - } - } -} - -#[cfg(target_os = "win32")] -mod stat { - pub mod arch { - use libc; - pub fn default_stat() -> libc::stat { - libc::stat { - st_dev: 0, - st_ino: 0, - st_mode: 0, - st_nlink: 0, - st_uid: 0, - st_gid: 0, - st_rdev: 0, - st_size: 0, - st_atime: 0, - st_mtime: 0, - st_ctime: 0, - } - } - } -} - -#[cfg(target_os = "win32")] -impl WindowsPath { - pub fn stat(&self) -> Option<libc::stat> { - #[fixed_stack_segment]; #[inline(never)]; - do self.with_c_str |buf| { - let mut st = stat::arch::default_stat(); - match unsafe { libc::stat(buf, &mut st) } { - 0 => Some(st), - _ => None, - } - } - } - - pub fn exists(&self) -> bool { - match self.stat() { - None => false, - Some(_) => true, - } - } - - pub fn get_size(&self) -> Option<i64> { - match self.stat() { - None => None, - Some(ref st) => Some(st.st_size as i64), - } - } - - pub fn get_mode(&self) -> Option<uint> { - match self.stat() { - None => None, - Some(ref st) => Some(st.st_mode as uint), - } - } -} - -#[cfg(not(target_os = "win32"))] -impl PosixPath { - pub fn stat(&self) -> Option<libc::stat> { - #[fixed_stack_segment]; #[inline(never)]; - do self.with_c_str |buf| { - let mut st = stat::arch::default_stat(); - match unsafe { libc::stat(buf as *libc::c_char, &mut st) } { - 0 => Some(st), - _ => None, - } - } - } - - pub fn exists(&self) -> bool { - match self.stat() { - None => false, - Some(_) => true, - } - } - - pub fn get_size(&self) -> Option<i64> { - match self.stat() { - None => None, - Some(ref st) => Some(st.st_size as i64), - } - } - - pub fn get_mode(&self) -> Option<uint> { - match self.stat() { - None => None, - Some(ref st) => Some(st.st_mode as uint), - } - } - - /// Executes a function `f` on `self` as well as on all of its ancestors. - pub fn each_parent(&self, f: &fn(&Path)) { - if !self.components.is_empty() { - f(self); - self.pop().each_parent(f); - } - } - -} - -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "linux")] -#[cfg(target_os = "macos")] -impl PosixPath { - pub fn get_atime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_atime as i64, - st.st_atime_nsec as int)) - } - } - } - - pub fn get_mtime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_mtime as i64, - st.st_mtime_nsec as int)) - } - } - } - - pub fn get_ctime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_ctime as i64, - st.st_ctime_nsec as int)) - } - } - } -} - -#[cfg(unix)] -impl PosixPath { - pub fn lstat(&self) -> Option<libc::stat> { - #[fixed_stack_segment]; #[inline(never)]; - do self.with_c_str |buf| { - let mut st = stat::arch::default_stat(); - match unsafe { libc::lstat(buf, &mut st) } { - 0 => Some(st), - _ => None, - } - } - } -} - -#[cfg(target_os = "freebsd")] -#[cfg(target_os = "macos")] -impl PosixPath { - pub fn get_birthtime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_birthtime as i64, - st.st_birthtime_nsec as int)) - } - } - } -} - -#[cfg(target_os = "win32")] -impl WindowsPath { - pub fn get_atime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_atime as i64, 0)) - } - } - } - - pub fn get_mtime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_mtime as i64, 0)) - } - } - } - - pub fn get_ctime(&self) -> Option<(i64, int)> { - match self.stat() { - None => None, - Some(ref st) => { - Some((st.st_ctime as i64, 0)) - } - } - } - - /// Executes a function `f` on `self` as well as on all of its ancestors. - pub fn each_parent(&self, f: &fn(&Path)) { - if !self.components.is_empty() { - f(self); - self.pop().each_parent(f); - } - } -} - -impl ToStr for PosixPath { - fn to_str(&self) -> ~str { - let mut s = ~""; - if self.is_absolute { - s.push_str("/"); - } - s + self.components.connect("/") - } -} - -impl ToCStr for PosixPath { - fn to_c_str(&self) -> c_str::CString { - self.to_str().to_c_str() - } - - unsafe fn to_c_str_unchecked(&self) -> c_str::CString { - self.to_str().to_c_str_unchecked() - } -} - -impl GenericPath for PosixPath { - fn from_str(s: &str) -> PosixPath { - let components = s.split_iter('/') - .filter_map(|s| if s.is_empty() {None} else {Some(s.to_owned())}) - .collect(); - let is_absolute = (s.len() != 0 && s[0] == '/' as u8); - PosixPath { - is_absolute: is_absolute, - components: components, - } - } - - fn with_dirname(&self, d: &str) -> PosixPath { - let dpath = PosixPath(d); - match self.filename() { - Some(ref f) => dpath.push(*f), - None => dpath, - } - } - - fn with_filename(&self, f: &str) -> PosixPath { - assert!(!f.iter().all(posix::is_sep)); - self.dir_path().push(f) - } - - fn file_path(&self) -> PosixPath { - let cs = match self.filename() { - None => ~[], - Some(ref f) => ~[(*f).to_owned()] - }; - PosixPath { - is_absolute: false, - components: cs, - } - } - - fn push(&self, s: &str) -> PosixPath { - let mut v = self.components.clone(); - for s in s.split_iter(posix::is_sep) { - if !s.is_empty() { - v.push(s.to_owned()) - } - } - PosixPath { - components: v, - ..(*self).clone() - } - } - - fn push_many<S: Str>(&self, cs: &[S]) -> PosixPath { - let mut v = self.components.clone(); - for e in cs.iter() { - for s in e.as_slice().split_iter(posix::is_sep) { - if !s.is_empty() { - v.push(s.to_owned()) - } - } - } - PosixPath { - is_absolute: self.is_absolute, - components: v, - } - } - - fn pop(&self) -> PosixPath { - let mut cs = self.components.clone(); - if cs.len() != 0 { - cs.pop(); - } - PosixPath { - is_absolute: self.is_absolute, - components: cs, - } //..self } - } - - fn unsafe_join(&self, other: &PosixPath) -> PosixPath { - if other.is_absolute { - PosixPath { - is_absolute: true, - components: other.components.clone(), - } - } else { - self.push_rel(other) - } - } - - fn is_restricted(&self) -> bool { - false - } - - fn normalize(&self) -> PosixPath { - PosixPath { - is_absolute: self.is_absolute, - components: normalize(self.components), - } // ..self } - } - - fn is_absolute(&self) -> bool { - self.is_absolute - } - - fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() } - -} - - -impl ToStr for WindowsPath { - fn to_str(&self) -> ~str { - let mut s = ~""; - match self.host { - Some(ref h) => { - s.push_str("\\\\"); - s.push_str(*h); - } - None => { } - } - match self.device { - Some(ref d) => { - s.push_str(*d); - s.push_str(":"); - } - None => { } - } - if self.is_absolute { - s.push_str("\\"); - } - s + self.components.connect("\\") - } -} - -impl c_str::ToCStr for WindowsPath { - fn to_c_str(&self) -> c_str::CString { - self.to_str().to_c_str() - } - - unsafe fn to_c_str_unchecked(&self) -> c_str::CString { - self.to_str().to_c_str_unchecked() - } -} - -impl GenericPath for WindowsPath { - fn from_str(s: &str) -> WindowsPath { - let host; - let device; - let rest; - - match ( - windows::extract_drive_prefix(s), - windows::extract_unc_prefix(s), - ) { - (Some((ref d, ref r)), _) => { - host = None; - device = Some((*d).clone()); - rest = (*r).clone(); - } - (None, Some((ref h, ref r))) => { - host = Some((*h).clone()); - device = None; - rest = (*r).clone(); - } - (None, None) => { - host = None; - device = None; - rest = s.to_owned(); - } - } - - let components = rest.split_iter(windows::is_sep) - .filter_map(|s| if s.is_empty() {None} else {Some(s.to_owned())}) - .collect(); - - let is_absolute = (rest.len() != 0 && windows::is_sep(rest[0] as char)); - WindowsPath { - host: host, - device: device, - is_absolute: is_absolute, - components: components, - } - } - - fn with_dirname(&self, d: &str) -> WindowsPath { - let dpath = WindowsPath(d); - match self.filename() { - Some(ref f) => dpath.push(*f), - None => dpath, - } - } - - fn with_filename(&self, f: &str) -> WindowsPath { - assert!(! f.iter().all(windows::is_sep)); - self.dir_path().push(f) - } - - fn file_path(&self) -> WindowsPath { - WindowsPath { - host: None, - device: None, - is_absolute: false, - components: match self.filename() { - None => ~[], - Some(ref f) => ~[(*f).to_owned()], - } - } - } - - fn push(&self, s: &str) -> WindowsPath { - let mut v = self.components.clone(); - for s in s.split_iter(windows::is_sep) { - if !s.is_empty() { - v.push(s.to_owned()) - } - } - WindowsPath { components: v, ..(*self).clone() } - } - - fn push_many<S: Str>(&self, cs: &[S]) -> WindowsPath { - let mut v = self.components.clone(); - for e in cs.iter() { - for s in e.as_slice().split_iter(windows::is_sep) { - if !s.is_empty() { - v.push(s.to_owned()) - } - } - } - // tedious, but as-is, we can't use ..self - WindowsPath { - host: self.host.clone(), - device: self.device.clone(), - is_absolute: self.is_absolute, - components: v - } - } - - fn pop(&self) -> WindowsPath { - let mut cs = self.components.clone(); - if cs.len() != 0 { - cs.pop(); - } - WindowsPath { - host: self.host.clone(), - device: self.device.clone(), - is_absolute: self.is_absolute, - components: cs, - } - } - - fn unsafe_join(&self, other: &WindowsPath) -> WindowsPath { - /* rhs not absolute is simple push */ - if !other.is_absolute { - return self.push_many(other.components); - } - - /* if rhs has a host set, then the whole thing wins */ - match other.host { - Some(ref host) => { - return WindowsPath { - host: Some((*host).clone()), - device: other.device.clone(), - is_absolute: true, - components: other.components.clone(), - }; - } - _ => {} - } - - /* if rhs has a device set, then a part wins */ - match other.device { - Some(ref device) => { - return WindowsPath { - host: None, - device: Some((*device).clone()), - is_absolute: true, - components: other.components.clone(), - }; - } - _ => {} - } - - /* fallback: host and device of lhs win, but the - whole path of the right */ - WindowsPath { - host: self.host.clone(), - device: self.device.clone(), - is_absolute: self.is_absolute || other.is_absolute, - components: other.components.clone(), - } - } - - fn is_restricted(&self) -> bool { - match self.filestem() { - Some(stem) => { - // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_move and to_str_move to not do a unnecessary copy. - match stem.to_ascii().to_lower().to_str_ascii() { - ~"con" | ~"aux" | ~"com1" | ~"com2" | ~"com3" | ~"com4" | - ~"lpt1" | ~"lpt2" | ~"lpt3" | ~"prn" | ~"nul" => true, - _ => false - } - }, - None => false - } - } - - fn normalize(&self) -> WindowsPath { - WindowsPath { - host: self.host.clone(), - device: match self.device { - None => None, - - // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use - // to_ascii_move and to_str_move to not do a unnecessary copy. - Some(ref device) => Some(device.to_ascii().to_upper().to_str_ascii()) - }, - is_absolute: self.is_absolute, - components: normalize(self.components) - } - } - - fn is_absolute(&self) -> bool { - self.is_absolute - } - - fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() } - -} - -pub fn normalize(components: &[~str]) -> ~[~str] { - let mut cs = ~[]; - for c in components.iter() { - if *c == ~"." && components.len() > 1 { continue; } - if *c == ~"" { continue; } - if *c == ~".." && cs.len() != 0 { - cs.pop(); - continue; - } - cs.push((*c).clone()); - } - cs -} - -// Various posix helpers. -pub mod posix { - - #[inline] - pub fn is_sep(u: char) -> bool { - u == '/' - } - -} - -// Various windows helpers. -pub mod windows { - use libc; - use option::{None, Option, Some}; - - #[inline] - pub fn is_sep(u: char) -> bool { - u == '/' || u == '\\' - } - - pub fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> { - if (s.len() > 1 && - (s[0] == '\\' as u8 || s[0] == '/' as u8) && - s[0] == s[1]) { - let mut i = 2; - while i < s.len() { - if is_sep(s[i] as char) { - let pre = s.slice(2, i).to_owned(); - let rest = s.slice(i, s.len()).to_owned(); - return Some((pre, rest)); - } - i += 1; - } - } - None - } - - pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> { - #[fixed_stack_segment]; #[inline(never)]; - - unsafe { - if (s.len() > 1 && - libc::isalpha(s[0] as libc::c_int) != 0 && - s[1] == ':' as u8) { - let rest = if s.len() == 2 { - ~"" - } else { - s.slice(2, s.len()).to_owned() - }; - return Some((s.slice(0,1).to_owned(), rest)); - } - None - } - } -} - -#[cfg(test)] -mod tests { - use option::{None, Some}; - use path::{PosixPath, WindowsPath, windows}; - - #[test] - fn test_double_slash_collapsing() { - let path = PosixPath("tmp/"); - let path = path.push("/hmm"); - let path = path.normalize(); - assert_eq!(~"tmp/hmm", path.to_str()); - - let path = WindowsPath("tmp/"); - let path = path.push("/hmm"); - let path = path.normalize(); - assert_eq!(~"tmp\\hmm", path.to_str()); - } - - #[test] - fn test_filetype_foo_bar() { - let wp = PosixPath("foo.bar"); - assert_eq!(wp.filetype(), Some(".bar")); - - let wp = WindowsPath("foo.bar"); - assert_eq!(wp.filetype(), Some(".bar")); - } - - #[test] - fn test_filetype_foo() { - let wp = PosixPath("foo"); - assert_eq!(wp.filetype(), None); - - let wp = WindowsPath("foo"); - assert_eq!(wp.filetype(), None); - } - - #[test] - fn test_posix_paths() { - fn t(wp: &PosixPath, s: &str) { - let ss = wp.to_str(); - let sss = s.to_owned(); - if (ss != sss) { - debug2!("got {}", ss); - debug2!("expected {}", sss); - assert_eq!(ss, sss); - } - } - - t(&(PosixPath("hi")), "hi"); - t(&(PosixPath("/lib")), "/lib"); - t(&(PosixPath("hi/there")), "hi/there"); - t(&(PosixPath("hi/there.txt")), "hi/there.txt"); - - t(&(PosixPath("hi/there.txt")), "hi/there.txt"); - t(&(PosixPath("hi/there.txt") - .with_filetype("")), "hi/there"); - - t(&(PosixPath("/a/b/c/there.txt") - .with_dirname("hi")), "hi/there.txt"); - - t(&(PosixPath("hi/there.txt") - .with_dirname(".")), "./there.txt"); - - t(&(PosixPath("a/b/c") - .push("..")), "a/b/c/.."); - - t(&(PosixPath("there.txt") - .with_filetype("o")), "there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o")), "hi/there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o") - .with_dirname("/usr/lib")), - "/usr/lib/there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o") - .with_dirname("/usr/lib/")), - "/usr/lib/there.o"); - - t(&(PosixPath("hi/there.txt") - .with_filetype("o") - .with_dirname("/usr//lib//")), - "/usr/lib/there.o"); - - t(&(PosixPath("/usr/bin/rust") - .push_many([~"lib", ~"thingy.so"]) - .with_filestem("librustc")), - "/usr/bin/rust/lib/librustc.so"); - - } - - #[test] - fn test_posix_push_with_backslash() { - let a = PosixPath("/aaa/bbb"); - let b = a.push("x\\y"); // \ is not a file separator for posix paths - assert_eq!(a.components.len(), 2); - assert_eq!(b.components.len(), 3); - } - - #[test] - fn test_normalize() { - fn t(wp: &PosixPath, s: &str) { - let ss = wp.to_str(); - let sss = s.to_owned(); - if (ss != sss) { - debug2!("got {}", ss); - debug2!("expected {}", sss); - assert_eq!(ss, sss); - } - } - - t(&(PosixPath("hi/there.txt") - .with_dirname(".").normalize()), "there.txt"); - - t(&(PosixPath("a/b/../c/././/../foo.txt/").normalize()), - "a/foo.txt"); - - t(&(PosixPath("a/b/c") - .push("..").normalize()), "a/b"); - } - - #[test] - fn test_extract_unc_prefixes() { - assert!(windows::extract_unc_prefix("\\\\").is_none()); - assert!(windows::extract_unc_prefix("//").is_none()); - assert!(windows::extract_unc_prefix("\\\\hi").is_none()); - assert!(windows::extract_unc_prefix("//hi").is_none()); - assert!(windows::extract_unc_prefix("\\\\hi\\") == - Some((~"hi", ~"\\"))); - assert!(windows::extract_unc_prefix("//hi\\") == - Some((~"hi", ~"\\"))); - assert!(windows::extract_unc_prefix("\\\\hi\\there") == - Some((~"hi", ~"\\there"))); - assert!(windows::extract_unc_prefix("//hi/there") == - Some((~"hi", ~"/there"))); - assert!(windows::extract_unc_prefix( - "\\\\hi\\there\\friends.txt") == - Some((~"hi", ~"\\there\\friends.txt"))); - assert!(windows::extract_unc_prefix( - "//hi\\there\\friends.txt") == - Some((~"hi", ~"\\there\\friends.txt"))); - } - - #[test] - fn test_extract_drive_prefixes() { - assert!(windows::extract_drive_prefix("c").is_none()); - assert!(windows::extract_drive_prefix("c:") == - Some((~"c", ~""))); - assert!(windows::extract_drive_prefix("d:") == - Some((~"d", ~""))); - assert!(windows::extract_drive_prefix("z:") == - Some((~"z", ~""))); - assert!(windows::extract_drive_prefix("c:\\hi") == - Some((~"c", ~"\\hi"))); - assert!(windows::extract_drive_prefix("d:hi") == - Some((~"d", ~"hi"))); - assert!(windows::extract_drive_prefix("c:hi\\there.txt") == - Some((~"c", ~"hi\\there.txt"))); - assert!(windows::extract_drive_prefix("c:\\hi\\there.txt") == - Some((~"c", ~"\\hi\\there.txt"))); - } - - #[test] - fn test_windows_paths() { - fn t(wp: &WindowsPath, s: &str) { - let ss = wp.to_str(); - let sss = s.to_owned(); - if (ss != sss) { - debug2!("got {}", ss); - debug2!("expected {}", sss); - assert_eq!(ss, sss); - } - } - - t(&(WindowsPath("hi")), "hi"); - t(&(WindowsPath("hi/there")), "hi\\there"); - t(&(WindowsPath("hi/there.txt")), "hi\\there.txt"); - - t(&(WindowsPath("there.txt") - .with_filetype("o")), "there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o")), "hi\\there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o") - .with_dirname("c:\\program files A")), - "c:\\program files A\\there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o") - .with_dirname("c:\\program files B\\")), - "c:\\program files B\\there.o"); - - t(&(WindowsPath("hi/there.txt") - .with_filetype("o") - .with_dirname("c:\\program files C\\/")), - "c:\\program files C\\there.o"); - - t(&(WindowsPath("c:\\program files (x86)\\rust") - .push_many([~"lib", ~"thingy.dll"]) - .with_filename("librustc.dll")), - "c:\\program files (x86)\\rust\\lib\\librustc.dll"); - - t(&(WindowsPath("\\\\computer\\share") - .unsafe_join(&WindowsPath("\\a"))), - "\\\\computer\\a"); - - t(&(WindowsPath("//computer/share") - .unsafe_join(&WindowsPath("\\a"))), - "\\\\computer\\a"); - - t(&(WindowsPath("//computer/share") - .unsafe_join(&WindowsPath("\\\\computer\\share"))), - "\\\\computer\\share"); - - t(&(WindowsPath("C:/whatever") - .unsafe_join(&WindowsPath("//computer/share/a/b"))), - "\\\\computer\\share\\a\\b"); - - t(&(WindowsPath("C:") - .unsafe_join(&WindowsPath("D:/foo"))), - "D:\\foo"); - - t(&(WindowsPath("C:") - .unsafe_join(&WindowsPath("B"))), - "C:B"); - - t(&(WindowsPath("C:") - .unsafe_join(&WindowsPath("/foo"))), - "C:\\foo"); - - t(&(WindowsPath("C:\\") - .unsafe_join(&WindowsPath("\\bar"))), - "C:\\bar"); - - t(&(WindowsPath("") - .unsafe_join(&WindowsPath(""))), - ""); - - t(&(WindowsPath("") - .unsafe_join(&WindowsPath("a"))), - "a"); - - t(&(WindowsPath("") - .unsafe_join(&WindowsPath("C:\\a"))), - "C:\\a"); - - t(&(WindowsPath("c:\\foo") - .normalize()), - "C:\\foo"); - } - - #[test] - fn test_windows_path_restrictions() { - assert_eq!(WindowsPath("hi").is_restricted(), false); - assert_eq!(WindowsPath("C:\\NUL").is_restricted(), true); - assert_eq!(WindowsPath("C:\\COM1.TXT").is_restricted(), true); - assert_eq!(WindowsPath("c:\\prn.exe").is_restricted(), true); - } - - #[test] - fn test_is_ancestor_of() { - assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d"))); - assert!(!&PosixPath("/a/b/c/d").is_ancestor_of(&PosixPath("/a/b"))); - assert!(!&PosixPath("/a/b").is_ancestor_of(&PosixPath("/c/d"))); - assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d"))); - assert!(&PosixPath("/").is_ancestor_of(&PosixPath("/a/b/c"))); - assert!(!&PosixPath("/").is_ancestor_of(&PosixPath(""))); - assert!(!&PosixPath("/a/b/c").is_ancestor_of(&PosixPath(""))); - assert!(!&PosixPath("").is_ancestor_of(&PosixPath("/a/b/c"))); - - assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d"))); - assert!(!&WindowsPath("C:\\a\\b\\c\\d").is_ancestor_of(&WindowsPath("C:\\a\\b"))); - assert!(!&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\c\\d"))); - assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d"))); - assert!(&WindowsPath("C:\\").is_ancestor_of(&WindowsPath("C:\\a\\b\\c"))); - assert!(!&WindowsPath("C:\\").is_ancestor_of(&WindowsPath(""))); - assert!(!&WindowsPath("C:\\a\\b\\c").is_ancestor_of(&WindowsPath(""))); - assert!(!&WindowsPath("").is_ancestor_of(&WindowsPath("C:\\a\\b\\c"))); - - } - - #[test] - fn test_relative_to1() { - let p1 = PosixPath("/usr/bin/rustc"); - let p2 = PosixPath("/usr/lib/mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("../lib")); - - let p1 = WindowsPath("C:\\usr\\bin\\rustc"); - let p2 = WindowsPath("C:\\usr\\lib\\mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("..\\lib")); - - } - - #[test] - fn test_relative_to2() { - let p1 = PosixPath("/usr/bin/rustc"); - let p2 = PosixPath("/usr/bin/../lib/mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("../lib")); - - let p1 = WindowsPath("C:\\usr\\bin\\rustc"); - let p2 = WindowsPath("C:\\usr\\bin\\..\\lib\\mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("..\\lib")); - } - - #[test] - fn test_relative_to3() { - let p1 = PosixPath("/usr/bin/whatever/rustc"); - let p2 = PosixPath("/usr/lib/whatever/mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("../../lib/whatever")); - - let p1 = WindowsPath("C:\\usr\\bin\\whatever\\rustc"); - let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("..\\..\\lib\\whatever")); - - } - - #[test] - fn test_relative_to4() { - let p1 = PosixPath("/usr/bin/whatever/../rustc"); - let p2 = PosixPath("/usr/lib/whatever/mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("../lib/whatever")); - - let p1 = WindowsPath("C:\\usr\\bin\\whatever\\..\\rustc"); - let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("..\\lib\\whatever")); - - } - - #[test] - fn test_relative_to5() { - let p1 = PosixPath("/usr/bin/whatever/../rustc"); - let p2 = PosixPath("/usr/lib/whatever/../mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("../lib")); - - let p1 = WindowsPath("C:\\usr\\bin/whatever\\..\\rustc"); - let p2 = WindowsPath("C:\\usr\\lib\\whatever\\..\\mylib"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("..\\lib")); - } - - #[test] - fn test_relative_to6() { - let p1 = PosixPath("/1"); - let p2 = PosixPath("/2/3"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("2")); - - let p1 = WindowsPath("C:\\1"); - let p2 = WindowsPath("C:\\2\\3"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("2")); - - } - - #[test] - fn test_relative_to7() { - let p1 = PosixPath("/1/2"); - let p2 = PosixPath("/3"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, PosixPath("..")); - - let p1 = WindowsPath("C:\\1\\2"); - let p2 = WindowsPath("C:\\3"); - let res = p1.get_relative_to(&p2); - assert_eq!(res, WindowsPath("..")); - - } - - #[test] - fn test_relative_to8() { - let p1 = PosixPath("/home/brian/Dev/rust/build/").push_rel( - &PosixPath("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so")); - let p2 = PosixPath("/home/brian/Dev/rust/build/stage2/bin/..").push_rel( - &PosixPath("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so")); - let res = p1.get_relative_to(&p2); - debug2!("test_relative_to8: {} vs. {}", - res.to_str(), - PosixPath(".").to_str()); - assert_eq!(res, PosixPath(".")); - - let p1 = WindowsPath("C:\\home\\brian\\Dev\\rust\\build\\").push_rel( - &WindowsPath("stage2\\lib\\rustc\\i686-unknown-linux-gnu\\lib\\librustc.so")); - let p2 = WindowsPath("\\home\\brian\\Dev\\rust\\build\\stage2\\bin\\..").push_rel( - &WindowsPath("lib\\rustc\\i686-unknown-linux-gnu\\lib\\libstd.so")); - let res = p1.get_relative_to(&p2); - debug2!("test_relative_to8: {} vs. {}", - res.to_str(), - WindowsPath(".").to_str()); - assert_eq!(res, WindowsPath(".")); - - } - - - #[test] - fn test_is_parent_of() { - fn is_parent_of_pp(p: &PosixPath, q: &PosixPath) -> bool { - p.is_parent_of(q) - } - - assert!(is_parent_of_pp(&PosixPath("/a/b/c/d/e"), &PosixPath("c/d/e"))); - assert!(!is_parent_of_pp(&PosixPath("a/b/c/d/e"), &PosixPath("c/d/e"))); - assert!(!is_parent_of_pp(&PosixPath("/a/b/c/d/e"), &PosixPath("/c/d/e"))); - assert!(!is_parent_of_pp(&PosixPath(""), &PosixPath(""))); - assert!(!is_parent_of_pp(&PosixPath(""), &PosixPath("a/b/c"))); - assert!(is_parent_of_pp(&PosixPath("/a/b/c"), &PosixPath(""))); - assert!(is_parent_of_pp(&PosixPath("/a/b/c"), &PosixPath("a/b/c"))); - assert!(!is_parent_of_pp(&PosixPath("/a/b/c"), &PosixPath("d/e/f"))); - - fn is_parent_of_wp(p: &WindowsPath, q: &WindowsPath) -> bool { - p.is_parent_of(q) - } - - let abcde = WindowsPath("C:\\a\\b\\c\\d\\e"); - let rel_abcde = WindowsPath("a\\b\\c\\d\\e"); - let cde = WindowsPath("c\\d\\e"); - let slashcde = WindowsPath("C:\\c\\d\\e"); - let empty = WindowsPath(""); - let abc = WindowsPath("C:\\a\\b\\c"); - let rel_abc = WindowsPath("a\\b\\c"); - let def = WindowsPath("d\\e\\f"); - - assert!(is_parent_of_wp(&abcde, &cde)); - assert!(!is_parent_of_wp(&rel_abcde, &cde)); - assert!(!is_parent_of_wp(&abcde, &slashcde)); - assert!(!is_parent_of_wp(&empty, &empty)); - assert!(!is_parent_of_wp(&empty, &rel_abc)); - assert!(is_parent_of_wp(&abc, &empty)); - assert!(is_parent_of_wp(&abc, &rel_abc)); - assert!(!is_parent_of_wp(&abc, &def)); - } - -} |
