summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/l-file.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/l-file.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/l-file.lua279
1 files changed, 154 insertions, 125 deletions
diff --git a/Master/texmf-dist/tex/context/base/l-file.lua b/Master/texmf-dist/tex/context/base/l-file.lua
index 212318fb751..c3199f0229e 100644
--- a/Master/texmf-dist/tex/context/base/l-file.lua
+++ b/Master/texmf-dist/tex/context/base/l-file.lua
@@ -8,47 +8,93 @@ if not modules then modules = { } end modules ['l-file'] = {
-- needs a cleanup
-file = file or { }
+file = file or { }
+local file = file
-local concat = table.concat
-local find, gmatch, match, gsub, sub, char = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char
+local insert, concat = table.insert, table.concat
+local find, gmatch, match, gsub, sub, char, lower = string.find, string.gmatch, string.match, string.gsub, string.sub, string.char, string.lower
local lpegmatch = lpeg.match
+local getcurrentdir, attributes = lfs.currentdir, lfs.attributes
-function file.removesuffix(filename)
- return (gsub(filename,"%.[%a%d]+$",""))
+local P, R, S, C, Cs, Cp, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Cs, lpeg.Cp, lpeg.Cc
+
+local function dirname(name,default)
+ return match(name,"^(.+)[/\\].-$") or (default or "")
end
-function file.addsuffix(filename, suffix)
- if not suffix or suffix == "" then
- return filename
- elseif not find(filename,"%.[%a%d]+$") then
- return filename .. "." .. suffix
- else
- return filename
- end
+local function basename(name)
+ return match(name,"^.+[/\\](.-)$") or name
end
-function file.replacesuffix(filename, suffix)
- return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+local function nameonly(name)
+ return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
end
-function file.dirname(name,default)
- return match(name,"^(.+)[/\\].-$") or (default or "")
+local function extname(name,default)
+ return match(name,"^.+%.([^/\\]-)$") or default or ""
end
-function file.basename(name)
- return match(name,"^.+[/\\](.-)$") or name
+local function splitname(name)
+ local n, s = match(name,"^(.+)%.([^/\\]-)$")
+ return n or name, s or ""
end
-function file.nameonly(name)
- return (gsub(match(name,"^.+[/\\](.-)$") or name,"%..*$",""))
+file.basename = basename
+file.dirname = dirname
+file.nameonly = nameonly
+file.extname = extname
+file.suffix = extname
+
+function file.removesuffix(filename)
+ return (gsub(filename,"%.[%a%d]+$",""))
end
-function file.extname(name,default)
- return match(name,"^.+%.([^/\\]-)$") or default or ""
+function file.addsuffix(filename, suffix, criterium)
+ if not suffix or suffix == "" then
+ return filename
+ elseif criterium == true then
+ return filename .. "." .. suffix
+ elseif not criterium then
+ local n, s = splitname(filename)
+ if not s or s == "" then
+ return filename .. "." .. suffix
+ else
+ return filename
+ end
+ else
+ local n, s = splitname(filename)
+ if s and s ~= "" then
+ local t = type(criterium)
+ if t == "table" then
+ -- keep if in criterium
+ for i=1,#criterium do
+ if s == criterium[i] then
+ return filename
+ end
+ end
+ elseif t == "string" then
+ -- keep if criterium
+ if s == criterium then
+ return filename
+ end
+ end
+ end
+ return n .. "." .. suffix
+ end
end
-file.suffix = file.extname
+--~ print("1 " .. file.addsuffix("name","new") .. " -> name.new")
+--~ print("2 " .. file.addsuffix("name.old","new") .. " -> name.old")
+--~ print("3 " .. file.addsuffix("name.old","new",true) .. " -> name.old.new")
+--~ print("4 " .. file.addsuffix("name.old","new","new") .. " -> name.new")
+--~ print("5 " .. file.addsuffix("name.old","new","old") .. " -> name.old")
+--~ print("6 " .. file.addsuffix("name.old","new","foo") .. " -> name.new")
+--~ print("7 " .. file.addsuffix("name.old","new",{"foo","bar"}) .. " -> name.new")
+--~ print("8 " .. file.addsuffix("name.old","new",{"old","bar"}) .. " -> name.old")
+
+function file.replacesuffix(filename, suffix)
+ return (gsub(filename,"%.[%a%d]+$","")) .. "." .. suffix
+end
--~ function file.join(...)
--~ local pth = concat({...},"/")
@@ -100,50 +146,59 @@ end
--~ print(file.join("http:///a","/y"))
--~ print(file.join("//nas-1","/y"))
-function file.iswritable(name)
- local a = lfs.attributes(name) or lfs.attributes(file.dirname(name,"."))
+function file.is_writable(name)
+ local a = attributes(name) or attributes(dirname(name,"."))
return a and sub(a.permissions,2,2) == "w"
end
-function file.isreadable(name)
- local a = lfs.attributes(name)
+function file.is_readable(name)
+ local a = attributes(name)
return a and sub(a.permissions,1,1) == "r"
end
-file.is_readable = file.isreadable
-file.is_writable = file.iswritable
+file.isreadable = file.is_readable -- depricated
+file.iswritable = file.is_writable -- depricated
--- todo: lpeg
-
---~ function file.split_path(str)
---~ local t = { }
---~ str = gsub(str,"\\", "/")
---~ str = gsub(str,"(%a):([;/])", "%1\001%2")
---~ for name in gmatch(str,"([^;:]+)") do
---~ if name ~= "" then
---~ t[#t+1] = gsub(name,"\001",":")
---~ end
---~ end
---~ return t
---~ end
+-- todo: lpeg \\ / .. does not save much
local checkedsplit = string.checkedsplit
-function file.split_path(str,separator)
+function file.splitpath(str,separator) -- string
str = gsub(str,"\\","/")
return checkedsplit(str,separator or io.pathseparator)
end
-function file.join_path(tab)
- return concat(tab,io.pathseparator) -- can have trailing //
+function file.joinpath(tab,separator) -- table
+ return concat(tab,separator or io.pathseparator) -- can have trailing //
end
-- we can hash them weakly
+--~ function file.collapsepath(str) -- fails on b.c/..
+--~ str = gsub(str,"\\","/")
+--~ if find(str,"/") then
+--~ str = gsub(str,"^%./",(gsub(getcurrentdir(),"\\","/")) .. "/") -- ./xx in qualified
+--~ str = gsub(str,"/%./","/")
+--~ local n, m = 1, 1
+--~ while n > 0 or m > 0 do
+--~ str, n = gsub(str,"[^/%.]+/%.%.$","")
+--~ str, m = gsub(str,"[^/%.]+/%.%./","")
+--~ end
+--~ str = gsub(str,"([^/])/$","%1")
+--~ -- str = gsub(str,"^%./","") -- ./xx in qualified
+--~ str = gsub(str,"/%.$","")
+--~ end
+--~ if str == "" then str = "." end
+--~ return str
+--~ end
+--~
+--~ The previous one fails on "a.b/c" so Taco came up with a split based
+--~ variant. After some skyping we got it sort of compatible with the old
+--~ one. After that the anchoring to currentdir was added in a better way.
+--~ Of course there are some optimizations too. Finally we had to deal with
+--~ windows drive prefixes and thinsg like sys://.
-local insert = table.insert
-
-function file.collapse_path(str,anchor)
+function file.collapsepath(str,anchor)
if anchor and not find(str,"^/") and not find(str,"^%a:") then
str = getcurrentdir() .. "/" .. str
end
@@ -197,64 +252,26 @@ function file.collapse_path(str,anchor)
return concat(newelements, '/')
end
end
-function file.xcollapse_path(str)
- print('collapse', str)
- if str == "" or str =="." then
- return "."
- elseif find(str,"^%.%.") then
- return str
- elseif not find(str,"%.") then
- return str
- end
- str = gsub(str,"^%./",lfs.currentdir() .. "/") -- ./xx in qualified
- str = gsub(str,"\\","/")
- local oldelements = checkedsplit(str,"/")
- local newelements = { }
- local i = #oldelements
- while i > 0 do
- local element = oldelements[i]
- if element == '.' then
- -- do nothing
- elseif element == '..' then
- local n = i -1
- while n > 0 do
- local element = oldelements[n]
- if element ~= '..' and element ~= '.' then
- oldelements[n] = '.'
- break
- else
- n = n - 1
- end
- end
- if n<1 then
- insert(newelements,1,'..')
- end
- elseif element ~= "" then
- insert(newelements,1,element)
- end
- i = i - 1
- end
- if #newelements == 0 then
- return "."
- elseif find(str,"^/") then
- return "/" .. concat(newelements,'/')
+
+--~ local function test(str)
+--~ print(string.format("%-20s %-15s %-15s",str,file.collapsepath(str),file.collapsepath(str,true)))
+--~ end
+--~ test("a/b.c/d") test("b.c/d") test("b.c/..")
+--~ test("/") test("c:/..") test("sys://..")
+--~ test("") test("./") test(".") test("..") test("./..") test("../..")
+--~ test("a") test("./a") test("/a") test("a/../..")
+--~ test("a/./b/..") test("a/aa/../b/bb") test("a/.././././b/..") test("a/./././b/..")
+--~ test("a/b/c/../..") test("./a/b/c/../..") test("a/b/c/../..")
+
+function file.robustname(str,strict)
+ str = gsub(str,"[^%a%d%/%-%.\\]+","-")
+ if strict then
+ return lower(gsub(str,"^%-*(.-)%-*$","%1"))
else
- return concat(newelements, '/')
+ return str
end
end
---~ print(file.collapse_path("/a"))
---~ print(file.collapse_path("a/./b/.."))
---~ print(file.collapse_path("a/aa/../b/bb"))
---~ print(file.collapse_path("a/../.."))
---~ print(file.collapse_path("a/.././././b/.."))
---~ print(file.collapse_path("a/./././b/.."))
---~ print(file.collapse_path("a/b/c/../.."))
-
-function file.robustname(str)
- return (gsub(str,"[^%a%d%/%-%.\\]+","-"))
-end
-
file.readdata = io.loaddata
file.savedata = io.savedata
@@ -264,31 +281,31 @@ end
-- lpeg variants, slightly faster, not always
---~ local period = lpeg.P(".")
---~ local slashes = lpeg.S("\\/")
+--~ local period = P(".")
+--~ local slashes = S("\\/")
--~ local noperiod = 1-period
--~ local noslashes = 1-slashes
--~ local name = noperiod^1
---~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.C(noperiod^1) * -1
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * C(noperiod^1) * -1
--~ function file.extname(name)
--~ return lpegmatch(pattern,name) or ""
--~ end
---~ local pattern = lpeg.Cs(((period * noperiod^1 * -1)/"" + 1)^1)
+--~ local pattern = Cs(((period * noperiod^1 * -1)/"" + 1)^1)
--~ function file.removesuffix(name)
--~ return lpegmatch(pattern,name)
--~ end
---~ local pattern = (noslashes^0 * slashes)^1 * lpeg.C(noslashes^1) * -1
+--~ local pattern = (noslashes^0 * slashes)^1 * C(noslashes^1) * -1
--~ function file.basename(name)
--~ return lpegmatch(pattern,name) or name
--~ end
---~ local pattern = (noslashes^0 * slashes)^1 * lpeg.Cp() * noslashes^1 * -1
+--~ local pattern = (noslashes^0 * slashes)^1 * Cp() * noslashes^1 * -1
--~ function file.dirname(name)
--~ local p = lpegmatch(pattern,name)
@@ -299,7 +316,7 @@ end
--~ end
--~ end
---~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * Cp() * noperiod^1 * -1
--~ function file.addsuffix(name, suffix)
--~ local p = lpegmatch(pattern,name)
@@ -310,7 +327,7 @@ end
--~ end
--~ end
---~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * lpeg.Cp() * noperiod^1 * -1
+--~ local pattern = (noslashes^0 * slashes)^0 * (noperiod^1 * period)^1 * Cp() * noperiod^1 * -1
--~ function file.replacesuffix(name,suffix)
--~ local p = lpegmatch(pattern,name)
@@ -321,7 +338,7 @@ end
--~ end
--~ end
---~ local pattern = (noslashes^0 * slashes)^0 * lpeg.Cp() * ((noperiod^1 * period)^1 * lpeg.Cp() + lpeg.P(true)) * noperiod^1 * -1
+--~ local pattern = (noslashes^0 * slashes)^0 * Cp() * ((noperiod^1 * period)^1 * Cp() + P(true)) * noperiod^1 * -1
--~ function file.nameonly(name)
--~ local a, b = lpegmatch(pattern,name)
@@ -353,11 +370,14 @@ end
-- also rewrite previous
-local letter = lpeg.R("az","AZ") + lpeg.S("_-+")
-local separator = lpeg.P("://")
+local letter = R("az","AZ") + S("_-+")
+local separator = P("://")
-local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + letter^1 * lpeg.P("/")
-local rootbased = lpeg.P("/") + letter*lpeg.P(":")
+local qualified = P(".")^0 * P("/") + letter*P(":") + letter^1*separator + letter^1 * P("/")
+local rootbased = P("/") + letter*P(":")
+
+lpeg.patterns.qualified = qualified
+lpeg.patterns.rootbased = rootbased
-- ./name ../name /name c: :// name/name
@@ -369,14 +389,16 @@ function file.is_rootbased_path(filename)
return lpegmatch(rootbased,filename) ~= nil
end
-local slash = lpeg.S("\\/")
-local period = lpeg.P(".")
-local drive = lpeg.C(lpeg.R("az","AZ")) * lpeg.P(":")
-local path = lpeg.C(((1-slash)^0 * slash)^0)
-local suffix = period * lpeg.C(lpeg.P(1-period)^0 * lpeg.P(-1))
-local base = lpeg.C((1-suffix)^0)
+-- actually these are schemes
+
+local slash = S("\\/")
+local period = P(".")
+local drive = C(R("az","AZ")) * P(":")
+local path = C(((1-slash)^0 * slash)^0)
+local suffix = period * C(P(1-period)^0 * P(-1))
+local base = C((1-suffix)^0)
-local pattern = (drive + lpeg.Cc("")) * (path + lpeg.Cc("")) * (base + lpeg.Cc("")) * (suffix + lpeg.Cc(""))
+local pattern = (drive + Cc("")) * (path + Cc("")) * (base + Cc("")) * (suffix + Cc(""))
function file.splitname(str) -- returns drive, path, base, suffix
return lpegmatch(pattern,str)
@@ -392,8 +414,15 @@ end
--~ -- todo:
--~
--~ if os.type == "windows" then
---~ local currentdir = lfs.currentdir
---~ function lfs.currentdir()
+--~ local currentdir = getcurrentdir
+--~ function getcurrentdir()
--~ return (gsub(currentdir(),"\\","/"))
--~ end
--~ end
+
+-- for myself:
+
+function file.strip(name,dir)
+ local b, a = match(name,"^(.-)" .. dir .. "(.*)$")
+ return a ~= "" and a or name
+end