diff options
Diffstat (limited to 'scripts/context/lua/mtxrun.lua')
-rw-r--r-- | scripts/context/lua/mtxrun.lua | 665 |
1 files changed, 448 insertions, 217 deletions
diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index d0c7469e0..a3cbb35e0 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -377,6 +377,31 @@ function string:split_settings() -- no {} handling, see l-aux for lpeg variant end end +local patterns_escapes = { + ["-"] = "%-", + ["."] = "%.", + ["+"] = "%+", + ["*"] = "%*", + ["%"] = "%%", + ["("] = "%)", + [")"] = "%)", + ["["] = "%[", + ["]"] = "%]", +} + + +function string:pattesc() + return (self:gsub(".",patterns_escapes)) +end + +function string:tohash() + local t = { } + for s in self:gmatch("([^, ]+)") do -- lpeg + t[s] = true + end + return t +end + -- filename : l-lpeg.lua -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL @@ -420,7 +445,6 @@ end - -- filename : l-table.lua -- comment : split off from luat-lib -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL @@ -502,7 +526,8 @@ end --~ return t --~ end -function table.merge(t, ...) +function table.merge(t, ...) -- first one is target + t = t or {} local lst = {...} for i=1,#lst do for k, v in pairs(lst[i]) do @@ -1031,6 +1056,14 @@ function table.tohash(t) return h end +function table.fromhash(t) + local h = { } + for k, v in pairs(t) do -- no ipairs here + if v then h[#h+1] = k end + end + return h +end + function table.contains(t, v) if t then for i=1, #t do @@ -1062,6 +1095,22 @@ end --~ return table.serialize(a) == table.serialize(b) --~ end +function table.clone(t,p) -- t is optional or nil or table + if not p then + t, p = { }, t or { } + elseif not t then + t = { } + end + setmetatable(t, { __index = function(_,key) return p[key] end }) + return t +end + + +function table.hexed(t,seperator) + local tt = { } + for i=1,#t do tt[i] = string.format("0x%04X",t[i]) end + return table.concat(tt,seperator or " ") +end -- filename : l-io.lua @@ -1133,38 +1182,10 @@ function io.noflines(f) return n end ---~ t, f, n = os.clock(), io.open("testbed/sample-utf16-bigendian-big.txt",'rb'), 0 ---~ for a in io.characters(f) do n = n + 1 end ---~ print(string.format("characters: %s, time: %s", n, os.clock()-t)) - do local sb = string.byte ---~ local nextchar = { ---~ [ 4] = function(f) ---~ return f:read(1), f:read(1), f:read(1), f:read(1) ---~ end, ---~ [ 2] = function(f) ---~ return f:read(1), f:read(1) ---~ end, ---~ [ 1] = function(f) ---~ return f:read(1) ---~ end, ---~ [-2] = function(f) ---~ local a = f:read(1) ---~ local b = f:read(1) ---~ return b, a ---~ end, ---~ [-4] = function(f) ---~ local a = f:read(1) ---~ local b = f:read(1) ---~ local c = f:read(1) ---~ local d = f:read(1) ---~ return d, c, b, a ---~ end ---~ } - local nextchar = { [ 4] = function(f) return f:read(1,1,1,1) @@ -1488,18 +1509,27 @@ function os.resultof(command) return io.popen(command,"r"):read("*all") end -if not os.exec then -- still not ok - os.exec = os.execute -end -if not os.spawn then -- still not ok - os.spawn = os.execute +if not os.exec then os.exec = os.execute end +if not os.spawn then os.spawn = os.execute end + +--~ os.type : windows | unix (new, we already guessed os.platform) +--~ os.name : windows | msdos | linux | macosx | solaris | .. | generic (new) + +if not io.fileseparator then + if string.find(os.getenv("PATH"),";") then + io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows" + else + io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix" + end end +os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix" + function os.launch(str) if os.platform == "windows" then - os.spawn("start " .. str) + os.execute("start " .. str) -- os.spawn ? else - os.spawn(str .. " &") + os.execute(str .. " &") -- os.spawn ? end end @@ -1514,19 +1544,15 @@ if not os.times then -- cstime = children system time function os.times() return { - utime = os.clock(), -- user - stime = 0, -- system - cutime = 0, -- children user - cstime = 0, -- children system + utime = os.gettimeofday(), -- user + stime = 0, -- system + cutime = 0, -- children user + cstime = 0, -- children system } end end -if os.gettimeofday then - os.clock = os.gettimeofday -else - os.gettimeofday = os.clock -end +os.gettimeofday = os.gettimeofday or os.clock do local startuptime = os.gettimeofday() @@ -1553,11 +1579,11 @@ if not versions then versions = { } end versions['l-file'] = 1.001 if not file then file = { } end function file.removesuffix(filename) - return filename:gsub("%.%a+$", "") + return filename:gsub("%.[%a%d]+$", "") end function file.addsuffix(filename, suffix) - if not filename:find("%.%a-$") then + if not filename:find("%.[%a%d]+$") then return filename .. "." .. suffix else return filename @@ -1565,7 +1591,11 @@ function file.addsuffix(filename, suffix) end function file.replacesuffix(filename, suffix) - return (filename:gsub("%.%a+$", "." .. suffix)) + if not filename:find("%.[%a%d]+$") then + return filename .. "." .. suffix + else + return (filename:gsub("%.[%a%d]+$","."..suffix)) + end end function file.dirname(name) @@ -1584,12 +1614,36 @@ function file.extname(name) return name:match("^.+%.([^/\\]-)$") or "" end +function file.stripsuffix(name) + return (name:gsub("%.[%a%d]+$","")) +end + +--~ function file.join(...) +--~ local t = { ... } +--~ for i=1,#t do +--~ t[i] = (t[i]:gsub("\\","/")):gsub("/+$","") +--~ end +--~ return table.concat(t,"/") +--~ end + +--~ print(file.join("x/","/y")) +--~ print(file.join("http://","/y")) +--~ print(file.join("http://a","/y")) +--~ print(file.join("http:///a","/y")) +--~ print(file.join("//nas-1","/y")) + function file.join(...) - local t = { ... } - for i=1,#t do - t[i] = (t[i]:gsub("\\","/")):gsub("/+$","") + local pth = table.concat({...},"/") + pth = pth:gsub("\\","/") + local a, b = pth:match("^(.*://)(.*)$") + if a and b then + return a .. b:gsub("//+","/") + end + a, b = pth:match("^(//)(.*)$") + if a and b then + return a .. b:gsub("//+","/") end - return table.concat(t,"/") + return (pth:gsub("//+","/")) end function file.is_writable(name) @@ -1888,6 +1942,8 @@ xml.trace_lpath = false xml.trace_print = false xml.trace_remap = false +-- todo: some things per xml file, liek namespace remapping + --[[ldx-- <p>First a hack to enable namespace resolving. A namespace is characterized by a <l n='url'/>. The following function associates a namespace prefix with a @@ -2506,7 +2562,7 @@ function xml.text(root) return (root and xml.tostring(root)) or "" end -function xml.content(root) +function xml.content(root) -- bugged return (root and root.dt and xml.tostring(root.dt)) or "" end @@ -2837,14 +2893,13 @@ do local t = {...} for i=1,#t do if s == t[i] then return true end end return false end - function xml.traverse(root,pattern,handle,reverse,index,parent,wildcard) + local function traverse(root,pattern,handle,reverse,index,parent,wildcard) if not root then -- error return false elseif pattern == false then -- root handle(root,root.dt,root.ri) return false elseif pattern == true then -- wildcard - local traverse = xml.traverse local rootdt = root.dt if rootdt then local start, stop, step = 1, #rootdt, 1 @@ -2875,7 +2930,7 @@ do elseif command == 11 then -- parent local ep = root.__p__ or parent if index < #pattern then - if not xml.traverse(ep,pattern,handle,reverse,index+1,root) then return false end + if not traverse(ep,pattern,handle,reverse,index+1,root) then return false end elseif handle(root,rootdt,k) then return false end @@ -2890,12 +2945,11 @@ do if command == 11 then -- parent local ep = root.__p__ or parent if index < #pattern then - if not xml.traverse(ep,pattern,handle,reverse,index+1,root) then return false end + if not traverse(ep,pattern,handle,reverse,index+1,root) then return false end elseif handle(root,rootdt,k) then return false end else - local traverse = xml.traverse local rootdt = root.dt local start, stop, step, n, dn = 1, #rootdt, 1, 0, 1 if command == 30 then @@ -2989,6 +3043,7 @@ do if index == #pattern then if handle(root,rootdt,root.ri or k) then return false end if wildcard and multiple then +--~ if wildcard or multiple then if not traverse(e,pattern,handle,reverse,index,root,true) then return false end end else @@ -3049,6 +3104,8 @@ do return true end + xml.traverse = traverse + end --[[ldx-- @@ -3119,7 +3176,7 @@ do traverse(root, lpath(pattern), function(r,d,k) rt,dt,dk = r,d,k return true end, 'reverse') return dt and dt[dk], rt, dt, dk end - function xml.filters.count(root, pattern,everything) + function xml.filters.count(root,pattern,everything) local n = 0 traverse(root, lpath(pattern), function(r,d,t) if everything or type(d[t]) == "table" then @@ -3189,13 +3246,15 @@ do local rt, dt, dk traverse(root, lpath(pattern), function(r,d,k) rt, dt, dk = r, d, k return true end) local ekat = (dt and dt[dk] and dt[dk].at) or (rt and rt.at) - return (ekat and ekat[arguments]) or "" + return (ekat and (ekat[arguments] or ekat[arguments:gsub("^([\"\'])(.*)%1$","%2")])) or "" end - function xml.filters.text(root,pattern,arguments) + function xml.filters.text(root,pattern,arguments) -- ?? why index local dtk, rt, dt, dk = xml.filters.index(root,pattern,arguments) if dtk then local dtkdt = dtk.dt - if #dtkdt == 1 and type(dtkdt[1]) == "string" then + if not dtkdt then + return "", rt, dt, dk + elseif #dtkdt == 1 and type(dtkdt[1]) == "string" then return dtkdt[1], rt, dt, dk else return xml.tostring(dtkdt), rt, dt, dk @@ -3260,7 +3319,7 @@ do </typing> <p>Which will print all the titles in the document. The iterator variant takes - 1.5 times the runtime of the function variant which si due to the overhead in + 1.5 times the runtime of the function variant which is due to the overhead in creating the wrapper. So, instead of:</p> <typing> @@ -3279,6 +3338,10 @@ do return coroutine.wrap(function() traverse(root, lpath(pattern), coroutine.yield, reverse) end) end + function xml.elements_only(root,pattern,reverse) + return coroutine.wrap(function() traverse(root, lpath(pattern), function(r,d,k) coroutine.yield(d[k]) end, reverse) end) + end + function xml.each_element(root, pattern, handle, reverse) local ok traverse(root, lpath(pattern), function(r,d,k) ok = true handle(r,d,k) end, reverse) @@ -3424,10 +3487,20 @@ do end end - function xml.include(xmldata,pattern,attribute,recursive,findfile) + local function load_data(name) -- == io.loaddata + local f, data = io.open(name), "" + if f then + data = f:read("*all",'b') -- 'b' ? + f:close() + end + return data + end + + function xml.include(xmldata,pattern,attribute,recursive,loaddata) -- parse="text" (default: xml), encoding="" (todo) - pattern = pattern or 'include' -- attribute = attribute or 'href' + pattern = pattern or 'include' + loaddata = loaddata or load_data local function include(r,d,k) local ek, name = d[k], nil if not attribute or attribute == "" then @@ -3442,29 +3515,21 @@ do end end end - if name then - name = (findfile and findfile(name)) or name - if name ~= "" then - local f = io.open(name) - if f then - if ek.at["parse"] == "text" then -- for the moment hard coded - d[k] = xml.escaped(f:read("*all")) - else - local xi = xml.load(f) - if recursive then - xml.include(xi,pattern,attribute,recursive,findfile) - end - xml.assign(d,k,xi) - end - f:close() - else - xml.empty(d,k) - end - else + local data = (name and name ~= "" and loaddata(name)) or "" + if data == "" then + xml.empty(d,k) + elseif ek.at["parse"] == "text" then -- for the moment hard coded + d[k] = xml.escaped(data) + else + local xi = xml.convert(data) + if not xi then xml.empty(d,k) + else + if recursive then + xml.include(xi,pattern,attribute,recursive,loaddata) + end + xml.assign(d,k,xi) end - else - xml.empty(d,k) end end xml.each_element(xmldata, pattern, include) @@ -3948,19 +4013,13 @@ os.setlocale(nil,nil) -- useless feature and even dangerous in luatex if not io.fileseparator then if string.find(os.getenv("PATH"),";") then - io.fileseparator, io.pathseparator, os.platform = "\\", ";", "windows" + io.fileseparator, io.pathseparator, os.platform = "\\", ";", os.type or "windows" else - io.fileseparator, io.pathseparator, os.platform = "/" , ":", "unix" + io.fileseparator, io.pathseparator, os.platform = "/" , ":", os.type or "unix" end end -if not os.platform then - if io.pathseparator == ";" then - os.platform = "windows" - else - os.platform = "unix" - end -end +os.platform = os.platform or os.type or (io.pathseparator == ";" and "windows") or "unix" -- arg normalization -- @@ -4159,17 +4218,22 @@ input.formats ['lua'] = 'LUAINPUTS' -- new input.suffixes['lua'] = { 'lua', 'luc', 'tma', 'tmc' } -- here we catch a few new thingies (todo: add these paths to context.tmf) +-- +-- FONTFEATURES = .;$TEXMF/fonts/fea// +-- FONTCIDMAPS = .;$TEXMF/fonts/cid// -function input.checkconfigdata(instance) +function input.checkconfigdata(instance) -- not yet ok, no time for debugging now local function fix(varname,default) local proname = varname .. "." .. instance.progname or "crap" - if not instance.environment[proname] and not instance.variables[proname] == "" and not instance.environment[varname] and not instance.variables[varname] == "" then - instance.variables[varname] = default + local p = instance.environment[proname] + local v = instance.environment[varname] + if not ((p and p ~= "") or (v and v ~= "")) then + instance.variables[varname] = default -- or environment? end end fix("LUAINPUTS" , ".;$TEXINPUTS;$TEXMFSCRIPTS") - fix("FONTFEATURES", ".;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") - fix("FONTCIDMAPS" , ".;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTFEATURES", ".;$TEXMF/fonts/fea//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") + fix("FONTCIDMAPS" , ".;$TEXMF/fonts/cid//;$OPENTYPEFONTS;$TTFONTS;$T1FONTS;$AFMFONTS") end -- backward compatible ones @@ -4270,6 +4334,11 @@ function input.reset() end +function input.reset_hashes(instance) + instance.lists = { } + instance.found = { } +end + function input.bare_variable(str) -- return string.gsub(string.gsub(string.gsub(str,"%s+$",""),'^"(.+)"$',"%1"),"^'(.+)'$","%1") return (str:gsub("\s*([\"\']?)(.+)%1\s*", "%2")) @@ -4335,7 +4404,7 @@ input.settrace(tonumber(os.getenv("MTX.INPUT.TRACE") or os.getenv("MTX_INPUT_TRA -- loading the database files. do - local clock = os.clock + local clock = os.gettimeofday or os.clock function input.starttiming(instance) if instance then @@ -4609,6 +4678,7 @@ function input.aux.extend_texmf_var(instance,specification) -- crap instance.variables['TEXMF'] = "{" .. instance.variables['TEXMF'] .. "}" end input.expand_variables(instance) + input.reset_hashes(instance) end -- locators @@ -4624,28 +4694,6 @@ function input.locatedatabase(instance,specification) return input.methodhandler('locators', instance, specification) end ---~ poor mans solution, from before we had lfs.isdir ---~ ---~ function input.locators.tex(instance,specification) ---~ if specification and specification ~= '' then ---~ local files = { ---~ file.join(specification,'files'..input.lucsuffix), ---~ file.join(specification,'files'..input.luasuffix), ---~ file.join(specification,input.lsrname) ---~ } ---~ for _, filename in pairs(files) do ---~ local f = io.open(filename) ---~ if f then ---~ input.logger('! tex locator', specification..' found') ---~ input.aux.append_hash(instance,'file',specification,filename) ---~ f:close() ---~ return ---~ end ---~ end ---~ input.logger('? tex locator', specification..' not found') ---~ end ---~ end - function input.locators.tex(instance,specification) if specification and specification ~= '' and lfs.isdir(specification) then input.logger('! tex locator', specification..' found') @@ -5004,8 +5052,6 @@ function input.expand_variables(instance) for k,v in pairs(instance.expansions) do instance.expansions[k] = v:gsub("\\", '/') end - -- ########## - --~ input.splitexpansions(instance) -- better not, fuzzy end function input.aux.expand_vars(instance,lst) -- simple vars @@ -5163,15 +5209,12 @@ do end function input.register_extra_path(instance,paths,subpaths) + local ep = instance.extra_paths or { } + local n = #ep if paths and paths ~= "" then - local ep = instance.extra_paths - if not ep then - ep = { } - instance.extra_paths = ep - end - local n = #ep - if subpath and subpaths ~= "" then + if subpaths and subpaths ~= "" then for p in paths:gmatch("[^,]+") do + -- we gmatch each step again, not that fast, but used seldom for s in subpaths:gmatch("[^,]+") do local ps = p .. "/" .. s if not done[ps] then @@ -5188,10 +5231,24 @@ do end end end - if n < #ep then - instance.lists = { } + elseif subpaths and subpaths ~= "" then + for i=1,n do + -- we gmatch each step again, not that fast, but used seldom + for s in subpaths:gmatch("[^,]+") do + local ps = ep[i] .. "/" .. s + if not done[ps] then + ep[#ep+1] = input.clean_path(ps) + done[ps] = true + end + end end end + if #ep > 0 then + instance.extra_paths = ep -- register paths + end + if #ep > n then + instance.lists = { } -- erase the cache + end end end @@ -5446,7 +5503,7 @@ input.is_readable.tex = input.is_readable.file -- name/name function input.aux.collect_files(instance,names) - local filelist = nil + local filelist = { } for _, fname in pairs(names) do if fname then if input.trace > 2 then @@ -5478,15 +5535,20 @@ function input.aux.collect_files(instance,names) if blobfile then if type(blobfile) == 'string' then if not dname or blobfile:find(dname) then - if not filelist then filelist = { } end - -- input.logger('= collected', blobpath.." | "..blobfile.." | "..bname) - filelist[#filelist+1] = file.join(blobpath,blobfile,bname) + filelist[#filelist+1] = { + hash.type, + file.join(blobpath,blobfile,bname), -- search + input.concatinators[hash.type](blobpath,blobfile,bname) -- result + } end else for _, vv in pairs(blobfile) do if not dname or vv:find(dname) then - if not filelist then filelist = { } end - filelist[#filelist+1] = file.join(blobpath,vv,bname) + filelist[#filelist+1] = { + hash.type, + file.join(blobpath,vv,bname), -- search + input.concatinators[hash.type](blobpath,vv,bname) -- result + } end end end @@ -5497,7 +5559,11 @@ function input.aux.collect_files(instance,names) end end end - return filelist + if #filelist > 0 then + return filelist + else + return nil + end end function input.suffix_of_format(str) @@ -5516,54 +5582,30 @@ function input.suffixes_of_format(str) end end ---~ function input.aux.qualified_path(filename) -- make platform dependent / not good yet ---~ return ---~ filename:find("^%.+/") or ---~ filename:find("^/") or ---~ filename:find("^%a+%:") or ---~ filename:find("^%a+##") ---~ end - ---~ function input.normalize_name(original) ---~ -- internally we use type##spec##subspec ; this hackery slightly slows down searching ---~ local str = original or "" ---~ str = str:gsub("::", "##") -- :: -> ## ---~ str = str:gsub("^(%a+)://" ,"%1##") -- zip:// -> zip## ---~ str = str:gsub("(.+)##(.+)##/(.+)","%1##%2##%3") -- ##/spec -> ##spec ---~ if (input.trace>1) and (original ~= str) then ---~ input.logger('= normalizer',original.." -> "..str) ---~ end ---~ return str ---~ end +do -do -- called about 700 times for an empty doc (font initializations etc) + -- called about 700 times for an empty doc (font initializations etc) -- i need to weed the font files for redundant calls local letter = lpeg.R("az","AZ") - local separator = lpeg.P("##") + local separator = lpeg.P("://") - local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator - local normalized = lpeg.Cs( - (letter^1*(lpeg.P("://")/"##") * (1-lpeg.P(false))^1) + - (lpeg.P("::")/"##" + (1-separator)^1*separator*(1-separator)^1*separator*(lpeg.P("/")/"") + 1)^0 - ) + local qualified = lpeg.P(".")^0 * lpeg.P("/") + letter*lpeg.P(":") + letter^1*separator + local rootbased = lpeg.P("/") + letter*lpeg.P(":") - -- ./name ../name /name c: zip## (todo: use url internally and get rid of ##) + -- ./name ../name /name c: :// function input.aux.qualified_path(filename) return qualified:match(filename) end + function input.aux.rootbased_path(filename) + return rootbased:match(filename) + end - -- zip:// -> zip## ; :: -> ## ; aa##bb##/cc -> aa##bb##cc function input.normalize_name(original) - local str = normalized:match(original or "") - if input.trace > 1 and original ~= str then - input.logger('= normalizer',original.." -> "..str) - end - return str + return original end -end --- split the next one up, better for jit +end function input.aux.register_in_trees(instance,name) if not name:find("^%.") then @@ -5571,11 +5613,13 @@ function input.aux.register_in_trees(instance,name) end end +-- split the next one up, better for jit + function input.aux.find_file(instance,filename) -- todo : plugin (scanners, checkers etc) local result = { } local stamp = nil - filename = input.normalize_name(filename) - filename = file.collapse_path(filename:gsub("\\","/")) + filename = input.normalize_name(filename) -- elsewhere + filename = file.collapse_path(filename:gsub("\\","/")) -- elsewhere -- speed up / beware: format problem if instance.remember then stamp = filename .. "--" .. instance.engine .. "--" .. instance.progname .. "--" .. instance.format @@ -5647,7 +5691,7 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec local typespec = input.variable_of_format(filetype) local pathlist = input.expanded_path_list(instance,typespec) if not pathlist or #pathlist == 0 then - -- no pathlist, access check only + -- no pathlist, access check only / todo == wildcard if input.trace > 2 then input.logger('? filename',filename) input.logger('? filetype',filetype or '?') @@ -5662,8 +5706,9 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end -- this is actually 'other text files' or 'any' or 'whatever' local filelist = input.aux.collect_files(instance,wantedfiles) - filename = filelist and filelist[1] - if filename then + local lf = filelist and filelist[1] + if fl then + filename = fl[3] result[#result+1] = filename done = true end @@ -5673,8 +5718,8 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec local doscan, recurse if input.trace > 2 then input.logger('? filename',filename) - if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end - if filelist then input.logger('? file list',table.concat(filelist," | ")) end + -- if pathlist then input.logger('? path list',table.concat(pathlist," | ")) end + -- if filelist then input.logger('? file list',table.concat(filelist," | ")) end end -- a bit messy ... esp the doscan setting here for _, path in pairs(pathlist) do @@ -5687,16 +5732,18 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec -- compare list entries with permitted pattern pathname = pathname:gsub("([%-%.])","%%%1") -- this also influences pathname = pathname:gsub("/+$", '/.*') -- later usage of pathname - pathname = pathname:gsub("//", '/.-/') + pathname = pathname:gsub("//", '/.-/') -- not ok for /// but harmless local expr = "^" .. pathname -- input.debug('?',expr) - for _, f in pairs(filelist) do + for _, fl in ipairs(filelist) do + local f = fl[2] if f:find(expr) then -- input.debug('T',' '..f) if input.trace > 2 then input.logger('= found in hash',f) end - result[#result+1] = f + --- todo, test for readable + result[#result+1] = fl[3] input.aux.register_in_trees(instance,f) -- for tracing used files done = true if not instance.allresults then break end @@ -5706,7 +5753,7 @@ function input.aux.find_file(instance,filename) -- todo : plugin (scanners, chec end end if not done and doscan then - -- check if on disk / unchecked / does not work at all + -- check if on disk / unchecked / does not work at all / also zips if input.method_is_file(pathname) then -- ? local pname = pathname:gsub("%.%*$",'') if not pname:find("%*") then @@ -5783,10 +5830,7 @@ end if not input.concatinators then input.concatinators = { } end -function input.concatinators.tex(tag,path,name) - return tag .. '/' .. path .. '/' .. name -end - +input.concatinators.tex = file.join input.concatinators.file = input.concatinators.tex function input.find_files(instance,filename,filetype,mustexist) @@ -5988,15 +6032,6 @@ function input.aux.register_file(files, name, path) end end --- zip:: zip## zip:// --- zip::pathtozipfile::pathinzipfile (also: pathtozipfile/pathinzipfile) --- file::name --- tex::name --- kpse::name --- kpse::format::name --- parent::n::name --- parent::name (default 2) - if not input.finders then input.finders = { } end if not input.openers then input.openers = { } end if not input.loaders then input.loaders = { } end @@ -6006,30 +6041,37 @@ input.openers.notfound = { nil } input.loaders.notfound = { false, nil, 0 } function input.splitmethod(filename) - local method, specification = filename:match("^(.-)##(.+)$") - if method and specification then - return method, specification + if not filename then + return { } -- safeguard + elseif type(filename) == "table" then + return filename -- already split + elseif not filename:find("://") then + return { scheme="file", path = filename, original=filename } -- quick hack else - return 'tex', filename + return url.hashed(filename) end end function input.method_is_file(filename) - local method, specification = input.splitmethod(filename) - return method == 'tex' or method == 'file' + return input.splitmethod(filename).scheme == 'file' +end + +function table.sequenced(t,sep) -- temp here + local s = { } + for k, v in pairs(t) do + s[#s+1] = k .. "=" .. v + end + return table.concat(s, sep or " | ") end function input.methodhandler(what, instance, filename, filetype) -- ... - local method, specification = input.splitmethod(filename) - if method and specification then -- redundant - if input[what][method] then - input.logger('= handler',filename.." -> "..what.." | "..method.." | "..specification) - return input[what][method](instance,specification,filetype) - else - return nil - end + local specification = (type(filename) == "string" and input.splitmethod(filename)) or filename -- no or { }, let it bomb + local scheme = specification.scheme + if input[what][scheme] then + input.logger('= handler',specification.original .." -> " .. what .. " -> " .. table.sequenced(specification)) + return input[what][scheme](instance,filename,filetype) -- todo: specification else - return input[what].tex(instance,filename,filetype) + return input[what].tex(instance,filename,filetype) -- todo: specification end end @@ -6063,6 +6105,8 @@ function input.texdatablob(instance, filename, filetype) return data or "" end +input.loadtexfile = input.texdatablob + function input.openfile(filename) -- brrr texmf.instance here / todo ! ! ! ! ! local fullname = input.findtexfile(texmf.instance, filename) if fullname and (fullname ~= "") then @@ -6641,7 +6685,7 @@ function input.aux.load_data(instance,pathname,dataname,filename) end end --- we will make a better format, maybe something xml or just text +-- we will make a better format, maybe something xml or just text or lua input.automounted = input.automounted or { } @@ -6879,6 +6923,191 @@ logs.set_level('error') logs.set_method('tex') +if not modules then modules = { } end modules ['luat-sta'] = { + version = 1.001, + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files" +} + +states = states or { } +states.data = states.data or { } +states.hash = states.hash or { } +states.tag = states.tag or "" +states.filename = states.filename or "" + +function states.save(filename,tag) + tag = tag or states.tag + filename = file.addsuffix(filename or states.filename,'lus') + io.savedata(filename, + "-- generator : luat-sta.lua\n" .. + "-- state tag : " .. tag .. "\n\n" .. + table.serialize(states.data[tag or states.tag] or {},true) + ) +end + +function states.load(filename,tag) + states.filename = filename + states.tag = tag or "whatever" + states.filename = file.addsuffix(states.filename,'lus') + states.data[states.tag], states.hash[states.tag] = (io.exists(filename) and dofile(filename)) or { }, { } +end + +function states.set_by_tag(tag,key,value,default,persistent) + local d, h = states.data[tag], states.hash[tag] + if d then + local dkey, hkey = key, key + local pre, post = key:match("(.+)%.([^%.]+)$") + if pre and post then + for k in pre:gmatch("[^%.]+") do + local dk = d[k] + if not dk then + dk = { } + d[k] = dk + end + d = dk + end + dkey, hkey = post, key + end + if type(value) == nil then + value = value or default + elseif persistent then + value = value or d[dkey] or default + else + value = value or default + end + d[dkey], h[hkey] = value, value + end +end + +function states.get_by_tag(tag,key,default) + local h = states.hash[tag] + if h and h[key] then + return h[key] + else + local d = states.data[tag] + if d then + for k in key:gmatch("[^%.]+") do + local dk = d[k] + if dk then + d = dk + else + return default + end + end + return d or default + end + end +end + +function states.set(key,value,default,persistent) + states.set_by_tag(states.tag,key,value,default,persistent) +end + +function states.get(key,default) + return states.get_by_tag(states.tag,key,default) +end + +--~ states.data.update = { +--~ ["version"] = { +--~ ["major"] = 0, +--~ ["minor"] = 1, +--~ }, +--~ ["rsync"] = { +--~ ["server"] = "contextgarden.net", +--~ ["module"] = "minimals", +--~ ["repository"] = "current", +--~ ["flags"] = "-rpztlv --stats", +--~ }, +--~ ["tasks"] = { +--~ ["update"] = true, +--~ ["make"] = true, +--~ ["delete"] = false, +--~ }, +--~ ["platform"] = { +--~ ["host"] = true, +--~ ["other"] = { +--~ ["mswin"] = false, +--~ ["linux"] = false, +--~ ["linux-64"] = false, +--~ ["osx-intel"] = false, +--~ ["osx-ppc"] = false, +--~ ["sun"] = false, +--~ }, +--~ }, +--~ ["context"] = { +--~ ["available"] = {"current", "beta", "alpha", "experimental"}, +--~ ["selected"] = "current", +--~ }, +--~ ["formats"] = { +--~ ["cont-en"] = true, +--~ ["cont-nl"] = true, +--~ ["cont-de"] = false, +--~ ["cont-cz"] = false, +--~ ["cont-fr"] = false, +--~ ["cont-ro"] = false, +--~ }, +--~ ["engine"] = { +--~ ["pdftex"] = { +--~ ["install"] = true, +--~ ["formats"] = { +--~ ["pdftex"] = true, +--~ }, +--~ }, +--~ ["luatex"] = { +--~ ["install"] = true, +--~ ["formats"] = { +--~ }, +--~ }, +--~ ["xetex"] = { +--~ ["install"] = true, +--~ ["formats"] = { +--~ ["xetex"] = false, +--~ }, +--~ }, +--~ ["metapost"] = { +--~ ["install"] = true, +--~ ["formats"] = { +--~ ["mpost"] = true, +--~ ["metafun"] = true, +--~ }, +--~ }, +--~ }, +--~ ["fonts"] = { +--~ }, +--~ ["doc"] = { +--~ }, +--~ ["modules"] = { +--~ ["f-urwgaramond"] = false, +--~ ["f-urwgothic"] = false, +--~ ["t-bnf"] = false, +--~ ["t-chromato"] = false, +--~ ["t-cmscbf"] = false, +--~ ["t-cmttbf"] = false, +--~ ["t-construction-plan"] = false, +--~ ["t-degrade"] = false, +--~ ["t-french"] = false, +--~ ["t-lettrine"] = false, +--~ ["t-lilypond"] = false, +--~ ["t-mathsets"] = false, +--~ ["t-tikz"] = false, +--~ ["t-typearea"] = false, +--~ ["t-vim"] = false, +--~ }, +--~ } + + +--~ states.save("teststate", "update") +--~ states.load("teststate", "update") + +--~ print(states.get_by_tag("update","rsync.server","unknown")) +--~ states.set_by_tag("update","rsync.server","oeps") +--~ print(states.get_by_tag("update","rsync.server","unknown")) +--~ states.save("teststate", "update") +--~ states.load("teststate", "update") +--~ print(states.get_by_tag("update","rsync.server","unknown")) + + -- end library merge own = { } @@ -6906,6 +7135,7 @@ own.libs = { -- todo: check which ones are really needed -- 'luat-kps.lua', 'luat-tmp.lua', 'luat-log.lua', + 'luat-sta.lua', } -- We need this hack till luatex is fixed. @@ -7185,6 +7415,7 @@ input.runners.registered = { if not messages then messages = { } end messages.help = [[ +--script run an mtx script --execute run a script or program --resolve resolve prefixed arguments --ctxlua run internally (using preloaded libs) |