(index<- )        ./libstd/path.rs

    1  // Copyright 2012 The Rust Project Developers. See the COPYRIGHT
    2  // file at the top-level directory of this distribution and at
    3  // http://rust-lang.org/COPYRIGHT.
    4  //
    5  // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
    6  // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
    7  // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
    8  // option. This file may not be copied, modified, or distributed
    9  // except according to those terms.
   10  
   11  /*!
   12  
   13  Cross-platform file path handling
   14  
   15  */
   16  
   17  #[allow(missing_doc)];
   18  
   19  use c_str::ToCStr;
   20  use c_str;
   21  use clone::Clone;
   22  use cmp::Eq;
   23  use container::Container;
   24  use iter::{Iterator, range};
   25  use libc;
   26  use num;
   27  use option::{None, Option, Some};
   28  use str::{OwnedStr, Str, StrSlice, StrVector};
   29  use to_str::ToStr;
   30  use ascii::{AsciiCast, AsciiStr};
   31  use vec::{Vector, OwnedVector, ImmutableVector, OwnedCopyableVector};
   32  
   33  #[cfg(windows)]
   34  pub use Path = self::WindowsPath;
   35  #[cfg(unix)]
   36  pub use Path = self::PosixPath;
   37  
   38  #[deriving(Clone, Eq)]
   39  pub struct WindowsPath {
   40      host: Option<~str>,
   41      device: Option<~str>,
   42      is_absolute: bool,
   43      components: ~[~str],
   44  }
   45  
   46  pub fn WindowsPath(s&str) -> WindowsPath {
   47      GenericPath::from_str(s)
   48  }
   49  
   50  #[deriving(Clone, Eq)]
   51  pub struct PosixPath {
   52      is_absolute: bool,
   53      components: ~[~str],
   54  }
   55  
   56  pub fn PosixPath(s&str) -> PosixPath {
   57      GenericPath::from_str(s)
   58  }
   59  
   60  pub trait GenericPath : Clone + Eq + ToStr {
   61      /// Converts a string to a path.
   62      fn from_str(&str) -> Self;
   63  
   64      /// Returns the directory component of `self`, as a string.
   65      fn dirname(&self) -> ~str {
   66          let s = self.dir_path().to_str();
   67          match s.len() {
   68              0 => ~".",
   69              _ => s,
   70          }
   71      }
   72  
   73      /// Returns the file component of `self`, as a string option.
   74      /// Returns None if `self` names a directory.
   75      fn filename<'a>(&'a self) -> Option<&'a str> {
   76          match self.components().len() {
   77              0 => None,
   78              n => Some(self.components()[n - 1].as_slice()),
   79          }
   80      }
   81  
   82      /// Returns the stem of the file component of `self`, as a string option.
   83      /// The stem is the slice of a filename starting at 0 and ending just before
   84      /// the last '.' in the name.
   85      /// Returns None if `self` names a directory.
   86      fn filestem<'a>(&'a self) -> Option<&'a str> {
   87          match self.filename() {
   88              None => None,
   89              Some(ref f) => {
   90                  match f.rfind('.') {
   91                      Some(p) => Some(f.slice_to(p)),
   92                      None => Some((*f)),
   93                  }
   94              }
   95          }
   96      }
   97  
   98      /// Returns the type of the file component of `self`, as a string option.
   99      /// The file type is the slice of a filename starting just after the last
  100      /// '.' in the name and ending at the last index in the filename.
  101      /// Returns None if `self` names a directory.
  102      fn filetype<'a>(&'a self) -> Option<&'a str> {
  103          match self.filename() {
  104              None => None,
  105              Some(ref f) => {
  106                  match f.rfind('.') {
  107                      Some(p) if p < f.len() => Some(f.slice_from(p)),
  108                      _ => None,
  109                  }
  110              }
  111          }
  112      }
  113  
  114      /// Returns a new path consisting of `self` with the parent directory component replaced
  115      /// with the given string.
  116      fn with_dirname(&self, (&str)) -> Self;
  117  
  118      /// Returns a new path consisting of `self` with the file component replaced
  119      /// with the given string.
  120      fn with_filename(&self, (&str)) -> Self;
  121  
  122      /// Returns a new path consisting of `self` with the file stem replaced
  123      /// with the given string.
  124      fn with_filestem(&self, s&str) -> Self {
  125          match self.filetype() {
  126              None => self.with_filename(s),
  127              Some(ref t) => self.with_filename(s.to_owned() + *t),
  128          }
  129      }
  130  
  131      /// Returns a new path consisting of `self` with the file type replaced
  132      /// with the given string.
  133      fn with_filetype(&self, t&str) -> Self {
  134          match (t.len(), self.filestem()) {
  135              (0, None)        => (*self).clone(),
  136              (0, Some(ref s)) => self.with_filename(*s),
  137              (_, None)        => self.with_filename(fmt!(".%s", t)),
  138              (_, Some(ref s)) => self.with_filename(fmt!("%s.%s", *s, t)),
  139          }
  140      }
  141  
  142      /// Returns the directory component of `self`, as a new path.
  143      /// If `self` has no parent, returns `self`.
  144      fn dir_path(&self) -> Self {
  145          match self.components().len() {
  146              0 => (*self).clone(),
  147              _ => self.pop(),
  148          }
  149      }
  150  
  151      /// Returns the file component of `self`, as a new path.
  152      /// If `self` names a directory, returns the empty path.
  153      fn file_path(&self) -> Self;
  154  
  155      /// Returns a new path whose parent directory is `self` and whose
  156      /// file component is the given string.
  157      fn push(&self, (&str)) -> Self;
  158  
  159      /// Returns a new path consisting of the given path, made relative to `self`.
  160      fn push_rel(&self, other&Self) -> Self {
  161          assert!(!other.is_absolute());
  162          self.push_many(other.components())
  163      }
  164  
  165      /// Returns a new path consisting of the path given by the given vector
  166      /// of strings, relative to `self`.
  167      fn push_many<S: Str>(&self, (&[S])) -> Self;
  168  
  169      /// Identical to `dir_path` except in the case where `self` has only one
  170      /// component. In this case, `pop` returns the empty path.
  171      fn pop(&self) -> Self;
  172  
  173      /// The same as `push_rel`, except that the directory argument must not
  174      /// contain directory separators in any of its components.
  175      fn unsafe_join(&self, (&Self)) -> Self;
  176  
  177      /// On Unix, always returns `false`. On Windows, returns `true` iff `self`'s
  178      /// file stem is one of: `con` `aux` `com1` `com2` `com3` `com4`
  179      /// `lpt1` `lpt2` `lpt3` `prn` `nul`.
  180      fn is_restricted(&self) -> bool;
  181  
  182      /// Returns a new path that names the same file as `self`, without containing
  183      /// any '.', '..', or empty components. On Windows, uppercases the drive letter
  184      /// as well.
  185      fn normalize(&self) -> Self;
  186  
  187      /// Returns `true` if `self` is an absolute path.
  188      fn is_absolute(&self) -> bool;
  189  
  190      /// True if `self` is an ancestor of `other`.
  191      // See `test_is_ancestor_of` for examples.
  192      fn is_ancestor_of(&self, other&Self) -> bool {
  193          debug!("%s / %s %? %?", self.to_str(), other.to_str(), self.is_absolute(),
  194                 self.components().len());
  195          self == other ||
  196              (!other.components().is_empty() &&
  197               !(self.components().is_empty() && !self.is_absolute()) &&
  198               self.is_ancestor_of(&other.pop()))
  199      }
  200  
  201      /// Finds the relative path from one file to another.
  202      fn get_relative_to(&self, abs2(&Self)) -> Self {
  203          assert!(self.is_absolute());
  204          assert!(abs2.is_absolute());
  205          let abs1 = self.normalize();
  206          let abs2 = abs2.normalize();
  207  
  208          let split1&[~str] = abs1.components();
  209          let split2&[~str] = abs2.components();
  210          let len1 = split1.len();
  211          let len2 = split2.len();
  212          assert!(len1 > 0);
  213          assert!(len2 > 0);
  214  
  215          let max_common_path = num::min(len1, len2) - 1;
  216          let mut start_idx = 0;
  217          while start_idx < max_common_path
  218              && split1[start_idx] == split2[start_idx] {
  219              start_idx += 1;
  220          }
  221  
  222          let mut path~[~str] = ~[];
  223          for _ in range(start_idx, len1 - 1) { path.push(~".."); };
  224  
  225          path.push_all(split2.slice(start_idx, len2 - 1));
  226  
  227          let mut resultSelf = GenericPath::from_str(".");
  228          if !path.is_empty() {
  229              // Without this type hint, the typechecker doesn't seem to like it
  230              let pSelf = GenericPath::from_str("");
  231              result = p.push_many(path);
  232          };
  233          result
  234      }
  235  
  236      fn components<'a>(&'a self) -> &'a [~str];
  237  }
  238  
  239  #[cfg(target_os = "linux")]
  240  #[cfg(target_os = "android")]
  241  mod stat {
  242      #[cfg(target_arch = "x86")]
  243      pub mod arch {
  244          use libc;
  245  
  246          pub fn default_stat() -> libc::stat {
  247              libc::stat {
  248                  st_dev: 0,
  249                  __pad1: 0,
  250                  st_ino: 0,
  251                  st_mode: 0,
  252                  st_nlink: 0,
  253                  st_uid: 0,
  254                  st_gid: 0,
  255                  st_rdev: 0,
  256                  __pad2: 0,
  257                  st_size: 0,
  258                  st_blksize: 0,
  259                  st_blocks: 0,
  260                  st_atime: 0,
  261                  st_atime_nsec: 0,
  262                  st_mtime: 0,
  263                  st_mtime_nsec: 0,
  264                  st_ctime: 0,
  265                  st_ctime_nsec: 0,
  266                  __unused4: 0,
  267                  __unused5: 0,
  268              }
  269          }
  270      }
  271  
  272      #[cfg(target_arch = "arm")]
  273      pub mod arch {
  274          use libc;
  275  
  276          pub fn default_stat() -> libc::stat {
  277              libc::stat {
  278                  st_dev: 0,
  279                  __pad0: [0, ..4],
  280                  __st_ino: 0,
  281                  st_mode: 0,
  282                  st_nlink: 0,
  283                  st_uid: 0,
  284                  st_gid: 0,
  285                  st_rdev: 0,
  286                  __pad3: [0, ..4],
  287                  st_size: 0,
  288                  st_blksize: 0,
  289                  st_blocks: 0,
  290                  st_atime: 0,
  291                  st_atime_nsec: 0,
  292                  st_mtime: 0,
  293                  st_mtime_nsec: 0,
  294                  st_ctime: 0,
  295                  st_ctime_nsec: 0,
  296                  st_ino: 0
  297              }
  298          }
  299      }
  300  
  301      #[cfg(target_arch = "mips")]
  302      pub mod arch {
  303          use libc;
  304  
  305          pub fn default_stat() -> libc::stat {
  306              libc::stat {
  307                  st_dev: 0,
  308                  st_pad1: [0, ..3],
  309                  st_ino: 0,
  310                  st_mode: 0,
  311                  st_nlink: 0,
  312                  st_uid: 0,
  313                  st_gid: 0,
  314                  st_rdev: 0,
  315                  st_pad2: [0, ..2],
  316                  st_size: 0,
  317                  st_pad3: 0,
  318                  st_atime: 0,
  319                  st_atime_nsec: 0,
  320                  st_mtime: 0,
  321                  st_mtime_nsec: 0,
  322                  st_ctime: 0,
  323                  st_ctime_nsec: 0,
  324                  st_blksize: 0,
  325                  st_blocks: 0,
  326                  st_pad5: [0, ..14],
  327              }
  328          }
  329      }
  330  
  331      #[cfg(target_arch = "x86_64")]
  332      pub mod arch {
  333          use libc;
  334  
  335          pub fn default_stat() -> libc::stat {
  336              libc::stat {
  337                  st_dev: 0,
  338                  st_ino: 0,
  339                  st_nlink: 0,
  340                  st_mode: 0,
  341                  st_uid: 0,
  342                  st_gid: 0,
  343                  __pad0: 0,
  344                  st_rdev: 0,
  345                  st_size: 0,
  346                  st_blksize: 0,
  347                  st_blocks: 0,
  348                  st_atime: 0,
  349                  st_atime_nsec: 0,
  350                  st_mtime: 0,
  351                  st_mtime_nsec: 0,
  352                  st_ctime: 0,
  353                  st_ctime_nsec: 0,
  354                  __unused: [0, 0, 0],
  355              }
  356          }
  357      }
  358  }
  359  
  360  #[cfg(target_os = "freebsd")]
  361  mod stat {
  362      #[cfg(target_arch = "x86_64")]
  363      pub mod arch {
  364          use libc;
  365  
  366          pub fn default_stat() -> libc::stat {
  367              libc::stat {
  368                  st_dev: 0,
  369                  st_ino: 0,
  370                  st_mode: 0,
  371                  st_nlink: 0,
  372                  st_uid: 0,
  373                  st_gid: 0,
  374                  st_rdev: 0,
  375                  st_atime: 0,
  376                  st_atime_nsec: 0,
  377                  st_mtime: 0,
  378                  st_mtime_nsec: 0,
  379                  st_ctime: 0,
  380                  st_ctime_nsec: 0,
  381                  st_size: 0,
  382                  st_blocks: 0,
  383                  st_blksize: 0,
  384                  st_flags: 0,
  385                  st_gen: 0,
  386                  st_lspare: 0,
  387                  st_birthtime: 0,
  388                  st_birthtime_nsec: 0,
  389                  __unused: [0, 0],
  390              }
  391          }
  392      }
  393  }
  394  
  395  #[cfg(target_os = "macos")]
  396  mod stat {
  397      pub mod arch {
  398          use libc;
  399  
  400          pub fn default_stat() -> libc::stat {
  401              libc::stat {
  402                  st_dev: 0,
  403                  st_mode: 0,
  404                  st_nlink: 0,
  405                  st_ino: 0,
  406                  st_uid: 0,
  407                  st_gid: 0,
  408                  st_rdev: 0,
  409                  st_atime: 0,
  410                  st_atime_nsec: 0,
  411                  st_mtime: 0,
  412                  st_mtime_nsec: 0,
  413                  st_ctime: 0,
  414                  st_ctime_nsec: 0,
  415                  st_birthtime: 0,
  416                  st_birthtime_nsec: 0,
  417                  st_size: 0,
  418                  st_blocks: 0,
  419                  st_blksize: 0,
  420                  st_flags: 0,
  421                  st_gen: 0,
  422                  st_lspare: 0,
  423                  st_qspare: [0, 0],
  424              }
  425          }
  426      }
  427  }
  428  
  429  #[cfg(target_os = "win32")]
  430  mod stat {
  431      pub mod arch {
  432          use libc;
  433          pub fn default_stat() -> libc::stat {
  434              libc::stat {
  435                  st_dev: 0,
  436                  st_ino: 0,
  437                  st_mode: 0,
  438                  st_nlink: 0,
  439                  st_uid: 0,
  440                  st_gid: 0,
  441                  st_rdev: 0,
  442                  st_size: 0,
  443                  st_atime: 0,
  444                  st_mtime: 0,
  445                  st_ctime: 0,
  446              }
  447          }
  448      }
  449  }
  450  
  451  #[cfg(target_os = "win32")]
  452  impl WindowsPath {
  453      pub fn stat(&self) -> Option<libc::stat> {
  454          #[fixed_stack_segment]; #[inline(never)];
  455          do self.with_c_str |buf| {
  456              let mut st = stat::arch::default_stat();
  457              match unsafe { libc::stat(buf, &mut st) } {
  458                  0 => Some(st),
  459                  _ => None,
  460              }
  461          }
  462      }
  463  
  464      pub fn exists(&self) -> bool {
  465          match self.stat() {
  466              None => false,
  467              Some(_) => true,
  468          }
  469      }
  470  
  471      pub fn get_size(&self) -> Option<i64> {
  472          match self.stat() {
  473              None => None,
  474              Some(ref st) => Some(st.st_size as i64),
  475          }
  476      }
  477  
  478      pub fn get_mode(&self) -> Option<uint> {
  479          match self.stat() {
  480              None => None,
  481              Some(ref st) => Some(st.st_mode as uint),
  482          }
  483      }
  484  }
  485  
  486  #[cfg(not(target_os = "win32"))]
  487  impl PosixPath {
  488      pub fn stat(&self) -> Option<libc::stat> {
  489          #[fixed_stack_segment]; #[inline(never)];
  490          do self.with_c_str |buf| {
  491              let mut st = stat::arch::default_stat();
  492              match unsafe { libc::stat(buf as *libc::c_char, &mut st) } {
  493                  0 => Some(st),
  494                  _ => None,
  495              }
  496          }
  497      }
  498  
  499      pub fn exists(&self) -> bool {
  500          match self.stat() {
  501              None => false,
  502              Some(_) => true,
  503          }
  504      }
  505  
  506      pub fn get_size(&self) -> Option<i64> {
  507          match self.stat() {
  508              None => None,
  509              Some(ref st) => Some(st.st_size as i64),
  510          }
  511      }
  512  
  513      pub fn get_mode(&self) -> Option<uint> {
  514          match self.stat() {
  515              None => None,
  516              Some(ref st) => Some(st.st_mode as uint),
  517          }
  518      }
  519  
  520      /// Executes a function `f` on `self` as well as on all of its ancestors.
  521      pub fn each_parent(&self, f&fn(&Path)) {
  522          if !self.components.is_empty() {
  523              f(self);
  524              self.pop().each_parent(f);
  525          }
  526      }
  527  
  528  }
  529  
  530  #[cfg(target_os = "freebsd")]
  531  #[cfg(target_os = "linux")]
  532  #[cfg(target_os = "macos")]
  533  impl PosixPath {
  534      pub fn get_atime(&self) -> Option<(i64, int)> {
  535          match self.stat() {
  536              None => None,
  537              Some(ref st) => {
  538                  Some((st.st_atime as i64,
  539                        st.st_atime_nsec as int))
  540              }
  541          }
  542      }
  543  
  544      pub fn get_mtime(&self) -> Option<(i64, int)> {
  545          match self.stat() {
  546              None => None,
  547              Some(ref st) => {
  548                  Some((st.st_mtime as i64,
  549                        st.st_mtime_nsec as int))
  550              }
  551          }
  552      }
  553  
  554      pub fn get_ctime(&self) -> Option<(i64, int)> {
  555          match self.stat() {
  556              None => None,
  557              Some(ref st) => {
  558                  Some((st.st_ctime as i64,
  559                        st.st_ctime_nsec as int))
  560              }
  561          }
  562      }
  563  }
  564  
  565  #[cfg(unix)]
  566  impl PosixPath {
  567      pub fn lstat(&self) -> Option<libc::stat> {
  568          #[fixed_stack_segment]; #[inline(never)];
  569          do self.with_c_str |buf| {
  570              let mut st = stat::arch::default_stat();
  571              match unsafe { libc::lstat(buf, &mut st) } {
  572                  0 => Some(st),
  573                  _ => None,
  574              }
  575          }
  576      }
  577  }
  578  
  579  #[cfg(target_os = "freebsd")]
  580  #[cfg(target_os = "macos")]
  581  impl PosixPath {
  582      pub fn get_birthtime(&self) -> Option<(i64, int){
  583          match self.stat() {
  584              None => None,
  585              Some(ref st) => {
  586                  Some((st.st_birthtime as i64,
  587                        st.st_birthtime_nsec as int))
  588              }
  589          }
  590      }
  591  }
  592  
  593  #[cfg(target_os = "win32")]
  594  impl WindowsPath {
  595      pub fn get_atime(&self) -> Option<(i64, int){
  596          match self.stat() {
  597              None => None,
  598              Some(ref st) => {
  599                  Some((st.st_atime as i64, 0))
  600              }
  601          }
  602      }
  603  
  604      pub fn get_mtime(&self) -> Option<(i64, int){
  605          match self.stat() {
  606              None => None,
  607              Some(ref st) => {
  608                  Some((st.st_mtime as i64, 0))
  609              }
  610          }
  611      }
  612  
  613      pub fn get_ctime(&self) -> Option<(i64, int){
  614          match self.stat() {
  615              None => None,
  616              Some(ref st) => {
  617                  Some((st.st_ctime as i64, 0))
  618              }
  619          }
  620      }
  621  
  622      /// Executes a function `f` on `self` as well as on all of its ancestors.
  623      pub fn each_parent(&self, f: &fn(&Path)) {
  624          if !self.components.is_empty() {
  625              f(self);
  626              self.pop().each_parent(f);
  627          }
  628      }
  629  }
  630  
  631  impl ToStr for PosixPath {
  632      fn to_str(&self) -> ~str {
  633          let mut s = ~"";
  634          if self.is_absolute {
  635              s.push_str("/");
  636          }
  637          s + self.components.connect("/")
  638      }
  639  }
  640  
  641  impl ToCStr for PosixPath {
  642      fn to_c_str(&self) -> c_str::CString {
  643          self.to_str().to_c_str()
  644      }
  645  
  646      unsafe fn to_c_str_unchecked(&self) -> c_str::CString {
  647          self.to_str().to_c_str_unchecked()
  648      }
  649  }
  650  
  651  impl GenericPath for PosixPath {
  652      fn from_str(s&str) -> PosixPath {
  653          let components = s.split_iter('/')
  654              .filter_map(|s| if s.is_empty() {None} else {Some(s.to_owned())})
  655              .collect();
  656          let is_absolute = (s.len() != 0 && s[0] == '/' as u8);
  657          PosixPath {
  658              is_absolute: is_absolute,
  659              components: components,
  660          }
  661      }
  662  
  663      fn with_dirname(&self, d&str) -> PosixPath {
  664          let dpath = PosixPath(d);
  665          match self.filename() {
  666              Some(ref f) => dpath.push(*f),
  667              None => dpath,
  668          }
  669      }
  670  
  671      fn with_filename(&self, f&str) -> PosixPath {
  672          assert!(!f.iter().all(posix::is_sep));
  673          self.dir_path().push(f)
  674      }
  675  
  676      fn file_path(&self) -> PosixPath {
  677          let cs = match self.filename() {
  678            None => ~[],
  679            Some(ref f) => ~[(*f).to_owned()]
  680          };
  681          PosixPath {
  682              is_absolute: false,
  683              components: cs,
  684          }
  685      }
  686  
  687      fn push(&self, s&str) -> PosixPath {
  688          let mut v = self.components.clone();
  689          for s in s.split_iter(posix::is_sep) {
  690              if !s.is_empty() {
  691                  v.push(s.to_owned())
  692              }
  693          }
  694          PosixPath {
  695              components: v,
  696              ..(*self).clone()
  697          }
  698      }
  699  
  700      fn push_many<S: Str>(&self, cs&[S]) -> PosixPath {
  701          let mut v = self.components.clone();
  702          for e in cs.iter() {
  703              for s in e.as_slice().split_iter(posix::is_sep) {
  704                  if !s.is_empty() {
  705                      v.push(s.to_owned())
  706                  }
  707              }
  708          }
  709          PosixPath {
  710              is_absolute: self.is_absolute,
  711              components: v,
  712          }
  713      }
  714  
  715      fn pop(&self) -> PosixPath {
  716          let mut cs = self.components.clone();
  717          if cs.len() != 0 {
  718              cs.pop();
  719          }
  720          PosixPath {
  721              is_absolute: self.is_absolute,
  722              components: cs,
  723          } //..self }
  724      }
  725  
  726      fn unsafe_join(&self, other&PosixPath) -> PosixPath {
  727          if other.is_absolute {
  728              PosixPath {
  729                  is_absolute: true,
  730                  components: other.components.clone(),
  731              }
  732          } else {
  733              self.push_rel(other)
  734          }
  735      }
  736  
  737      fn is_restricted(&self) -> bool {
  738          false
  739      }
  740  
  741      fn normalize(&self) -> PosixPath {
  742          PosixPath {
  743              is_absolute: self.is_absolute,
  744              components: normalize(self.components),
  745          } // ..self }
  746      }
  747  
  748      fn is_absolute(&self) -> bool {
  749          self.is_absolute
  750      }
  751  
  752      fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() }
  753  
  754  }
  755  
  756  
  757  impl ToStr for WindowsPath {
  758      fn to_str(&self) -> ~str {
  759          let mut s = ~"";
  760          match self.host {
  761            Some(ref h) => {
  762              s.push_str("\\\\");
  763              s.push_str(*h);
  764            }
  765            None => { }
  766          }
  767          match self.device {
  768            Some(ref d) => {
  769              s.push_str(*d);
  770              s.push_str(":");
  771            }
  772            None => { }
  773          }
  774          if self.is_absolute {
  775              s.push_str("\\");
  776          }
  777          s + self.components.connect("\\")
  778      }
  779  }
  780  
  781  impl c_str::ToCStr for WindowsPath {
  782      fn to_c_str(&self) -> c_str::CString {
  783          self.to_str().to_c_str()
  784      }
  785  
  786      unsafe fn to_c_str_unchecked(&self) -> c_str::CString {
  787          self.to_str().to_c_str_unchecked()
  788      }
  789  }
  790  
  791  impl GenericPath for WindowsPath {
  792      fn from_str(s&str) -> WindowsPath {
  793          let host;
  794          let device;
  795          let rest;
  796  
  797          match (
  798              windows::extract_drive_prefix(s),
  799              windows::extract_unc_prefix(s),
  800          ) {
  801              (Some((ref d, ref r)), _) => {
  802                  host = None;
  803                  device = Some((*d).clone());
  804                  rest = (*r).clone();
  805              }
  806              (None, Some((ref h, ref r))) => {
  807                  host = Some((*h).clone());
  808                  device = None;
  809                  rest = (*r).clone();
  810              }
  811              (None, None) => {
  812                  host = None;
  813                  device = None;
  814                  rest = s.to_owned();
  815              }
  816          }
  817  
  818          let components = rest.split_iter(windows::is_sep)
  819              .filter_map(|s| if s.is_empty() {None} else {Some(s.to_owned())})
  820              .collect();
  821  
  822          let is_absolute = (rest.len() != 0 && windows::is_sep(rest[0] as char));
  823          WindowsPath {
  824              host: host,
  825              device: device,
  826              is_absolute: is_absolute,
  827              components: components,
  828          }
  829      }
  830  
  831      fn with_dirname(&self, d&str) -> WindowsPath {
  832          let dpath = WindowsPath(d);
  833          match self.filename() {
  834              Some(ref f) => dpath.push(*f),
  835              None => dpath,
  836          }
  837      }
  838  
  839      fn with_filename(&self, f&str) -> WindowsPath {
  840          assert!(f.iter().all(windows::is_sep));
  841          self.dir_path().push(f)
  842      }
  843  
  844      fn file_path(&self) -> WindowsPath {
  845          WindowsPath {
  846              host: None,
  847              device: None,
  848              is_absolute: false,
  849              components: match self.filename() {
  850                  None => ~[],
  851                  Some(ref f) => ~[(*f).to_owned()],
  852              }
  853          }
  854      }
  855  
  856      fn push(&self, s&str) -> WindowsPath {
  857          let mut v = self.components.clone();
  858          for s in s.split_iter(windows::is_sep) {
  859              if !s.is_empty() {
  860                  v.push(s.to_owned())
  861              }
  862          }
  863          WindowsPath { components: v, ..(*self).clone() }
  864      }
  865  
  866      fn push_many<S: Str>(&self, cs&[S]) -> WindowsPath {
  867          let mut v = self.components.clone();
  868          for e in cs.iter() {
  869              for s in e.as_slice().split_iter(windows::is_sep) {
  870                  if !s.is_empty() {
  871                      v.push(s.to_owned())
  872                  }
  873              }
  874          }
  875          // tedious, but as-is, we can't use ..self
  876          WindowsPath {
  877              host: self.host.clone(),
  878              device: self.device.clone(),
  879              is_absolute: self.is_absolute,
  880              components: v
  881          }
  882      }
  883  
  884      fn pop(&self) -> WindowsPath {
  885          let mut cs = self.components.clone();
  886          if cs.len() != 0 {
  887              cs.pop();
  888          }
  889          WindowsPath {
  890              host: self.host.clone(),
  891              device: self.device.clone(),
  892              is_absolute: self.is_absolute,
  893              components: cs,
  894          }
  895      }
  896  
  897      fn unsafe_join(&self, other&WindowsPath) -> WindowsPath {
  898          /* rhs not absolute is simple push */
  899          if !other.is_absolute {
  900              return self.push_many(other.components);
  901          }
  902  
  903          /* if rhs has a host set, then the whole thing wins */
  904          match other.host {
  905              Some(ref host) => {
  906                  return WindowsPath {
  907                      host: Some((*host).clone()),
  908                      device: other.device.clone(),
  909                      is_absolute: true,
  910                      components: other.components.clone(),
  911                  };
  912              }
  913              _ => {}
  914          }
  915  
  916          /* if rhs has a device set, then a part wins */
  917          match other.device {
  918              Some(ref device) => {
  919                  return WindowsPath {
  920                      host: None,
  921                      device: Some((*device).clone()),
  922                      is_absolute: true,
  923                      components: other.components.clone(),
  924                  };
  925              }
  926              _ => {}
  927          }
  928  
  929          /* fallback: host and device of lhs win, but the
  930             whole path of the right */
  931          WindowsPath {
  932              host: self.host.clone(),
  933              device: self.device.clone(),
  934              is_absolute: self.is_absolute || other.is_absolute,
  935              components: other.components.clone(),
  936          }
  937      }
  938  
  939      fn is_restricted(&self) -> bool {
  940          match self.filestem() {
  941              Some(stem) => {
  942                  // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
  943                  // to_ascii_move and to_str_move to not do a unnecessary copy.
  944                  match stem.to_ascii().to_lower().to_str_ascii() {
  945                      ~"con" | ~"aux" | ~"com1" | ~"com2" | ~"com3" | ~"com4" |
  946                      ~"lpt1" | ~"lpt2" | ~"lpt3" | ~"prn" | ~"nul" => true,
  947                      _ => false
  948                  }
  949              },
  950              None => false
  951          }
  952      }
  953  
  954      fn normalize(&self) -> WindowsPath {
  955          WindowsPath {
  956              host: self.host.clone(),
  957              device: match self.device {
  958                  None => None,
  959  
  960                  // FIXME: #4318 Instead of to_ascii and to_str_ascii, could use
  961                  // to_ascii_move and to_str_move to not do a unnecessary copy.
  962                  Some(ref device) => Some(device.to_ascii().to_upper().to_str_ascii())
  963              },
  964              is_absolute: self.is_absolute,
  965              components: normalize(self.components)
  966          }
  967      }
  968  
  969      fn is_absolute(&self) -> bool {
  970          self.is_absolute
  971      }
  972  
  973      fn components<'a>(&'a self) -> &'a [~str] { self.components.as_slice() }
  974  
  975  }
  976  
  977  pub fn normalize(components&[~str]) -> ~[~str] {
  978      let mut cs = ~[];
  979      for c in components.iter() {
  980          if *c == ~"." && components.len() > 1 { loop; }
  981          if *c == ~"" { loop; }
  982          if *c == ~".." && cs.len() != 0 {
  983              cs.pop();
  984              loop;
  985          }
  986          cs.push((*c).clone());
  987      }
  988      cs
  989  }
  990  
  991  // Various posix helpers.
  992  pub mod posix {
  993  
  994      #[inline]
  995      pub fn is_sep(uchar) -> bool {
  996          u == '/'
  997      }
  998  
  999  }
 1000  
 1001  // Various windows helpers.
 1002  pub mod windows {
 1003      use libc;
 1004      use option::{None, Option, Some};
 1005  
 1006      #[inline]
 1007      pub fn is_sep(uchar) -> bool {
 1008          u == '/' || u == '\\'
 1009      }
 1010  
 1011      pub fn extract_unc_prefix(s&str) -> Option<(~str,~str)> {
 1012          if (s.len() > 1 &&
 1013              (s[0] == '\\' as u8 || s[0] == '/' as u8) &&
 1014              s[0] == s[1]) {
 1015              let mut i = 2;
 1016              while i < s.len() {
 1017                  if is_sep(s[i] as char) {
 1018                      let pre = s.slice(2, i).to_owned();
 1019                      let rest = s.slice(i, s.len()).to_owned();
 1020                      return Some((pre, rest));
 1021                  }
 1022                  i += 1;
 1023              }
 1024          }
 1025          None
 1026      }
 1027  
 1028      pub fn extract_drive_prefix(s&str) -> Option<(~str,~str)> {
 1029          #[fixed_stack_segment]; #[inline(never)];
 1030  
 1031          unsafe {
 1032              if (s.len() > 1 &&
 1033                  libc::isalpha(s[0] as libc::c_int) != 0 &&
 1034                  s[1] == ':' as u8) {
 1035                  let rest = if s.len() == 2 {
 1036                      ~""
 1037                  } else {
 1038                      s.slice(2, s.len()).to_owned()
 1039                  };
 1040                  return Some((s.slice(0,1).to_owned(), rest));
 1041              }
 1042              None
 1043          }
 1044      }
 1045  }
 1046  
 1047  #[cfg(test)]
 1048  mod tests {
 1049      use option::{None, Some};
 1050      use path::{PosixPath, WindowsPath, windows};
 1051  
 1052      #[test]
 1053      fn test_double_slash_collapsing() {
 1054          let path = PosixPath("tmp/");
 1055          let path = path.push("/hmm");
 1056          let path = path.normalize();
 1057          assert_eq!(~"tmp/hmm", path.to_str());
 1058  
 1059          let path = WindowsPath("tmp/");
 1060          let path = path.push("/hmm");
 1061          let path = path.normalize();
 1062          assert_eq!(~"tmp\\hmm", path.to_str());
 1063      }
 1064  
 1065      #[test]
 1066      fn test_filetype_foo_bar() {
 1067          let wp = PosixPath("foo.bar");
 1068          assert_eq!(wp.filetype(), Some(".bar"));
 1069  
 1070          let wp = WindowsPath("foo.bar");
 1071          assert_eq!(wp.filetype(), Some(".bar"));
 1072      }
 1073  
 1074      #[test]
 1075      fn test_filetype_foo() {
 1076          let wp = PosixPath("foo");
 1077          assert_eq!(wp.filetype(), None);
 1078  
 1079          let wp = WindowsPath("foo");
 1080          assert_eq!(wp.filetype(), None);
 1081      }
 1082  
 1083      #[test]
 1084      fn test_posix_paths() {
 1085          fn t(wp: &PosixPath, s: &str) {
 1086              let ss = wp.to_str();
 1087              let sss = s.to_owned();
 1088              if (ss != sss) {
 1089                  debug!("got %s", ss);
 1090                  debug!("expected %s", sss);
 1091                  assert_eq!(ss, sss);
 1092              }
 1093          }
 1094  
 1095          t(&(PosixPath("hi")), "hi");
 1096          t(&(PosixPath("/lib")), "/lib");
 1097          t(&(PosixPath("hi/there")), "hi/there");
 1098          t(&(PosixPath("hi/there.txt")), "hi/there.txt");
 1099  
 1100          t(&(PosixPath("hi/there.txt")), "hi/there.txt");
 1101          t(&(PosixPath("hi/there.txt")
 1102             .with_filetype("")), "hi/there");
 1103  
 1104          t(&(PosixPath("/a/b/c/there.txt")
 1105              .with_dirname("hi")), "hi/there.txt");
 1106  
 1107          t(&(PosixPath("hi/there.txt")
 1108              .with_dirname(".")), "./there.txt");
 1109  
 1110          t(&(PosixPath("a/b/c")
 1111              .push("..")), "a/b/c/..");
 1112  
 1113          t(&(PosixPath("there.txt")
 1114              .with_filetype("o")), "there.o");
 1115  
 1116          t(&(PosixPath("hi/there.txt")
 1117              .with_filetype("o")), "hi/there.o");
 1118  
 1119          t(&(PosixPath("hi/there.txt")
 1120              .with_filetype("o")
 1121              .with_dirname("/usr/lib")),
 1122            "/usr/lib/there.o");
 1123  
 1124          t(&(PosixPath("hi/there.txt")
 1125              .with_filetype("o")
 1126              .with_dirname("/usr/lib/")),
 1127            "/usr/lib/there.o");
 1128  
 1129          t(&(PosixPath("hi/there.txt")
 1130              .with_filetype("o")
 1131              .with_dirname("/usr//lib//")),
 1132              "/usr/lib/there.o");
 1133  
 1134          t(&(PosixPath("/usr/bin/rust")
 1135              .push_many([~"lib", ~"thingy.so"])
 1136              .with_filestem("librustc")),
 1137            "/usr/bin/rust/lib/librustc.so");
 1138  
 1139      }
 1140  
 1141      #[test]
 1142      fn test_posix_push_with_backslash() {
 1143          let a = PosixPath("/aaa/bbb");
 1144          let b = a.push("x\\y"); // \ is not a file separator for posix paths
 1145          assert_eq!(a.components.len(), 2);
 1146          assert_eq!(b.components.len(), 3);
 1147      }
 1148  
 1149      #[test]
 1150      fn test_normalize() {
 1151          fn t(wp: &PosixPath, s: &str) {
 1152              let ss = wp.to_str();
 1153              let sss = s.to_owned();
 1154              if (ss != sss) {
 1155                  debug!("got %s", ss);
 1156                  debug!("expected %s", sss);
 1157                  assert_eq!(ss, sss);
 1158              }
 1159          }
 1160  
 1161          t(&(PosixPath("hi/there.txt")
 1162              .with_dirname(".").normalize()), "there.txt");
 1163  
 1164          t(&(PosixPath("a/b/../c/././/../foo.txt/").normalize()),
 1165            "a/foo.txt");
 1166  
 1167          t(&(PosixPath("a/b/c")
 1168              .push("..").normalize()), "a/b");
 1169      }
 1170  
 1171      #[test]
 1172      fn test_extract_unc_prefixes() {
 1173          assert!(windows::extract_unc_prefix("\\\\").is_none());
 1174          assert!(windows::extract_unc_prefix("//").is_none());
 1175          assert!(windows::extract_unc_prefix("\\\\hi").is_none());
 1176          assert!(windows::extract_unc_prefix("//hi").is_none());
 1177          assert!(windows::extract_unc_prefix("\\\\hi\\") ==
 1178              Some((~"hi", ~"\\")));
 1179          assert!(windows::extract_unc_prefix("//hi\\") ==
 1180              Some((~"hi", ~"\\")));
 1181          assert!(windows::extract_unc_prefix("\\\\hi\\there") ==
 1182              Some((~"hi", ~"\\there")));
 1183          assert!(windows::extract_unc_prefix("//hi/there") ==
 1184              Some((~"hi", ~"/there")));
 1185          assert!(windows::extract_unc_prefix(
 1186              "\\\\hi\\there\\friends.txt") ==
 1187              Some((~"hi", ~"\\there\\friends.txt")));
 1188          assert!(windows::extract_unc_prefix(
 1189              "//hi\\there\\friends.txt") ==
 1190              Some((~"hi", ~"\\there\\friends.txt")));
 1191      }
 1192  
 1193      #[test]
 1194      fn test_extract_drive_prefixes() {
 1195          assert!(windows::extract_drive_prefix("c").is_none());
 1196          assert!(windows::extract_drive_prefix("c:") ==
 1197                       Some((~"c", ~"")));
 1198          assert!(windows::extract_drive_prefix("d:") ==
 1199                       Some((~"d", ~"")));
 1200          assert!(windows::extract_drive_prefix("z:") ==
 1201                       Some((~"z", ~"")));
 1202          assert!(windows::extract_drive_prefix("c:\\hi") ==
 1203                       Some((~"c", ~"\\hi")));
 1204          assert!(windows::extract_drive_prefix("d:hi") ==
 1205                       Some((~"d", ~"hi")));
 1206          assert!(windows::extract_drive_prefix("c:hi\\there.txt") ==
 1207                       Some((~"c", ~"hi\\there.txt")));
 1208          assert!(windows::extract_drive_prefix("c:\\hi\\there.txt") ==
 1209                       Some((~"c", ~"\\hi\\there.txt")));
 1210      }
 1211  
 1212      #[test]
 1213      fn test_windows_paths() {
 1214          fn t(wp: &WindowsPath, s: &str) {
 1215              let ss = wp.to_str();
 1216              let sss = s.to_owned();
 1217              if (ss != sss) {
 1218                  debug!("got %s", ss);
 1219                  debug!("expected %s", sss);
 1220                  assert_eq!(ss, sss);
 1221              }
 1222          }
 1223  
 1224          t(&(WindowsPath("hi")), "hi");
 1225          t(&(WindowsPath("hi/there")), "hi\\there");
 1226          t(&(WindowsPath("hi/there.txt")), "hi\\there.txt");
 1227  
 1228          t(&(WindowsPath("there.txt")
 1229              .with_filetype("o")), "there.o");
 1230  
 1231          t(&(WindowsPath("hi/there.txt")
 1232              .with_filetype("o")), "hi\\there.o");
 1233  
 1234          t(&(WindowsPath("hi/there.txt")
 1235              .with_filetype("o")
 1236              .with_dirname("c:\\program files A")),
 1237            "c:\\program files A\\there.o");
 1238  
 1239          t(&(WindowsPath("hi/there.txt")
 1240              .with_filetype("o")
 1241              .with_dirname("c:\\program files B\\")),
 1242            "c:\\program files B\\there.o");
 1243  
 1244          t(&(WindowsPath("hi/there.txt")
 1245              .with_filetype("o")
 1246              .with_dirname("c:\\program files C\\/")),
 1247              "c:\\program files C\\there.o");
 1248  
 1249          t(&(WindowsPath("c:\\program files (x86)\\rust")
 1250              .push_many([~"lib", ~"thingy.dll"])
 1251              .with_filename("librustc.dll")),
 1252            "c:\\program files (x86)\\rust\\lib\\librustc.dll");
 1253  
 1254          t(&(WindowsPath("\\\\computer\\share")
 1255              .unsafe_join(&WindowsPath("\\a"))),
 1256            "\\\\computer\\a");
 1257  
 1258          t(&(WindowsPath("//computer/share")
 1259              .unsafe_join(&WindowsPath("\\a"))),
 1260            "\\\\computer\\a");
 1261  
 1262          t(&(WindowsPath("//computer/share")
 1263              .unsafe_join(&WindowsPath("\\\\computer\\share"))),
 1264            "\\\\computer\\share");
 1265  
 1266          t(&(WindowsPath("C:/whatever")
 1267              .unsafe_join(&WindowsPath("//computer/share/a/b"))),
 1268            "\\\\computer\\share\\a\\b");
 1269  
 1270          t(&(WindowsPath("C:")
 1271              .unsafe_join(&WindowsPath("D:/foo"))),
 1272            "D:\\foo");
 1273  
 1274          t(&(WindowsPath("C:")
 1275              .unsafe_join(&WindowsPath("B"))),
 1276            "C:B");
 1277  
 1278          t(&(WindowsPath("C:")
 1279              .unsafe_join(&WindowsPath("/foo"))),
 1280            "C:\\foo");
 1281  
 1282          t(&(WindowsPath("C:\\")
 1283              .unsafe_join(&WindowsPath("\\bar"))),
 1284            "C:\\bar");
 1285  
 1286          t(&(WindowsPath("")
 1287              .unsafe_join(&WindowsPath(""))),
 1288            "");
 1289  
 1290          t(&(WindowsPath("")
 1291              .unsafe_join(&WindowsPath("a"))),
 1292            "a");
 1293  
 1294          t(&(WindowsPath("")
 1295              .unsafe_join(&WindowsPath("C:\\a"))),
 1296            "C:\\a");
 1297  
 1298          t(&(WindowsPath("c:\\foo")
 1299              .normalize()),
 1300            "C:\\foo");
 1301      }
 1302  
 1303      #[test]
 1304      fn test_windows_path_restrictions() {
 1305          assert_eq!(WindowsPath("hi").is_restricted(), false);
 1306          assert_eq!(WindowsPath("C:\\NUL").is_restricted(), true);
 1307          assert_eq!(WindowsPath("C:\\COM1.TXT").is_restricted(), true);
 1308          assert_eq!(WindowsPath("c:\\prn.exe").is_restricted(), true);
 1309      }
 1310  
 1311      #[test]
 1312      fn test_is_ancestor_of() {
 1313          assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d")));
 1314          assert!(!&PosixPath("/a/b/c/d").is_ancestor_of(&PosixPath("/a/b")));
 1315          assert!(!&PosixPath("/a/b").is_ancestor_of(&PosixPath("/c/d")));
 1316          assert!(&PosixPath("/a/b").is_ancestor_of(&PosixPath("/a/b/c/d")));
 1317          assert!(&PosixPath("/").is_ancestor_of(&PosixPath("/a/b/c")));
 1318          assert!(!&PosixPath("/").is_ancestor_of(&PosixPath("")));
 1319          assert!(!&PosixPath("/a/b/c").is_ancestor_of(&PosixPath("")));
 1320          assert!(!&PosixPath("").is_ancestor_of(&PosixPath("/a/b/c")));
 1321  
 1322          assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d")));
 1323          assert!(!&WindowsPath("C:\\a\\b\\c\\d").is_ancestor_of(&WindowsPath("C:\\a\\b")));
 1324          assert!(!&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\c\\d")));
 1325          assert!(&WindowsPath("C:\\a\\b").is_ancestor_of(&WindowsPath("C:\\a\\b\\c\\d")));
 1326          assert!(&WindowsPath("C:\\").is_ancestor_of(&WindowsPath("C:\\a\\b\\c")));
 1327          assert!(!&WindowsPath("C:\\").is_ancestor_of(&WindowsPath("")));
 1328          assert!(!&WindowsPath("C:\\a\\b\\c").is_ancestor_of(&WindowsPath("")));
 1329          assert!(!&WindowsPath("").is_ancestor_of(&WindowsPath("C:\\a\\b\\c")));
 1330  
 1331      }
 1332  
 1333      #[test]
 1334      fn test_relative_to1() {
 1335          let p1 = PosixPath("/usr/bin/rustc");
 1336          let p2 = PosixPath("/usr/lib/mylib");
 1337          let res = p1.get_relative_to(&p2);
 1338          assert_eq!(res, PosixPath("../lib"));
 1339  
 1340          let p1 = WindowsPath("C:\\usr\\bin\\rustc");
 1341          let p2 = WindowsPath("C:\\usr\\lib\\mylib");
 1342          let res = p1.get_relative_to(&p2);
 1343          assert_eq!(res, WindowsPath("..\\lib"));
 1344  
 1345      }
 1346  
 1347      #[test]
 1348      fn test_relative_to2() {
 1349          let p1 = PosixPath("/usr/bin/rustc");
 1350          let p2 = PosixPath("/usr/bin/../lib/mylib");
 1351          let res = p1.get_relative_to(&p2);
 1352          assert_eq!(res, PosixPath("../lib"));
 1353  
 1354          let p1 = WindowsPath("C:\\usr\\bin\\rustc");
 1355          let p2 = WindowsPath("C:\\usr\\bin\\..\\lib\\mylib");
 1356          let res = p1.get_relative_to(&p2);
 1357          assert_eq!(res, WindowsPath("..\\lib"));
 1358      }
 1359  
 1360      #[test]
 1361      fn test_relative_to3() {
 1362          let p1 = PosixPath("/usr/bin/whatever/rustc");
 1363          let p2 = PosixPath("/usr/lib/whatever/mylib");
 1364          let res = p1.get_relative_to(&p2);
 1365          assert_eq!(res, PosixPath("../../lib/whatever"));
 1366  
 1367          let p1 = WindowsPath("C:\\usr\\bin\\whatever\\rustc");
 1368          let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib");
 1369          let res = p1.get_relative_to(&p2);
 1370          assert_eq!(res, WindowsPath("..\\..\\lib\\whatever"));
 1371  
 1372      }
 1373  
 1374      #[test]
 1375      fn test_relative_to4() {
 1376          let p1 = PosixPath("/usr/bin/whatever/../rustc");
 1377          let p2 = PosixPath("/usr/lib/whatever/mylib");
 1378          let res = p1.get_relative_to(&p2);
 1379          assert_eq!(res, PosixPath("../lib/whatever"));
 1380  
 1381          let p1 = WindowsPath("C:\\usr\\bin\\whatever\\..\\rustc");
 1382          let p2 = WindowsPath("C:\\usr\\lib\\whatever\\mylib");
 1383          let res = p1.get_relative_to(&p2);
 1384          assert_eq!(res, WindowsPath("..\\lib\\whatever"));
 1385  
 1386      }
 1387  
 1388      #[test]
 1389      fn test_relative_to5() {
 1390          let p1 = PosixPath("/usr/bin/whatever/../rustc");
 1391          let p2 = PosixPath("/usr/lib/whatever/../mylib");
 1392          let res = p1.get_relative_to(&p2);
 1393          assert_eq!(res, PosixPath("../lib"));
 1394  
 1395          let p1 = WindowsPath("C:\\usr\\bin/whatever\\..\\rustc");
 1396          let p2 = WindowsPath("C:\\usr\\lib\\whatever\\..\\mylib");
 1397          let res = p1.get_relative_to(&p2);
 1398          assert_eq!(res, WindowsPath("..\\lib"));
 1399      }
 1400  
 1401      #[test]
 1402      fn test_relative_to6() {
 1403          let p1 = PosixPath("/1");
 1404          let p2 = PosixPath("/2/3");
 1405          let res = p1.get_relative_to(&p2);
 1406          assert_eq!(res, PosixPath("2"));
 1407  
 1408          let p1 = WindowsPath("C:\\1");
 1409          let p2 = WindowsPath("C:\\2\\3");
 1410          let res = p1.get_relative_to(&p2);
 1411          assert_eq!(res, WindowsPath("2"));
 1412  
 1413      }
 1414  
 1415      #[test]
 1416      fn test_relative_to7() {
 1417          let p1 = PosixPath("/1/2");
 1418          let p2 = PosixPath("/3");
 1419          let res = p1.get_relative_to(&p2);
 1420          assert_eq!(res, PosixPath(".."));
 1421  
 1422          let p1 = WindowsPath("C:\\1\\2");
 1423          let p2 = WindowsPath("C:\\3");
 1424          let res = p1.get_relative_to(&p2);
 1425          assert_eq!(res, WindowsPath(".."));
 1426  
 1427      }
 1428  
 1429      #[test]
 1430      fn test_relative_to8() {
 1431          let p1 = PosixPath("/home/brian/Dev/rust/build/").push_rel(
 1432              &PosixPath("stage2/lib/rustc/i686-unknown-linux-gnu/lib/librustc.so"));
 1433          let p2 = PosixPath("/home/brian/Dev/rust/build/stage2/bin/..").push_rel(
 1434              &PosixPath("lib/rustc/i686-unknown-linux-gnu/lib/libstd.so"));
 1435          let res = p1.get_relative_to(&p2);
 1436          debug!("test_relative_to8: %s vs. %s",
 1437                 res.to_str(),
 1438                 PosixPath(".").to_str());
 1439          assert_eq!(res, PosixPath("."));
 1440  
 1441          let p1 = WindowsPath("C:\\home\\brian\\Dev\\rust\\build\\").push_rel(
 1442              &WindowsPath("stage2\\lib\\rustc\\i686-unknown-linux-gnu\\lib\\librustc.so"));
 1443          let p2 = WindowsPath("\\home\\brian\\Dev\\rust\\build\\stage2\\bin\\..").push_rel(
 1444              &WindowsPath("lib\\rustc\\i686-unknown-linux-gnu\\lib\\libstd.so"));
 1445          let res = p1.get_relative_to(&p2);
 1446          debug!("test_relative_to8: %s vs. %s",
 1447                 res.to_str(),
 1448                 WindowsPath(".").to_str());
 1449          assert_eq!(res, WindowsPath("."));
 1450  
 1451      }
 1452  
 1453  }

libstd/path.rs:45:1-45:1 -fn- definition:

pub fn WindowsPath(s: &str) -> WindowsPath {
references:-
832:         let dpath = WindowsPath(d);


libstd/path.rs:38:23-38:23 -struct- definition:
#[deriving(Clone, Eq)]
pub struct WindowsPath {
references:-
897:     fn unsafe_join(&self, other: &WindowsPath) -> WindowsPath {
955:         WindowsPath {
38: #[deriving(Clone, Eq)]
38: #[deriving(Clone, Eq)]
839:     fn with_filename(&self, f: &str) -> WindowsPath {
931:         WindowsPath {
38: #[deriving(Clone, Eq)]
897:     fn unsafe_join(&self, other: &WindowsPath) -> WindowsPath {
823:         WindowsPath {
792:     fn from_str(s: &str) -> WindowsPath {
906:                 return WindowsPath {
863:         WindowsPath { components: v, ..(*self).clone() }
38: #[deriving(Clone, Eq)]
781: impl c_str::ToCStr for WindowsPath {
38: #[deriving(Clone, Eq)]
38: #[deriving(Clone, Eq)]
954:     fn normalize(&self) -> WindowsPath {
919:                 return WindowsPath {
791: impl GenericPath for WindowsPath {
856:     fn push(&self, s: &str) -> WindowsPath {
38: #[deriving(Clone, Eq)]
876:         WindowsPath {
889:         WindowsPath {
38: #[deriving(Clone, Eq)]
845:         WindowsPath {
844:     fn file_path(&self) -> WindowsPath {
757: impl ToStr for WindowsPath {
38: #[deriving(Clone, Eq)]
38: #[deriving(Clone, Eq)]
884:     fn pop(&self) -> WindowsPath {
(866)(831)(46)(38)

libstd/path.rs:55:1-55:1 -fn- definition:

pub fn PosixPath(s: &str) -> PosixPath {
references:-
664:         let dpath = PosixPath(d);
libstd/rt/uv/uvio.rs:
2180:             let mut fd = (*io).fs_open(&Path(path), create_fm, create_fa).unwrap();
2193:         (*io).fs_unlink(&Path(path));
634:                                 path: Path(path_str),
723:                                 paths.push(Path(path_str+"/"+*r));
2187:             let mut fd = (*io).fs_open(&Path(path), ro_fm, ro_fa).unwrap();
libstd/os.rs:
591:             Path("/data/tmp")
537:           Some(Path(*p))
593:             getenv_nonempty("TMPDIR").unwrap_or(Path("/tmp"))
517:     load_self().map_move(|path| Path(path).dir_path())
81:             Path(str::raw::from_c_str(buf as *c_char))
582:                     Some(Path(x))


libstd/path.rs:1028:4-1028:4 -fn- definition:
    pub fn extract_drive_prefix(s: &str) -> Option<(~str,~str)> {
        #[fixed_stack_segment]; #[inline(never)];
references:-
798:             windows::extract_drive_prefix(s),


libstd/path.rs:976:1-976:1 -fn- definition:

pub fn normalize(components: &[~str]) -> ~[~str] {
references:-
744:             components: normalize(self.components),
965:             components: normalize(self.components)


libstd/path.rs:995:4-995:4 -fn- definition:
    pub fn is_sep(u: char) -> bool {
        u == '/'
references:-
672:         assert!(!f.iter().all(posix::is_sep));
689:         for s in s.split_iter(posix::is_sep) {
703:             for s in e.as_slice().split_iter(posix::is_sep) {


libstd/path.rs:1007:4-1007:4 -fn- definition:
    pub fn is_sep(u: char) -> bool {
        u == '/' || u == '\\'
references:-
869:             for s in e.as_slice().split_iter(windows::is_sep) {
858:         for s in s.split_iter(windows::is_sep) {
1017:                 if is_sep(s[i] as char) {
840:         assert!(! f.iter().all(windows::is_sep));
822:         let is_absolute = (rest.len() != 0 && windows::is_sep(rest[0] as char));
818:         let components = rest.split_iter(windows::is_sep)


libstd/path.rs:50:23-50:23 -struct- definition:
#[deriving(Clone, Eq)]
pub struct PosixPath {
references:-
50: #[deriving(Clone, Eq)]
687:     fn push(&self, s: &str) -> PosixPath {
50: #[deriving(Clone, Eq)]
50: #[deriving(Clone, Eq)]
657:         PosixPath {
652:     fn from_str(s: &str) -> PosixPath {
487: impl PosixPath {
694:         PosixPath {
742:         PosixPath {
50: #[deriving(Clone, Eq)]
681:         PosixPath {
50: #[deriving(Clone, Eq)]
50: #[deriving(Clone, Eq)]
726:     fn unsafe_join(&self, other: &PosixPath) -> PosixPath {
715:     fn pop(&self) -> PosixPath {
676:     fn file_path(&self) -> PosixPath {
631: impl ToStr for PosixPath {
50: #[deriving(Clone, Eq)]
651: impl GenericPath for PosixPath {
641: impl ToCStr for PosixPath {
50: #[deriving(Clone, Eq)]
726:     fn unsafe_join(&self, other: &PosixPath) -> PosixPath {
50: #[deriving(Clone, Eq)]
533: impl PosixPath {
566: impl PosixPath {
663:     fn with_dirname(&self, d: &str) -> PosixPath {
671:     fn with_filename(&self, f: &str) -> PosixPath {
700:     fn push_many<S: Str>(&self, cs: &[S]) -> PosixPath {
728:             PosixPath {
720:         PosixPath {
(741)(50)(50)(521)(709)(56)
libstd/run.rs:
(80)(795)(638)
libstd/unstable/dynamic_lib.rs:
(150)(44)
libstd/rt/io/mod.rs:
(626)
libstd/rt/io/file.rs:
(679)(564)(449)(282)(685)(569)(565)
libstd/rt/io/support.rs:
(23)
libstd/rt/rtio.rs:
(65)(86)
libstd/rt/uv/uvio.rs:
(706)(703)
libstd/io.rs:
(1064)(1793)(1626)(1323)(1620)(1781)
libstd/os.rs:
(626)(534)(980)(607)(706)(906)(862)(991)(573)(991)(655)(965)(616)(807)(576)(72)(877)(888)(835)(589)(813)(717)(645)(888)(807)(906)(645)(689)(850)(607)..3more..


libstd/path.rs:335:8-335:8 -fn- definition:
        pub fn default_stat() -> libc::stat {
            libc::stat {
references:-
570:             let mut st = stat::arch::default_stat();
491:             let mut st = stat::arch::default_stat();


libstd/path.rs:1011:4-1011:4 -fn- definition:
    pub fn extract_unc_prefix(s: &str) -> Option<(~str,~str)> {
        if (s.len() > 1 &&
references:-
799:             windows::extract_unc_prefix(s),


libstd/path.rs:59:1-59:1 -trait- definition:

pub trait GenericPath : Clone + Eq + ToStr {
references:-
175:     fn unsafe_join(&self, (&Self)) -> Self;
202:     fn get_relative_to(&self, abs2: (&Self)) -> Self {
157:     fn push(&self, (&str)) -> Self;
124:     fn with_filestem(&self, s: &str) -> Self {
160:     fn push_rel(&self, other: &Self) -> Self {
160:     fn push_rel(&self, other: &Self) -> Self {
227:         let mut result: Self = GenericPath::from_str(".");
192:     fn is_ancestor_of(&self, other: &Self) -> bool {
651: impl GenericPath for PosixPath {
791: impl GenericPath for WindowsPath {
144:     fn dir_path(&self) -> Self {
175:     fn unsafe_join(&self, (&Self)) -> Self;
133:     fn with_filetype(&self, t: &str) -> Self {
171:     fn pop(&self) -> Self;
62:     fn from_str(&str) -> Self;
230:             let p: Self = GenericPath::from_str("");
202:     fn get_relative_to(&self, abs2: (&Self)) -> Self {
153:     fn file_path(&self) -> Self;
120:     fn with_filename(&self, (&str)) -> Self;
167:     fn push_many<S: Str>(&self, (&[S])) -> Self;
185:     fn normalize(&self) -> Self;
116:     fn with_dirname(&self, (&str)) -> Self;