Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
mc/lib/std/pathjoin.myr
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
116 lines (105 sloc)
2.03 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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][:])) | |
;; | |
} |