diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/data-exp.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/data-exp.lua | 211 |
1 files changed, 158 insertions, 53 deletions
diff --git a/Master/texmf-dist/tex/context/base/data-exp.lua b/Master/texmf-dist/tex/context/base/data-exp.lua index 11e69bcae5d..52368f8a82e 100644 --- a/Master/texmf-dist/tex/context/base/data-exp.lua +++ b/Master/texmf-dist/tex/context/base/data-exp.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['data-exp'] = { license = "see context related readme files", } -local format, find, gmatch, lower = string.format, string.find, string.gmatch, string.lower +local format, find, gmatch, lower, char, sub = string.format, string.find, string.gmatch, string.lower, string.char, string.sub local concat, sort = table.concat, table.sort local lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns local Ct, Cs, Cc, P, C, S = lpeg.Ct, lpeg.Cs, lpeg.Cc, lpeg.P, lpeg.C, lpeg.S @@ -26,19 +26,6 @@ local resolvers = resolvers -- all, when working on the main resolver code, I don't want to scroll -- past this every time. See data-obs.lua for the gsub variant. --- {a,b,c,d} --- a,b,c/{p,q,r},d --- a,b,c/{p,q,r}/d/{x,y,z}// --- a,b,c/{p,q/{x,y,z},r},d/{p,q,r} --- a,b,c/{p,q/{x,y,z},r},d/{p,q,r} --- a{b,c}{d,e}f --- {a,b,c,d} --- {a,b,c/{p,q,r},d} --- {a,b,c/{p,q,r}/d/{x,y,z}//} --- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}} --- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}} --- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c} - local function f_first(a,b) local t, n = { }, 0 for s in gmatch(b,"[^,]+") do @@ -95,12 +82,9 @@ local function splitpathexpr(str, newlist, validate) -- I couldn't resist lpeggi str = lpegmatch(stripper_1,str) if validate then for s in gmatch(str,"[^,]+") do - local restoreslashes = false - if find(s, "//$") then restoreslashes = true end s = validate(s) if s then n = n + 1 ; t[n] = s - if restoreslashes and not find(s, "//$") then t[n] = t[n] .. '//' end end end else @@ -133,41 +117,56 @@ function resolvers.expandedpathfromlist(pathlist) return newlist end +-- {a,b,c,d} +-- a,b,c/{p,q,r},d +-- a,b,c/{p,q,r}/d/{x,y,z}// +-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r} +-- a,b,c/{p,q/{x,y,z},r},d/{p,q,r} +-- a{b,c}{d,e}f +-- {a,b,c,d} +-- {a,b,c/{p,q,r},d} +-- {a,b,c/{p,q,r}/d/{x,y,z}//} +-- {a,b,c/{p,q/{x,y,z}},d/{p,q,r}} +-- {a,b,c/{p,q/{x,y,z},w}v,d/{p,q,r}} +-- {$SELFAUTODIR,$SELFAUTOPARENT}{,{/share,}/texmf{-local,.local,}/web2c} + local cleanup = lpeg.replacer { { "!" , "" }, { "\\" , "/" }, } -local homedir - -function resolvers.cleanpath(str) - if not homedir then - homedir = lpegmatch(cleanup,environment.homedir or "") - if homedir == string.char(127) or homedir == "" or not lfs.isdir(homedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent paths") - end - function resolvers.cleanpath(str) - if find(str,"~") then - return "" -- special case - else - return str and lpegmatch(cleanup,str) - end - end - else - cleanup = lpeg.replacer { - { "!" , "" }, - { "\\" , "/" }, - { "~" , homedir }, - } - function resolvers.cleanpath(str) - return str and lpegmatch(cleanup,str) +function resolvers.cleanpath(str) -- tricky, maybe only simple paths + local doslashes = (P("\\")/"/" + 1)^0 + local donegation = (P("!") /"" )^0 + local homedir = lpegmatch(Cs(donegation * doslashes),environment.homedir or "") + if homedir == "~" or homedir == "" or not lfs.isdir(homedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent paths") + end + function resolvers.cleanpath(str) + if not str or find(str,"~") then + return "" -- special case + else + return lpegmatch(cleanup,str) end end + else + local dohome = ((P("~")+P("$HOME"))/homedir)^0 + local cleanup = Cs(donegation * dohome * doslashes) + function resolvers.cleanpath(str) + return str and lpegmatch(cleanup,str) or "" + end end return resolvers.cleanpath(str) end +-- print(resolvers.cleanpath("")) +-- print(resolvers.cleanpath("!")) +-- print(resolvers.cleanpath("~")) +-- print(resolvers.cleanpath("~/test")) +-- print(resolvers.cleanpath("!~/test")) +-- print(resolvers.cleanpath("~/test~test")) + -- This one strips quotes and funny tokens. local expandhome = P("~") / "$HOME" -- environment.homedir @@ -192,8 +191,8 @@ end local cache = { } ----- splitter = Ct(lpeg.splitat(S(ostype == "windows" and ";" or ":;"))) -- maybe add , -local splitter = Ct(lpeg.splitat(";")) -- as we move towards urls, prefixes and use tables we no longer do : +----- splitter = lpeg.tsplitat(S(ostype == "windows" and ";" or ":;")) -- maybe add , +local splitter = lpeg.tsplitat(";") -- as we move towards urls, prefixes and use tables we no longer do : local backslashswapper = lpeg.replacer("\\","/") @@ -267,13 +266,22 @@ end --~ test("ヒラギノ明朝 /Pro W3;") --~ test("ヒラギノ明朝 Pro W3") -local weird = P(".")^1 + lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) +-- a lot of this caching can be stripped away when we have ssd's everywhere +-- +-- we could cache all the (sub)paths here if needed local attributes, directory = lfs.attributes, lfs.dir +local weird = P(".")^1 + lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) +local timer = { } +local scanned = { } +local nofscans = 0 +local scancache = { } + local function scan(files,spec,path,n,m,r) - local full = (path == "" and spec) or (spec .. path .. '/') - local dirs, nofdirs = { }, 0 + local full = (path == "" and spec) or (spec .. path .. '/') + local dirs = { } + local nofdirs = 0 for name in directory(full) do if not lpegmatch(weird,name) then local mode = attributes(full..name,'mode') @@ -311,23 +319,120 @@ local function scan(files,spec,path,n,m,r) files, n, m, r = scan(files,spec,dirs[i],n,m,r) end end + scancache[sub(full,1,-2)] = files return files, n, m, r end -function resolvers.scanfiles(path,branch) +local fullcache = { } + +function resolvers.scanfiles(path,branch,usecache) + statistics.starttiming(timer) + local realpath = resolvers.resolve(path) -- no shortcut + if usecache then + local files = fullcache[realpath] + if files then + if trace_locating then + report_expansions("using caches scan of path '%s', branch '%s'",path,branch or path) + end + return files + end + end if trace_locating then - report_expansions("scanning path '%s', branch '%s'",path, branch or path) + report_expansions("scanning path '%s', branch '%s'",path,branch or path) end - local realpath = resolvers.resolve(path) -- no shortcut local files, n, m, r = scan({ },realpath .. '/',"",0,0,0) - files.__path__ = path -- can be selfautoparent:texmf-whatever - files.__files__ = n - files.__directories__ = m - files.__remappings__ = r + files.__path__ = path -- can be selfautoparent:texmf-whatever + files.__files__ = n + files.__directories__ = m + files.__remappings__ = r if trace_locating then report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end + if usecache then + scanned[#scanned+1] = realpath + fullcache[realpath] = files + end + nofscans = nofscans + 1 + statistics.stoptiming(timer) + return files +end + +local function simplescan(files,spec,path) -- first match only, no map and such + local full = (path == "" and spec) or (spec .. path .. '/') + local dirs = { } + local nofdirs = 0 + for name in directory(full) do + if not lpegmatch(weird,name) then + local mode = attributes(full..name,'mode') + if mode == 'file' then + if not files[name] then + -- only first match + files[name] = path + end + elseif mode == 'directory' then + nofdirs = nofdirs + 1 + if path ~= "" then + dirs[nofdirs] = path..'/'..name + else + dirs[nofdirs] = name + end + end + end + end + if nofdirs > 0 then + sort(dirs) + for i=1,nofdirs do + files = simplescan(files,spec,dirs[i]) + end + end return files end +local simplecache = { } +local nofsharedscans = 0 + +function resolvers.simplescanfiles(path,branch,usecache) + statistics.starttiming(timer) + local realpath = resolvers.resolve(path) -- no shortcut + if usecache then + local files = simplecache[realpath] + if not files then + files = scancache[realpath] + if files then + nofsharedscans = nofsharedscans + 1 + end + end + if files then + if trace_locating then + report_expansions("using caches scan of path '%s', branch '%s'",path,branch or path) + end + return files + end + end + if trace_locating then + report_expansions("scanning path '%s', branch '%s'",path,branch or path) + end + local files = simplescan({ },realpath .. '/',"") + if trace_locating then + report_expansions("%s files found",table.count(files)) + end + if usecache then + scanned[#scanned+1] = realpath + simplecache[realpath] = files + end + nofscans = nofscans + 1 + statistics.stoptiming(timer) + return files +end + +function resolvers.scandata() + table.sort(scanned) + return { + n = nofscans, + shared = nofsharedscans, + time = statistics.elapsedtime(timer), + paths = scanned, + } +end + --~ print(table.serialize(resolvers.scanfiles("t:/sources"))) |