-
Notifications
You must be signed in to change notification settings - Fork 33
/
Copy pathpathjoin.myr
116 lines (105 loc) · 2.03 KB
/
pathjoin.myr
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
use "alloc"
use "die"
use "extremum"
use "fmt"
use "hasprefix"
use "getcwd"
use "sleq"
use "slcp"
use "sldup"
use "sljoin"
use "strjoin"
use "strsplit"
use "traits"
pkg std =
const pathcat : (a : byte[:], b : byte[:] -> byte[:])
const pathjoin : (p : byte[:][:] -> byte[:])
const pathnorm : (p : byte[:] -> byte[:])
const pathabs : (p : byte[:] -> byte[:])
;;
const pathcat = {a, b
-> pathjoin([a, b][:])
}
const pathjoin = {l
var p, i, q
for i = 0; i < l.len; i++
if l[i].len != 0
break
;;
;;
p = strjoin(l[i:], "/")
q = pathnorm(p)
slfree(p)
-> q
}
const pathnorm = {p
var comps
var i, del, dst
var s, ret
comps = strsplit(p, "/")
/*
"." is a no-op component, so we drop it. In order
to drop a component, we set it to the empty string,
and remove it later on.
*/
for i = 0; i < comps.len; i++
if eq(comps[i], ".")
comps[i] = ""
;;
;;
/*
then, resolve '..' by cancelling out previous components. Scan
backwards in the component list for the first real component,
and delete both it and the '..' that lead to it.
Leave in extra '..' components, so that, eg, ../foo doesn't
get mangled.
*/
for i = 0; i < comps.len; i++
if !eq(comps[i], "..")
continue
;;
for del = 1; del <= i; del++
if comps[i - del].len > 0 && !eq(comps[i-del], "..")
comps[i - del] = ""
comps[i] = ""
break
;;
;;
;;
/* clear out the path nodes we decided to drop */
dst = 0
for i = 0; i < comps.len; i++
if comps[i].len > 0
comps[dst++] = comps[i]
;;
;;
comps = comps[:dst]
/*
and reassemble. If we have an absolute path,
make it absolute. If we have an empty path, return
".". Otherwise, just return the path.
*/
if p.len > 0 && eq(p[:1], "/")
for i = 0; i < comps.len; i++
if !eq(comps[i], "..")
break
;;
;;
s = strjoin(comps[i:], "/")
ret = fmt("/{}", s)
slfree(s)
elif comps.len == 0
ret = sldup(".")
else
ret = strjoin(comps, "/")
;;
slfree(comps)
-> ret
}
const pathabs = {p
if hasprefix(p, "/")
-> pathnorm(p)
else
-> pathnorm(pathjoin([getcwd(), p][:]))
;;
}