Skip to content

Commit 08441fc

Browse files
committed
Add PosixPath to path2. Add path2 to core build. Add dot/dotdot-normalizing.
1 parent a14485b commit 08441fc

File tree

3 files changed

+241
-9
lines changed

3 files changed

+241
-9
lines changed

src/libcore/core.rc

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@ mod libc;
252252
mod os;
253253
#[warn(non_camel_case_types)]
254254
mod path;
255+
mod path2;
255256
#[warn(non_camel_case_types)]
256257
mod rand;
257258
#[warn(non_camel_case_types)]

src/libcore/path2.rs

Lines changed: 239 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
extern mod std;
1+
// NB: transitionary, de-mode-ing.
2+
#[forbid(deprecated_mode)];
3+
#[forbid(deprecated_pattern)];
24

35
struct WindowsPath {
46
host: option<~str>;
@@ -31,6 +33,148 @@ trait Path {
3133
fn pop_component() -> self;
3234
}
3335

36+
// FIXME (#3227): when default methods in traits are working, de-duplicate
37+
// PosixPath and WindowsPath, most of their methods are common.
38+
39+
impl PosixPath : Path {
40+
fn to_str() -> ~str {
41+
match self.filename() {
42+
none => self.dirname(),
43+
some(ref f) =>
44+
if (self.components.len() == 1 &&
45+
!self.is_absolute) {
46+
copy *f
47+
} else {
48+
self.dirname() + "/" + *f
49+
}
50+
}
51+
}
52+
53+
static fn from_str(s: &str) -> PosixPath {
54+
let mut components = str::split_nonempty(s, |c| c == '/');
55+
let is_absolute = (s.len() != 0 && s[0] == '/' as u8);
56+
return PosixPath { is_absolute: is_absolute,
57+
components: normalize(components) }
58+
}
59+
60+
fn dirname() -> ~str {
61+
let mut s = ~"";
62+
if self.is_absolute {
63+
s += "/";
64+
}
65+
let mut d = copy self.components;
66+
if d.len() != 0 {
67+
vec::pop(d);
68+
}
69+
s += str::connect(d, "/");
70+
if s.len() == 0 {
71+
s = ~".";
72+
}
73+
return s;
74+
}
75+
76+
fn filename() -> option<~str> {
77+
match self.components.len() {
78+
0 => none,
79+
n => some(copy self.components[n - 1])
80+
}
81+
}
82+
83+
fn filestem() -> option<~str> {
84+
match self.filename() {
85+
none => none,
86+
some(ref f) => {
87+
match str::rfind_char(*f, '.') {
88+
some(p) => some(f.slice(0, p)),
89+
none => some(copy *f)
90+
}
91+
}
92+
}
93+
}
94+
95+
fn filetype() -> option<~str> {
96+
match self.filename() {
97+
none => none,
98+
some(ref f) => {
99+
match str::rfind_char(*f, '.') {
100+
some(p) if p+1 < f.len() => some(f.slice(p+1, f.len())),
101+
_ => none
102+
}
103+
}
104+
}
105+
}
106+
107+
fn with_dirname(d: &str) -> PosixPath {
108+
let dpath = from_str::<PosixPath>(d);
109+
match self.filename() {
110+
some(ref f) => dpath.push_components(~[copy *f]),
111+
none => dpath
112+
}
113+
}
114+
115+
fn with_filename(f: &str) -> PosixPath {
116+
assert ! str::any(f, |c| windows::is_sep(c as u8));
117+
self.dir_path().push_components(~[str::from_slice(f)])
118+
}
119+
120+
fn with_filestem(s: &str) -> PosixPath {
121+
match self.filetype() {
122+
none => self.with_filename(s),
123+
some(ref t) =>
124+
self.with_filename(str::from_slice(s) + "." + *t)
125+
}
126+
}
127+
128+
fn with_filetype(t: &str) -> PosixPath {
129+
if t.len() == 0 {
130+
match self.filestem() {
131+
none => copy self,
132+
some(s) => self.with_filename(s)
133+
}
134+
} else {
135+
let t = ~"." + str::from_slice(t);
136+
match self.filestem() {
137+
none => self.with_filename(t),
138+
some(ref s) =>
139+
self.with_filename(*s + t)
140+
}
141+
}
142+
}
143+
144+
fn dir_path() -> PosixPath {
145+
if self.components.len() != 0 {
146+
self.pop_component()
147+
} else {
148+
copy self
149+
}
150+
}
151+
152+
fn file_path() -> PosixPath {
153+
let cs = match self.filename() {
154+
none => ~[],
155+
some(ref f) => ~[copy *f]
156+
};
157+
return PosixPath { is_absolute: false,
158+
components: cs }
159+
}
160+
161+
fn push_components(cs: &[~str]) -> PosixPath {
162+
return PosixPath { components: normalize(self.components + cs),
163+
..self }
164+
}
165+
166+
fn pop_component() -> PosixPath {
167+
let mut cs = copy self.components;
168+
if cs.len() != 0 {
169+
vec::pop(cs);
170+
}
171+
return PosixPath { components: cs, ..self }
172+
}
173+
174+
175+
176+
}
177+
34178

35179
impl WindowsPath : Path {
36180

@@ -82,7 +226,7 @@ impl WindowsPath : Path {
82226
return WindowsPath { host: host,
83227
device: device,
84228
is_absolute: is_absolute,
85-
components: components }
229+
components: normalize(components) }
86230
}
87231

88232
fn dirname() -> ~str {
@@ -112,7 +256,6 @@ impl WindowsPath : Path {
112256
fn filename() -> option<~str> {
113257
match self.components.len() {
114258
0 => none,
115-
1 => some(copy self.components[0]),
116259
n => some(copy self.components[n - 1])
117260
}
118261
}
@@ -163,11 +306,18 @@ impl WindowsPath : Path {
163306
}
164307

165308
fn with_filetype(t: &str) -> WindowsPath {
166-
let t = ~"." + str::from_slice(t);
167-
match self.filestem() {
168-
none => self.with_filename(t),
169-
some(ref s) =>
170-
self.with_filename(*s + t)
309+
if t.len() == 0 {
310+
match self.filestem() {
311+
none => copy self,
312+
some(s) => self.with_filename(s)
313+
}
314+
} else {
315+
let t = ~"." + str::from_slice(t);
316+
match self.filestem() {
317+
none => self.with_filename(t),
318+
some(ref s) =>
319+
self.with_filename(*s + t)
320+
}
171321
}
172322
}
173323

@@ -191,7 +341,8 @@ impl WindowsPath : Path {
191341
}
192342

193343
fn push_components(cs: &[~str]) -> WindowsPath {
194-
return WindowsPath { components: self.components + cs, ..self }
344+
return WindowsPath { components: normalize(self.components + cs),
345+
..self }
195346
}
196347

197348
fn pop_component() -> WindowsPath {
@@ -203,6 +354,85 @@ impl WindowsPath : Path {
203354
}
204355
}
205356

357+
358+
fn normalize(components: &[~str]) -> ~[~str] {
359+
let mut cs = ~[];
360+
for components.each |c| {
361+
if c == ~"." { again; }
362+
if c == ~".." && cs.len() != 0 {
363+
vec::pop(cs);
364+
again;
365+
}
366+
vec::push(cs, copy c);
367+
}
368+
cs
369+
}
370+
371+
mod posix {
372+
373+
#[test]
374+
fn test_posix_paths() {
375+
fn mk(s: &str) -> PosixPath { from_str::<PosixPath>(s) }
376+
fn t(wp: &PosixPath, s: &str) {
377+
let ss = wp.to_str();
378+
let sss = str::from_slice(s);
379+
if (ss != sss) {
380+
debug!("got %s", ss);
381+
debug!("expected %s", sss);
382+
assert ss == sss;
383+
}
384+
}
385+
386+
t(&(mk("hi")), "hi");
387+
t(&(mk("hi/there")), "hi/there");
388+
t(&(mk("hi/there.txt")), "hi/there.txt");
389+
390+
t(&(mk("hi/there.txt")), "hi/there.txt");
391+
t(&(mk("hi/there.txt")
392+
.with_filetype("")), "hi/there");
393+
394+
t(&(mk("/a/b/c/there.txt")
395+
.with_dirname("hi")), "hi/there.txt");
396+
397+
t(&(mk("hi/there.txt")
398+
.with_dirname(".")), "there.txt");
399+
400+
t(&(mk("a/b/../c/././/../foo.txt/")),
401+
"a/foo.txt");
402+
403+
t(&(mk("a/b/c")
404+
.push_components([~".."])), "a/b");
405+
406+
t(&(mk("there.txt")
407+
.with_filetype("o")), "there.o");
408+
409+
t(&(mk("hi/there.txt")
410+
.with_filetype("o")), "hi/there.o");
411+
412+
t(&(mk("hi/there.txt")
413+
.with_filetype("o")
414+
.with_dirname("/usr/lib")),
415+
"/usr/lib/there.o");
416+
417+
t(&(mk("hi/there.txt")
418+
.with_filetype("o")
419+
.with_dirname("/usr/lib/")),
420+
"/usr/lib/there.o");
421+
422+
t(&(mk("hi/there.txt")
423+
.with_filetype("o")
424+
.with_dirname("/usr//lib//")),
425+
"/usr/lib/there.o");
426+
427+
t(&(mk("/usr/bin/rust")
428+
.push_components([~"lib", ~"thingy.so"])
429+
.with_filestem("librustc")),
430+
"/usr/bin/rust/lib/librustc.so");
431+
432+
}
433+
434+
}
435+
206436
// Various windows helpers, and tests for the impl.
207437
mod windows {
208438

src/libcore/str.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export
1414
// Creating a string
1515
from_bytes,
1616
from_byte,
17+
from_slice,
1718
from_char,
1819
from_chars,
1920
append,

0 commit comments

Comments
 (0)