path2: Update based on more review feedback

Standardize the is_sep() functions to be the same in both posix and
windows, and re-export from path. Update extra::glob to use this.

Remove the usage of either, as it's going away.

Move the WindowsPath-specific methods out of WindowsPath and make them
top-level functions of path::windows instead. This way you cannot
accidentally write code that will fail to compile on non-windows
architectures without typing ::windows anywhere.

Remove GenericPath::from_c_str() and just impl BytesContainer for
CString instead.

Remove .join_path() and .push_path() and just implement BytesContainer
for Path instead.

Remove FilenameDisplay and add a boolean flag to Display instead.

Remove .each_parent(). It only had one caller, so just inline its
definition there.
This commit is contained in:
Kevin Ballard 2013-10-07 19:16:58 -07:00
parent c01a97b7a9
commit bab7eb20df
17 changed files with 274 additions and 390 deletions

View File

@ -189,7 +189,7 @@ fn run_pretty_test(config: &config, props: &TestProps, testfile: &Path) {
let mut expected = match props.pp_exact {
Some(ref file) => {
let filepath = testfile.dir_path().join_path(file);
let filepath = testfile.dir_path().join(file);
io::read_whole_file_str(&filepath).unwrap()
}
None => { srcs[srcs.len() - 2u].clone() }
@ -657,7 +657,7 @@ fn make_lib_name(config: &config, auxfile: &Path, testfile: &Path) -> Path {
// what we return here is not particularly important, as it
// happens; rustc ignores everything except for the directory.
let auxname = output_testname(auxfile);
aux_output_dir_name(config, testfile).join_path(&auxname)
aux_output_dir_name(config, testfile).join(&auxname)
}
fn make_exe_name(config: &config, testfile: &Path) -> Path {
@ -757,7 +757,7 @@ fn output_testname(testfile: &Path) -> Path {
fn output_base_name(config: &config, testfile: &Path) -> Path {
config.build_base
.join_path(&output_testname(testfile))
.join(&output_testname(testfile))
.with_extension(config.stage_id.as_slice())
}

View File

@ -24,6 +24,7 @@
*/
use std::{os, path};
use std::path::is_sep;
use sort;
@ -81,11 +82,7 @@ pub fn glob(pattern: &str) -> GlobIterator {
*/
pub fn glob_with(pattern: &str, options: MatchOptions) -> GlobIterator {
#[cfg(windows)]
use is_sep = std::path::windows::is_sep2;
#[cfg(not(windows))]
fn is_sep(c: char) -> bool { c <= '\x7F' && ::std::path::posix::is_sep(&(c as u8)) }
#[cfg(windows)]
fn check_windows_verbatim(p: &Path) -> bool { p.is_verbatim() }
fn check_windows_verbatim(p: &Path) -> bool { path::windows::is_verbatim(p) }
#[cfg(not(windows))]
fn check_windows_verbatim(_: &Path) -> bool { false }
@ -98,7 +95,7 @@ fn check_windows_verbatim(_: &Path) -> bool { false }
// since we can't very well find all UNC shares with a 1-letter server name.
return GlobIterator { root: root, dir_patterns: ~[], options: options, todo: ~[] };
}
root.push_path(pat_root.get_ref());
root.push(pat_root.get_ref());
}
let root_len = pat_root.map_move_default(0u, |p| p.as_vec().len());
@ -462,7 +459,7 @@ fn in_char_specifiers(specifiers: &[CharSpecifier], c: char, options: MatchOptio
/// A helper function to determine if two chars are (possibly case-insensitively) equal.
fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
if cfg!(windows) && path::windows::is_sep2(a) && path::windows::is_sep2(b) {
if cfg!(windows) && path::windows::is_sep(a) && path::windows::is_sep(b) {
true
} else if !case_sensitive && a.is_ascii() && b.is_ascii() {
// FIXME: work with non-ascii chars properly (issue #1347)
@ -472,16 +469,6 @@ fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
}
}
/// A helper function to determine if a char is a path separator on the current platform.
fn is_sep(c: char) -> bool {
if cfg!(windows) {
path::windows::is_sep2(c)
} else {
c <= '\x7F' && path::posix::is_sep(&(c as u8))
}
}
/**
* Configuration options to modify the behaviour of `Pattern::matches_with(..)`
*/

View File

@ -45,7 +45,7 @@ pub fn get_rpath_flags(sess: session::Session, out_filename: &Path)
fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
let r = filesearch::relative_target_lib_path(sess.opts.target_triple);
let mut p = sess.filesearch.sysroot().join_path(&r);
let mut p = sess.filesearch.sysroot().join(&r);
p.push(os::dll_filename("rustrt"));
p
}
@ -148,7 +148,7 @@ pub fn get_install_prefix_rpath(target_triple: &str) -> ~str {
let tlib = filesearch::relative_target_lib_path(target_triple);
let mut path = Path::new(install_prefix);
path.push_path(&tlib);
path.push(&tlib);
let path = os::make_absolute(&path);
// FIXME (#9639): This needs to handle non-utf8 paths
path.as_str().expect("non-utf8 component in rpath").to_owned()

View File

@ -100,7 +100,7 @@ fn get_target_lib_path(&self) -> Path {
}
fn get_target_lib_file_path(&self, file: &Path) -> Path {
let mut p = self.get_target_lib_path();
p.push_path(file);
p.push(file);
p
}
}
@ -148,7 +148,7 @@ pub fn relative_target_lib_path(target_triple: &str) -> Path {
fn make_target_lib_path(sysroot: &Path,
target_triple: &str) -> Path {
sysroot.join_path(&relative_target_lib_path(target_triple))
sysroot.join(&relative_target_lib_path(target_triple))
}
fn make_rustpkg_target_lib_path(dir: &Path,
@ -196,7 +196,7 @@ pub fn rust_path() -> ~[Path] {
}
None => ~[]
};
let cwd = os::getcwd();
let mut cwd = os::getcwd();
// now add in default entries
let cwd_dot_rust = cwd.join(".rust");
if !env_rust_path.contains(&cwd_dot_rust) {
@ -205,30 +205,27 @@ pub fn rust_path() -> ~[Path] {
if !env_rust_path.contains(&cwd) {
env_rust_path.push(cwd.clone());
}
do cwd.each_parent() |p| {
if !env_rust_path.contains(&p.join(".rust")) {
push_if_exists(&mut env_rust_path, p);
loop {
let f = cwd.pop();
if f.is_none() || bytes!("..") == f.unwrap() {
break;
}
true
};
cwd.push(".rust");
if !env_rust_path.contains(&cwd) && os::path_exists(&cwd) {
env_rust_path.push(cwd.clone());
}
cwd.pop();
}
let h = os::homedir();
for h in h.iter() {
if !env_rust_path.contains(&h.join(".rust")) {
push_if_exists(&mut env_rust_path, h);
let p = h.join(".rust");
if !env_rust_path.contains(&p) && os::path_exists(&p) {
env_rust_path.push(p);
}
}
env_rust_path
}
/// Adds p/.rust into vec, only if it exists
fn push_if_exists(vec: &mut ~[Path], p: &Path) {
let maybe_dir = p.join(".rust");
if os::path_exists(&maybe_dir) {
vec.push(maybe_dir);
}
}
// The name of the directory rustc expects libraries to be located.
// On Unix should be "lib", on windows "bin"
pub fn libdir() -> ~str {

View File

@ -95,20 +95,20 @@ pub fn new(mut source_workspace: Path,
// We search for sources under both src/ and build/ , because build/ is where
// automatically-checked-out sources go.
let mut result = source_workspace.join("src");
result.push_path(&id.path.dir_path());
result.push(&id.path.dir_path());
result.push(format!("{}-{}", id.short_name, id.version.to_str()));
to_try.push(result);
let mut result = source_workspace.join("src");
result.push_path(&id.path);
result.push(&id.path);
to_try.push(result);
let mut result = build_dir.join("src");
result.push_path(&id.path.dir_path());
result.push(&id.path.dir_path());
result.push_str(format!("{}-{}", id.short_name, id.version.to_str()));
to_try.push(result.clone());
output_names.push(result);
let mut other_result = build_dir.join("src");
other_result.push_path(&id.path);
other_result.push(&id.path);
to_try.push(other_result.clone());
output_names.push(other_result);
@ -146,7 +146,7 @@ pub fn new(mut source_workspace: Path,
source_workspace: source.clone(),
build_in_destination: build_in_destination,
destination_workspace: destination,
start_dir: start.join_path(&suffix),
start_dir: start.join(&suffix),
id: id,
libs: ~[],
mains: ~[],
@ -371,7 +371,7 @@ fn build_crates(&self,
cfgs: &[~str],
what: OutputType) {
for crate in crates.iter() {
let path = self.start_dir.join_path(&crate.file);
let path = self.start_dir.join(&crate.file);
debug2!("build_crates: compiling {}", path.display());
let cfgs = crate.cfgs + cfgs;
@ -416,7 +416,7 @@ pub fn declare_inputs(&self, prep: &mut workcache::Prep) {
debug2!("In declare inputs, self = {}", self.to_str());
for cs in to_do.iter() {
for c in cs.iter() {
let path = self.start_dir.join_path(&c.file);
let path = self.start_dir.join(&c.file);
debug2!("Declaring input: {}", path.display());
// FIXME (#9639): This needs to handle non-utf8 paths
prep.declare_input("file", path.as_str().unwrap(),

View File

@ -68,7 +68,7 @@ pub fn workspace_contains_package_id_(pkgid: &PkgId, workspace: &Path,
let mut found = None;
do os::walk_dir(&src_dir) |p| {
if os::path_is_dir(p) {
if *p == src_dir.join_path(&pkgid.path) || {
if *p == src_dir.join(&pkgid.path) || {
let pf = p.filename_str();
do pf.iter().any |&g| {
match split_version_general(g, '-') {
@ -196,7 +196,7 @@ pub fn library_in_workspace(path: &Path, short_name: &str, where: Target,
prefix = {}", short_name, where, workspace.display(), prefix);
let dir_to_search = match where {
Build => target_build_dir(workspace).join_path(path),
Build => target_build_dir(workspace).join(path),
Install => target_lib_dir(workspace)
};
@ -273,7 +273,7 @@ fn library_in(short_name: &str, version: &Version, dir_to_search: &Path) -> Opti
// Return the filename that matches, which we now know exists
// (if result_filename != None)
let abs_path = do result_filename.map |result_filename| {
let absolute_path = dir_to_search.join_path(&result_filename);
let absolute_path = dir_to_search.join(&result_filename);
debug2!("result_filename = {}", absolute_path.display());
absolute_path
};
@ -329,7 +329,7 @@ fn target_file_in_workspace(pkgid: &PkgId, workspace: &Path,
// Artifacts in the build directory live in a package-ID-specific subdirectory,
// but installed ones don't.
let result = match (where, what) {
(Build, _) => target_build_dir(workspace).join_path(&pkgid.path),
(Build, _) => target_build_dir(workspace).join(&pkgid.path),
(Install, Lib) => target_lib_dir(workspace),
(Install, _) => target_bin_dir(workspace)
};
@ -347,7 +347,7 @@ pub fn build_pkg_id_in_workspace(pkgid: &PkgId, workspace: &Path) -> Path {
use conditions::bad_path::cond;
let mut result = target_build_dir(workspace);
result.push_path(&pkgid.path);
result.push(&pkgid.path);
debug2!("Creating build dir {} for package id {}", result.display(),
pkgid.to_str());
if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) {
@ -370,7 +370,7 @@ pub fn mk_output_path(what: OutputType, where: Target,
// If we're installing, it just goes under <workspace>...
Install => workspace,
// and if we're just building, it goes in a package-specific subdir
Build => workspace.join_path(&pkg_id.path)
Build => workspace.join(&pkg_id.path)
};
debug2!("[{:?}:{:?}] mk_output_path: short_name = {}, path = {}", what, where,
if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() },
@ -388,7 +388,7 @@ pub fn mk_output_path(what: OutputType, where: Target,
os::EXE_SUFFIX))
};
if !output_path.is_absolute() {
output_path = os::getcwd().join_path(&output_path);
output_path = os::getcwd().join(&output_path);
}
debug2!("mk_output_path: returning {}", output_path.display());
output_path

View File

@ -416,15 +416,15 @@ fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) {
debug2!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
pkgid = {} pkgsrc start_dir = {}", workspace.display(),
in_rust_path(&workspace), is_git_dir(&workspace.join_path(&pkgid.path)),
in_rust_path(&workspace), is_git_dir(&workspace.join(&pkgid.path)),
pkgid.to_str(), pkg_src.start_dir.display());
// If workspace isn't in the RUST_PATH, and it's a git repo,
// then clone it into the first entry in RUST_PATH, and repeat
if !in_rust_path(&workspace) && is_git_dir(&workspace.join_path(&pkgid.path)) {
if !in_rust_path(&workspace) && is_git_dir(&workspace.join(&pkgid.path)) {
let mut out_dir = default_workspace().join("src");
out_dir.push_path(&pkgid.path);
let git_result = source_control::safe_git_clone(&workspace.join_path(&pkgid.path),
out_dir.push(&pkgid.path);
let git_result = source_control::safe_git_clone(&workspace.join(&pkgid.path),
&pkgid.version,
&out_dir);
match git_result {
@ -494,7 +494,7 @@ fn build(&self, pkg_src: &mut PkgSrc, what_to_build: &WhatToBuild) {
// We expect that p is relative to the package source's start directory,
// so check that assumption
debug2!("JustOne: p = {}", p.display());
assert!(os::path_exists(&pkg_src.start_dir.join_path(p)));
assert!(os::path_exists(&pkg_src.start_dir.join(p)));
if is_lib(p) {
PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
} else if is_main(p) {
@ -553,7 +553,7 @@ fn install(&self, mut pkg_src: PkgSrc, what: &WhatToBuild) -> (~[Path], ~[(~str,
debug2!("In declare inputs for {}", id.to_str());
for cs in to_do.iter() {
for c in cs.iter() {
let path = pkg_src.start_dir.join_path(&c.file);
let path = pkg_src.start_dir.join(&c.file);
debug2!("Recording input: {}", path.display());
// FIXME (#9639): This needs to handle non-utf8 paths
inputs.push((~"file", path.as_str().unwrap().to_owned()));

View File

@ -156,7 +156,7 @@ fn run_git(args: &[~str], env: Option<~[(~str, ~str)]>, cwd: &Path, err_msg: &st
fn init_git_repo(p: &Path) -> TempDir {
assert!(p.is_relative());
let tmp = TempDir::new("git_local").expect("couldn't create temp dir");
let work_dir = tmp.path().join_path(p);
let work_dir = tmp.path().join(p);
let work_dir_for_opts = work_dir.clone();
assert!(os::mkdir_recursive(&work_dir, U_RWX));
debug2!("Running: git init in {}", work_dir.display());
@ -793,7 +793,7 @@ fn test_package_request_version() {
== repo.join_many([".rust", "bin", "test_pkg_version"]));
let mut dir = target_build_dir(&repo.join(".rust"));
dir.push_path(&Path::new("src/mockgithub.com/catamorphism/test_pkg_version-0.3"));
dir.push(&Path::new("src/mockgithub.com/catamorphism/test_pkg_version-0.3"));
debug2!("dir = {}", dir.display());
assert!(os::path_is_dir(&dir));
assert!(os::path_exists(&dir.join("version-0.3-file.txt")));

View File

@ -177,7 +177,7 @@ pub fn compile_input(context: &BuildContext,
// not sure if we should support anything else
let mut out_dir = target_build_dir(workspace);
out_dir.push_path(&pkg_id.path);
out_dir.push(&pkg_id.path);
// Make the output directory if it doesn't exist already
assert!(os::mkdir_recursive(&out_dir, U_RWX));

View File

@ -98,7 +98,7 @@ pub fn parse_vers(vers: ~str) -> result::Result<semver::Version, ~str> {
pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
let rustpath = rust_path();
for rp in rustpath.iter() {
let local_path = rp.join_path(local_path);
let local_path = rp.join(local_path);
let git_dir = local_path.join(".git");
if !os::path_is_dir(&git_dir) {
continue;

View File

@ -78,7 +78,7 @@ pub fn getcwd() -> Path {
fail2!()
}
GenericPath::from_c_str(CString::new(buf as *c_char, false))
Path::new(CString::new(buf as *c_char, false))
}
}
}
@ -608,7 +608,7 @@ fn lookup() -> Path {
pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
let r = list_dir(p);
r.iter().advance(|q| {
let path = &p.join_path(q);
let path = &p.join(q);
f(path) && (!path_is_dir(path) || walk_dir(path, |p| f(p)))
})
}
@ -648,7 +648,7 @@ pub fn make_absolute(p: &Path) -> Path {
p.clone()
} else {
let mut ret = getcwd();
ret.push_path(p);
ret.push(p);
ret
}
}
@ -730,7 +730,7 @@ unsafe fn get_list(p: &Path) -> ~[Path] {
let mut entry_ptr = readdir(dir_ptr);
while (entry_ptr as uint != 0) {
let cstr = CString::new(rust_list_dir_val(entry_ptr), false);
paths.push(GenericPath::from_c_str(cstr));
paths.push(Path::new(cstr));
entry_ptr = readdir(dir_ptr);
}
closedir(dir_ptr);
@ -800,7 +800,7 @@ unsafe fn get_list(p: &Path) -> ~[Path] {
* This version prepends each entry with the directory.
*/
pub fn list_dir_path(p: &Path) -> ~[Path] {
list_dir(p).map(|f| p.join_path(f))
list_dir(p).map(|f| p.join(f))
}
/// Removes a directory at the specified path, after removing

View File

@ -30,9 +30,7 @@
## Usage
Usage of this module is fairly straightforward. Unless writing platform-specific
code, `Path` should be used to refer to the platform-native path, and methods
used should be restricted to those defined in `GenericPath`, and those methods
that are declared identically on both `PosixPath` and `WindowsPath`.
code, `Path` should be used to refer to the platform-native path.
Creation of a path is typically done with either `Path::new(some_str)` or
`Path::new(some_vec)`. This path can be modified with `.push()` and
@ -69,7 +67,6 @@
use container::Container;
use c_str::CString;
use clone::Clone;
use either::{Left, Right};
use fmt;
use iter::Iterator;
use option::{Option, None, Some};
@ -121,6 +118,19 @@
#[cfg(windows)]
pub use RevStrComponentIter = self::windows::RevStrComponentIter;
/// Typedef for the platform-native separator char func
#[cfg(unix)]
pub use is_sep = self::posix::is_sep;
/// Typedef for the platform-native separator char func
#[cfg(windows)]
pub use is_sep = self::windows::is_sep;
/// Typedef for the platform-native separator byte func
#[cfg(unix)]
pub use is_sep_byte = self::posix::is_sep_byte;
/// Typedef for the platform-native separator byte func
#[cfg(windows)]
pub use is_sep_byte = self::windows::is_sep_byte;
pub mod posix;
pub mod windows;
@ -162,19 +172,6 @@ fn new_opt<T: BytesContainer>(path: T) -> Option<Self> {
}
}
/// Creates a new Path from a CString.
/// The resulting Path will always be normalized.
///
/// See individual Path impls for potential restrictions.
#[inline]
fn from_c_str(path: CString) -> Self {
// CStrings can't contain NULs
let v = path.as_bytes();
// v is NUL-terminated. Strip it off
let v = v.slice_to(v.len()-1);
unsafe { GenericPathUnsafe::new_unchecked(v) }
}
/// Returns the path as a string, if possible.
/// If the path is not representable in utf-8, this returns None.
#[inline]
@ -195,15 +192,15 @@ fn as_str<'a>(&'a self) -> Option<&'a str> {
///
/// This will print the equivalent of `to_display_str()` when used with a {} format parameter.
fn display<'a>(&'a self) -> Display<'a, Self> {
Display{ path: self }
Display{ path: self, filename: false }
}
/// Returns an object that implements `fmt::Default` for printing filenames
///
/// This will print the equivalent of `to_filename_display_str()` when used with a {}
/// format parameter. If there is no filename, nothing will be printed.
fn filename_display<'a>(&'a self) -> FilenameDisplay<'a, Self> {
FilenameDisplay{ path: self }
fn filename_display<'a>(&'a self) -> Display<'a, Self> {
Display{ path: self, filename: true }
}
/// Returns the directory component of `self`, as a byte vector (with no trailing separator).
@ -314,13 +311,17 @@ fn set_filename<T: BytesContainer>(&mut self, filename: T) {
/// Raises the `null_byte` condition if the filestem contains a NUL.
fn set_filestem<T: BytesContainer>(&mut self, filestem: T) {
// borrowck is being a pain here
enum Value<T> {
Checked(T),
Unchecked(~[u8])
}
let val = {
match self.filename() {
None => Left(filestem),
None => Checked(filestem),
Some(name) => {
let dot = '.' as u8;
match name.rposition_elem(&dot) {
None | Some(0) => Left(filestem),
None | Some(0) => Checked(filestem),
Some(idx) => {
let mut v;
if contains_nul(filestem.container_as_bytes()) {
@ -336,15 +337,15 @@ fn set_filestem<T: BytesContainer>(&mut self, filestem: T) {
v.push_all(filestem);
}
v.push_all(name.slice_from(idx));
Right(v)
Unchecked(v)
}
}
}
}
};
match val {
Left(v) => self.set_filename(v),
Right(v) => unsafe { self.set_filename_unchecked(v) }
Checked(v) => self.set_filename(v),
Unchecked(v) => unsafe { self.set_filename_unchecked(v) }
}
}
/// Replaces the extension with the given byte vector or string.
@ -545,12 +546,6 @@ fn push<T: BytesContainer>(&mut self, path: T) {
unsafe { self.push_unchecked(path) }
}
}
/// Pushes a Path onto `self`.
/// If the argument represents an absolute path, it replaces `self`.
#[inline]
fn push_path(&mut self, path: &Self) {
self.push(path.as_vec())
}
/// Pushes multiple paths (as byte vectors or strings) onto `self`.
/// See `push` for details.
#[inline]
@ -590,14 +585,6 @@ fn join<T: BytesContainer>(&self, path: T) -> Self {
p.push(path);
p
}
/// Returns a new Path constructed by joining `self` with the given path.
/// If the given path is absolute, the new Path will represent just that.
#[inline]
fn join_path(&self, path: &Self) -> Self {
let mut p = self.clone();
p.push_path(path);
p
}
/// Returns a new Path constructed by joining `self` with the given paths
/// (as byte vectors or strings).
/// See `join` for details.
@ -632,21 +619,6 @@ fn is_relative(&self) -> bool {
/// paths refer to separate drives, an absolute path is returned.
fn path_relative_from(&self, base: &Self) -> Option<Self>;
/// Executes a callback with the receiver and every parent
fn each_parent(&self, f: &fn(&Self) -> bool) -> bool {
let mut p = self.clone();
loop {
if !f(&p) {
return false;
}
let f = p.pop();
if f.is_none() || bytes!("..") == f.unwrap() {
break;
}
}
true
}
/// Returns whether the relative path `child` is a suffix of `self`.
fn ends_with_path(&self, child: &Self) -> bool;
}
@ -674,7 +646,7 @@ fn container_as_str<'a>(&'a self) -> &'a str {
fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
str::from_utf8_slice_opt(self.container_as_bytes())
}
/// Returns whether the concrete receiver is a string type
/// Returns whether .container_as_str() is guaranteed to not fail
// FIXME (#8888): Remove unused arg once ::<for T> works
#[inline]
fn is_str(_: Option<Self>) -> bool { false }
@ -703,11 +675,8 @@ pub trait GenericPathUnsafe {
/// Helper struct for printing paths with format!()
pub struct Display<'self, P> {
priv path: &'self P
}
/// Helper struct for printing filenames with format!()
pub struct FilenameDisplay<'self, P> {
priv path: &'self P
priv path: &'self P,
priv filename: bool
}
impl<'self, P: GenericPath> fmt::Default for Display<'self, P> {
@ -724,7 +693,14 @@ impl<'self, P: GenericPath> ToStr for Display<'self, P> {
/// If the path is not UTF-8, invalid sequences with be replaced with the
/// unicode replacement char. This involves allocation.
fn to_str(&self) -> ~str {
from_utf8_with_replacement(self.path.as_vec())
if self.filename {
match self.path.filename() {
None => ~"",
Some(v) => from_utf8_with_replacement(v)
}
} else {
from_utf8_with_replacement(self.path.as_vec())
}
}
}
@ -735,47 +711,9 @@ impl<'self, P: GenericPath> Display<'self, P> {
/// unicode replacement char. This involves allocation.
#[inline]
pub fn with_str<T>(&self, f: &fn(&str) -> T) -> T {
match self.path.as_str() {
Some(s) => f(s),
None => {
let s = self.to_str();
f(s.as_slice())
}
}
}
}
impl<'self, P: GenericPath> fmt::Default for FilenameDisplay<'self, P> {
fn fmt(d: &FilenameDisplay<P>, f: &mut fmt::Formatter) {
do d.with_str |s| {
f.pad(s)
}
}
}
impl<'self, P: GenericPath> ToStr for FilenameDisplay<'self, P> {
/// Returns the filename as a string. If there is no filename, ~"" will be
/// returned.
///
/// If the filename is not UTF-8, invalid sequences will be replaced with
/// the unicode replacement char. This involves allocation.
fn to_str(&self) -> ~str {
match self.path.filename() {
None => ~"",
Some(v) => from_utf8_with_replacement(v)
}
}
}
impl<'self, P: GenericPath> FilenameDisplay<'self, P> {
/// Provides the filename as a string to a closure. If there is no
/// filename, "" will be provided.
///
/// If the filename is not UTF-8, invalid sequences will be replaced with
/// the unicode replacement char. This involves allocation.
#[inline]
pub fn with_str<T>(&self, f: &fn(&str) -> T) -> T {
match self.path.filename_str() {
let opt = if self.filename { self.path.filename_str() }
else { self.path.as_str() };
match opt {
Some(s) => f(s),
None => {
let s = self.to_str();
@ -865,6 +803,14 @@ fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
}
}
impl BytesContainer for CString {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
let s = self.as_bytes();
s.slice_to(s.len()-1)
}
}
#[inline(always)]
fn contains_nul(v: &[u8]) -> bool {
v.iter().any(|&x| x == 0)
@ -1121,13 +1067,13 @@ mod tests {
use c_str::ToCStr;
#[test]
fn test_from_c_str() {
fn test_cstring() {
let input = "/foo/bar/baz";
let path: PosixPath = GenericPath::from_c_str(input.to_c_str());
let path: PosixPath = PosixPath::new(input.to_c_str());
assert_eq!(path.as_vec(), input.as_bytes());
let input = "\\foo\\bar\\baz";
let path: WindowsPath = GenericPath::from_c_str(input.to_c_str());
let path: WindowsPath = WindowsPath::new(input.to_c_str());
assert_eq!(path.as_str().unwrap(), input.as_slice());
}
}

View File

@ -48,12 +48,19 @@ pub struct Path {
}
/// The standard path separator character
pub static sep: u8 = '/' as u8;
pub static sep: char = '/';
static sep_byte: u8 = sep as u8;
/// Returns whether the given byte is a path separator
#[inline]
pub fn is_sep(u: &u8) -> bool {
*u == sep
pub fn is_sep_byte(u: &u8) -> bool {
*u as char == sep
}
/// Returns whether the given char is a path separator
#[inline]
pub fn is_sep(c: char) -> bool {
c == sep
}
impl Eq for Path {
@ -89,11 +96,29 @@ fn iter_bytes(&self, lsb0: bool, f: &fn(buf: &[u8]) -> bool) -> bool {
}
}
impl BytesContainer for Path {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
self.as_vec()
}
#[inline]
fn container_into_owned_bytes(self) -> ~[u8] {
self.into_vec()
}
}
impl<'self> BytesContainer for &'self Path {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
self.as_vec()
}
}
impl GenericPathUnsafe for Path {
unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
let path = Path::normalize(path.container_as_bytes());
assert!(!path.is_empty());
let idx = path.rposition_elem(&sep);
let idx = path.rposition_elem(&sep_byte);
Path{ repr: path, sepidx: idx }
}
@ -106,11 +131,11 @@ unsafe fn set_dirname_unchecked<T: BytesContainer>(&mut self, dirname: T) {
None => {
let mut v = vec::with_capacity(dirname.len() + self.repr.len() + 1);
v.push_all(dirname);
v.push(sep);
v.push(sep_byte);
v.push_all(self.repr);
self.repr = Path::normalize(v);
}
Some(0) if self.repr.len() == 1 && self.repr[0] == sep => {
Some(0) if self.repr.len() == 1 && self.repr[0] == sep_byte => {
self.repr = Path::normalize(dirname);
}
Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
@ -127,7 +152,7 @@ unsafe fn set_dirname_unchecked<T: BytesContainer>(&mut self, dirname: T) {
self.repr = Path::normalize(v);
}
}
self.sepidx = self.repr.rposition_elem(&sep);
self.sepidx = self.repr.rposition_elem(&sep_byte);
}
unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
@ -136,7 +161,7 @@ unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
None if bytes!("..") == self.repr => {
let mut v = vec::with_capacity(3 + filename.len());
v.push_all(dot_dot_static);
v.push(sep);
v.push(sep_byte);
v.push_all(filename);
self.repr = Path::normalize(v);
}
@ -146,7 +171,7 @@ unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len());
v.push_all(self.repr);
v.push(sep);
v.push(sep_byte);
v.push_all(filename);
self.repr = Path::normalize(v);
}
@ -157,22 +182,22 @@ unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
self.repr = Path::normalize(v);
}
}
self.sepidx = self.repr.rposition_elem(&sep);
self.sepidx = self.repr.rposition_elem(&sep_byte);
}
unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
let path = path.container_as_bytes();
if !path.is_empty() {
if path[0] == sep {
if path[0] == sep_byte {
self.repr = Path::normalize(path);
} else {
let mut v = vec::with_capacity(self.repr.len() + path.len() + 1);
v.push_all(self.repr);
v.push(sep);
v.push(sep_byte);
v.push_all(path);
self.repr = Path::normalize(v);
}
self.sepidx = self.repr.rposition_elem(&sep);
self.sepidx = self.repr.rposition_elem(&sep_byte);
}
}
}
@ -228,7 +253,7 @@ fn pop(&mut self) -> Option<~[u8]> {
} else {
self.repr.truncate(idx);
}
self.sepidx = self.repr.rposition_elem(&sep);
self.sepidx = self.repr.rposition_elem(&sep_byte);
Some(v)
}
}
@ -244,7 +269,7 @@ fn root_path(&self) -> Option<Path> {
#[inline]
fn is_absolute(&self) -> bool {
self.repr[0] == sep
self.repr[0] == sep_byte
}
fn is_ancestor_of(&self, other: &Path) -> bool {
@ -305,7 +330,7 @@ fn path_relative_from(&self, base: &Path) -> Option<Path> {
}
}
}
Some(Path::new(comps.connect_vec(&sep)))
Some(Path::new(comps.connect_vec(&sep_byte)))
}
}
@ -347,14 +372,14 @@ pub fn new_opt<T: BytesContainer>(path: T) -> Option<Path> {
fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
// borrowck is being very picky
let val = {
let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == sep;
let is_abs = !v.as_slice().is_empty() && v.as_slice()[0] == sep_byte;
let v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
let comps = normalize_helper(v_, is_abs);
match comps {
None => None,
Some(comps) => {
if is_abs && comps.is_empty() {
Some(~[sep])
Some(~[sep_byte])
} else {
let n = if is_abs { comps.len() } else { comps.len() - 1} +
comps.iter().map(|v| v.len()).sum();
@ -367,7 +392,7 @@ fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
}
}
for comp in it {
v.push(sep);
v.push(sep_byte);
v.push_all(comp);
}
Some(v)
@ -386,10 +411,10 @@ fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
/// /a/b/c and a/b/c yield the same set of components.
/// A path of "/" yields no components. A path of "." yields one component.
pub fn component_iter<'a>(&'a self) -> ComponentIter<'a> {
let v = if self.repr[0] == sep {
let v = if self.repr[0] == sep_byte {
self.repr.slice_from(1)
} else { self.repr.as_slice() };
let mut ret = v.split_iter(is_sep);
let mut ret = v.split_iter(is_sep_byte);
if v.is_empty() {
// consume the empty "" component
ret.next();
@ -400,10 +425,10 @@ pub fn component_iter<'a>(&'a self) -> ComponentIter<'a> {
/// Returns an iterator that yields each component of the path in reverse.
/// See component_iter() for details.
pub fn rev_component_iter<'a>(&'a self) -> RevComponentIter<'a> {
let v = if self.repr[0] == sep {
let v = if self.repr[0] == sep_byte {
self.repr.slice_from(1)
} else { self.repr.as_slice() };
let mut ret = v.rsplit_iter(is_sep);
let mut ret = v.rsplit_iter(is_sep_byte);
if v.is_empty() {
// consume the empty "" component
ret.next();
@ -432,7 +457,7 @@ fn normalize_helper<'a>(v: &'a [u8], is_abs: bool) -> Option<~[&'a [u8]]> {
let mut comps: ~[&'a [u8]] = ~[];
let mut n_up = 0u;
let mut changed = false;
for comp in v.split_iter(is_sep) {
for comp in v.split_iter(is_sep_byte) {
if comp.is_empty() { changed = true }
else if comp == bytes!(".") { changed = true }
else if comp == bytes!("..") {
@ -928,7 +953,7 @@ macro_rules! t(
{
let mut p = Path::new($path);
let push = Path::new($push);
p.push_path(&push);
p.push(&push);
assert_eq!(p.as_str(), Some($exp));
}
)
@ -1049,7 +1074,7 @@ macro_rules! t(
{
let path = Path::new($path);
let join = Path::new($join);
let res = path.join_path(&join);
let res = path.join(&join);
assert_eq!(res.as_str(), Some($exp));
}
)
@ -1598,58 +1623,4 @@ macro_rules! t(
// str_component_iter is a wrapper around component_iter, so no need to do
// the full set of tests
}
#[test]
fn test_each_parent() {
assert!(Path::new("/foo/bar").each_parent(|_| true));
assert!(!Path::new("/foo/bar").each_parent(|_| false));
macro_rules! t(
(s: $path:expr, $exp:expr) => (
{
let path = Path::new($path);
let exp: &[&str] = $exp;
let mut comps = exp.iter().map(|&x|x);
do path.each_parent |p| {
let p = p.as_str();
assert!(p.is_some());
let e = comps.next();
assert!(e.is_some());
assert_eq!(p.unwrap(), e.unwrap());
true
};
assert!(comps.next().is_none());
}
);
(v: $path:expr, $exp:expr) => (
{
let path = Path::new($path);
let exp: &[&[u8]] = $exp;
let mut comps = exp.iter().map(|&x|x);
do path.each_parent |p| {
let p = p.as_vec();
let e = comps.next();
assert!(e.is_some());
assert_eq!(p, e.unwrap());
true
};
assert!(comps.next().is_none());
}
)
)
t!(s: "/foo/bar", ["/foo/bar", "/foo", "/"]);
t!(s: "/foo/bar/baz", ["/foo/bar/baz", "/foo/bar", "/foo", "/"]);
t!(s: "/foo", ["/foo", "/"]);
t!(s: "/", ["/"]);
t!(s: "foo/bar/baz", ["foo/bar/baz", "foo/bar", "foo", "."]);
t!(s: "foo/bar", ["foo/bar", "foo", "."]);
t!(s: "foo", ["foo", "."]);
t!(s: ".", ["."]);
t!(s: "..", [".."]);
t!(s: "../../foo", ["../../foo", "../.."]);
t!(v: b!("foo/bar", 0x80), [b!("foo/bar", 0x80), b!("foo"), b!(".")]);
t!(v: b!(0xff, "/bar"), [b!(0xff, "/bar"), b!(0xff), b!(".")]);
}
}

View File

@ -121,6 +121,44 @@ fn iter_bytes(&self, lsb0: bool, f: &fn(&[u8]) -> bool) -> bool {
}
}
impl BytesContainer for Path {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
self.as_vec()
}
#[inline]
fn container_into_owned_bytes(self) -> ~[u8] {
self.into_vec()
}
#[inline]
fn container_as_str<'a>(&'a self) -> &'a str {
self.as_str().unwrap()
}
#[inline]
fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
self.as_str()
}
#[inline]
fn is_str(_: Option<Path>) -> bool { true }
}
impl<'self> BytesContainer for &'self Path {
#[inline]
fn container_as_bytes<'a>(&'a self) -> &'a [u8] {
self.as_vec()
}
#[inline]
fn container_as_str<'a>(&'a self) -> &'a str {
self.as_str().unwrap()
}
#[inline]
fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
self.as_str()
}
#[inline]
fn is_str(_: Option<&'self Path>) -> bool { true }
}
impl GenericPathUnsafe for Path {
/// See `GenericPathUnsafe::from_vec_unchecked`.
///
@ -235,7 +273,7 @@ unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
fn is_vol_abs(path: &str, prefix: Option<PathPrefix>) -> bool {
// assume prefix is Some(DiskPrefix)
let rest = path.slice_from(prefix_len(prefix));
!rest.is_empty() && rest[0].is_ascii() && is_sep2(rest[0] as char)
!rest.is_empty() && rest[0].is_ascii() && is_sep(rest[0] as char)
}
fn shares_volume(me: &Path, path: &str) -> bool {
// path is assumed to have a prefix of Some(DiskPrefix)
@ -246,8 +284,8 @@ fn shares_volume(me: &Path, path: &str) -> bool {
}
}
fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
u.is_ascii() && if prefix_is_verbatim(prefix) { is_sep(u as char) }
else { is_sep2(u as char) }
if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) }
else { is_sep(u as char) }
}
fn replace_path(me: &mut Path, path: &str, prefix: Option<PathPrefix>) {
@ -262,7 +300,7 @@ fn replace_path(me: &mut Path, path: &str, prefix: Option<PathPrefix>) {
fn append_path(me: &mut Path, path: &str) {
// appends a path that has no prefix
// if me is verbatim, we need to pre-normalize the new path
let path_ = if me.is_verbatim() { Path::normalize__(path, None) }
let path_ = if is_verbatim(me) { Path::normalize__(path, None) }
else { None };
let pathlen = path_.map_default(path.len(), |p| p.len());
let mut s = str::with_capacity(me.repr.len() + 1 + pathlen);
@ -291,7 +329,7 @@ fn append_path(me: &mut Path, path: &str) {
}
None if !path.is_empty() && is_sep_(self.prefix, path[0]) => {
// volume-relative path
if self.prefix().is_some() {
if self.prefix.is_some() {
// truncate self down to the prefix, then append
let n = self.prefix_len();
self.repr.truncate(n);
@ -418,11 +456,6 @@ fn file_path(&self) -> Option<Path> {
self.filename_str().map_move(|s| unsafe { GenericPathUnsafe::new_unchecked(s) })
}
#[inline]
fn push_path(&mut self, path: &Path) {
self.push(path.as_str().unwrap())
}
#[inline]
fn pop(&mut self) -> Option<~[u8]> {
self.pop_str().map_move(|s| s.into_bytes())
@ -463,7 +496,7 @@ fn root_path(&self) -> Option<Path> {
}
_ => self.repr.slice_to(self.prefix_len())
}))
} else if self.is_vol_relative() {
} else if is_vol_relative(self) {
Some(Path::new(self.repr.slice_to(1)))
} else {
None
@ -493,14 +526,14 @@ fn is_absolute(&self) -> bool {
#[inline]
fn is_relative(&self) -> bool {
self.prefix.is_none() && !self.is_vol_relative()
self.prefix.is_none() && !is_vol_relative(self)
}
fn is_ancestor_of(&self, other: &Path) -> bool {
if !self.equiv_prefix(other) {
false
} else if self.is_absolute() != other.is_absolute() ||
self.is_vol_relative() != other.is_vol_relative() {
is_vol_relative(self) != is_vol_relative(other) {
false
} else {
let mut ita = self.str_component_iter().map(|x|x.unwrap());
@ -544,8 +577,8 @@ fn comp_requires_verbatim(s: &str) -> bool {
} else {
None
}
} else if self.is_vol_relative() != base.is_vol_relative() {
if self.is_vol_relative() {
} else if is_vol_relative(self) != is_vol_relative(base) {
if is_vol_relative(self) {
Some(self.clone())
} else {
None
@ -555,8 +588,8 @@ fn comp_requires_verbatim(s: &str) -> bool {
let mut itb = base.str_component_iter().map(|x|x.unwrap());
let mut comps = ~[];
let a_verb = self.is_verbatim();
let b_verb = base.is_verbatim();
let a_verb = is_verbatim(self);
let b_verb = is_verbatim(base);
loop {
match (ita.next(), itb.next()) {
(None, None) => break,
@ -598,20 +631,6 @@ fn comp_requires_verbatim(s: &str) -> bool {
}
}
fn each_parent(&self, f: &fn(&Path) -> bool) -> bool {
let mut p = self.clone();
loop {
if !f(&p) {
return false;
}
let f = p.pop();
if f.is_none() || (!p.is_verbatim() && bytes!("..") == f.unwrap()) {
break;
}
}
true
}
fn ends_with_path(&self, child: &Path) -> bool {
if !child.is_relative() { return false; }
let mut selfit = self.str_component_iter().invert();
@ -694,34 +713,6 @@ fn convert<'a>(x: Option<&'a str>) -> &'a [u8] {
self.rev_str_component_iter().map(convert)
}
/// Returns whether the path is considered "volume-relative", which means a path
/// that looks like "\foo". Paths of this form are relative to the current volume,
/// but absolute within that volume.
#[inline]
pub fn is_vol_relative(&self) -> bool {
self.prefix.is_none() && self.repr[0] == sep as u8
}
/// Returns whether the path is considered "cwd-relative", which means a path
/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths
/// of this form are relative to the cwd on the given volume.
#[inline]
pub fn is_cwd_relative(&self) -> bool {
self.prefix == Some(DiskPrefix) && !self.is_absolute()
}
/// Returns the PathPrefix for this Path
#[inline]
pub fn prefix(&self) -> Option<PathPrefix> {
self.prefix
}
/// Returns whether the prefix is a verbatim prefix, i.e. \\?\
#[inline]
pub fn is_verbatim(&self) -> bool {
prefix_is_verbatim(self.prefix)
}
fn equiv_prefix(&self, other: &Path) -> bool {
match (self.prefix, other.prefix) {
(Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
@ -866,8 +857,8 @@ fn update_sepidx(&mut self) {
let s = if self.has_nonsemantic_trailing_slash() {
self.repr.slice_to(self.repr.len()-1)
} else { self.repr.as_slice() };
let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep2 }
else { is_sep });
let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep }
else { is_sep_verbatim });
let prefixlen = self.prefix_len();
self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) });
}
@ -893,7 +884,7 @@ fn sepidx_or_prefix_len(&self) -> Option<(uint,uint,uint)> {
}
fn has_nonsemantic_trailing_slash(&self) -> bool {
self.is_verbatim() && self.repr.len() > self.prefix_len()+1 &&
is_verbatim(self) && self.repr.len() > self.prefix_len()+1 &&
self.repr[self.repr.len()-1] == sep as u8
}
@ -905,23 +896,65 @@ fn update_normalized<S: Str>(&mut self, s: S) {
}
}
/// Returns whether the path is considered "volume-relative", which means a path
/// that looks like "\foo". Paths of this form are relative to the current volume,
/// but absolute within that volume.
#[inline]
pub fn is_vol_relative(path: &Path) -> bool {
path.prefix.is_none() && is_sep_byte(&path.repr[0])
}
/// Returns whether the path is considered "cwd-relative", which means a path
/// with a volume prefix that is not absolute. This look like "C:foo.txt". Paths
/// of this form are relative to the cwd on the given volume.
#[inline]
pub fn is_cwd_relative(path: &Path) -> bool {
path.prefix == Some(DiskPrefix) && !path.is_absolute()
}
/// Returns the PathPrefix for this Path
#[inline]
pub fn prefix(path: &Path) -> Option<PathPrefix> {
path.prefix
}
/// Returns whether the Path's prefix is a verbatim prefix, i.e. \\?\
#[inline]
pub fn is_verbatim(path: &Path) -> bool {
prefix_is_verbatim(path.prefix)
}
/// The standard path separator character
pub static sep: char = '\\';
/// The alternative path separator character
pub static sep2: char = '/';
/// Returns whether the given byte is a path separator.
/// Only allows the primary separator '\'; use is_sep2 to allow '/'.
/// Returns whether the given char is a path separator.
/// Allows both the primary separator '\' and the alternative separator '/'.
#[inline]
pub fn is_sep(c: char) -> bool {
c == sep || c == sep2
}
/// Returns whether the given char is a path separator.
/// Only allows the primary separator '\'; use is_sep to allow '/'.
#[inline]
pub fn is_sep_verbatim(c: char) -> bool {
c == sep
}
/// Returns whether the given byte is a path separator.
/// Allows both the primary separator '\' and the alternative separator '/'.
#[inline]
pub fn is_sep2(c: char) -> bool {
c == sep || c == sep2
pub fn is_sep_byte(u: &u8) -> bool {
*u as char == sep || *u as char == sep2
}
/// Returns whether the given byte is a path separator.
/// Only allows the primary separator '\'; use is_sep_byte to allow '/'.
#[inline]
pub fn is_sep_byte_verbatim(u: &u8) -> bool {
*u as char == sep
}
/// Prefix types for Path
@ -953,7 +986,7 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
if path.starts_with("UNC\\") {
// \\?\UNC\server\share
path = path.slice_from(4);
let (idx_a, idx_b) = match parse_two_comps(path, is_sep) {
let (idx_a, idx_b) = match parse_two_comps(path, is_sep_verbatim) {
Some(x) => x,
None => (path.len(), 0)
};
@ -977,7 +1010,7 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
let idx = path.find('\\').unwrap_or(path.len());
return Some(DeviceNSPrefix(idx));
}
match parse_two_comps(path, is_sep2) {
match parse_two_comps(path, is_sep) {
Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => {
// \\server\share
return Some(UNCPrefix(idx_a, idx_b));
@ -1006,14 +1039,14 @@ fn parse_two_comps<'a>(mut path: &'a str, f: &fn(char)->bool) -> Option<(uint, u
// None result means the string didn't need normalizing
fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool,Option<~[&'a str]>) {
let f = if !prefix_is_verbatim(prefix) { is_sep2 } else { is_sep };
let f = if !prefix_is_verbatim(prefix) { is_sep } else { is_sep_verbatim };
let is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
let s_ = s.slice_from(prefix_len(prefix));
let s_ = if is_abs { s_.slice_from(1) } else { s_ };
if is_abs && s_.is_empty() {
return (is_abs, match prefix {
Some(DiskPrefix) | None => (if is_sep(s.char_at(prefix_len(prefix))) { None }
Some(DiskPrefix) | None => (if is_sep_verbatim(s.char_at(prefix_len(prefix))) { None }
else { Some(~[]) }),
Some(_) => Some(~[]), // need to trim the trailing separator
});
@ -1036,7 +1069,7 @@ fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool,Option<
} else { comps.push(comp) }
}
if !changed && !prefix_is_verbatim(prefix) {
changed = s.find(is_sep2).is_some();
changed = s.find(is_sep).is_some();
}
if changed {
if comps.is_empty() && !is_abs && prefix.is_none() {
@ -1078,8 +1111,8 @@ fn prefix_len(p: Option<PathPrefix>) -> uint {
}
fn prefix_is_sep(p: Option<PathPrefix>, c: u8) -> bool {
c.is_ascii() && if !prefix_is_verbatim(p) { is_sep2(c as char) }
else { is_sep(c as char) }
c.is_ascii() && if !prefix_is_verbatim(p) { is_sep(c as char) }
else { is_sep_verbatim(c as char) }
}
// Stat support
@ -1636,9 +1669,9 @@ macro_rules! t(
// we do want to check one odd case though to ensure the prefix is re-parsed
let mut p = Path::new("\\\\?\\C:");
assert_eq!(p.prefix(), Some(VerbatimPrefix(2)));
assert_eq!(prefix(&p), Some(VerbatimPrefix(2)));
p.push("foo");
assert_eq!(p.prefix(), Some(VerbatimDiskPrefix));
assert_eq!(prefix(&p), Some(VerbatimDiskPrefix));
assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo"));
// and another with verbatim non-normalized paths
@ -1654,7 +1687,7 @@ macro_rules! t(
{
let mut p = Path::new($path);
let push = Path::new($push);
p.push_path(&push);
p.push(&push);
assert_eq!(p.as_str(), Some($exp));
}
)
@ -1837,7 +1870,7 @@ macro_rules! t(
{
let path = Path::new($path);
let join = Path::new($join);
let res = path.join_path(&join);
let res = path.join(&join);
assert_eq!(res.as_str(), Some($exp));
}
)
@ -1849,7 +1882,7 @@ macro_rules! t(
t!(s: "a\\b", "\\c\\d", "\\c\\d");
t!(s: ".", "a\\b", "a\\b");
t!(s: "\\", "a\\b", "\\a\\b");
// join_path is implemented using push_path, so there's no need for
// join is implemented using push, so there's no need for
// the full set of prefix tests
}
@ -2217,11 +2250,11 @@ macro_rules! t(
let b = path.is_absolute();
assert!(b == abs, "Path '{}'.is_absolute(): expected {:?}, found {:?}",
path.as_str().unwrap(), abs, b);
let b = path.is_vol_relative();
assert!(b == vol, "Path '{}'.is_vol_relative(): expected {:?}, found {:?}",
let b = is_vol_relative(&path);
assert!(b == vol, "is_vol_relative('{}'): expected {:?}, found {:?}",
path.as_str().unwrap(), vol, b);
let b = path.is_cwd_relative();
assert!(b == cwd, "Path '{}'.is_cwd_relative(): expected {:?}, found {:?}",
let b = is_cwd_relative(&path);
assert!(b == cwd, "is_cwd_relative('{}'): expected {:?}, found {:?}",
path.as_str().unwrap(), cwd, b);
let b = path.is_relative();
assert!(b == rel, "Path '{}'.is_relativf(): expected {:?}, found {:?}",
@ -2614,54 +2647,4 @@ macro_rules! t(
t!(s: ".", [b!(".")]);
// since this is really a wrapper around str_component_iter, those tests suffice
}
#[test]
fn test_each_parent() {
assert!(Path::new("/foo/bar").each_parent(|_| true));
assert!(!Path::new("/foo/bar").each_parent(|_| false));
macro_rules! t(
(s: $path:expr, $exp:expr) => (
{
let path = Path::new($path);
let exp: &[&str] = $exp;
let mut comps = exp.iter().map(|&x|x);
do path.each_parent |p| {
let p = p.as_str();
assert!(p.is_some());
let e = comps.next();
assert!(e.is_some());
assert_eq!(p.unwrap(), e.unwrap());
true
};
assert!(comps.next().is_none());
}
)
)
t!(s: "\\foo\\bar", ["\\foo\\bar", "\\foo", "\\"]);
t!(s: "\\foo\\bar\\baz", ["\\foo\\bar\\baz", "\\foo\\bar", "\\foo", "\\"]);
t!(s: "\\foo", ["\\foo", "\\"]);
t!(s: "\\", ["\\"]);
t!(s: "foo\\bar\\baz", ["foo\\bar\\baz", "foo\\bar", "foo", "."]);
t!(s: "foo\\bar", ["foo\\bar", "foo", "."]);
t!(s: "foo", ["foo", "."]);
t!(s: ".", ["."]);
t!(s: "..", [".."]);
t!(s: "..\\..\\foo", ["..\\..\\foo", "..\\.."]);
t!(s: "C:\\a\\b", ["C:\\a\\b", "C:\\a", "C:\\"]);
t!(s: "C:\\", ["C:\\"]);
t!(s: "C:a\\b", ["C:a\\b", "C:a", "C:"]);
t!(s: "C:", ["C:"]);
t!(s: "C:..\\..\\a", ["C:..\\..\\a", "C:..\\.."]);
t!(s: "C:..", ["C:.."]);
t!(s: "\\\\a\\b\\c", ["\\\\a\\b\\c", "\\\\a\\b"]);
t!(s: "\\\\a\\b", ["\\\\a\\b"]);
t!(s: "\\\\?\\a\\b\\c", ["\\\\?\\a\\b\\c", "\\\\?\\a\\b", "\\\\?\\a"]);
t!(s: "\\\\?\\C:\\a\\b", ["\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", "\\\\?\\C:\\"]);
t!(s: "\\\\?\\UNC\\a\\b\\c", ["\\\\?\\UNC\\a\\b\\c", "\\\\?\\UNC\\a\\b"]);
t!(s: "\\\\.\\a\\b\\c", ["\\\\.\\a\\b\\c", "\\\\.\\a\\b", "\\\\.\\a"]);
t!(s: "\\\\?\\a\\..\\b\\.\\c/d", ["\\\\?\\a\\..\\b\\.\\c/d", "\\\\?\\a\\..\\b\\.",
"\\\\?\\a\\..\\b", "\\\\?\\a\\..", "\\\\?\\a"]);
}
}

View File

@ -147,7 +147,7 @@ fn res_rel_file(cx: @ExtCtxt, sp: codemap::Span, arg: &Path) -> Path {
if !arg.is_absolute() {
let mut cu = Path::new(cx.codemap().span_to_filename(sp));
cu.pop();
cu.push_path(arg);
cu.push(arg);
cu
} else {
arg.clone()

View File

@ -3996,7 +3996,7 @@ fn eval_src_mod(&self,
prefix.pop();
let mod_path_stack = &*self.mod_path_stack;
let mod_path = Path::new(".").join_many(*mod_path_stack);
let dir_path = prefix.join_path(&mod_path);
let dir_path = prefix.join(&mod_path);
let file_path = match ::attr::first_attr_value_str_by_name(
outer_attrs, "path") {
Some(d) => dir_path.join(d),

View File

@ -27,7 +27,7 @@ fn mk_file(path: &str, directory: bool) {
}
fn abs_path(path: &str) -> Path {
os::getcwd().join_path(&Path::new(path))
os::getcwd().join(&Path::new(path))
}
fn glob_vec(pattern: &str) -> ~[Path] {