4 File system manipulation
16 fn rust_path_is_dir(path: str::sbuf) -> int;
17 fn rust_path_exists(path: str::sbuf) -> int;
23 Get the default path separator for the host platform
25 fn path_sep() -> str { ret str::from_char(os_fs::path_sep); }
27 // FIXME: This type should probably be constrained
31 A path or fragment of a filesystem path
38 Get the directory portion of a path
40 Returns all of the path up to, but excluding, the final path separator.
41 The dirname of "/usr/share" will be "/usr", but the dirname of
42 "/usr/share/" is "/usr/share".
44 If the path is not prefixed with a directory, then "." is returned.
46 fn dirname(p: path) -> path {
47 let i: int = str::rindex(p, os_fs::path_sep as u8);
49 i = str::rindex(p, os_fs::alt_path_sep as u8);
50 if i == -1 { ret "."; }
52 ret str::substr(p, 0u, i as uint);
58 Get the file name portion of a path
60 Returns the portion of the path after the final path separator.
61 The basename of "/usr/share" will be "share". If there are no
62 path separators in the path then the returned path is identical to
63 the provided path. If an empty path is provided or the path ends
64 with a path separator then an empty path is returned.
66 fn basename(p: path) -> path {
67 let i: int = str::rindex(p, os_fs::path_sep as u8);
69 i = str::rindex(p, os_fs::alt_path_sep as u8);
72 let len = str::byte_len(p);
73 if i + 1 as uint >= len { ret p; }
74 ret str::slice(p, i + 1 as uint, len);
78 // FIXME: Need some typestate to avoid bounds check when len(pre) == 0
82 Connects to path segments
84 Given paths `pre` and `post` this function will return a path
85 that is equal to `post` appended to `pre`, inserting a path separator
86 between the two as needed.
88 fn connect(pre: path, post: path) -> path {
89 let len = str::byte_len(pre);
90 ret if pre[len - 1u] == os_fs::path_sep as u8 {
94 } else { pre + path_sep() + post };
98 Function: connect_many
100 Connects a vector of path segments into a single path.
102 Inserts path separators as needed.
104 fn connect_many(paths: [path]) : vec::is_not_empty(paths) -> path {
105 ret if vec::len(paths) == 1u {
108 let rest = vec::slice(paths, 1u, vec::len(paths));
109 check vec::is_not_empty(rest);
110 connect(paths[0], connect_many(rest))
115 Function: path_is_dir
117 Indicates whether a path represents a directory.
119 fn path_is_dir(p: path) -> bool {
120 ret str::as_buf(p, {|buf| rustrt::rust_path_is_dir(buf) != 0 });
124 Function: path_exists
126 Indicates whether a path exists.
128 fn path_exists(p: path) -> bool {
129 ret str::as_buf(p, {|buf| rustrt::rust_path_exists(buf) != 0 });
135 Creates a directory at the specified path.
137 fn make_dir(p: path, mode: ctypes::c_int) -> bool {
140 #[cfg(target_os = "win32")]
141 fn mkdir(_p: path, _mode: ctypes::c_int) -> bool unsafe {
142 // FIXME: turn mode into something useful?
143 ret str::as_buf(_p, {|buf|
144 os::kernel32::CreateDirectoryA(
145 buf, unsafe::reinterpret_cast(0))
149 #[cfg(target_os = "linux")]
150 #[cfg(target_os = "macos")]
151 #[cfg(target_os = "freebsd")]
152 fn mkdir(_p: path, _mode: ctypes::c_int) -> bool {
153 ret str::as_buf(_p, {|buf| os::libc::mkdir(buf, _mode) == 0i32 });
160 Lists the contents of a directory.
162 fn list_dir(p: path) -> [str] {
164 let pl = str::byte_len(p);
165 if pl == 0u || p[pl - 1u] as char != os_fs::path_sep { p += path_sep(); }
166 let full_paths: [str] = [];
167 for filename: str in os_fs::list_dir(p) {
168 if !str::eq(filename, ".") {
169 if !str::eq(filename, "..") { full_paths += [p + filename]; }
178 Removes a directory at the specified path.
180 fn remove_dir(p: path) -> bool {
183 #[cfg(target_os = "win32")]
184 fn rmdir(_p: path) -> bool {
185 ret str::as_buf(_p, {|buf| os::kernel32::RemoveDirectoryA(buf)});
188 #[cfg(target_os = "linux")]
189 #[cfg(target_os = "macos")]
190 #[cfg(target_os = "freebsd")]
191 fn rmdir(_p: path) -> bool {
192 ret str::as_buf(_p, {|buf| os::libc::rmdir(buf) == 0i32 });
196 fn change_dir(p: path) -> bool {
199 #[cfg(target_os = "win32")]
200 fn chdir(_p: path) -> bool {
201 ret str::as_buf(_p, {|buf| os::kernel32::SetCurrentDirectoryA(buf)});
204 #[cfg(target_os = "linux")]
205 #[cfg(target_os = "macos")]
206 #[cfg(target_os = "freebsd")]
207 fn chdir(_p: path) -> bool {
208 ret str::as_buf(_p, {|buf| os::libc::chdir(buf) == 0i32 });
213 Function: path_is_absolute
215 Indicates whether a path is absolute.
217 A path is considered absolute if it begins at the filesystem root ("/") or,
218 on Windows, begins with a drive letter.
220 fn path_is_absolute(p: path) -> bool { ret os_fs::path_is_absolute(p); }
222 // FIXME: under Windows, we should prepend the current drive letter to paths
223 // that start with a slash.
225 Function: make_absolute
227 Convert a relative path to an absolute path
229 If the given path is relative, return it prepended with the current working
230 directory. If the given path is already an absolute path, return it
233 fn make_absolute(p: path) -> path {
234 if path_is_absolute(p) { ret p; } else { ret connect(getcwd(), p); }
240 Split a path into it's individual components
242 Splits a given path by path separators and returns a vector containing
243 each piece of the path. On Windows, if the path is absolute then
244 the first element of the returned vector will be the drive letter
247 fn split(p: path) -> [path] {
248 let split1 = str::split(p, os_fs::path_sep as u8);
251 split2 += str::split(s, os_fs::alt_path_sep as u8);
259 Split a path into a pair of strings with the first element being the filename
260 without the extension and the second being either empty or the file extension
261 including the period. Leading periods in the basename are ignored. If the
262 path includes directory components then they are included in the filename part
265 fn splitext(p: path) -> (str, str) {
266 if str::is_empty(p) { ("", "") }
268 let parts = str::split(p, '.' as u8);
269 if vec::len(parts) > 1u {
270 let base = str::connect(vec::init(parts), ".");
271 let ext = "." + option::get(vec::last(parts));
273 fn is_dotfile(base: str) -> bool {
276 base, str::from_char(os_fs::path_sep))
278 base, str::from_char(os_fs::alt_path_sep))
281 fn ext_contains_sep(ext: str) -> bool {
282 vec::len(split(ext)) > 1u
285 fn no_basename(ext: str) -> bool {
287 ext, str::from_char(os_fs::path_sep))
289 ext, str::from_char(os_fs::alt_path_sep))
293 || ext_contains_sep(ext)
294 || no_basename(ext) {
308 Removes extra "." and ".." entries from paths.
310 Does not follow symbolic links.
312 fn normalize(p: path) -> path {
314 let s = strip_dots(s);
315 let s = rollup_doubledots(s);
317 let s = if check vec::is_not_empty(s) {
322 let s = reabsolute(p, s);
323 let s = reterminate(p, s);
325 let s = if str::byte_len(s) == 0u {
333 fn strip_dots(s: [path]) -> [path] {
334 vec::filter_map(s, { |elem|
343 fn rollup_doubledots(s: [path]) -> [path] {
344 if vec::is_empty(s) {
363 let t = vec::reversed(t);
371 #[cfg(target_os = "linux")]
372 #[cfg(target_os = "macos")]
373 #[cfg(target_os = "freebsd")]
374 fn reabsolute(orig: path, new: path) -> path {
375 if path_is_absolute(orig) {
382 #[cfg(target_os = "win32")]
383 fn reabsolute(orig: path, new: path) -> path {
384 if path_is_absolute(orig) && orig[0] == os_fs::path_sep as u8 {
385 str::from_char(os_fs::path_sep) + new
391 fn reterminate(orig: path, new: path) -> path {
392 let last = orig[str::byte_len(orig) - 1u];
393 if last == os_fs::path_sep as u8
394 || last == os_fs::path_sep as u8 {
395 ret new + path_sep();
405 Returns the path to the user's home directory, if known.
407 On Unix, returns the value of the "HOME" environment variable if it is set and
408 not equal to the empty string.
410 On Windows, returns the value of the "HOME" environment variable if it is set
411 and not equal to the empty string. Otherwise, returns the value of the
412 "USERPROFILE" environment variable if it is set and not equal to the empty
415 Otherwise, homedir returns option::none.
417 fn homedir() -> option<path> {
418 ret alt generic_os::getenv("HOME") {
420 if !str::is_empty(p) {
431 #[cfg(target_os = "linux")]
432 #[cfg(target_os = "macos")]
433 #[cfg(target_os = "freebsd")]
434 fn secondary() -> option<path> {
438 #[cfg(target_os = "win32")]
439 fn secondary() -> option<path> {
440 option::maybe(none, generic_os::getenv("USERPROFILE")) {|p|
441 if !str::is_empty(p) {
453 // indent-tabs-mode: nil
455 // buffer-file-coding-system: utf-8-unix