Skip to content

Instantly share code, notes, and snippets.

@StefanKarpinski
Created January 4, 2013 23:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save StefanKarpinski/4458304 to your computer and use it in GitHub Desktop.
Save StefanKarpinski/4458304 to your computer and use it in GitHub Desktop.
@unix_only begin
const path_separator = "/"
const path_separator_regex = r"/+"
const path_absolute_regex = r"^/"
const path_parse_regex = r"^(.*?/|)([^/]+?)(\.[^\.]+|)$"
splitdrive(path::String) = ("",path)
end
@windows_only begin
const path_separator = "\\"
const path_separator_regex = r"[/\\]+"
const path_absolute_regex = r"^(?:\w+:)?[/\\]"
const path_parse_regex = r"^(.*?[/\\]|)([^/\\]+?)(\.[^\.]+|)$"
function splitdrive(path::String)
# TODO: split out network drives?
m = match(r"^(\w+:|)(.*)$", path)
m.captures[1], m.captures[2]
end
end
isabspath(path::String) = ismatch(path_absolute_regex, path)
joinpath(a::String) = a
joinpath(a::String, b::String, c::String...) = joinpath(joinpath(a,b), c...)
joinpath(a::String, b::String) = isempty(a) || isabspath(b) ? b :
ismatch(path_separator_regex, a[thisind(a,end):end]) ?
strcat(a,b) : strcat(a,path_separator,b)
function parsepath(path::String)
m = match(path_parse_regex, path)
m != nothing ? (m.captures[2], m.captures[3], m.captures[4]) : (path, "", "")
end
function normpath(path::String)
isabs = isabspath(path)
drive, path = splitdrive(path)
parts = split(path, path_separator_regex)
# isdir = ismatch(r"^\.{0,2}$", parts[end])
parts = filter(x->!isempty(x) && x!=".", parts)
while true
clean = true
for j = 1:length(parts)-1
if parts[j] != ".." && parts[j+1] == ".."
del(parts, j:j+1)
clean = false
break
end
end
clean && break
end
if isabs
while isabs && !isempty(parts) && parts[1] == ".."
shift(parts)
end
elseif isempty(parts)
push(parts, ".")
end
path = join(parts, path_separator)
if isabs
path = strcat(path_separator, path)
end
# if isdir && !isempty(parts) && !ismatch(r"^\.{0,2}$", parts[end])
# path = strcat(path, path_separator)
# end
strcat(drive,path)
end
normpath(a::String, b::String...) = normpath(joinpath(a,b...))
abspath(path::String) = normpath(isabspath(path) ? path : joinpath(pwd(),path))
function realpath(path::String)
path = tilde_expand(path)
sp = ccall(:realpath, Ptr{Uint8}, (Ptr{Uint8}, Ptr{Uint8}), path, C_NULL)
system_error(:realpath, sp != C_NULL)
s = bytestring(sp)
c_free(sp)
return s
end
@carlobaldassi
Copy link

Just a small question: why the removal of the isdir check? Performance? Compatibility with ThatOtherOS? Originally, I introduced it so that paths like /dir1/dir2/filename/. or /dir1/dir2/filename/anything/.. are not resolved to /dir1/dir2/filename, i.e. they don't yield a valid file name, which seems wrong (and bug-prone) to me.

@carlobaldassi
Copy link

(I was referring to normpath of course.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment