Skip to content

Commit 802deac

Browse files
committed
stdlib: Add fs::splitext
Splits a path into the filename + extension
1 parent a2377cc commit 802deac

File tree

2 files changed

+105
-0
lines changed

2 files changed

+105
-0
lines changed

src/lib/fs.rs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,55 @@ fn split(p: path) -> [path] {
176176
ret split2;
177177
}
178178

179+
/*
180+
Function: splitext
181+
182+
Split a path into a pair of strings with the first element being the filename
183+
without the extension and the second being either empty or the file extension
184+
including the period. Leading periods in the basename are ignored. If the
185+
path includes directory components then they are included in the filename part
186+
of the result pair.
187+
*/
188+
fn splitext(p: path) -> (str, str) {
189+
if str::is_empty(p) { ("", "") }
190+
else {
191+
let parts = str::split(p, '.' as u8);
192+
if vec::len(parts) > 1u {
193+
let base = str::connect(vec::init(parts), ".");
194+
let ext = "." + option::get(vec::last(parts));
195+
196+
fn is_dotfile(base: str) -> bool {
197+
str::is_empty(base)
198+
|| str::ends_with(
199+
base, str::from_char(os_fs::path_sep))
200+
|| str::ends_with(
201+
base, str::from_char(os_fs::alt_path_sep))
202+
}
203+
204+
fn ext_contains_sep(ext: str) -> bool {
205+
vec::len(split(ext)) > 1u
206+
}
207+
208+
fn no_basename(ext: str) -> bool {
209+
str::ends_with(
210+
ext, str::from_char(os_fs::path_sep))
211+
|| str::ends_with(
212+
ext, str::from_char(os_fs::alt_path_sep))
213+
}
214+
215+
if is_dotfile(base)
216+
|| ext_contains_sep(ext)
217+
|| no_basename(ext) {
218+
(p, "")
219+
} else {
220+
(base, ext)
221+
}
222+
} else {
223+
(p, "")
224+
}
225+
}
226+
}
227+
179228
/*
180229
Function: normalize
181230

src/test/stdtest/fs.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,60 @@ fn normalize12() {
156156
#[cfg(target_os = "win32")]
157157
fn path_is_absolute_win32() {
158158
assert fs::path_is_absolute("C:/whatever");
159+
}
160+
161+
#[test]
162+
fn splitext_empty() {
163+
let (base, ext) = fs::splitext("");
164+
assert base == "";
165+
assert ext == "";
166+
}
167+
168+
#[test]
169+
fn splitext_ext() {
170+
let (base, ext) = fs::splitext("grum.exe");
171+
assert base == "grum";
172+
assert ext == ".exe";
173+
}
174+
175+
#[test]
176+
fn splitext_noext() {
177+
let (base, ext) = fs::splitext("grum");
178+
assert base == "grum";
179+
assert ext == "";
180+
}
181+
182+
#[test]
183+
fn splitext_dotfile() {
184+
let (base, ext) = fs::splitext(".grum");
185+
assert base == ".grum";
186+
assert ext == "";
187+
}
188+
189+
#[test]
190+
fn splitext_path_ext() {
191+
let (base, ext) = fs::splitext("oh/grum.exe");
192+
assert base == "oh/grum";
193+
assert ext == ".exe";
194+
}
195+
196+
#[test]
197+
fn splitext_path_noext() {
198+
let (base, ext) = fs::splitext("oh/grum");
199+
assert base == "oh/grum";
200+
assert ext == "";
201+
}
202+
203+
#[test]
204+
fn splitext_dot_in_path() {
205+
let (base, ext) = fs::splitext("oh.my/grum");
206+
assert base == "oh.my/grum";
207+
assert ext == "";
208+
}
209+
210+
#[test]
211+
fn splitext_nobasename() {
212+
let (base, ext) = fs::splitext("oh.my/");
213+
assert base == "oh.my/";
214+
assert ext == "";
159215
}

0 commit comments

Comments
 (0)