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

View File

@ -24,6 +24,7 @@
*/ */
use std::{os, path}; use std::{os, path};
use std::path::is_sep;
use sort; use sort;
@ -81,11 +82,7 @@ pub fn glob(pattern: &str) -> GlobIterator {
*/ */
pub fn glob_with(pattern: &str, options: MatchOptions) -> GlobIterator { pub fn glob_with(pattern: &str, options: MatchOptions) -> GlobIterator {
#[cfg(windows)] #[cfg(windows)]
use is_sep = std::path::windows::is_sep2; fn check_windows_verbatim(p: &Path) -> bool { path::windows::is_verbatim(p) }
#[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() }
#[cfg(not(windows))] #[cfg(not(windows))]
fn check_windows_verbatim(_: &Path) -> bool { false } fn check_windows_verbatim(_: &Path) -> bool { false }
@ -98,7 +95,7 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> GlobIterator {
// since we can't very well find all UNC shares with a 1-letter server name. // 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: ~[] }; 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()); 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. /// A helper function to determine if two chars are (possibly case-insensitively) equal.
fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool { 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 true
} else if !case_sensitive && a.is_ascii() && b.is_ascii() { } else if !case_sensitive && a.is_ascii() && b.is_ascii() {
// FIXME: work with non-ascii chars properly (issue #1347) // 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(..)` * 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 { fn get_sysroot_absolute_rt_lib(sess: session::Session) -> Path {
let r = filesearch::relative_target_lib_path(sess.opts.target_triple); 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.push(os::dll_filename("rustrt"));
p 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 tlib = filesearch::relative_target_lib_path(target_triple);
let mut path = Path::new(install_prefix); let mut path = Path::new(install_prefix);
path.push_path(&tlib); path.push(&tlib);
let path = os::make_absolute(&path); let path = os::make_absolute(&path);
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
path.as_str().expect("non-utf8 component in rpath").to_owned() path.as_str().expect("non-utf8 component in rpath").to_owned()

View File

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

View File

@ -95,20 +95,20 @@ impl PkgSrc {
// We search for sources under both src/ and build/ , because build/ is where // We search for sources under both src/ and build/ , because build/ is where
// automatically-checked-out sources go. // automatically-checked-out sources go.
let mut result = source_workspace.join("src"); 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())); result.push(format!("{}-{}", id.short_name, id.version.to_str()));
to_try.push(result); to_try.push(result);
let mut result = source_workspace.join("src"); let mut result = source_workspace.join("src");
result.push_path(&id.path); result.push(&id.path);
to_try.push(result); to_try.push(result);
let mut result = build_dir.join("src"); 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())); result.push_str(format!("{}-{}", id.short_name, id.version.to_str()));
to_try.push(result.clone()); to_try.push(result.clone());
output_names.push(result); output_names.push(result);
let mut other_result = build_dir.join("src"); 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()); to_try.push(other_result.clone());
output_names.push(other_result); output_names.push(other_result);
@ -146,7 +146,7 @@ impl PkgSrc {
source_workspace: source.clone(), source_workspace: source.clone(),
build_in_destination: build_in_destination, build_in_destination: build_in_destination,
destination_workspace: destination, destination_workspace: destination,
start_dir: start.join_path(&suffix), start_dir: start.join(&suffix),
id: id, id: id,
libs: ~[], libs: ~[],
mains: ~[], mains: ~[],
@ -371,7 +371,7 @@ impl PkgSrc {
cfgs: &[~str], cfgs: &[~str],
what: OutputType) { what: OutputType) {
for crate in crates.iter() { 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()); debug2!("build_crates: compiling {}", path.display());
let cfgs = crate.cfgs + cfgs; let cfgs = crate.cfgs + cfgs;
@ -416,7 +416,7 @@ impl PkgSrc {
debug2!("In declare inputs, self = {}", self.to_str()); debug2!("In declare inputs, self = {}", self.to_str());
for cs in to_do.iter() { for cs in to_do.iter() {
for c in cs.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()); debug2!("Declaring input: {}", path.display());
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
prep.declare_input("file", path.as_str().unwrap(), 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; let mut found = None;
do os::walk_dir(&src_dir) |p| { do os::walk_dir(&src_dir) |p| {
if os::path_is_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(); let pf = p.filename_str();
do pf.iter().any |&g| { do pf.iter().any |&g| {
match split_version_general(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); prefix = {}", short_name, where, workspace.display(), prefix);
let dir_to_search = match where { 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) 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 // Return the filename that matches, which we now know exists
// (if result_filename != None) // (if result_filename != None)
let abs_path = do result_filename.map |result_filename| { 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()); debug2!("result_filename = {}", absolute_path.display());
absolute_path 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, // Artifacts in the build directory live in a package-ID-specific subdirectory,
// but installed ones don't. // but installed ones don't.
let result = match (where, what) { 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, Lib) => target_lib_dir(workspace),
(Install, _) => target_bin_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; use conditions::bad_path::cond;
let mut result = target_build_dir(workspace); 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(), debug2!("Creating build dir {} for package id {}", result.display(),
pkgid.to_str()); pkgid.to_str());
if os::path_exists(&result) || os::mkdir_recursive(&result, U_RWX) { 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>... // If we're installing, it just goes under <workspace>...
Install => workspace, Install => workspace,
// and if we're just building, it goes in a package-specific subdir // 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, debug2!("[{:?}:{:?}] mk_output_path: short_name = {}, path = {}", what, where,
if what == Lib { short_name_with_version.clone() } else { pkg_id.short_name.clone() }, 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)) os::EXE_SUFFIX))
}; };
if !output_path.is_absolute() { 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()); debug2!("mk_output_path: returning {}", output_path.display());
output_path output_path

View File

@ -416,15 +416,15 @@ impl CtxMethods for BuildContext {
debug2!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \ debug2!("build: workspace = {} (in Rust path? {:?} is git dir? {:?} \
pkgid = {} pkgsrc start_dir = {}", workspace.display(), 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()); pkgid.to_str(), pkg_src.start_dir.display());
// If workspace isn't in the RUST_PATH, and it's a git repo, // 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 // 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"); let mut out_dir = default_workspace().join("src");
out_dir.push_path(&pkgid.path); out_dir.push(&pkgid.path);
let git_result = source_control::safe_git_clone(&workspace.join_path(&pkgid.path), let git_result = source_control::safe_git_clone(&workspace.join(&pkgid.path),
&pkgid.version, &pkgid.version,
&out_dir); &out_dir);
match git_result { match git_result {
@ -494,7 +494,7 @@ impl CtxMethods for BuildContext {
// We expect that p is relative to the package source's start directory, // We expect that p is relative to the package source's start directory,
// so check that assumption // so check that assumption
debug2!("JustOne: p = {}", p.display()); 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) { if is_lib(p) {
PkgSrc::push_crate(&mut pkg_src.libs, 0, p); PkgSrc::push_crate(&mut pkg_src.libs, 0, p);
} else if is_main(p) { } else if is_main(p) {
@ -553,7 +553,7 @@ impl CtxMethods for BuildContext {
debug2!("In declare inputs for {}", id.to_str()); debug2!("In declare inputs for {}", id.to_str());
for cs in to_do.iter() { for cs in to_do.iter() {
for c in cs.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()); debug2!("Recording input: {}", path.display());
// FIXME (#9639): This needs to handle non-utf8 paths // FIXME (#9639): This needs to handle non-utf8 paths
inputs.push((~"file", path.as_str().unwrap().to_owned())); 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 { fn init_git_repo(p: &Path) -> TempDir {
assert!(p.is_relative()); assert!(p.is_relative());
let tmp = TempDir::new("git_local").expect("couldn't create temp dir"); 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(); let work_dir_for_opts = work_dir.clone();
assert!(os::mkdir_recursive(&work_dir, U_RWX)); assert!(os::mkdir_recursive(&work_dir, U_RWX));
debug2!("Running: git init in {}", work_dir.display()); 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"])); == repo.join_many([".rust", "bin", "test_pkg_version"]));
let mut dir = target_build_dir(&repo.join(".rust")); 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()); debug2!("dir = {}", dir.display());
assert!(os::path_is_dir(&dir)); assert!(os::path_is_dir(&dir));
assert!(os::path_exists(&dir.join("version-0.3-file.txt"))); 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 // not sure if we should support anything else
let mut out_dir = target_build_dir(workspace); 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 // Make the output directory if it doesn't exist already
assert!(os::mkdir_recursive(&out_dir, U_RWX)); 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> { pub fn try_getting_local_version(local_path: &Path) -> Option<Version> {
let rustpath = rust_path(); let rustpath = rust_path();
for rp in rustpath.iter() { 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"); let git_dir = local_path.join(".git");
if !os::path_is_dir(&git_dir) { if !os::path_is_dir(&git_dir) {
continue; continue;

View File

@ -78,7 +78,7 @@ pub fn getcwd() -> Path {
fail2!() 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 @@ pub fn tmpdir() -> Path {
pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool { pub fn walk_dir(p: &Path, f: &fn(&Path) -> bool) -> bool {
let r = list_dir(p); let r = list_dir(p);
r.iter().advance(|q| { 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))) 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() p.clone()
} else { } else {
let mut ret = getcwd(); let mut ret = getcwd();
ret.push_path(p); ret.push(p);
ret ret
} }
} }
@ -730,7 +730,7 @@ pub fn list_dir(p: &Path) -> ~[Path] {
let mut entry_ptr = readdir(dir_ptr); let mut entry_ptr = readdir(dir_ptr);
while (entry_ptr as uint != 0) { while (entry_ptr as uint != 0) {
let cstr = CString::new(rust_list_dir_val(entry_ptr), false); 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); entry_ptr = readdir(dir_ptr);
} }
closedir(dir_ptr); closedir(dir_ptr);
@ -800,7 +800,7 @@ pub fn list_dir(p: &Path) -> ~[Path] {
* This version prepends each entry with the directory. * This version prepends each entry with the directory.
*/ */
pub fn list_dir_path(p: &Path) -> ~[Path] { 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 /// Removes a directory at the specified path, after removing

View File

@ -30,9 +30,7 @@ no restriction on paths beyond disallowing NUL).
## Usage ## Usage
Usage of this module is fairly straightforward. Unless writing platform-specific 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 code, `Path` should be used to refer to the platform-native path.
used should be restricted to those defined in `GenericPath`, and those methods
that are declared identically on both `PosixPath` and `WindowsPath`.
Creation of a path is typically done with either `Path::new(some_str)` or 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 `Path::new(some_vec)`. This path can be modified with `.push()` and
@ -69,7 +67,6 @@ debug2!("path exists: {}", b);
use container::Container; use container::Container;
use c_str::CString; use c_str::CString;
use clone::Clone; use clone::Clone;
use either::{Left, Right};
use fmt; use fmt;
use iter::Iterator; use iter::Iterator;
use option::{Option, None, Some}; use option::{Option, None, Some};
@ -121,6 +118,19 @@ pub use StrComponentIter = self::windows::StrComponentIter;
#[cfg(windows)] #[cfg(windows)]
pub use RevStrComponentIter = self::windows::RevStrComponentIter; 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 posix;
pub mod windows; pub mod windows;
@ -162,19 +172,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
} }
} }
/// 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. /// Returns the path as a string, if possible.
/// If the path is not representable in utf-8, this returns None. /// If the path is not representable in utf-8, this returns None.
#[inline] #[inline]
@ -195,15 +192,15 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
/// ///
/// This will print the equivalent of `to_display_str()` when used with a {} format parameter. /// This will print the equivalent of `to_display_str()` when used with a {} format parameter.
fn display<'a>(&'a self) -> Display<'a, Self> { 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 /// Returns an object that implements `fmt::Default` for printing filenames
/// ///
/// This will print the equivalent of `to_filename_display_str()` when used with a {} /// 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. /// format parameter. If there is no filename, nothing will be printed.
fn filename_display<'a>(&'a self) -> FilenameDisplay<'a, Self> { fn filename_display<'a>(&'a self) -> Display<'a, Self> {
FilenameDisplay{ path: self } Display{ path: self, filename: true }
} }
/// Returns the directory component of `self`, as a byte vector (with no trailing separator). /// Returns the directory component of `self`, as a byte vector (with no trailing separator).
@ -314,13 +311,17 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
/// Raises the `null_byte` condition if the filestem contains a NUL. /// Raises the `null_byte` condition if the filestem contains a NUL.
fn set_filestem<T: BytesContainer>(&mut self, filestem: T) { fn set_filestem<T: BytesContainer>(&mut self, filestem: T) {
// borrowck is being a pain here // borrowck is being a pain here
enum Value<T> {
Checked(T),
Unchecked(~[u8])
}
let val = { let val = {
match self.filename() { match self.filename() {
None => Left(filestem), None => Checked(filestem),
Some(name) => { Some(name) => {
let dot = '.' as u8; let dot = '.' as u8;
match name.rposition_elem(&dot) { match name.rposition_elem(&dot) {
None | Some(0) => Left(filestem), None | Some(0) => Checked(filestem),
Some(idx) => { Some(idx) => {
let mut v; let mut v;
if contains_nul(filestem.container_as_bytes()) { if contains_nul(filestem.container_as_bytes()) {
@ -336,15 +337,15 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
v.push_all(filestem); v.push_all(filestem);
} }
v.push_all(name.slice_from(idx)); v.push_all(name.slice_from(idx));
Right(v) Unchecked(v)
} }
} }
} }
} }
}; };
match val { match val {
Left(v) => self.set_filename(v), Checked(v) => self.set_filename(v),
Right(v) => unsafe { self.set_filename_unchecked(v) } Unchecked(v) => unsafe { self.set_filename_unchecked(v) }
} }
} }
/// Replaces the extension with the given byte vector or string. /// Replaces the extension with the given byte vector or string.
@ -545,12 +546,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
unsafe { self.push_unchecked(path) } 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`. /// Pushes multiple paths (as byte vectors or strings) onto `self`.
/// See `push` for details. /// See `push` for details.
#[inline] #[inline]
@ -590,14 +585,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
p.push(path); p.push(path);
p 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 /// Returns a new Path constructed by joining `self` with the given paths
/// (as byte vectors or strings). /// (as byte vectors or strings).
/// See `join` for details. /// See `join` for details.
@ -632,21 +619,6 @@ pub trait GenericPath: Clone + GenericPathUnsafe {
/// paths refer to separate drives, an absolute path is returned. /// paths refer to separate drives, an absolute path is returned.
fn path_relative_from(&self, base: &Self) -> Option<Self>; 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`. /// Returns whether the relative path `child` is a suffix of `self`.
fn ends_with_path(&self, child: &Self) -> bool; fn ends_with_path(&self, child: &Self) -> bool;
} }
@ -674,7 +646,7 @@ pub trait BytesContainer {
fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> { fn container_as_str_opt<'a>(&'a self) -> Option<&'a str> {
str::from_utf8_slice_opt(self.container_as_bytes()) 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 // FIXME (#8888): Remove unused arg once ::<for T> works
#[inline] #[inline]
fn is_str(_: Option<Self>) -> bool { false } fn is_str(_: Option<Self>) -> bool { false }
@ -703,11 +675,8 @@ pub trait GenericPathUnsafe {
/// Helper struct for printing paths with format!() /// Helper struct for printing paths with format!()
pub struct Display<'self, P> { pub struct Display<'self, P> {
priv path: &'self P priv path: &'self P,
} priv filename: bool
/// Helper struct for printing filenames with format!()
pub struct FilenameDisplay<'self, P> {
priv path: &'self P
} }
impl<'self, P: GenericPath> fmt::Default for Display<'self, P> { 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 /// If the path is not UTF-8, invalid sequences with be replaced with the
/// unicode replacement char. This involves allocation. /// unicode replacement char. This involves allocation.
fn to_str(&self) -> ~str { 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. /// unicode replacement char. This involves allocation.
#[inline] #[inline]
pub fn with_str<T>(&self, f: &fn(&str) -> T) -> T { pub fn with_str<T>(&self, f: &fn(&str) -> T) -> T {
match self.path.as_str() { let opt = if self.filename { self.path.filename_str() }
Some(s) => f(s), else { self.path.as_str() };
None => { match opt {
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() {
Some(s) => f(s), Some(s) => f(s),
None => { None => {
let s = self.to_str(); let s = self.to_str();
@ -865,6 +803,14 @@ impl BytesContainer for @[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)] #[inline(always)]
fn contains_nul(v: &[u8]) -> bool { fn contains_nul(v: &[u8]) -> bool {
v.iter().any(|&x| x == 0) v.iter().any(|&x| x == 0)
@ -1121,13 +1067,13 @@ mod tests {
use c_str::ToCStr; use c_str::ToCStr;
#[test] #[test]
fn test_from_c_str() { fn test_cstring() {
let input = "/foo/bar/baz"; 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()); assert_eq!(path.as_vec(), input.as_bytes());
let input = "\\foo\\bar\\baz"; 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()); assert_eq!(path.as_str().unwrap(), input.as_slice());
} }
} }

View File

@ -48,12 +48,19 @@ pub struct Path {
} }
/// The standard path separator character /// 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 /// Returns whether the given byte is a path separator
#[inline] #[inline]
pub fn is_sep(u: &u8) -> bool { pub fn is_sep_byte(u: &u8) -> bool {
*u == sep *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 { impl Eq for Path {
@ -89,11 +96,29 @@ impl IterBytes for Path {
} }
} }
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 { impl GenericPathUnsafe for Path {
unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path { unsafe fn new_unchecked<T: BytesContainer>(path: T) -> Path {
let path = Path::normalize(path.container_as_bytes()); let path = Path::normalize(path.container_as_bytes());
assert!(!path.is_empty()); assert!(!path.is_empty());
let idx = path.rposition_elem(&sep); let idx = path.rposition_elem(&sep_byte);
Path{ repr: path, sepidx: idx } Path{ repr: path, sepidx: idx }
} }
@ -106,11 +131,11 @@ impl GenericPathUnsafe for Path {
None => { None => {
let mut v = vec::with_capacity(dirname.len() + self.repr.len() + 1); let mut v = vec::with_capacity(dirname.len() + self.repr.len() + 1);
v.push_all(dirname); v.push_all(dirname);
v.push(sep); v.push(sep_byte);
v.push_all(self.repr); v.push_all(self.repr);
self.repr = Path::normalize(v); 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); self.repr = Path::normalize(dirname);
} }
Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => { Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
@ -127,7 +152,7 @@ impl GenericPathUnsafe for Path {
self.repr = Path::normalize(v); 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) { unsafe fn set_filename_unchecked<T: BytesContainer>(&mut self, filename: T) {
@ -136,7 +161,7 @@ impl GenericPathUnsafe for Path {
None if bytes!("..") == self.repr => { None if bytes!("..") == self.repr => {
let mut v = vec::with_capacity(3 + filename.len()); let mut v = vec::with_capacity(3 + filename.len());
v.push_all(dot_dot_static); v.push_all(dot_dot_static);
v.push(sep); v.push(sep_byte);
v.push_all(filename); v.push_all(filename);
self.repr = Path::normalize(v); self.repr = Path::normalize(v);
} }
@ -146,7 +171,7 @@ impl GenericPathUnsafe for Path {
Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => { Some(idx) if self.repr.slice_from(idx+1) == bytes!("..") => {
let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len()); let mut v = vec::with_capacity(self.repr.len() + 1 + filename.len());
v.push_all(self.repr); v.push_all(self.repr);
v.push(sep); v.push(sep_byte);
v.push_all(filename); v.push_all(filename);
self.repr = Path::normalize(v); self.repr = Path::normalize(v);
} }
@ -157,22 +182,22 @@ impl GenericPathUnsafe for Path {
self.repr = Path::normalize(v); 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) { unsafe fn push_unchecked<T: BytesContainer>(&mut self, path: T) {
let path = path.container_as_bytes(); let path = path.container_as_bytes();
if !path.is_empty() { if !path.is_empty() {
if path[0] == sep { if path[0] == sep_byte {
self.repr = Path::normalize(path); self.repr = Path::normalize(path);
} else { } else {
let mut v = vec::with_capacity(self.repr.len() + path.len() + 1); let mut v = vec::with_capacity(self.repr.len() + path.len() + 1);
v.push_all(self.repr); v.push_all(self.repr);
v.push(sep); v.push(sep_byte);
v.push_all(path); v.push_all(path);
self.repr = Path::normalize(v); self.repr = Path::normalize(v);
} }
self.sepidx = self.repr.rposition_elem(&sep); self.sepidx = self.repr.rposition_elem(&sep_byte);
} }
} }
} }
@ -228,7 +253,7 @@ impl GenericPath for Path {
} else { } else {
self.repr.truncate(idx); self.repr.truncate(idx);
} }
self.sepidx = self.repr.rposition_elem(&sep); self.sepidx = self.repr.rposition_elem(&sep_byte);
Some(v) Some(v)
} }
} }
@ -244,7 +269,7 @@ impl GenericPath for Path {
#[inline] #[inline]
fn is_absolute(&self) -> bool { fn is_absolute(&self) -> bool {
self.repr[0] == sep self.repr[0] == sep_byte
} }
fn is_ancestor_of(&self, other: &Path) -> bool { fn is_ancestor_of(&self, other: &Path) -> bool {
@ -305,7 +330,7 @@ impl GenericPath for Path {
} }
} }
} }
Some(Path::new(comps.connect_vec(&sep))) Some(Path::new(comps.connect_vec(&sep_byte)))
} }
} }
@ -347,14 +372,14 @@ impl Path {
fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] { fn normalize<V: Vector<u8>+CopyableVector<u8>>(v: V) -> ~[u8] {
// borrowck is being very picky // borrowck is being very picky
let val = { 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 v_ = if is_abs { v.as_slice().slice_from(1) } else { v.as_slice() };
let comps = normalize_helper(v_, is_abs); let comps = normalize_helper(v_, is_abs);
match comps { match comps {
None => None, None => None,
Some(comps) => { Some(comps) => {
if is_abs && comps.is_empty() { if is_abs && comps.is_empty() {
Some(~[sep]) Some(~[sep_byte])
} else { } else {
let n = if is_abs { comps.len() } else { comps.len() - 1} + let n = if is_abs { comps.len() } else { comps.len() - 1} +
comps.iter().map(|v| v.len()).sum(); comps.iter().map(|v| v.len()).sum();
@ -367,7 +392,7 @@ impl Path {
} }
} }
for comp in it { for comp in it {
v.push(sep); v.push(sep_byte);
v.push_all(comp); v.push_all(comp);
} }
Some(v) Some(v)
@ -386,10 +411,10 @@ impl Path {
/// /a/b/c and a/b/c yield the same set of components. /// /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. /// A path of "/" yields no components. A path of "." yields one component.
pub fn component_iter<'a>(&'a self) -> ComponentIter<'a> { 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) self.repr.slice_from(1)
} else { self.repr.as_slice() }; } 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() { if v.is_empty() {
// consume the empty "" component // consume the empty "" component
ret.next(); ret.next();
@ -400,10 +425,10 @@ impl Path {
/// Returns an iterator that yields each component of the path in reverse. /// Returns an iterator that yields each component of the path in reverse.
/// See component_iter() for details. /// See component_iter() for details.
pub fn rev_component_iter<'a>(&'a self) -> RevComponentIter<'a> { 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) self.repr.slice_from(1)
} else { self.repr.as_slice() }; } 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() { if v.is_empty() {
// consume the empty "" component // consume the empty "" component
ret.next(); 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 comps: ~[&'a [u8]] = ~[];
let mut n_up = 0u; let mut n_up = 0u;
let mut changed = false; 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 } if comp.is_empty() { changed = true }
else if comp == bytes!(".") { changed = true } else if comp == bytes!(".") { changed = true }
else if comp == bytes!("..") { else if comp == bytes!("..") {
@ -928,7 +953,7 @@ mod tests {
{ {
let mut p = Path::new($path); let mut p = Path::new($path);
let push = Path::new($push); let push = Path::new($push);
p.push_path(&push); p.push(&push);
assert_eq!(p.as_str(), Some($exp)); assert_eq!(p.as_str(), Some($exp));
} }
) )
@ -1049,7 +1074,7 @@ mod tests {
{ {
let path = Path::new($path); let path = Path::new($path);
let join = Path::new($join); let join = Path::new($join);
let res = path.join_path(&join); let res = path.join(&join);
assert_eq!(res.as_str(), Some($exp)); assert_eq!(res.as_str(), Some($exp));
} }
) )
@ -1598,58 +1623,4 @@ mod tests {
// str_component_iter is a wrapper around component_iter, so no need to do // str_component_iter is a wrapper around component_iter, so no need to do
// the full set of tests // 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 @@ impl IterBytes for Path {
} }
} }
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 { impl GenericPathUnsafe for Path {
/// See `GenericPathUnsafe::from_vec_unchecked`. /// See `GenericPathUnsafe::from_vec_unchecked`.
/// ///
@ -235,7 +273,7 @@ impl GenericPathUnsafe for Path {
fn is_vol_abs(path: &str, prefix: Option<PathPrefix>) -> bool { fn is_vol_abs(path: &str, prefix: Option<PathPrefix>) -> bool {
// assume prefix is Some(DiskPrefix) // assume prefix is Some(DiskPrefix)
let rest = path.slice_from(prefix_len(prefix)); 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 { fn shares_volume(me: &Path, path: &str) -> bool {
// path is assumed to have a prefix of Some(DiskPrefix) // path is assumed to have a prefix of Some(DiskPrefix)
@ -246,8 +284,8 @@ impl GenericPathUnsafe for Path {
} }
} }
fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool { fn is_sep_(prefix: Option<PathPrefix>, u: u8) -> bool {
u.is_ascii() && if prefix_is_verbatim(prefix) { is_sep(u as char) } if prefix_is_verbatim(prefix) { is_sep_verbatim(u as char) }
else { is_sep2(u as char) } else { is_sep(u as char) }
} }
fn replace_path(me: &mut Path, path: &str, prefix: Option<PathPrefix>) { fn replace_path(me: &mut Path, path: &str, prefix: Option<PathPrefix>) {
@ -262,7 +300,7 @@ impl GenericPathUnsafe for Path {
fn append_path(me: &mut Path, path: &str) { fn append_path(me: &mut Path, path: &str) {
// appends a path that has no prefix // appends a path that has no prefix
// if me is verbatim, we need to pre-normalize the new path // 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 }; else { None };
let pathlen = path_.map_default(path.len(), |p| p.len()); let pathlen = path_.map_default(path.len(), |p| p.len());
let mut s = str::with_capacity(me.repr.len() + 1 + pathlen); let mut s = str::with_capacity(me.repr.len() + 1 + pathlen);
@ -291,7 +329,7 @@ impl GenericPathUnsafe for Path {
} }
None if !path.is_empty() && is_sep_(self.prefix, path[0]) => { None if !path.is_empty() && is_sep_(self.prefix, path[0]) => {
// volume-relative path // volume-relative path
if self.prefix().is_some() { if self.prefix.is_some() {
// truncate self down to the prefix, then append // truncate self down to the prefix, then append
let n = self.prefix_len(); let n = self.prefix_len();
self.repr.truncate(n); self.repr.truncate(n);
@ -418,11 +456,6 @@ impl GenericPath for Path {
self.filename_str().map_move(|s| unsafe { GenericPathUnsafe::new_unchecked(s) }) 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] #[inline]
fn pop(&mut self) -> Option<~[u8]> { fn pop(&mut self) -> Option<~[u8]> {
self.pop_str().map_move(|s| s.into_bytes()) self.pop_str().map_move(|s| s.into_bytes())
@ -463,7 +496,7 @@ impl GenericPath for Path {
} }
_ => self.repr.slice_to(self.prefix_len()) _ => 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))) Some(Path::new(self.repr.slice_to(1)))
} else { } else {
None None
@ -493,14 +526,14 @@ impl GenericPath for Path {
#[inline] #[inline]
fn is_relative(&self) -> bool { 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 { fn is_ancestor_of(&self, other: &Path) -> bool {
if !self.equiv_prefix(other) { if !self.equiv_prefix(other) {
false false
} else if self.is_absolute() != other.is_absolute() || } 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 false
} else { } else {
let mut ita = self.str_component_iter().map(|x|x.unwrap()); let mut ita = self.str_component_iter().map(|x|x.unwrap());
@ -544,8 +577,8 @@ impl GenericPath for Path {
} else { } else {
None None
} }
} else if self.is_vol_relative() != base.is_vol_relative() { } else if is_vol_relative(self) != is_vol_relative(base) {
if self.is_vol_relative() { if is_vol_relative(self) {
Some(self.clone()) Some(self.clone())
} else { } else {
None None
@ -555,8 +588,8 @@ impl GenericPath for Path {
let mut itb = base.str_component_iter().map(|x|x.unwrap()); let mut itb = base.str_component_iter().map(|x|x.unwrap());
let mut comps = ~[]; let mut comps = ~[];
let a_verb = self.is_verbatim(); let a_verb = is_verbatim(self);
let b_verb = base.is_verbatim(); let b_verb = is_verbatim(base);
loop { loop {
match (ita.next(), itb.next()) { match (ita.next(), itb.next()) {
(None, None) => break, (None, None) => break,
@ -598,20 +631,6 @@ impl GenericPath for Path {
} }
} }
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 { fn ends_with_path(&self, child: &Path) -> bool {
if !child.is_relative() { return false; } if !child.is_relative() { return false; }
let mut selfit = self.str_component_iter().invert(); let mut selfit = self.str_component_iter().invert();
@ -694,34 +713,6 @@ impl Path {
self.rev_str_component_iter().map(convert) 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 { fn equiv_prefix(&self, other: &Path) -> bool {
match (self.prefix, other.prefix) { match (self.prefix, other.prefix) {
(Some(DiskPrefix), Some(VerbatimDiskPrefix)) => { (Some(DiskPrefix), Some(VerbatimDiskPrefix)) => {
@ -866,8 +857,8 @@ impl Path {
let s = if self.has_nonsemantic_trailing_slash() { let s = if self.has_nonsemantic_trailing_slash() {
self.repr.slice_to(self.repr.len()-1) self.repr.slice_to(self.repr.len()-1)
} else { self.repr.as_slice() }; } else { self.repr.as_slice() };
let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep2 } let idx = s.rfind(if !prefix_is_verbatim(self.prefix) { is_sep }
else { is_sep }); else { is_sep_verbatim });
let prefixlen = self.prefix_len(); let prefixlen = self.prefix_len();
self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) }); self.sepidx = idx.and_then(|x| if x < prefixlen { None } else { Some(x) });
} }
@ -893,7 +884,7 @@ impl Path {
} }
fn has_nonsemantic_trailing_slash(&self) -> bool { 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 self.repr[self.repr.len()-1] == sep as u8
} }
@ -905,23 +896,65 @@ impl Path {
} }
} }
/// 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 /// The standard path separator character
pub static sep: char = '\\'; pub static sep: char = '\\';
/// The alternative path separator character /// The alternative path separator character
pub static sep2: char = '/'; pub static sep2: char = '/';
/// Returns whether the given byte is a path separator. /// Returns whether the given char is a path separator.
/// Only allows the primary separator '\'; use is_sep2 to allow '/'. /// Allows both the primary separator '\' and the alternative separator '/'.
#[inline] #[inline]
pub fn is_sep(c: char) -> bool { 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 c == sep
} }
/// Returns whether the given byte is a path separator. /// Returns whether the given byte is a path separator.
/// Allows both the primary separator '\' and the alternative separator '/'. /// Allows both the primary separator '\' and the alternative separator '/'.
#[inline] #[inline]
pub fn is_sep2(c: char) -> bool { pub fn is_sep_byte(u: &u8) -> bool {
c == sep || c == sep2 *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 /// Prefix types for Path
@ -953,7 +986,7 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
if path.starts_with("UNC\\") { if path.starts_with("UNC\\") {
// \\?\UNC\server\share // \\?\UNC\server\share
path = path.slice_from(4); 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, Some(x) => x,
None => (path.len(), 0) 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()); let idx = path.find('\\').unwrap_or(path.len());
return Some(DeviceNSPrefix(idx)); 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 => { Some((idx_a, idx_b)) if idx_a > 0 && idx_b > 0 => {
// \\server\share // \\server\share
return Some(UNCPrefix(idx_a, idx_b)); return Some(UNCPrefix(idx_a, idx_b));
@ -1006,14 +1039,14 @@ pub fn parse_prefix<'a>(mut path: &'a str) -> Option<PathPrefix> {
// None result means the string didn't need normalizing // None result means the string didn't need normalizing
fn normalize_helper<'a>(s: &'a str, prefix: Option<PathPrefix>) -> (bool,Option<~[&'a str]>) { 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 is_abs = s.len() > prefix_len(prefix) && f(s.char_at(prefix_len(prefix)));
let s_ = s.slice_from(prefix_len(prefix)); let s_ = s.slice_from(prefix_len(prefix));
let s_ = if is_abs { s_.slice_from(1) } else { s_ }; let s_ = if is_abs { s_.slice_from(1) } else { s_ };
if is_abs && s_.is_empty() { if is_abs && s_.is_empty() {
return (is_abs, match prefix { 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(~[]) }), else { Some(~[]) }),
Some(_) => Some(~[]), // need to trim the trailing separator 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) } } else { comps.push(comp) }
} }
if !changed && !prefix_is_verbatim(prefix) { if !changed && !prefix_is_verbatim(prefix) {
changed = s.find(is_sep2).is_some(); changed = s.find(is_sep).is_some();
} }
if changed { if changed {
if comps.is_empty() && !is_abs && prefix.is_none() { 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 { fn prefix_is_sep(p: Option<PathPrefix>, c: u8) -> bool {
c.is_ascii() && if !prefix_is_verbatim(p) { is_sep2(c as char) } c.is_ascii() && if !prefix_is_verbatim(p) { is_sep(c as char) }
else { is_sep(c as char) } else { is_sep_verbatim(c as char) }
} }
// Stat support // Stat support
@ -1636,9 +1669,9 @@ mod tests {
// we do want to check one odd case though to ensure the prefix is re-parsed // we do want to check one odd case though to ensure the prefix is re-parsed
let mut p = Path::new("\\\\?\\C:"); let mut p = Path::new("\\\\?\\C:");
assert_eq!(p.prefix(), Some(VerbatimPrefix(2))); assert_eq!(prefix(&p), Some(VerbatimPrefix(2)));
p.push("foo"); p.push("foo");
assert_eq!(p.prefix(), Some(VerbatimDiskPrefix)); assert_eq!(prefix(&p), Some(VerbatimDiskPrefix));
assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo")); assert_eq!(p.as_str(), Some("\\\\?\\C:\\foo"));
// and another with verbatim non-normalized paths // and another with verbatim non-normalized paths
@ -1654,7 +1687,7 @@ mod tests {
{ {
let mut p = Path::new($path); let mut p = Path::new($path);
let push = Path::new($push); let push = Path::new($push);
p.push_path(&push); p.push(&push);
assert_eq!(p.as_str(), Some($exp)); assert_eq!(p.as_str(), Some($exp));
} }
) )
@ -1837,7 +1870,7 @@ mod tests {
{ {
let path = Path::new($path); let path = Path::new($path);
let join = Path::new($join); let join = Path::new($join);
let res = path.join_path(&join); let res = path.join(&join);
assert_eq!(res.as_str(), Some($exp)); assert_eq!(res.as_str(), Some($exp));
} }
) )
@ -1849,7 +1882,7 @@ mod tests {
t!(s: "a\\b", "\\c\\d", "\\c\\d"); t!(s: "a\\b", "\\c\\d", "\\c\\d");
t!(s: ".", "a\\b", "a\\b"); t!(s: ".", "a\\b", "a\\b");
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 // the full set of prefix tests
} }
@ -2217,11 +2250,11 @@ mod tests {
let b = path.is_absolute(); let b = path.is_absolute();
assert!(b == abs, "Path '{}'.is_absolute(): expected {:?}, found {:?}", assert!(b == abs, "Path '{}'.is_absolute(): expected {:?}, found {:?}",
path.as_str().unwrap(), abs, b); path.as_str().unwrap(), abs, b);
let b = path.is_vol_relative(); let b = is_vol_relative(&path);
assert!(b == vol, "Path '{}'.is_vol_relative(): expected {:?}, found {:?}", assert!(b == vol, "is_vol_relative('{}'): expected {:?}, found {:?}",
path.as_str().unwrap(), vol, b); path.as_str().unwrap(), vol, b);
let b = path.is_cwd_relative(); let b = is_cwd_relative(&path);
assert!(b == cwd, "Path '{}'.is_cwd_relative(): expected {:?}, found {:?}", assert!(b == cwd, "is_cwd_relative('{}'): expected {:?}, found {:?}",
path.as_str().unwrap(), cwd, b); path.as_str().unwrap(), cwd, b);
let b = path.is_relative(); let b = path.is_relative();
assert!(b == rel, "Path '{}'.is_relativf(): expected {:?}, found {:?}", assert!(b == rel, "Path '{}'.is_relativf(): expected {:?}, found {:?}",
@ -2614,54 +2647,4 @@ mod tests {
t!(s: ".", [b!(".")]); t!(s: ".", [b!(".")]);
// since this is really a wrapper around str_component_iter, those tests suffice // 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() { if !arg.is_absolute() {
let mut cu = Path::new(cx.codemap().span_to_filename(sp)); let mut cu = Path::new(cx.codemap().span_to_filename(sp));
cu.pop(); cu.pop();
cu.push_path(arg); cu.push(arg);
cu cu
} else { } else {
arg.clone() arg.clone()

View File

@ -3996,7 +3996,7 @@ impl Parser {
prefix.pop(); prefix.pop();
let mod_path_stack = &*self.mod_path_stack; let mod_path_stack = &*self.mod_path_stack;
let mod_path = Path::new(".").join_many(*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( let file_path = match ::attr::first_attr_value_str_by_name(
outer_attrs, "path") { outer_attrs, "path") {
Some(d) => dir_path.join(d), Some(d) => dir_path.join(d),

View File

@ -27,7 +27,7 @@ pub fn main() {
} }
fn abs_path(path: &str) -> Path { 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] { fn glob_vec(pattern: &str) -> ~[Path] {