diff options
author | Mojca Miklavec <mojca.miklavec@gmail.com> | 2014-05-05 20:29:55 +0000 |
---|---|---|
committer | Mojca Miklavec <mojca.miklavec@gmail.com> | 2014-05-05 20:29:55 +0000 |
commit | ba9a57343987f1c2c72396e7c38f1fa30352c24c (patch) | |
tree | 66a8b12cdf67427ce96770fd0e9e581759aade1c /Master/texmf-dist/scripts/context/lua | |
parent | 15242121b8ddf7d4a041fb3998d295dd8232e1eb (diff) |
ConTeXt 2014.04.28 23:24
git-svn-id: svn://tug.org/texlive/trunk@33856 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/scripts/context/lua')
20 files changed, 2486 insertions, 1103 deletions
diff --git a/Master/texmf-dist/scripts/context/lua/mtx-bibtex.lua b/Master/texmf-dist/scripts/context/lua/mtx-bibtex.lua new file mode 100644 index 00000000000..c81fd596f10 --- /dev/null +++ b/Master/texmf-dist/scripts/context/lua/mtx-bibtex.lua @@ -0,0 +1,106 @@ +if not modules then modules = { } end modules ['mtx-bibtex'] = { + version = 1.002, + comment = "this script is part of publication support", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE", + license = "see context related readme files" +} + +local helpinfo = [[ +<?xml version="1.0"?> +<application> + <metadata> + <entry name="name">mtx-bibtex</entry> + <entry name="detail">bibtex helpers</entry> + <entry name="version">1.00</entry> + </metadata> + <flags> + <category name="basic"> + <subcategory> + <flag name="toxml"><short>convert bibtex database(s) to xml</short></flag> + <flag name="tolua"><short>convert bibtex database(s) to lua</short></flag> + </subcategory> + </category> + </flags> + <examples> + <category> + <title>Example</title> + <subcategory> + <example><command>mtxrun --script bibtex --tolua bibl-001.bib</command></example> + <example><command>mtxrun --script bibtex --tolua --simple bibl-001.bib</command></example> + <example><command>mtxrun --script bibtex --toxml bibl-001.bib bibl-002.bib bibl-003.bib biblio.xml</command></example> + </subcategory> + </category> + </examples> +</application> +]] + +local application = logs.application { + name = "mtx-bibtex", + banner = "bibtex helpers", + helpinfo = helpinfo, +} + +local report = application.report + +require("publ-dat") + +scripts = scripts or { } +scripts.bibtex = scripts.bibtex or { } + +function scripts.bibtex.toxml(files) + local instance = bibtex.new() + local target = "mtx-bibtex-output.xml" + for i=1,#files do + local filename = files[i] + local filetype = file.suffix(filename) + if filetype == "xml" then + target = filename + elseif filetype == "bib" then + bibtex.load(instance,filename) + else + -- not supported + end + end + bibtex.converttoxml(instance,true) + instance.shortcuts = nil + instance.luadata = nil + xml.save(instance.xmldata,target) +end + +function scripts.bibtex.tolua(files) + local instance = bibtex.new() + local target = "mtx-bibtex-output.lua" + for i=1,#files do + local filename = files[i] + local filetype = file.suffix(filename) + if filetype == "lua" then + target = filename + elseif filetype == "bib" then + bibtex.load(instance,filename) + else + -- not supported + end + end + instance.shortcuts = nil + instance.xmldata = nil + bibtex.analyze(instance) + if environment.arguments.simple then + table.save(target,instance) + else + table.save(target,instance.luadata) + end +end + +if environment.arguments.toxml then + scripts.bibtex.toxml(environment.files) +elseif environment.arguments.tolua then + scripts.bibtex.tolua(environment.files) +elseif environment.arguments.exporthelp then + application.export(environment.arguments.exporthelp,environment.files[1]) +else + application.help() +end + +-- scripts.bibtex.toxml { "tugboat.bib" } +-- scripts.bibtex.tolua { "tugboat.bib" } diff --git a/Master/texmf-dist/scripts/context/lua/mtx-context.lua b/Master/texmf-dist/scripts/context/lua/mtx-context.lua index 87ed3475d0f..b53110bb1a4 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-context.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-context.lua @@ -17,8 +17,17 @@ local settings_to_array = utilities.parsers.settings_to_array local appendtable = table.append local lpegpatterns, lpegmatch, Cs, P = lpeg.patterns, lpeg.match, lpeg.Cs, lpeg.P -local getargument = environment.getargument or environment.argument -local setargument = environment.setargument +local getargument = environment.getargument or environment.argument +local setargument = environment.setargument + +local filejoinname = file.join +local filebasename = file.basename +local filepathpart = file.pathpart +local filesuffix = file.suffix +local fileaddsuffix = file.addsuffix +local filenewsuffix = file.replacesuffix +local removesuffix = file.removesuffix +local validfile = lfs.isfile local application = logs.application { name = "mtx-context", @@ -78,14 +87,17 @@ scripts.context = scripts.context or { } -- for the moment here -if getargument("jit") or getargument("jiton") then +if jit then -- already luajittex + setargument("engine","luajittex") + setargument("jit",nil) +elseif getargument("jit") or getargument("jiton") then -- relaunch luajittex -- bonus shortcut, we assume than --jit also indicates the engine -- although --jit and --engine=luajittex are independent setargument("engine","luajittex") end -local engine_new = getargument("engine") or directives.value("system.engine") -local engine_old = environment.ownbin +local engine_new = file.nameonly(getargument("engine") or directives.value("system.engine")) +local engine_old = file.nameonly(environment.ownbin) local function restart(engine_old,engine_new) local command = format("%s --luaonly %q %s --redirected",engine_new,environment.ownname,environment.reconstructcommandline()) @@ -162,14 +174,14 @@ function ctxrunner.checkfile(ctxdata,ctxname,defaultname) return end - ctxdata.ctxname = ctxname or file.removesuffix(ctxdata.jobname) or "" + ctxdata.ctxname = ctxname or removesuffix(ctxdata.jobname) or "" if ctxdata.ctxname == "" then return end - ctxdata.jobname = file.addsuffix(ctxdata.jobname,'tex') - ctxdata.ctxname = file.addsuffix(ctxdata.ctxname,'ctx') + ctxdata.jobname = fileaddsuffix(ctxdata.jobname,'tex') + ctxdata.ctxname = fileaddsuffix(ctxdata.ctxname,'ctx') report("jobname: %s",ctxdata.jobname) report("ctxname: %s",ctxdata.ctxname) @@ -177,14 +189,14 @@ function ctxrunner.checkfile(ctxdata,ctxname,defaultname) -- mtxrun should resolve kpse: and file: local usedname = ctxdata.ctxname - local found = lfs.isfile(usedname) + local found = validfile(usedname) -- no further test if qualified path if not found then for _, path in next, ctx_locations do - local fullname = file.join(path,ctxdata.ctxname) - if lfs.isfile(fullname) then + local fullname = filejoinname(path,ctxdata.ctxname) + if validfile(fullname) then usedname = fullname found = true break @@ -197,7 +209,7 @@ function ctxrunner.checkfile(ctxdata,ctxname,defaultname) found = usedname ~= "" end - if not found and defaultname and defaultname ~= "" and lfs.isfile(defaultname) then + if not found and defaultname and defaultname ~= "" and validfile(defaultname) then usedname = defaultname found = true end @@ -214,7 +226,7 @@ function ctxrunner.checkfile(ctxdata,ctxname,defaultname) -- test for valid, can be text file end - local ctxpaths = table.append({'.', file.dirname(ctxdata.ctxname)}, ctx_locations) + local ctxpaths = table.append({'.', filepathpart(ctxdata.ctxname)}, ctx_locations) xml.include(xmldata,'ctx:include','name', ctxpaths) @@ -244,8 +256,9 @@ end -- multipass control -local multipass_suffixes = { ".tuc" } -local multipass_nofruns = 8 -- or 7 to test oscillation +local multipass_suffixes = { ".tuc" } +local multipass_nofruns = 8 -- or 7 to test oscillation +local multipass_forcedruns = false local function multipass_hashfiles(jobname) local hash = { } @@ -268,7 +281,7 @@ end local function multipass_copyluafile(jobname) local tuaname, tucname = jobname..".tua", jobname..".tuc" - if lfs.isfile(tuaname) then + if validfile(tuaname) then os.remove(tucname) os.rename(tuaname,tucname) end @@ -278,32 +291,38 @@ end local pattern = lpegpatterns.utfbom^-1 * (P("%% ") + P("% ")) * Cs((1-lpegpatterns.newline)^1) +local prefile = nil +local predata = nil + local function preamble_analyze(filename) -- only files on current path - local t = { } - local line = io.loadlines(file.addsuffix(filename,"tex")) + filename = fileaddsuffix(filename,"tex") -- to be sure + if predata and prefile == filename then + return predata + end + prefile = filename + predata = { } + local line = io.loadlines(prefile) if line then local preamble = lpegmatch(pattern,line) if preamble then - for key, value in gmatch(preamble,"(%S+)%s*=%s*(%S+)") do - t[key] = value - end - t.type = "tex" + utilities.parsers.options_to_hash(preamble,predata) + predata.type = "tex" elseif find(line,"^<?xml ") then - t.type = "xml" + predata.type = "xml" end - if t.nofruns then - multipass_nofruns = t.nofruns + if predata.nofruns then + multipass_nofruns = predata.nofruns end - if not t.engine then - t.engine = environment.basicengines[engine_old] --'luatex' + if not predata.engine then + predata.engine = environment.basicengines[engine_old] --'luatex' end - if t.engine ~= engine_old then -- hack - if environment.validengines[t.engine] and t.engine ~= environment.basicengines[engine_old] then - restart(engine_old,t.engine) + if predata.engine ~= engine_old then -- hack + if environment.validengines[predata.engine] and predata.engine ~= environment.basicengines[engine_old] then + restart(engine_old,predata.engine) end end end - return t + return predata end -- automatically opening and closing pdf files @@ -314,21 +333,21 @@ local function pdf_open(name,method) pdfview = pdfview or dofile(resolvers.findfile("l-pdfview.lua","tex")) pdfview.setmethod(method) report(pdfview.status()) - pdfview.open(file.replacesuffix(name,"pdf")) + pdfview.open(filenewsuffix(name,"pdf")) end local function pdf_close(name,method) pdfview = pdfview or dofile(resolvers.findfile("l-pdfview.lua","tex")) pdfview.setmethod(method) - pdfview.close(file.replacesuffix(name,"pdf")) + pdfview.close(filenewsuffix(name,"pdf")) end -- result file handling local function result_push_purge(oldbase,newbase) for _, suffix in next, usedsuffixes.after do - local oldname = file.addsuffix(oldbase,suffix) - local newname = file.addsuffix(newbase,suffix) + local oldname = fileaddsuffix(oldbase,suffix) + local newname = fileaddsuffix(newbase,suffix) os.remove(newname) os.remove(oldname) end @@ -336,8 +355,8 @@ end local function result_push_keep(oldbase,newbase) for _, suffix in next, usedsuffixes.before do - local oldname = file.addsuffix(oldbase,suffix) - local newname = file.addsuffix(newbase,suffix) + local oldname = fileaddsuffix(oldbase,suffix) + local newname = fileaddsuffix(newbase,suffix) local tmpname = "keep-"..oldname os.remove(tmpname) os.rename(oldname,tmpname) @@ -348,8 +367,8 @@ end local function result_save_error(oldbase,newbase) for _, suffix in next, usedsuffixes.keep do - local oldname = file.addsuffix(oldbase,suffix) - local newname = file.addsuffix(newbase,suffix) + local oldname = fileaddsuffix(oldbase,suffix) + local newname = fileaddsuffix(newbase,suffix) os.remove(newname) -- to be sure os.rename(oldname,newname) end @@ -357,8 +376,8 @@ end local function result_save_purge(oldbase,newbase) for _, suffix in next, usedsuffixes.after do - local oldname = file.addsuffix(oldbase,suffix) - local newname = file.addsuffix(newbase,suffix) + local oldname = fileaddsuffix(oldbase,suffix) + local newname = fileaddsuffix(newbase,suffix) os.remove(newname) -- to be sure os.rename(oldname,newname) end @@ -366,8 +385,8 @@ end local function result_save_keep(oldbase,newbase) for _, suffix in next, usedsuffixes.after do - local oldname = file.addsuffix(oldbase,suffix) - local newname = file.addsuffix(newbase,suffix) + local oldname = fileaddsuffix(oldbase,suffix) + local newname = fileaddsuffix(newbase,suffix) local tmpname = "keep-"..oldname os.remove(newname) os.rename(oldname,newname) @@ -420,7 +439,7 @@ local function run_plain(plainformat,filename) local command = format("mtxrun --script --texformat=%s plain %s",plainformat,filename) report("running command: %s\n\n",command) -- todo: load and run - local resultname = file.replacesuffix(filename,"pdf") + local resultname = filenewsuffix(filename,"pdf") local pdfview = getargument("autopdf") or getargument("closepdf") if pdfview then pdf_close(resultname,pdfview) @@ -462,6 +481,10 @@ end -- +local function check_synctex(a_synctex) + return a_synctex and (tonumber(a_synctex) or (toboolean(a_synctex,true) and 1) or (a_synctex == "zipped" and 1) or (a_synctex == "unzipped" and -1)) or nil +end + function scripts.context.run(ctxdata,filename) -- local a_nofile = getargument("nofile") @@ -523,30 +546,33 @@ function scripts.context.run(ctxdata,filename) local a_arrange = getargument("arrange") local a_noarrange = getargument("noarrange") local a_jiton = getargument("jiton") + local a_jithash = getargument("jithash") local a_texformat = getargument("texformat") -- a_batchmode = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or nil - a_synctex = tonumber(a_synctex) or (toboolean(a_synctex,true) and 1) or (a_synctex == "zipped" and 1) or (a_synctex == "unzipped" and -1) or nil + a_synctex = check_synctex(a_synctex) -- for i=1,#filelist do -- local filename = filelist[i] - local basename = file.basename(filename) -- use splitter - local pathname = file.dirname(filename) + local basename = filebasename(filename) -- use splitter + local pathname = filepathpart(filename) -- if pathname == "" and not a_global and filename ~= usedfiles.nop then filename = "./" .. filename - if not lfs.isfile(filename) then + if not validfile(filename) then report("warning: no (local) file %a, proceeding",filename) end end -- - local jobname = file.removesuffix(basename) - -- local jobname = file.removesuffix(filename) + local jobname = removesuffix(basename) + -- local jobname = removesuffix(filename) local ctxname = ctxdata and ctxdata.ctxname -- local analysis = preamble_analyze(filename) -- + a_synctex = a_synctex or check_synctex(analysis.synctex) + -- if a_mkii or analysis.engine == 'pdftex' or analysis.engine == 'xetex' then run_texexec(filename,a_purge,a_purgeall) elseif plain_format(a_texformat or analysis.texformat) then @@ -557,7 +583,8 @@ function scripts.context.run(ctxdata,filename) formatfile, scriptfile = resolvers.locateformat(formatname) end -- - a_jiton = (a_jiton or toboolean(analysis.jiton,true)) and true or nil + a_jiton = (a_jiton or toboolean(analysis.jiton,true)) and true or nil + a_jithash = validstring(a_jithash or analysis.jithash) or nil -- if not formatfile or not scriptfile then report("warning: no format found, forcing remake (source driven)") @@ -568,13 +595,13 @@ function scripts.context.run(ctxdata,filename) local suffix = validstring(getargument("suffix")) local resultname = validstring(getargument("result")) if suffix then - resultname = file.removesuffix(jobname) .. suffix + resultname = removesuffix(jobname) .. suffix end local oldbase = "" local newbase = "" if resultname then - oldbase = file.removesuffix(jobname) - newbase = file.removesuffix(resultname) + oldbase = removesuffix(jobname) + newbase = removesuffix(resultname) if oldbase ~= newbase then if a_purgeresult then result_push_purge(oldbase,newbase) @@ -640,6 +667,7 @@ function scripts.context.run(ctxdata,filename) ["lua"] = scriptfile, ["jobname"] = jobname, ["jiton"] = a_jiton, + ["jithash"] = a_jithash, } -- if a_synctex then @@ -669,6 +697,7 @@ function scripts.context.run(ctxdata,filename) c_flags.final = false c_flags.kindofrun = (a_once and 3) or (currentrun==1 and 1) or (currentrun==maxnofruns and 4) or 2 c_flags.maxnofruns = maxnofruns + c_flags.forcedruns = multipass_forcedruns and multipass_forcedruns > 0 and multipass_forcedruns or nil c_flags.currentrun = currentrun c_flags.noarrange = a_noarrange or a_arrange or nil -- @@ -686,10 +715,15 @@ function scripts.context.run(ctxdata,filename) break elseif returncode == 0 then multipass_copyluafile(jobname) - newhash = multipass_hashfiles(jobname) - if multipass_changed(oldhash,newhash) then - oldhash = newhash - else + if not multipass_forcedruns then + newhash = multipass_hashfiles(jobname) + if multipass_changed(oldhash,newhash) then + oldhash = newhash + else + break + end + elseif currentrun == multipass_forcedruns then + report("quitting after force %i runs",multipass_forcedruns) break end else @@ -807,7 +841,7 @@ function scripts.context.pipe() -- still used? filename = "\\relax" report("entering scrollmode, end job with \\end") else - filename = file.addsuffix(filename,"tmp") + filename = fileaddsuffix(filename,"tmp") io.savedata(filename,"\\relax") report("entering scrollmode using '%s' with optionfile, end job with \\end",filename) end @@ -833,7 +867,7 @@ local function make_mkiv_format(name,engine) end local function make_mkii_format(name,engine) - local command = format("mtxrun texexec.rb --make --%s %s",name,engine) + local command = format("mtxrun texexec.rb --make %s --%s",name,engine) report("running command: %s",command) os.spawn(command) end @@ -875,24 +909,26 @@ function scripts.context.ctx() end function scripts.context.autoctx() - local ctxdata = nil - local files = environment.files + local ctxdata = nil + local files = environment.files local firstfile = #files > 0 and files[1] if firstfile then - local suffix = file.suffix(firstfile) + local suffix = filesuffix(firstfile) + local ctxname = nil if suffix == "xml" then local chunk = io.loadchunk(firstfile) -- 1024 if chunk then - local ctxname = match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>") - if ctxname then - ctxdata = ctxrunner.new() - ctxdata.jobname = firstfile - ctxrunner.checkfile(ctxdata,ctxname) - ctxrunner.checkflags(ctxdata) - end + ctxname = match(chunk,"<%?context%-directive%s+job%s+ctxfile%s+([^ ]-)%s*?>") end - elseif suffix == "tex" then - -- maybe but we scan the preamble later too + elseif suffix == "tex" or suffix == "mkiv" then + local analysis = preamble_analyze(firstfile) + ctxname = analysis.ctxfile or analysis.ctx + end + if ctxname then + ctxdata = ctxrunner.new() + ctxdata.jobname = firstfile + ctxrunner.checkfile(ctxdata,ctxname) + ctxrunner.checkflags(ctxdata) end end scripts.context.run(ctxdata) @@ -921,10 +957,10 @@ end -- formatname = "metafun" -- end -- if getargument("pdf") then --- local basename = file.removesuffix(filename) +-- local basename = removesuffix(filename) -- local resultname = getargument("result") or basename -- local jobname = "mtx-context-metapost" --- local tempname = file.addsuffix(jobname,"tex") +-- local tempname = fileaddsuffix(jobname,"tex") -- io.savedata(tempname,format(template,"metafun",filename)) -- environment.files[1] = tempname -- setargument("result",resultname) @@ -961,7 +997,7 @@ function scripts.context.version() end end --- purging files +-- purging files (we should have an mkii and mkiv variants) local generic_files = { "texexec.tex", "texexec.tui", "texexec.tuo", @@ -975,15 +1011,32 @@ local obsolete_results = { } local temporary_runfiles = { - "tui", "tua", "tup", "ted", "tes", "top", - "log", "tmp", "run", "bck", "rlg", - "mpt", "mpx", "mpd", "mpo", "mpb", "ctl", - "synctex", "synctex.gz", "pgf", - "prep", + "tui", -- mkii two pass file + "tua", -- mkiv obsolete + "tup", "ted", "tes", -- texexec + "top", -- mkii options file + "log", -- tex log file + "tmp", -- mkii buffer file + "run", -- mkii stub + "bck", -- backup (obsolete) + "rlg", -- resource log + "ctl", -- + "mpt", "mpx", "mpd", "mpo", "mpb", -- metafun + "prep", -- context preprocessed + "pgf", -- tikz + "aux", "blg", -- bibtex +} + +local synctex_runfiles = { + "synctex", "synctex.gz", -- synctex } local persistent_runfiles = { - "tuo", "tub", "top", "tuc" + "tuo", -- mkii two pass file + "tub", -- mkii buffer file + "top", -- mkii options file + "tuc", -- mkiv two pass file + "bbl", -- bibtex } local special_runfiles = { @@ -991,34 +1044,40 @@ local special_runfiles = { } local function purge_file(dfile,cfile) - if cfile and lfs.isfile(cfile) then + if cfile and validfile(cfile) then if os.remove(dfile) then - return file.basename(dfile) + return filebasename(dfile) end elseif dfile then if os.remove(dfile) then - return file.basename(dfile) + return filebasename(dfile) end end end function scripts.context.purge_job(jobname,all,mkiitoo) if jobname and jobname ~= "" then - jobname = file.basename(jobname) - local filebase = file.removesuffix(jobname) + jobname = filebasename(jobname) + local filebase = removesuffix(jobname) if mkiitoo then scripts.context.purge(all,filebase,true) -- leading "./" else local deleted = { } for i=1,#obsolete_results do - deleted[#deleted+1] = purge_file(filebase.."."..obsolete_results[i],filebase..".pdf") + deleted[#deleted+1] = purge_file(fileaddsuffix(filebase,obsolete_results[i]),fileaddsuffix(filebase,"pdf")) end for i=1,#temporary_runfiles do - deleted[#deleted+1] = purge_file(filebase.."."..temporary_runfiles[i]) + deleted[#deleted+1] = purge_file(fileaddsuffix(filebase,temporary_runfiles[i])) + end + if not environment.argument("synctex") then + -- special case: not deleted when --synctex is given, but what if given in preamble + for i=1,#synctex_runfiles do + deleted[#deleted+1] = purge_file(fileaddsuffix(filebase,synctex_runfiles[i])) + end end if all then for i=1,#persistent_runfiles do - deleted[#deleted+1] = purge_file(filebase.."."..persistent_runfiles[i]) + deleted[#deleted+1] = purge_file(fileaddsuffix(filebase,persistent_runfiles[i])) end end if #deleted > 0 then @@ -1034,14 +1093,15 @@ function scripts.context.purge(all,pattern,mkiitoo) local files = dir.glob(pattern) local obsolete = table.tohash(obsolete_results) local temporary = table.tohash(temporary_runfiles) + local synctex = table.tohash(synctex_runfiles) local persistent = table.tohash(persistent_runfiles) local generic = table.tohash(generic_files) local deleted = { } for i=1,#files do local name = files[i] - local suffix = file.suffix(name) - local basename = file.basename(name) - if obsolete[suffix] or temporary[suffix] or persistent[suffix] or generic[basename] then + local suffix = filesuffix(name) + local basename = filebasename(name) + if obsolete[suffix] or temporary[suffix] or synctex[suffix] or persistent[suffix] or generic[basename] then deleted[#deleted+1] = purge_file(name) elseif mkiitoo then for i=1,#special_runfiles do @@ -1060,8 +1120,7 @@ end local function touch(path,name,versionpattern,kind,kindpattern) if path and path ~= "" then - name = file.join(path,name) -print(name) + name = filejoinname(path,name) else name = resolvers.findfile(name) end @@ -1083,7 +1142,7 @@ print(name) end) or newdata end if newdata ~= "" and (oldversion ~= newversion or oldkind ~= newkind or newdata ~= olddata) then - local backup = file.replacesuffix(name,"tmp") + local backup = filenewsuffix(name,"tmp") os.remove(backup) os.rename(name,backup) io.savedata(name,newdata) @@ -1097,12 +1156,12 @@ local p_contextversion = "(\\edef\\contextversion%s*{)(.-)(})" local p_newcontextversion = "(\\newcontextversion%s*{)(.-)(})" local function touchfiles(suffix,kind,path) - local foundname, oldversion, newversion, oldkind, newkind = touch(path,file.addsuffix("context",suffix),p_contextversion,kind,p_contextkind) + local foundname, oldversion, newversion, oldkind, newkind = touch(path,fileaddsuffix("context",suffix),p_contextversion,kind,p_contextkind) if foundname then report("old version : %s (%s)",oldversion,oldkind) report("new version : %s (%s)",newversion,newkind) report("touched file : %s",foundname) - local foundname = touch(path,file.addsuffix("cont-new",suffix),p_newcontextversion) + local foundname = touch(path,fileaddsuffix("cont-new",suffix),p_newcontextversion) if foundname then report("touched file : %s", foundname) end @@ -1143,19 +1202,19 @@ function scripts.context.modules(pattern) end -- my dev path for i=1,#cards do - dir.glob(file.join(file.dirname(found),cards[i]),list) + dir.glob(filejoinname(filepathpart(found),cards[i]),list) end else resolvers.findwildcardfiles(pattern,list) - dir.glob(file.join(file.dirname(found,pattern)),list) + dir.glob(filejoinname(filepathpart(found,pattern)),list) end local done = { } -- todo : sort for i=1,#list do local v = list[i] - local base = file.basename(v) + local base = filebasename(v) if not done[base] then done[base] = true - local suffix = file.suffix(base) + local suffix = filesuffix(base) if suffix == "tex" or suffix == "mkiv" or suffix == "mkvi" or suffix == "mkix" or suffix == "mkxi" then local prefix = match(base,"^([xmst])%-") if prefix then @@ -1193,7 +1252,7 @@ function scripts.context.extras(pattern) end local found = resolvers.findfile("context.mkiv") if found ~= "" then - pattern = file.join(dir.expandname(file.dirname(found)),format("mtx-context-%s.tex",pattern or "*")) + pattern = filejoinname(dir.expandname(filepathpart(found)),format("mtx-context-%s.tex",pattern or "*")) local list = dir.glob(pattern) for i=1,#list do local v = list[i] @@ -1432,9 +1491,12 @@ do end if getargument("once") then - multipass_nofruns = 1 -elseif getargument("runs") then - multipass_nofruns = tonumber(getargument("runs")) or nil + multipass_nofruns = 1 +else + if getargument("runs") then + multipass_nofruns = tonumber(getargument("runs")) or nil + end + multipass_forcedruns = tonumber(getargument("forcedruns")) or nil end if getargument("run") then diff --git a/Master/texmf-dist/scripts/context/lua/mtx-context.xml b/Master/texmf-dist/scripts/context/lua/mtx-context.xml index a3812288f29..af8d5cc20e5 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-context.xml +++ b/Master/texmf-dist/scripts/context/lua/mtx-context.xml @@ -108,6 +108,14 @@ <flag name="once"> <short>only run once (no multipass data file is produced)</short> </flag> + <flag name="runs"> + <short>process at most this many times</short> + </flag> + <flag name="forcedruns"> + <short>process this many times (permits for optimization trial runs)</short> + </flag> + </subcategory> + <subcategory> <flag name="batchmode"> <short>run without stopping and do not show messages on the console</short> </flag> @@ -117,7 +125,7 @@ <flag name="synctex"> <short>run with synctex enabled (optional value: zipped, unzipped, 1, -1)</short> </flag> - </subcategory> + </subcategory> <subcategory> <flag name="generate"> <short>generate file database etc. (as luatools does)</short> diff --git a/Master/texmf-dist/scripts/context/lua/mtx-fcd.lua b/Master/texmf-dist/scripts/context/lua/mtx-fcd.lua index ba9299020ba..2fcb9a2c7e9 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-fcd.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-fcd.lua @@ -122,13 +122,25 @@ local stubdata local stubdummy local stubchdir -if os.platform == 'mswin' then - gotofile = 'mtx-fcd-goto.cmd' - datafile = 'mtx-fcd-data.lua' - stubfile = 'fcd.cmd' - stubdata = mswinstub - stubdummy = 'rem no dir to change to' - stubchdir = 'cd /d "%s"' + +if os.type == 'windows' then + local shell = "cmd" +-- local shell = "powershell" + if shell == "powershell" then + gotofile = 'mtx-fcd-goto.ps1' + datafile = 'mtx-fcd-data.lua' + stubfile = 'fcd.cmd' + stubdata = mswinstub + stubdummy = '# no dir to change to' + stubchdir = '. Set-Location %s' -- powershell + else + gotofile = 'mtx-fcd-goto.cmd' + datafile = 'mtx-fcd-data.lua' + stubfile = 'fcd.cmd' + stubdata = mswinstub + stubdummy = 'rem no dir to change to' + stubchdir = 'cd /d "%s"' -- cmd + end else gotofile = 'mtx-fcd-goto.sh' datafile = 'mtx-fcd-data.lua' @@ -183,7 +195,7 @@ end local function fcd_changeto(dir) if dir and dir ~= "" then - io.savedata(gotofile,format(stubchdir,dir)) + io.savedata(gotofile,format(stubchdir,dir,dir)) end end diff --git a/Master/texmf-dist/scripts/context/lua/mtx-flac.lua b/Master/texmf-dist/scripts/context/lua/mtx-flac.lua index 2155b24becb..4e01abc997f 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-flac.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-flac.lua @@ -56,11 +56,20 @@ readers.default = function(f,size,target) f:seek("cur",size) end +local valid = { + ["fLaC"] = true, + ["ID3♥"] = false, +} + function flac.getmetadata(filename) local f = io.open(filename, "rb") if f then - local banner = readstring(f,4) - if banner == "fLaC" then + local banner = readstring(f,4) + local whatsit = valid[banner] + if whatsit ~= nil then + if whatsit == false then + flac.report("suspicious flac file: %s (%s)",filename,banner) + end local data = { banner = banner, filename = filename, @@ -96,13 +105,14 @@ function flac.savecollection(pattern,filename) local files = dir.glob(pattern) flac.report("%s files found, analyzing files",#files) local music = { } + table.sort(files) for i=1,#files do local data = flac.getmetadata(files[i]) if data then - local tags = data.tags - local info = data.info - local artist = tags.artist - local album = tags.album + local tags = data.tags + local info = data.info + local artist = tags.artist or "no-artist" + local album = tags.album or "no-album" local albums = music[artist] if not albums then albums = { } @@ -134,8 +144,18 @@ function flac.savecollection(pattern,filename) f:write("\t<artist>\n") f:write("\t\t<name>",lpegmatch(p_escaped,artist),"</name>\n") f:write("\t\t<albums>\n") - for album, data in sortedpairs(albums) do - nofalbums = nofalbums + 1 + local list = table.keys(albums) + table.sort(list,function(a,b) + local ya, yb = albums[a].year or 0, albums[b].year or 0 + if ya == yb then + return a < b + else + return ya < yb + end + end) + for nofalbums=1,#list do + local album = list[nofalbums] + local data = albums[album] f:write("\t\t\t<album year='",data.year or 0,"'>\n") f:write("\t\t\t\t<name>",lpegmatch(p_escaped,album),"</name>\n") f:write("\t\t\t\t<tracks>\n") @@ -179,6 +199,7 @@ local helpinfo = [[ <category name="basic"> <subcategory> <flag name="collect"><short>collect albums in xml file</short></flag> + <flag name="pattern"><short>use pattern for locating files</short></flag> </subcategory> </category> </flags> diff --git a/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua b/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua index b171dd611f4..675d9fb129e 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-fonts.lua @@ -85,8 +85,8 @@ local report = application.report if not fontloader then fontloader = fontforge end dofile(resolvers.findfile("font-otp.lua","tex")) -- we need to unpack the font for analysis -dofile(resolvers.findfile("font-trt.lua","tex")) dofile(resolvers.findfile("font-syn.lua","tex")) +dofile(resolvers.findfile("font-trt.lua","tex")) dofile(resolvers.findfile("font-mis.lua","tex")) scripts = scripts or { } @@ -132,9 +132,9 @@ function fonts.names.statistics() end -function fonts.names.simple() +function fonts.names.simple(alsotypeone) local simpleversion = 1.001 - local simplelist = { "ttf", "otf", "ttc", "dfont" } + local simplelist = { "ttf", "otf", "ttc", "dfont", alsotypeone and "afm" or nil } local name = "luatex-fonts-names.lua" local path = file.collapsepath(caches.getwritablepath("..","..","generic","fonts","data")) fonts.names.filters.list = simplelist @@ -182,7 +182,7 @@ end function scripts.fonts.reload() if getargument("simple") then - fonts.names.simple() + fonts.names.simple(getargument("typeone")) else fonts.names.load(true,getargument("force")) end @@ -385,6 +385,7 @@ function scripts.fonts.justload() local result = fontloader.open(fullname) if type(result) == "table" then report("loading %s: %s","succeeded",fullname) + fontloader.close(result) end end report("loading %s: %s","failed",fullname) @@ -412,8 +413,12 @@ function scripts.fonts.save() local sub = givenfiles[2] or "" local function save(savename,fontblob) if fontblob then + if fontblob.validation_state and table.contains(fontblob.validation_state,"bad_ps_fontname") then + report("ignoring bad fontname for %a",name) + savename = file.nameonly(name) .. "-bad-ps-name" + end savename = file.addsuffix(string.lower(savename),"lua") - report("fontsave, saving data in %s",savename) + report("fontsave, saving data in %a",savename) table.tofile(savename,fontloader.to_table(fontblob),"return") fontloader.close(fontblob) end @@ -425,8 +430,8 @@ function scripts.fonts.save() if suffix == 'ttf' or suffix == 'otf' or suffix == 'ttc' or suffix == "dfont" then local fontinfo = fontloader.info(filename) if fontinfo then - report("font: %s located as %s",name,filename) - if fontinfo[1] then + report("font: %a located as %a",name,filename) + if #fontinfo > 0 then for k=1,#fontinfo do local v = fontinfo[k] save(v.fontname,fontloader.open(filename,v.fullname)) @@ -435,13 +440,13 @@ function scripts.fonts.save() save(fontinfo.fullname,fontloader.open(filename)) end else - report("font: %s cannot be read",filename) + report("font: %a cannot be read",filename) end else - report("font: %s not saved",filename) + report("font: %a not saved",filename) end else - report("font: %s not found",name) + report("font: %a not found",name) end else report("font: no name given") diff --git a/Master/texmf-dist/scripts/context/lua/mtx-grep.lua b/Master/texmf-dist/scripts/context/lua/mtx-grep.lua index dbcce67f6a2..d0f33cb2182 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-grep.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-grep.lua @@ -51,7 +51,9 @@ local content = lpeg.C((1-newline)^0) * newline + lpeg.C(lpeg.P(1)^1) local write_nl = texio.write_nl - -- local pattern = "LIJST[@TYPE='BULLET']/LIJSTITEM[contains(text(),'Kern')]" +-- local pattern = "LIJST[@TYPE='BULLET']/LIJSTITEM[contains(text(),'Kern')]" + +-- 'Cc%(\\\"\\\"%)' function scripts.grep.find(pattern, files, offset) if pattern and pattern ~= "" then diff --git a/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua b/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua index dca81568e41..5e2b2d902ca 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-patterns.lua @@ -129,7 +129,7 @@ scripts.patterns.list = { -- { "lo", "hyph-lo", "lao" }, { "lt", "hyph-lt", "lithuanian" }, { "lv", "hyph-lv", "latvian" }, - -- { "ml", "hyph-ml", "..." }, + { "ml", "hyph-ml", "malayalam" }, { "mn", "hyph-mn-cyrl", "mongolian, cyrillic script" }, -- { "mr", "hyph-mr", "..." }, { "nb", "hyph-nb", "norwegian bokmål" }, @@ -282,12 +282,15 @@ function scripts.patterns.load(path,name,mnemonic,ignored) report("%s: no entry in chardata for character %C",basename,b) else local ct = cdb.category - if ct == "lu" or ct == "ll" or ct == "lo" or ct == "mn" then -- hm, really mn ? + if ct == "lu" or ct == "ll" or ct == "lo" or ct == "mn" or ct == "mc" then -- hm, really mn and mc ? used[char(b)] = true elseif ct == "nd" then -- number - else - report("%s: removing line with suspected utf character %C, category %s: %s",basename,b,ct,line) + elseif ct == "cf" then + report("%s: %s line with suspected utf character %C, category %s: %s",basename,"keeping",b,ct,line) + used[char(b)] = true + else -- maybe accent cf (200D) + report("%s: %s line with suspected utf character %C, category %s: %s",basename,"removing",b,ct,line) splitdata[i] = "" break end diff --git a/Master/texmf-dist/scripts/context/lua/mtx-plain.lua b/Master/texmf-dist/scripts/context/lua/mtx-plain.lua index f43dcdeafcc..de13717d396 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-plain.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-plain.lua @@ -24,6 +24,7 @@ local helpinfo = [[ <category name="basic"> <subcategory> <flag name="make"><short>create format file</short></flag> + <flag name="fonts"><short>create plain font database</short></flag> <flag name="run"><short>process file</short></flag> <flag name="format" value="string"><short>format name (default: luatex-plain)</short></flag> <flag name="engine" value="string"><short>engine to use (default: luatex)</short></flag> @@ -105,11 +106,15 @@ function scripts.plain.run(texengine,texformat,filename) execute('%s --fmt=%s "%s"',texengine,file.removesuffix(texformat),filename) end +function scripts.plain.fonts() + execute('mtxrun --script fonts --reload --simple --typeone') +end + local texformat = environment.arguments.texformat or environment.arguments.format local texengine = environment.arguments.texengine or environment.arguments.engine if type(texengine) ~= "string" or texengine == "" then - texengine = environment.arguments.jit and "luajittex" or"luatex" + texengine = (jit or environment.arguments.jit) and "luajittex" or "luatex" end if type(texformat) ~= "string" or texformat == "" then @@ -122,6 +127,8 @@ if environment.arguments.exporthelp then application.export(environment.arguments.exporthelp,filename) elseif environment.arguments.make then scripts.plain.make(texengine,texformat) +elseif environment.arguments.fonts then + scripts.plain.fonts() elseif filename then scripts.plain.run(texengine,texformat,filename) else diff --git a/Master/texmf-dist/scripts/context/lua/mtx-profile.lua b/Master/texmf-dist/scripts/context/lua/mtx-profile.lua index 3550474f38c..0d0c28084f3 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-profile.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-profile.lua @@ -31,7 +31,7 @@ local helpinfo = [[ ]] local application = logs.application { - name = "mtx-cache", + name = "mtx-profile", banner = "ConTeXt MkIV LuaTeX Profiler 1.00", helpinfo = helpinfo, } @@ -56,20 +56,22 @@ function scripts.profiler.analyze(filename) local times, counts, calls = { }, { }, { } local totalruntime, totalcount, totalcalls = 0, 0, 0 for line in f:lines() do - local stacklevel, filename, functionname, linenumber, currentline, localtime, totaltime = line:match("^(%d+)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)") - if not filename then - -- next - elseif filename == "=[C]" then - if not functionname:find("^%(") then - calls[functionname] = (calls[functionname] or 0) + 1 - end - else - local filename = filename:match("^@(.*)$") - if filename then - local fi = times[filename] - if not fi then fi = { } times[filename] = fi end - fi[functionname] = (fi[functionname] or 0) + tonumber(localtime) - counts[functionname] = (counts[functionname] or 0) + 1 + if not find(line,"__index") and not find(line,"__newindex") then + local stacklevel, filename, functionname, linenumber, currentline, localtime, totaltime = line:match("^(%d+)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)\t(.-)") + if not filename then + -- next + elseif filename == "=[C]" then + if not functionname:find("^%(") then + calls[functionname] = (calls[functionname] or 0) + 1 + end + else + local filename = filename:match("^@(.*)$") + if filename then + local fi = times[filename] + if not fi then fi = { } times[filename] = fi end + fi[functionname] = (fi[functionname] or 0) + tonumber(localtime) + counts[functionname] = (counts[functionname] or 0) + 1 + end end end end diff --git a/Master/texmf-dist/scripts/context/lua/mtx-rsync.lua b/Master/texmf-dist/scripts/context/lua/mtx-rsync.lua index 65f795ee557..d3f01d85b71 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-rsync.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-rsync.lua @@ -81,7 +81,7 @@ local report_command = logs.new("rsync command") local cleanup -if os.platform == "mswin" then +if os.type == "windows" then os.setenv("CYGWIN","nontsec") cleanup = function(name) return (gsub(name,"([a-zA-Z]):/", "/cygdrive/%1/")) @@ -92,13 +92,26 @@ else end end -function rsynccommand(dryrun,recurse,origin,target) - local command = "rsync -ptlva " +function rsynccommand(origin,target,dryrun,recurse,delete,exclude) + local command = "rsync -t -p" if dryrun then - command = command .. "-n " + command = command .. " -n" end if recurse then - command = command .. "-r " + command = command .. " -r" + end + if type(exclude) == "table" then + for i=1,#exclude do + local e = exclude[i] + if e then + command = command .. ' --exclude "' .. e .. '"' + end + end + elseif type(exclude) == "string" then + command = command .. " --exclude-from " .. exclude + end + if delete and recurse then + command = command .. " --delete" end return format('%s %s %s',command,origin,target) end @@ -109,7 +122,7 @@ local rsync = scripts.rsync rsync.mode = "command" -function rsync.run(origin,target,message,recurse) +function rsync.run(origin,target,message,recurse,delete,exclude) if type(origin) == "table" then origin = concat(origin,"/") end @@ -127,15 +140,15 @@ function rsync.run(origin,target,message,recurse) report_message(message) end if rsync.mode == "dryrun" then - local command = rsynccommand(true,recurse,origin,target) + local command = rsynccommand(origin,target,true,recurse,delete,exclude) report_dryrun(command.."\n") os.execute(command) elseif rsync.mode == "force" then - local command = rsynccommand(false,recurse,origin,target) + local command = rsynccommand(origin,target,false,recurse,delete,exclude) report_normal(command.."\n") os.execute(command) else - local command = rsynccommand(true,recurse,origin,target) + local command = rsynccommand(origin,target,true,recurse,delete,exclude) report_command(command) end end @@ -154,8 +167,10 @@ function rsync.job(list) local target = li.target local message = li.message local recurse = li.recurse + local delete = li.delete + local exclude = li.exclude if origin and #origin > 0 and target and #target > 0 then -- string or table - rsync.run(origin,target,message,recurse) + rsync.run(origin,target,message,recurse,delete,exclude) else report_message("invalid job specification at index %s",i) end diff --git a/Master/texmf-dist/scripts/context/lua/mtx-scite.lua b/Master/texmf-dist/scripts/context/lua/mtx-scite.lua index 972edbfe6a6..ae8c673879f 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-scite.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-scite.lua @@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['mtx-scite'] = { license = "see context related readme files" } +-- mtxrun --script scite --tree --source=t:/texmf/tex/context --target=e:/tmp/context --numbers + local P, R, S, C, Ct, Cf, Cc, Cg = lpeg.P, lpeg.R, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cf, lpeg.Cc, lpeg.Cg local lpegmatch = lpeg.match local format, lower, gmatch = string.format, string.lower, string.gmatch @@ -22,6 +24,8 @@ local helpinfo = [[ <category name="basic"> <subcategory> <flag name="words"><short>convert spell-*.txt into spell-*.lua</short></flag> + <flag name="tree"><short>converts a tree into an html tree (--source --target --numbers)</short></flag> + <flag name="file"><short>converts a file into an html tree (--source --target --numbers --lexer)</short></flag> </subcategory> </category> </flags> @@ -36,6 +40,8 @@ local application = logs.application { local report = application.report +local scite = require("util-sci") + scripts = scripts or { } scripts.scite = scripts.scite or { } @@ -241,6 +247,51 @@ function scripts.scite.words() report("you need to move the lua files to lexers/data") end +function scripts.scite.tree() + local source = environment.argument("source") + local target = environment.argument("target") + local numbers = environment.argument("numbers") + if not lfs.isdir(source) then + report("you need to pass a valid source path with --source") + return + end + if not lfs.isdir(target) then + report("you need to pass a valid target path with --target") + return + end + if source == target then + report("source and target paths must be different") + return + end + scite.converttree(source,target,numbers) +end + +function scripts.scite.file() + local source = environment.argument("source") + local target = environment.argument("target") + local lexer = environment.argument("lexer") + local numbers = environment.argument("numbers") + if source then + local target = target or file.replacesuffix(source,"html") + if source == target then + report("the source file cannot be the same as the target") + else + scite.filetohtml(source,lexer,target,numbers) + end + + else + for i=1,#environment.files do + local source = environment.files[i] + local target = file.replacesuffix(source,"html") + if source == target then + report("the source file cannot be the same as the target") + else + scite.filetohtml(source,nil,target,numbers) + end + end + end +end + -- if environment.argument("start") then -- scripts.scite.start(true) -- elseif environment.argument("test") then @@ -251,6 +302,10 @@ end if environment.argument("words") then scripts.scite.words() +elseif environment.argument("tree") then + scripts.scite.tree() +elseif environment.argument("file") then + scripts.scite.file() elseif environment.argument("exporthelp") then application.export(environment.argument("exporthelp"),environment.files[1]) else diff --git a/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-fonttest.lua b/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-fonttest.lua index a8d7edf4106..da87fe9e8b9 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-fonttest.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-fonttest.lua @@ -20,44 +20,62 @@ dofile(resolvers.findfile("font-mis.lua","tex")) local format, gsub, concat, match, find = string.format, string.gsub, table.concat, string.match, string.find -local report = logs.reporter("ctx-fonttest") +local formatters = string.formatters -local sample_line = "This is a sample line!" -local tempname = "mtx-server-ctx-fonttest-temp" -local temppath = caches.setfirstwritablefile("temp","mtx-server-ctx-fonttest") -local basename = "mtx-server-ctx-fonttest-data.lua" -local basepath = temppath +local report = logs.reporter("ctx-fonttest") + +local sample_line = "This is a sample line!" +local tempname = "mtx-server-ctx-fonttest-temp" +local temppath = caches.setfirstwritablefile("temp","mtx-server-ctx-fonttest") +local basename = "mtx-server-ctx-fonttest-data.lua" +local basepath = temppath local remove_suffixes = { "tex", "pdf", "log" } -local what_options = { "trace", "basemode" } +local what_options = { "trace", "basemode" } for i=1,#remove_suffixes do os.remove(file.join(temppath,file.addsuffix(tempname,remove_suffixes[i]))) end +local foolcache = 0 + +local function makename(name,new) + if new then + foolcache = foolcache > 25 and 1 or foolcache + 1 + end + return formatters["%s-%02i"](name,foolcache) +end + +-- nowadays i would use the more advanced template mechanism with named variables + local process_templates = { } -process_templates.default = [[ +-- %\definedfont[name:%s*sample] + +process_templates.default = formatters [ [[ \starttext - \setupdirections[bidi=global] + \setupdirections[bidi=one] \definefontfeature[sample][analyze=yes,%s] - \definedfont[name:%s*sample] + \definedfont[name:%s*none] \startTEXpage[offset=3pt] \detokenize{%s} + \blank + \definedfont[name:%s*sample] + \detokenize{%s} \stopTEXpage \stoptext -]] +]] ] -process_templates.cache = [[ +process_templates.cache = formatters [ [[ \starttext \definedfont[name:%s] \startTEXpage[offset=3pt] cached: \detokenize{%s} \stopTEXpage \stoptext -]] +]] ] -process_templates.trace = [[ +process_templates.trace = formatters [ [[ \usemodule[fnt-20] \definefontfeature[sample][%s] @@ -73,9 +91,9 @@ process_templates.trace = [[ direction=0, features=sample, sample={\detokenize{%s}}] -]] +]] ] -local javascripts = [[ +local javascripts = formatters [ [[ function selected_radio(name) { var form = document.forms["main-form"] ; var script = form.elements[name] ; @@ -151,7 +169,28 @@ function check_language() { function check_feature() { // not needed } -]] +]] ] + +local jitmode = false -- assumes local use (one user as shared) + +local run_context_normal = formatters["mtxrun --path=%q --script context --once --batchmode %q"] +local run_context_jitted = formatters["mtxrun --path=%q --script context --once --batchmode --jit %q"] + +local function runcontext(temppath,filename) + local start = os.clock() + local command = (jitmode and run_context_jitted or run_context_normal)(temppath,filename) + report("temppath: %s",temppath) + report("filename: %s",filename) + report("command: %s",command) + os.execute(command) + return os.clock() - start +end + +local function identifyfonts() + local command = "mtxrun --script font --reload" + report("command: %s",command) + os.execute(command) +end local cache = { } @@ -163,8 +202,9 @@ local function showfeatures(f) features = fonts.helpers.getfeatures(resolvers.findfile(f)) if not features then report("building cache for '%s'",f) - io.savedata(file.join(temppath,file.addsuffix(tempname,"tex")),format(process_templates.cache,f,f)) - os.execute(format("mtxrun --path=%s --script context --once --batchmode %s",temppath,tempname)) + local usedname = file.addsuffix(tempname,"tex") + io.savedata(file.join(temppath,usedname),process_templates.cache(f,f)) + runcontext(temppath,usedname) features = fonts.helpers.getfeatures(f) end cache[f] = features or false @@ -206,14 +246,15 @@ local function showfeatures(f) for what, v in table.sortedhash(features) do show(what) end + -- we could json this local stupid = { } stupid[#stupid+1] = "var feature_hash = new Array ;" for s, sr in next, rev do - stupid[#stupid+1] = format("feature_hash['%s'] = new Array ;",s) + stupid[#stupid+1] = formatters["feature_hash['%s'] = new Array ;"](s) for l, lr in next, sr do - stupid[#stupid+1] = format("feature_hash['%s']['%s'] = new Array ;",s,l) + stupid[#stupid+1] = formatters["feature_hash['%s']['%s'] = new Array ;"](s,l) for f, fr in next, lr do - stupid[#stupid+1] = format("feature_hash['%s']['%s']['%s'] = true ;",s,l,f) + stupid[#stupid+1] = formatters["feature_hash['%s']['%s']['%s'] = true ;"](s,l,f) end end end @@ -228,7 +269,7 @@ local function showfeatures(f) end end -local template_h = [[ +local template_h = formatters [ [[ <tr> <th>safe name </th> <th>family name </th> @@ -236,9 +277,9 @@ local template_h = [[ <th>font name </th> <th>weight </th> <th>filename</th> -</tr>]] +</tr>]] ] -local template_d = [[ +local template_d = formatters [ [[ <tr> <td><a href='mtx-server-ctx-fonttest.lua?selection=%s'>%s</a> </td> <td>%s </td> @@ -246,19 +287,22 @@ local template_d = [[ <td>%s </td> <td>%s </td> <td>%s</td> -</tr>]] +</tr>]] ] local function select_font() local t = fonts.names.list(".*",false,true) if t then local listoffonts = { } + listoffonts[#listoffonts+1] = "<h1>Fonts</h1><br/>" listoffonts[#listoffonts+1] = "<table>" - listoffonts[#listoffonts+1] = template_h + listoffonts[#listoffonts+1] = template_h() for k, v in table.sortedhash(t) do local kind = v.format if kind == "otf" or kind == "ttf" or kind == "ttc" then local fontname = v.fontname - listoffonts[#listoffonts+1] = format(template_d, fontname, fontname, + listoffonts[#listoffonts+1] = template_d( + fontname, + fontname, v.familyname or "", t.variant or "normal", t.weight or "normal", @@ -276,25 +320,32 @@ local function select_font() return "<b>no fonts</b>" end -local edit_template = [[ +local edit_template = formatters [ [[ <textarea name='sampletext' rows='5' cols='100'>%s</textarea> <br/> <br/>name: <input type='text' name='name' size='20' value=%q/> title: <input type='text' name='title' size='40' value=%q/> <br/> <br/>scripts: %s <br/> <br/>languages: %s <br/> <br/>features: %s <br/> <br/>options: %s -]] +]] ] -- <embed src="%s#toolbar=0&navpanes=0&scrollbar=0" width="100%%"/> -local result_template = [[ +local result_template = formatters [ [[ <br/> <br/> <embed src="%s#view=Fit&toolbar=0&navpanes=0&scrollbar=0" width="100%%"/> - <br/> <br/> results: - <a href='%s' target="source">tex file</a> - <a href='%s' target="result">pdf file</a> + <br/> <br/> results: + <a href='%s' target="source">tex file</a> + <a href='%s' target="result">pdf file</a> + (runtime: %s) <br/> <br/> -]] +]] ] + +local main_template = formatters [ [[ + <h1>Font: %s</h1><br/> + %s + %s +]] ] scripts.webserver.registerpath(temppath) @@ -302,7 +353,7 @@ local function get_specification(name) return fonts.names.resolvedspecification(name or "") end -local function edit_font(currentfont,detail,tempname) +local function edit_font(currentfont,detail,tempname,runtime) report("entering edit mode for '%s'",currentfont) local specification = get_specification(currentfont) if specification then @@ -314,9 +365,9 @@ local function edit_font(currentfont,detail,tempname) local v = sorted[k] local s = fonts.handlers.otf.tables.scripts[v] or v if detail and v == detail.script then - scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/> <span id='t-s-%s'>%s</span>",s,v,v,v,v) + scripts[#scripts+1] = formatters["<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' checked='checked'/> <span id='t-s-%s'>%s</span>"](s,v,v,v,v) else - scripts[#scripts+1] = format("<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' /> <span id='t-s-%s'>%s</span>",s,v,v,v,v) + scripts[#scripts+1] = formatters["<input title='%s' id='s-%s' type='radio' name='script' value='%s' onclick='check_script()' /> <span id='t-s-%s'>%s</span>"](s,v,v,v,v) end end local sorted = table.sortedkeys(htmldata.languages) @@ -324,9 +375,9 @@ local function edit_font(currentfont,detail,tempname) local v = sorted[k] local l = fonts.handlers.otf.tables.languages[v] or v if detail and v == detail.language then - languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/> <span id='t-l-%s'>%s</span>",l,v,v,v,v) + languages[#languages+1] = formatters["<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' checked='checked'/> <span id='t-l-%s'>%s</span>"](l,v,v,v,v) else - languages[#languages+1] = format("<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' /> <span id='t-l-%s'>%s</span>",l,v,v,v,v) + languages[#languages+1] = formatters["<input title='%s' id='l-%s' type='radio' name='language' value='%s' onclick='check_language()' /> <span id='t-l-%s'>%s</span>"](l,v,v,v,v) end end local sorted = table.sortedkeys(htmldata.features) @@ -334,28 +385,34 @@ local function edit_font(currentfont,detail,tempname) local v = sorted[k] local f = fonts.handlers.otf.tables.features[v] or v if detail and detail["f-"..v] then - features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/> <span id='t-f-%s'>%s</span>",f,v,v,v,v) + features[#features+1] = formatters["<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' checked='checked'/> <span id='t-f-%s'>%s</span>"](f,v,v,v,v) else - features[#features+1] = format("<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' /> <span id='t-f-%s'>%s</span>",f,v,v,v,v) + features[#features+1] = formatters["<input title='%s' id='f-%s' type='checkbox' name='f-%s' onclick='check_feature()' /> <span id='t-f-%s'>%s</span>"](f,v,v,v,v) end end for k=1,#what_options do local v = what_options[k] if detail and detail["o-"..v] then - options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/> %s",v,v,v) + options[#options+1] = formatters["<input id='o-%s' type='checkbox' name='o-%s' checked='checked'/> %s"](v,v,v) else - options[#options+1] = format("<input id='o-%s' type='checkbox' name='o-%s'/> %s",v,v,v) + options[#options+1] = formatters["<input id='o-%s' type='checkbox' name='o-%s'/> %s"](v,v,v) end end - local e = format(edit_template, - (detail and detail.sampletext) or sample_line,(detail and detail.name) or "no name",(detail and detail.title) or "", - concat(scripts," "),concat(languages," "),concat(features," "),concat(options," ")) + local e = edit_template( + detail and detail.sampletext or sample_line, + detail and detail.name or "no name", + detail and detail.title or "", + concat(scripts," "), + concat(languages," "), + concat(features," "), + concat(options," ") + ) if tempname then - local pdffile, texfile = file.addsuffix(tempname,"pdf"), file.addsuffix(tempname,"tex") - local r = format(result_template,pdffile,texfile,pdffile) - return e .. r, htmldata.javascript or "" + local pdffile, texfile = file.replacesuffix(tempname,"pdf"), file.replacesuffix(tempname,"tex") + local r = result_template(pdffile,texfile,pdffile,runtime and formatters["%0.3f"](runtime) or "-") + return main_template(currentfont,e,r), htmldata.javascript or "" else - return e, htmldata.javascript or "" + return main_template(currentfont,e,""), htmldata.javascript or "" end else return "error, nothing set up yet" @@ -368,13 +425,13 @@ end local function process_font(currentfont,detail) -- maybe just fontname local features = { "mode=node", - format("language=%s",detail.language or "dflt"), - format("script=%s",detail.script or "dflt"), + formatters["language=%s"](detail.language or "dflt"), + formatters["script=%s"](detail.script or "dflt"), } for k,v in next, detail do local f = match(k,"^f%-(.*)$") if f then - features[#features+1] = format("%s=yes",f) + features[#features+1] = formatters["%s=yes"](f) end end local variant = process_templates.default @@ -385,69 +442,76 @@ local function process_font(currentfont,detail) -- maybe just fontname if sample == "" then sample = sample_line end report("sample text: %s",sample) dir.mkdirs(temppath) - local fullname = file.join(temppath,file.addsuffix(tempname,"tex")) - local data = format(variant,concat(features,","),currentfont,sample) - local command = format("mtxrun --path=%q --script context --once --batchmode %q",temppath,tempname) - report("filename: %s",fullname) - report("command: %s",command) + local tempname = makename(tempname,true) + local usedname = file.addsuffix(tempname,"tex") + local fullname = file.join(temppath,usedname) + local data = variant(concat(features,","),currentfont,sample,currentfont,sample) io.savedata(fullname,data) - os.execute(command) - return edit_font(currentfont,detail,tempname) + io.flush() + local runtime = runcontext(temppath,usedname) + return edit_font(currentfont,detail,tempname,runtime) end -local tex_template = [[ +local tex_template = formatters [ [[ +<h1>Font: %s</h1><br/> <pre><tt> %s </tt></pre> -]] +]] ] local function show_source(currentfont,detail) + local tempname = makename(tempname) if tempname and tempname ~= "" then - local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,"tex"))) or "no source yet" - return format(tex_template,data) + local data = io.loaddata(file.join(temppath,file.replacesuffix(tempname,"tex"))) or "no source yet" + return tex_template(currentfont,data) else return "no source file" end end local function show_log(currentfont,detail) + local tempname = makename(tempname) if tempname and tempname ~= "" then - local data = io.loaddata(file.join(temppath,file.addsuffix(tempname,'log'))) or "no log file yet" + local data = io.loaddata(file.join(temppath,file.replacesuffix(tempname,'log'))) or "no log file yet" data = gsub(data,"[%s%%]*begin of optionfile.-end of optionfile[%s%%]*","\n") - return format(tex_template,data) + return tex_template(currentfont,data) else return "no log file" end end +-- much nicer would be an lmx template + local function show_font(currentfont,detail) local specification = get_specification(currentfont) local features = fonts.helpers.getfeatures(specification.filename) local result = { } - result[#result+1] = format("<h1>names</h1>",what) + result[#result+1] = formatters["<h1>Font: %s</h1><br/>"](currentfont) result[#result+1] = "<table>" - result[#result+1] = format("<tr><td class='tc'>fontname: </td><td>%s</td></tr>",currentfont) - result[#result+1] = format("<tr><td class='tc'>fullname: </td><td>%s</td></tr>",specification.fontname or "-") - result[#result+1] = format("<tr><td class='tc'>filename: </td><td>%s</td></tr>",specification.fontfile or "-") - result[#result+1] = format("<tr><td class='tc'>familyname: </td><td>%s</td></tr>",specification.familyname or "-") - result[#result+1] = format("<tr><td class='tc'>fontweight: </td><td>%s</td></tr>",specification.fontweight or "-") - result[#result+1] = format("<tr><td class='tc'>format: </td><td>%s</td></tr>",specification.format or "-") - result[#result+1] = format("<tr><td class='tc'>fullname: </td><td>%s</td></tr>",specification.fullname or "-") - result[#result+1] = format("<tr><td class='tc'>subfamily: </td><td>%s</td></tr>",specification.subfamily or "-") - result[#result+1] = format("<tr><td class='tc'>rawname: </td><td>%s</td></tr>",specification.rawname or "-") - result[#result+1] = format("<tr><td class='tc'>designsize: </td><td>%s</td></tr>",specification.designsize or "-") - result[#result+1] = format("<tr><td class='tc'>minimumsize:</td><td>%s</td></tr>",specification.minsize or "-") - result[#result+1] = format("<tr><td class='tc'>maximumsize:</td><td>%s</td></tr>",specification.maxsize or "-") - result[#result+1] = format("<tr><td class='tc'>style: </td><td>%s</td></tr>",specification.style ~= "" and specification.style or "normal") - result[#result+1] = format("<tr><td class='tc'>variant: </td><td>%s</td></tr>",specification.variant ~= "" and specification.variant or "normal") - result[#result+1] = format("<tr><td class='tc'>weight: </td><td>%s</td></tr>",specification.weight ~= "" and specification.weight or "normal") - result[#result+1] = format("<tr><td class='tc'>width: </td><td>%s</td></tr>",specification.width ~= "" and specification.width or "normal") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>fontname </td><td style='width:20em'>%s</td>"] (specification.fontname or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>designsize </td><td style='width:20em'>%s</td></tr>"](specification.designsize or "-") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>fullname </td><td style='width:20em'>%s</td>"] (specification.fullname or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>minimumsize</td><td style='width:20em'>%s</td></tr>"](specification.minsize or "-") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>filename </td><td style='width:20em'>%s</td>"] (specification.fontfile or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>maximumsize</td><td style='width:20em'>%s</td></tr>"](specification.maxsize or "-") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>rawname </td><td style='width:20em'>%s</td>"] (specification.rawname or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>fontweight </td><td style='width:20em'>%s</td></tr>"](specification.fontweight or "-") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>familyname </td><td style='width:20em'>%s</td>"] (specification.familyname or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>angle </td><td style='width:20em'>%s</td></tr>"](specification.angle or "-") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>subfamily </td><td style='width:20em'>%s</td>"] (specification.subfamily or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>variant </td><td style='width:20em'>%s</td></tr>"](specification.variant ~= "" and specification.variant or "normal") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>format </td><td style='width:20em'>%s</td>"] (specification.format or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>style </td><td style='width:20em'>%s</td></tr>"](specification.style ~= "" and specification.style or "normal") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>pfmwidth </td><td style='width:20em'>%s</td>"] (specification.pfmwidth ~= "" and specification.pfmwidth or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>weight </td><td style='width:20em'>%s</td></tr>"](specification.weight ~= "" and specification.weight or "normal") + result[#result+1] = formatters["<tr><td class='tc' style='width:10em'>pfmheight </td><td style='width:20em'>%s</td>"] (specification.pfmweight ~= "" and specification.pfmweight or "-") + result[#result+1] = formatters[" <td class='tc' style='width:10em'>width </td><td style='width:20em'>%s</td></tr>"](specification.width ~= "" and specification.width or "normal") result[#result+1] = "</table>" if features then for what, v in table.sortedhash(features) do local data = features[what] if data and next(data) then - result[#result+1] = format("<h1>%s features</h1>",what) + result[#result+1] = formatters["<h1>%s features</h1><br/>"](what) result[#result+1] = "<table>" result[#result+1] = "<tr><th>feature</th><th>tag </th><th>script </th><th>languages </th></tr>" for f,ff in table.sortedhash(data) do @@ -461,7 +525,7 @@ local function show_font(currentfont,detail) done = true end local title = fonts.handlers.otf.tables.features[f] or "" - result[#result+1] = format("<tr><td width='50%%'>%s </td><td><tt>%s </tt></td><td><tt>%s </tt></td><td><tt>%s </tt></td></tr>",title,f,s,concat(table.sortedkeys(ss)," ")) + result[#result+1] = formatters["<tr><td width='50%%'>%s </td><td><tt>%s </tt></td><td><tt>%s </tt></td><td><tt>%s </tt></td></tr>"](title,f,s,concat(table.sortedkeys(ss)," ")) end end result[#result+1] = "</table>" @@ -473,8 +537,7 @@ local function show_font(currentfont,detail) return concat(result,"\n") end - -local info_template = [[ +local info_template = formatters [ [[ <pre><tt> version : %s comment : %s @@ -485,14 +548,14 @@ maillist : ntg-context at ntg.nl webpage : www.pragma-ade.nl wiki : contextgarden.net </tt></pre> -]] +]] ] local function info_about() local m = modules ['mtx-server-ctx-fonttest'] - return format(info_template,m.version,m.comment,m.author,m.copyright) + return info_template(m.version,m.comment,m.author,m.copyright) end -local save_template = [[ +local save_template = formatters [ [[ the current setup has been saved: <br/> <br/> <table> @@ -505,7 +568,7 @@ local save_template = [[ <tr><td class='tc'>options </td><td>%s</td></tr> <tr><td class='tc'>sampletext </td><td>%s</td></tr> </table> -]] +]] ] local function loadbase() local datafile = file.join(basepath,basename) @@ -584,23 +647,23 @@ local function save_font(currentfont,detail) font = currentfont, title = title, script = script, language = language, features = features, options = options, text = text, } savebase(storage,name) - return format(save_template,name,title,currentfont,script,language,concat(table.sortedkeys(features)," "),concat(table.sortedkeys(options)," "),text) + return save_template(name,title,currentfont,script,language,concat(table.sortedkeys(features)," "),concat(table.sortedkeys(options)," "),text) end local function load_font(currentfont) local datafile = file.join(basepath,basename) local storage = loadbase(datafile) local result = {} - result[#result+1] = format("<tr><th>del </th><th>name </th><th>font </th><th>fontname </th><th>script </th><th>language </th><th>features </th><th>title </th><th>sampletext </th></tr>") + result[#result+1] = "<tr><th>del </th><th>name </th><th>font </th><th>fontname </th><th>script </th><th>language </th><th>features </th><th>title </th><th>sampletext </th></tr>" for k,v in table.sortedhash(storage) do local fontname, fontfile = get_specification(v.font) - result[#result+1] = format("<tr><td><a href='mtx-server-ctx-fonttest.lua?deletename=%s'>x</a> </td><td><a href='mtx-server-ctx-fonttest.lua?loadname=%s'>%s</a> </td><td>%s </td<td>%s </td><td>%s </td><td>%s </td><td>%s </td><td>%s </td><td>%s </td></tr>", + result[#result+1] = formatters["<tr><td><a href='mtx-server-ctx-fonttest.lua?deletename=%s'>x</a> </td><td><a href='mtx-server-ctx-fonttest.lua?loadname=%s'>%s</a> </td><td>%s </td<td>%s </td><td>%s </td><td>%s </td><td>%s </td><td>%s </td><td>%s </td></tr>"]( k,k,k,v.font,fontname,v.script,v.language,concat(table.sortedkeys(v.features)," "),v.title or "no title",v.text or "") end if #result == 1 then return "nothing saved yet" else - return format("<table>%s</table>",concat(result,"\n")) + return formatters["<table>%s</table>"](concat(result,"\n")) end end @@ -608,12 +671,12 @@ local function reset_font(currentfont) return edit_font(currentfont) end -local extras_template = [[ +local extras_template = formatters [ [[ <a href='mtx-server-ctx-fonttest.lua?extra=reload'>remake font database</a> (take some time)<br/><br/> -]] +]] ] local function do_extras(detail,currentfont,extra) - return extras_template + return extras_template() end local extras = { } @@ -625,16 +688,13 @@ local function do_extra(detail,currentfont,extra) end function extras.reload() - local command = "mtxrun --script font --reload" - report("run command: %s",command) - os.execute(command) + identifyfonts() return do_extras() end - -local status_template = [[ +local status_template = formatters [ [[ <input type="hidden" name="currentfont" value="%s" /> -]] +]] ] local variables = { ['color-background-one'] = lmx.get('color-background-green'), @@ -643,6 +703,8 @@ local variables = { ['formaction'] = "mtx-server-ctx-fonttest.lua", } +-- todo: use lmx file + function doit(configuration,filename,hashed) local start = os.clock() @@ -653,6 +715,12 @@ function doit(configuration,filename,hashed) local action = detail.action local selection = detail.selection + if action == "luajittex" then + jitmode = true + elseif action == "luatex" then + jitmode = false + end + local loadname = detail.loadname local deletename = detail.deletename local extra = detail.extra @@ -673,30 +741,34 @@ function doit(configuration,filename,hashed) local fontname, fontfile = get_specification(currentfont) if fontfile then - variables.title = format('ConTeXt Font Tester: %s (%s)',fontname,fontfile) + variables.title = formatters['ConTeXt Font Tester: %s (%s)'](fontname,fontfile) else variables.title = 'ConTeXt Font Tester' end + if jitmode then + variables.title = variables.title .. " (using LuaJit vm)" + end + -- lua table and adapt - local buttons = { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras'} + report("action: %s",action or "no action") + + local buttons = { 'process', 'select', 'save', 'load', 'edit', 'reset', 'features', 'source', 'log', 'info', 'extras', jitmode and "luatex" or "luajittex" } local menu = { } for i=1,#buttons do local button = buttons[i] - menu[#menu+1] = format("<button name='action' value='%s' type='submit'>%s</button>",button,button) + menu[#menu+1] = formatters["<button name='action' value='%s' type='submit'>%s</button>"](button,button) end variables.menu = concat(menu," ") - variables.status = format(status_template,currentfont or "") + variables.status = status_template(currentfont or "") variables.maintext = "" variables.javascriptdata = "" variables.javascripts = "" variables.javascriptinit = "" - report("action: %s",action or "no action") - local result if action == "select" then diff --git a/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-help.lua b/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-help.lua index b8dc0dfb278..d948c6e46d1 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-help.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-server-ctx-help.lua @@ -542,11 +542,11 @@ function document.setups.collect(name,int,lastmode) local left, right = d[k].at.name or "?", { } if tag == "inherit" then local name = d[k].at.name or "?" - local goto = format(document.setups.formats.href_as_command[lastmode],name,lastmode,name) + local url = format(document.setups.formats.href_as_command[lastmode],name,lastmode,name) if #parameters > 0 and not find(parameters[#parameters],"<br/>") then parameters[#parameters+1] = format(formats.parameter,"<br/>","","") end - parameters[#parameters+1] = format(formats.parameter,what,format(formats.special,translate("inherits",int)),goto) + parameters[#parameters+1] = format(formats.parameter,what,format(formats.special,translate("inherits",int)),url) else for r, d, k in xml.elements(d[k],"(cd:constant|cd:resolve)") do local tag = d[k].tg @@ -664,9 +664,23 @@ local function doit(configuration,filename,hashed) if document.setups.showsources and lastsource and lastsource ~= "" then -- todo: mkii, mkiv, tex (can be different) - local data = io.loaddata(resolvers.findfile(lastsource)) - variables.maintitle = lastsource - variables.maintext = format(formats.listing,data) + local name = lastsource + local full = resolvers.findfile(name) + if full == "" and file.suffix(lastsource) == "tex" then + name = file.replacesuffix(lastsource,"mkiv") + full = resolvers.findfile(name) + if full == "" then + name = file.replacesuffix(lastsource,"mkvi") + full = resolvers.findfile(name) + end + end + if full == "" then + variables.maintitle = lastsource + variables.maintext = format(formats.listing,"no source found") + else + variables.maintitle = name + variables.maintext = format(formats.listing,io.loaddata(full)) + end lastsource = "" elseif lastcommand and lastcommand ~= "" then local data = document.setups.collect(lastcommand,lastinterface,lastmode) diff --git a/Master/texmf-dist/scripts/context/lua/mtx-server.lua b/Master/texmf-dist/scripts/context/lua/mtx-server.lua index 5ec15de708f..5466bfe80a2 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-server.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-server.lua @@ -43,7 +43,7 @@ scripts.webserver = scripts.webserver or { } dofile(resolvers.findfile("luat-soc.lua","tex")) local socket = socket or require("socket") -local http = http or require("socket.http") -- not needed +----- http = http or require("socket.http") -- not needed local format = string.format -- The following two lists are taken from webrick (ruby) and @@ -197,6 +197,7 @@ function handlers.generic(client,configuration,data,suffix,iscontent) client:send("Connection: close\r\n") client:send(format("Content-Length: %s\r\n",#data)) client:send(format("Content-Type: %s\r\n",(suffix and mimetypes[suffix]) or "text/html")) + client:send("Cache-Control: no-cache, no-store, must-revalidate, max-age=0\r\n") client:send("\r\n") client:send(data) client:send("\r\n") @@ -333,8 +334,9 @@ function scripts.webserver.run(configuration) report("no url") errormessage(client,configuration,404) else + fullurl = url.unescapeget(fullurl) report("requested url: %s",fullurl) - fullurl = socket.url.unescape(fullurl) -- still needed? + -- fullurl = socket.url.unescape(fullurl) -- happens later local hashed = url.hashed(fullurl) local query = url.query(hashed.query) local filename = hashed.path -- hm, not query? diff --git a/Master/texmf-dist/scripts/context/lua/mtx-tools.lua b/Master/texmf-dist/scripts/context/lua/mtx-tools.lua index 19b7458a19a..a38e9d7e66b 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-tools.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-tools.lua @@ -31,6 +31,7 @@ local helpinfo = [[ <flag name="recurse"><short>recurse into subdirecories</short></flag> <flag name="stripname"><short>take pathpart of given pattern</short></flag> <flag name="longname"><short>set name attributes to full path name</short></flag> + <flag name="downcase"><short>lowercase names</short></flag> </subcategory> <subcategory> <flag name="pattern"><short>glob pattern (default: *)</short></flag> diff --git a/Master/texmf-dist/scripts/context/lua/mtx-update.lua b/Master/texmf-dist/scripts/context/lua/mtx-update.lua index 64203d3e3e2..aedc48041e3 100644 --- a/Master/texmf-dist/scripts/context/lua/mtx-update.lua +++ b/Master/texmf-dist/scripts/context/lua/mtx-update.lua @@ -11,13 +11,15 @@ if not modules then modules = { } end modules ['mtx-update'] = { -- Together with Arthur Reutenauer she made sure that it worked well on all -- platforms that matter. +-- LuaTeX and LuajitTeX are now always installed together. + local helpinfo = [[ <?xml version="1.0"?> <application> <metadata> <entry name="name">mtx-update</entry> <entry name="detail">ConTeXt Minimals Updater</entry> - <entry name="version">0.31</entry> + <entry name="version">1.02</entry> </metadata> <flags> <category name="basic"> @@ -48,7 +50,7 @@ local helpinfo = [[ local application = logs.application { name = "mtx-update", - banner = "ConTeXt Minimals Updater 0.31", + banner = "ConTeXt Minimals Updater 1.02", helpinfo = helpinfo, } @@ -124,7 +126,7 @@ scripts.update.engines = { ["luatex"] = { { "fonts/new/", "texmf" }, { "bin/luatex/<platform>/", "texmf-<platform>" }, - { "bin/luajittex/<platform>/","texmf-<platform>" }, + -- { "bin/luajittex/<platform>/","texmf-<platform>" }, }, ["xetex"] = { { "base/xetex/", "texmf" }, @@ -142,7 +144,7 @@ scripts.update.engines = { { "fonts/old/", "texmf" }, { "base/xetex/", "texmf" }, { "bin/luatex/<platform>/", "texmf-<platform>" }, - { "bin/luajittex/<platform>/","texmf-<platform>" }, + -- { "bin/luajittex/<platform>/","texmf-<platform>" }, { "bin/xetex/<platform>/", "texmf-<platform>" }, { "bin/pdftex/<platform>/", "texmf-<platform>" }, }, @@ -162,32 +164,61 @@ scripts.update.platforms = { ["windows"] = "mswin", ["win32"] = "mswin", ["win"] = "mswin", + -- ["mswin"] = "win32", + -- ["windows"] = "win32", + -- ["win32"] = "win32", + -- ["win"] = "win32", + -- + -- ["mswin-64"] = "mswin-64", + -- ["windows-64"] = "mswin-64", + -- ["win64"] = "mswin-64", + ["mswin-64"] = "win64", + ["windows-64"] = "win64", + ["win64"] = "win64", + -- ["linux"] = "linux", + ["linux-32"] = "linux", + ["linux32"] = "linux", + -- + ["linux-64"] = "linux-64", + ["linux64"] = "linux-64", + -- ["freebsd"] = "freebsd", + -- ["freebsd-amd64"] = "freebsd-amd64", + -- ["kfreebsd"] = "kfreebsd-i386", ["kfreebsd-i386"] = "kfreebsd-i386", + -- ["kfreebsd-amd64"] = "kfreebsd-amd64", - ["linux-32"] = "linux", - ["linux-64"] = "linux-64", - ["linux32"] = "linux", - ["linux64"] = "linux-64", + -- ["linux-ppc"] = "linux-ppc", ["ppc"] = "linux-ppc", + -- ["osx"] = "osx-intel", ["macosx"] = "osx-intel", ["osx-intel"] = "osx-intel", + ["osxintel"] = "osx-intel", + -- ["osx-ppc"] = "osx-ppc", ["osx-powerpc"] = "osx-ppc", - ["osx-64"] = "osx-64", - ["osxintel"] = "osx-intel", ["osxppc"] = "osx-ppc", ["osxpowerpc"] = "osx-ppc", + -- + ["osx-64"] = "osx-64", + -- ["solaris-intel"] = "solaris-intel", + -- ["solaris-sparc"] = "solaris-sparc", ["solaris"] = "solaris-sparc", } +local windowsplatform = { + ["mswin"] = true, + ["win32"] = true, + ["win64"] = true, +} + scripts.update.selfscripts = { "mtxrun", -- "luatools", @@ -250,7 +281,7 @@ function scripts.update.synchronize() bin = gsub(bin,"\\","/") - if not url:find("::$") then url = url .. "::" end + if not find(url,"::$") then url = url .. "::" end local ok = lfs.attributes(texroot,"mode") == "directory" if not ok and force then dir.mkdirs(texroot) @@ -311,10 +342,10 @@ function scripts.update.synchronize() os.execute(command) -- read output of rsync local data = io.loaddata(temp_file) or "" - -- for every line extract the filename - for chmod, s in data:gmatch("([d%-][rwx%-]+).-(%S+)[\n\r]") do + -- for every line extract the filename : drwxr-sr-x 18 2013/10/06 06:16:10 libertine + for chmod, s in gmatch(data,"([d%-][rwxst%-]+).-(%S+)[\n\r]") do -- skip "current" folder - if s ~= '.' and chmod:len() == 10 then + if s ~= '.' and #chmod >= 10 then folders[#folders+1] = s end end @@ -325,22 +356,31 @@ function scripts.update.synchronize() -- rsync://contextgarden.net/minimals/current/modules/ + local available_platforms = get_list_of_files_from_rsync({"bin/luatex/"}) + + report("available platforms: % t",table.sorted(available_platforms)) + if modules and type(modules) == "table" then -- fetch the list of available modules from rsync server - local available_modules = get_list_of_files_from_rsync({"modules/"}) + -- local available_modules = get_list_of_files_from_rsync({"modules/"}) -- hash of requested modules -- local h = table.tohash(modules:split(",")) + local available_modules = get_list_of_files_from_rsync({"modules/"}) local asked = table.copy(modules) asked.all = nil + report("available modules: %s",#available_modules) for i=1,#available_modules do local s = available_modules[i] if modules.all or modules[s] then scripts.update.modules[#scripts.update.modules+1] = { format("modules/%s/",s), "texmf-modules" } + report("+ %s",s) + else + report(" %s",s) end asked[s] = nil end if next(asked) then - report("skipping unknown modules: %s",table.concat(table.sortedkeys(asked),", ")) + report("skipping unknown modules: %s",concat(table.sortedkeys(asked),", ")) end end @@ -358,7 +398,7 @@ function scripts.update.synchronize() asked[s] = nil end if next(asked) then - report("skipping unknown fonts: %s",table.concat(table.sortedkeys(asked),", ")) + report("skipping unknown fonts: %s",concat(table.sortedkeys(asked),", ")) end end @@ -372,7 +412,7 @@ function scripts.update.synchronize() local destination = format("%s/%s", texroot, gsub(c[2],"<platform>", platform)) destination = gsub(destination,"\\","/") archive = gsub(archive,"<version>",version) - if osplatform == "windows" or osplatform == "mswin" then + if osplatform == "windows" or osplatform == "mswin" or osplatform == "win64" then destination = drive(destination) end individual[#individual+1] = { archive, destination } @@ -381,24 +421,24 @@ function scripts.update.synchronize() end end - for platform, _ in next, platforms do + for platform in table.sortedhash(platforms) do add_collection(scripts.update.base,platform) end - for platform, _ in next, platforms do + for platform in table.sortedhash(platforms) do add_collection(scripts.update.modules,platform) end - for platform, _ in next, platforms do + for platform in table.sortedhash(platforms) do add_collection(scripts.update.fonts,platform) end - for engine, _ in next, engines do - for platform, _ in next, platforms do + for engine in table.sortedhash(engines) do + for platform in table.sortedhash(platforms) do add_collection(scripts.update.engines[engine],platform) end end if goodies and type(goodies) == "table" then - for goodie, _ in next, goodies do - for platform, _ in next, platforms do + for goodie in table.sortedhash(goodies) do + for platform in table.sortedhash(platforms) do add_collection(scripts.update.goodies[goodie],platform) end end @@ -409,7 +449,7 @@ function scripts.update.synchronize() for i=1,#update_repositories do local repository = update_repositories[i] if repositories[repository] then - for _, v in next, individual do + for _, v in table.sortedhash(individual) do local archive, destination = v[1], v[2] local cd = combined[destination] if not cd then @@ -420,7 +460,7 @@ function scripts.update.synchronize() end end end - for destination, archive in next, combined do + for destination, archive in table.sortedhash(combined) do local archives, command = concat(archive," "), "" local normalflags, deleteflags = states.get("rsync.flags.normal"), "" if os.name == "windows" then @@ -430,10 +470,10 @@ function scripts.update.synchronize() if not environment.argument("force") then dryrunflags = "--dry-run" end - if (destination:find("texmf$") or destination:find("texmf%-context$") or destination:find("texmf%-modules$")) and (not environment.argument("keep")) then + if (find(destination,"texmf$") or find(destination,"texmf%-context$") or find(destination,"texmf%-modules$")) and (not environment.argument("keep")) then deleteflags = states.get("rsync.flags.delete") end - command = format("%s %s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, dryrunflags, url, archives, destination) + command = format("%s %s %s %s %s'%s' '%s'", bin, normalflags, deleteflags, dryrunflags, url, archives, drive(destination)) -- report("running command: %s",command) if not fetched[command] then scripts.update.run(command,true) @@ -447,10 +487,10 @@ function scripts.update.synchronize() platform = scripts.update.platforms[platform] if platform then local command - if platform == 'mswin' then + if windowsplatform[platform] then bin = drive(bin) texroot = drive(texroot) - command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-mswin/bin/"]], bin, texroot, script, texroot) + command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-%s/bin/"]], bin, texroot, script, texroot, platform) else command = format([[%s -tgo --chmod=a+x '%s/texmf-context/scripts/context/lua/%s.lua' '%s/texmf-%s/bin/%s']], bin, texroot, script, texroot, platform, script) end @@ -459,7 +499,7 @@ function scripts.update.synchronize() end end - for platform, _ in next, platforms do + for platform in table.sortedhash(platforms) do for i=1, #scripts.update.selfscripts do update_script(scripts.update.selfscripts[i],platform) end @@ -484,7 +524,7 @@ end function table.fromhash(t) local h = { } - for k, v in next, t do -- not indexed + for k, v in table.sortedhash(t) do -- not indexed if v then h[#h+1] = k end end return h @@ -510,22 +550,21 @@ function scripts.update.make() local askedformats = formats local texformats = table.tohash(scripts.update.texformats) local mpformats = table.tohash(scripts.update.mpformats) - for k,v in next, texformats do + for k,v in table.sortedhash(texformats) do if not askedformats[k] then texformats[k] = nil end end - for k,v in next, mpformats do + for k,v in table.sortedhash(mpformats) do if not askedformats[k] then mpformats[k] = nil end end local formatlist = concat(table.fromhash(texformats), " ") if formatlist ~= "" then - for engine in next, engines do - if engine == "luatex" then + for engine in table.sortedhash(engines) do + if engine == "luatex" or engine == "luajittex" then scripts.update.run(format('mtxrun --tree="%s" --script context --autogenerate --make',texroot)) - elseif engine == "luajittex" then scripts.update.run(format('mtxrun --tree="%s" --script context --autogenerate --make --engine=luajittex',texroot)) else scripts.update.run(format('mtxrun --tree="%s" --script texexec --make --all --%s %s',texroot,engine,formatlist)) diff --git a/Master/texmf-dist/scripts/context/lua/mtx-youless.lua b/Master/texmf-dist/scripts/context/lua/mtx-youless.lua new file mode 100644 index 00000000000..740fdcb65c4 --- /dev/null +++ b/Master/texmf-dist/scripts/context/lua/mtx-youless.lua @@ -0,0 +1,111 @@ +if not modules then modules = { } end modules ['mtx-youless'] = { + version = 1.002, + comment = "script to fetch data from kwh meter polling device", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE", + license = "see context related readme files" +} + +-- This script can fetch data from a youless device (http://www.youless.nl/) where data +-- is merged into a file. The data concerns energy consumption (current wattage as well +-- as kwh usage). There is an accompanying module to generate graphics. + +require("util-you") + +local formatters = string.formatters + +-- the script + +local helpinfo = [[ +<?xml version="1.0"?> +<application> + <metadata> + <entry name="name">mtx-youless</entry> + <entry name="detail">youless Fetcher</entry> + <entry name="version">1.00</entry> + </metadata> + <flags> + <category name="basic"> + <subcategory> + <flag name="collect"><short>collect data from device</short></flag> + <flag name="nobackup"><short>don't backup old datafile</short></flag> + <flag name="nofile"><short>don't write data to file (for checking)</short></flag> + <flag name="kwh"><short>summative kwh data</short></flag> + <flag name="watt"><short>collected watt data</short></flag> + <flag name="host"><short>ip address of device</short></flag> + </subcategory> + </category> + </flags> + <examples> + <category> + <title>Example</title> + <subcategory> + <example><command>mtxrun --script youless --collect --host=192.168.2.50 --kwh</command></example> + <example><command>mtxrun --script youless --collect --host=192.168.2.50 --watt somefile.lua</command></example> + </subcategory> + </category> + </examples> +</application> +]] + +local application = logs.application { + name = "mtx-youless", + banner = "YouLess Fetcher 1.00", + helpinfo = helpinfo, +} + +local report = application.report + +scripts = scripts or { } +scripts.youless = scripts.youless or { } + +function scripts.youless.collect() + local host = environment.arguments.host + local variant = environment.arguments.kwh and "kwh" or environment.arguments.watt and "watt" + local nobackup = environment.arguments.nobackup + local nofile = environment.arguments.nofile + local password = environment.arguments.password + local filename = environment.files[1] + if not variant then + report("provide variant --kwh or --watt") + return + else + report("using variant %a",variant) + end + if not host then + host = "192.168.2.50" + report("using default host %a",host) + else + report("using host %a",host) + end + if nobackup then + report("not backing up data file") + end + if not filename and not nofile then + filename = formatters["youless-%s.lua"](variant) + end + if filename ~= "" then + report("using file %a",filename) + end + local data = utilities.youless.collect { + filename = filename, + host = host, + variant = variant, + nobackup = nobackup, + password = password, + } + if type(data) ~= "table" then + report("no data collected") + elseif filename == "" then + report("data collected but not saved") + end + report("current time %a",os.now()) +end + +if environment.argument("collect") then + scripts.youless.collect() +elseif environment.argument("exporthelp") then + application.export(environment.argument("exporthelp"),environment.files[1]) +else + application.help() +end diff --git a/Master/texmf-dist/scripts/context/lua/mtxlibs.lua b/Master/texmf-dist/scripts/context/lua/mtxlibs.lua index 7f52ac8bdfa..ae9d70108a1 100644 --- a/Master/texmf-dist/scripts/context/lua/mtxlibs.lua +++ b/Master/texmf-dist/scripts/context/lua/mtxlibs.lua @@ -111,6 +111,7 @@ local ownlibs = { "lxml-aux.lua", "lxml-xml.lua", + "trac-xml.lua", -- handy for helpinfo } package.path = "t:/sources/?.lua;t:/sources/?;" .. package.path @@ -184,7 +185,7 @@ end local arguments = environment.arguments local files = environment.files -if environment.ownname ~= "mtxlibs.lua" then +if file.basename(environment.ownname) ~= "mtxlibs.lua" then return end diff --git a/Master/texmf-dist/scripts/context/lua/mtxrun.lua b/Master/texmf-dist/scripts/context/lua/mtxrun.lua index d07dfc9a7a1..8679aefb10d 100755 --- a/Master/texmf-dist/scripts/context/lua/mtxrun.lua +++ b/Master/texmf-dist/scripts/context/lua/mtxrun.lua @@ -56,7 +56,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-lua"] = package.loaded["l-lua"] or true --- original size: 3123, stripped down to: 1694 +-- original size: 3409, stripped down to: 1763 if not modules then modules={} end modules ['l-lua']={ version=1.001, @@ -136,6 +136,9 @@ function optionalrequire(...) return result end end +if lua then + lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" +end end -- of closure @@ -144,7 +147,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-package"] = package.loaded["l-package"] or true --- original size: 9893, stripped down to: 7253 +-- original size: 10587, stripped down to: 7815 if not modules then modules={} end modules ['l-package']={ version=1.001, @@ -154,7 +157,7 @@ if not modules then modules={} end modules ['l-package']={ license="see context related readme files" } local type=type -local gsub,format=string.gsub,string.format +local gsub,format,find=string.gsub,string.format,string.find local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match local package=package local searchers=package.searchers or package.loaders @@ -184,6 +187,7 @@ local helpers=package.helpers or { sequence={ "already loaded", "preload table", + "qualified path", "lua extra list", "lib extra list", "path specification", @@ -329,14 +333,32 @@ local function loadedbypath(name,rawname,paths,islib,what) end end helpers.loadedbypath=loadedbypath +local function loadedbyname(name,rawname) + if find(name,"^/") or find(name,"^[a-zA-Z]:/") then + local trace=helpers.trace + if trace then + helpers.report("qualified name, identifying '%s'",what,name) + end + if isreadable(name) then + if trace then + helpers.report("qualified name, '%s' found",what,name) + end + return loadfile(name) + end + end +end +helpers.loadedbyname=loadedbyname methods["already loaded"]=function(name) return package.loaded[name] end methods["preload table"]=function(name) return builtin["preload table"](name) end +methods["qualified path"]=function(name) + return loadedbyname(addsuffix(lualibfile(name),"lua"),name) +end methods["lua extra list"]=function(name) - return loadedbypath(addsuffix(lualibfile(name),"lua" ),name,getextraluapaths(),false,"lua") + return loadedbypath(addsuffix(lualibfile(name),"lua"),name,getextraluapaths(),false,"lua") end methods["lib extra list"]=function(name) return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib") @@ -415,7 +437,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true --- original size: 26252, stripped down to: 14371 +-- original size: 29808, stripped down to: 16182 if not modules then modules={} end modules ['l-lpeg']={ version=1.001, @@ -425,12 +447,15 @@ if not modules then modules={} end modules ['l-lpeg']={ license="see context related readme files" } lpeg=require("lpeg") +if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end local type,next,tostring=type,next,tostring local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format local floor=math.floor local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print -setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) +if setinspector then + setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) +end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns local anything=P(1) @@ -440,28 +465,46 @@ patterns.anything=anything patterns.endofstring=endofstring patterns.beginofstring=alwaysmatched patterns.alwaysmatched=alwaysmatched -local digit,sign=R('09'),S('+-') +local sign=S('+-') +local zero=P('0') +local digit=R('09') +local octdigit=R("07") +local lowercase=R("az") +local uppercase=R("AZ") +local underscore=P("_") +local hexdigit=digit+lowercase+uppercase local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") local newline=crlf+S("\r\n") local escaped=P("\\")*anything local squote=P("'") local dquote=P('"') local space=P(" ") -local utfbom_32_be=P('\000\000\254\255') -local utfbom_32_le=P('\255\254\000\000') -local utfbom_16_be=P('\255\254') -local utfbom_16_le=P('\254\255') -local utfbom_8=P('\239\187\191') +local period=P(".") +local comma=P(",") +local utfbom_32_be=P('\000\000\254\255') +local utfbom_32_le=P('\255\254\000\000') +local utfbom_16_be=P('\254\255') +local utfbom_16_le=P('\255\254') +local utfbom_8=P('\239\187\191') local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8 local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") +local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8") local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0) local utf8next=R("\128\191") +patterns.utfbom_32_be=utfbom_32_be +patterns.utfbom_32_le=utfbom_32_le +patterns.utfbom_16_be=utfbom_16_be +patterns.utfbom_16_le=utfbom_16_le +patterns.utfbom_8=utfbom_8 +patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") +patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") patterns.utf8one=R("\000\127") patterns.utf8two=R("\194\223")*utf8next patterns.utf8three=R("\224\239")*utf8next*utf8next patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next patterns.utfbom=utfbom patterns.utftype=utftype +patterns.utfstricttype=utfstricttype patterns.utfoffset=utfoffset local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false) @@ -481,27 +524,14 @@ patterns.spacer=spacer patterns.whitespace=whitespace patterns.nonspacer=nonspacer patterns.nonwhitespace=nonwhitespace -local stripper=spacer^0*C((spacer^0*nonspacer^1)^0) +local stripper=spacer^0*C((spacer^0*nonspacer^1)^0) +local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0) local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0)) patterns.stripper=stripper +patterns.fullstripper=fullstripper patterns.collapser=collapser -patterns.digit=digit -patterns.sign=sign -patterns.cardinal=sign^0*digit^1 -patterns.integer=sign^0*digit^1 -patterns.unsigned=digit^0*P('.')*digit^1 -patterns.float=sign^0*patterns.unsigned -patterns.cunsigned=digit^0*P(',')*digit^1 -patterns.cfloat=sign^0*patterns.cunsigned -patterns.number=patterns.float+patterns.integer -patterns.cnumber=patterns.cfloat+patterns.integer -patterns.oct=P("0")*R("07")^1 -patterns.octal=patterns.oct -patterns.HEX=P("0x")*R("09","AF")^1 -patterns.hex=P("0x")*R("09","af")^1 -patterns.hexadecimal=P("0x")*R("09","AF","af")^1 -patterns.lowercase=R("az") -patterns.uppercase=R("AZ") +patterns.lowercase=lowercase +patterns.uppercase=uppercase patterns.letter=patterns.lowercase+patterns.uppercase patterns.space=space patterns.tab=P("\t") @@ -509,12 +539,12 @@ patterns.spaceortab=patterns.space+patterns.tab patterns.newline=newline patterns.emptyline=newline^1 patterns.equal=P("=") -patterns.comma=P(",") -patterns.commaspacer=P(",")*spacer^0 -patterns.period=P(".") +patterns.comma=comma +patterns.commaspacer=comma*spacer^0 +patterns.period=period patterns.colon=P(":") patterns.semicolon=P(";") -patterns.underscore=P("_") +patterns.underscore=underscore patterns.escaped=escaped patterns.squote=squote patterns.dquote=dquote @@ -527,10 +557,29 @@ patterns.unspacer=((patterns.spacer^1)/"")^0 patterns.singlequoted=squote*patterns.nosquote*squote patterns.doublequoted=dquote*patterns.nodquote*dquote patterns.quoted=patterns.doublequoted+patterns.singlequoted -patterns.propername=R("AZ","az","__")*R("09","AZ","az","__")^0*P(-1) +patterns.digit=digit +patterns.octdigit=octdigit +patterns.hexdigit=hexdigit +patterns.sign=sign +patterns.cardinal=digit^1 +patterns.integer=sign^-1*digit^1 +patterns.unsigned=digit^0*period*digit^1 +patterns.float=sign^-1*patterns.unsigned +patterns.cunsigned=digit^0*comma*digit^1 +patterns.cfloat=sign^-1*patterns.cunsigned +patterns.number=patterns.float+patterns.integer +patterns.cnumber=patterns.cfloat+patterns.integer +patterns.oct=zero*octdigit^1 +patterns.octal=patterns.oct +patterns.HEX=zero*P("X")*(digit+uppercase)^1 +patterns.hex=zero*P("x")*(digit+lowercase)^1 +patterns.hexadecimal=zero*S("xX")*hexdigit^1 +patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigit^1+hexdigit^1*period*hexdigit^0+hexdigit^1)*(S("pP")*sign^-1*hexdigit^1)^-1 +patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^1)*S("eE")*sign^-1*digit^1 +patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring patterns.somecontent=(anything-newline-space)^1 patterns.beginline=#(1-newline) -patterns.longtostring=Cs(whitespace^0/""*nonwhitespace^0*((whitespace^0/" "*(patterns.quoted+nonwhitespace)^1)^0)) +patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) local function anywhere(pattern) return P { P(pattern)+1*V(1) } end @@ -702,7 +751,7 @@ function lpeg.replacer(one,two,makefunction,isutf) return pattern end end -function lpeg.finder(lst,makefunction) +function lpeg.finder(lst,makefunction,isutf) local pattern if type(lst)=="table" then pattern=P(false) @@ -718,7 +767,11 @@ function lpeg.finder(lst,makefunction) else pattern=P(lst) end - pattern=(1-pattern)^0*pattern + if isutf then + pattern=((utf8char or 1)-pattern)^0*pattern + else + pattern=(1-pattern)^0*pattern + end if makefunction then return function(str) return lpegmatch(pattern,str) @@ -731,8 +784,8 @@ local splitters_f,splitters_s={},{} function lpeg.firstofsplit(separator) local splitter=splitters_f[separator] if not splitter then - separator=P(separator) - splitter=C((1-separator)^0) + local pattern=P(separator) + splitter=C((1-pattern)^0) splitters_f[separator]=splitter end return splitter @@ -740,12 +793,31 @@ end function lpeg.secondofsplit(separator) local splitter=splitters_s[separator] if not splitter then - separator=P(separator) - splitter=(1-separator)^0*separator*C(anything^0) + local pattern=P(separator) + splitter=(1-pattern)^0*pattern*C(anything^0) splitters_s[separator]=splitter end return splitter end +local splitters_s,splitters_p={},{} +function lpeg.beforesuffix(separator) + local splitter=splitters_s[separator] + if not splitter then + local pattern=P(separator) + splitter=C((1-pattern)^0)*pattern*endofstring + splitters_s[separator]=splitter + end + return splitter +end +function lpeg.afterprefix(separator) + local splitter=splitters_p[separator] + if not splitter then + local pattern=P(separator) + splitter=pattern*C(anything^0) + splitters_p[separator]=splitter + end + return splitter +end function lpeg.balancer(left,right) left,right=P(left),P(right) return P { left*((1-left-right)+V(1))^0*right } @@ -977,9 +1049,6 @@ end function lpeg.times(pattern,n) return P(nextstep(n,2^16,{ "start",["1"]=pattern })) end -local digit=R("09") -local period=P(".") -local zero=P("0") local trailingzeros=zero^0*-digit local case_1=period*trailingzeros/"" local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"") @@ -1013,7 +1082,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-string"] = package.loaded["l-string"] or true --- original size: 5513, stripped down to: 2708 +-- original size: 5671, stripped down to: 2827 if not modules then modules={} end modules ['l-string']={ version=1.001, @@ -1049,11 +1118,15 @@ function string.limit(str,n,sentinel) end end local stripper=patterns.stripper +local fullstripper=patterns.fullstripper local collapser=patterns.collapser local longtostring=patterns.longtostring function string.strip(str) return lpegmatch(stripper,str) or "" end +function string.fullstrip(str) + return lpegmatch(fullstripper,str) or "" +end function string.collapsespaces(str) return lpegmatch(collapser,str) or "" end @@ -1114,7 +1187,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 44626, stripped down to: 19688 +-- original size: 31860, stripped down to: 20846 if not modules then modules={} end modules ['l-table']={ version=1.001, @@ -1192,6 +1265,36 @@ local function sortedkeys(tab) return {} end end +local function sortedhashonly(tab) + if tab then + local srt,s={},0 + for key,_ in next,tab do + if type(key)=="string" then + s=s+1 + srt[s]=key + end + end + sort(srt) + return srt + else + return {} + end +end +local function sortedindexonly(tab) + if tab then + local srt,s={},0 + for key,_ in next,tab do + if type(key)=="number" then + s=s+1 + srt[s]=key + end + end + sort(srt) + return srt + else + return {} + end +end local function sortedhashkeys(tab,cmp) if tab then local srt,s={},0 @@ -1217,6 +1320,8 @@ function table.allkeys(t) return sortedkeys(keys) end table.sortedkeys=sortedkeys +table.sortedhashonly=sortedhashonly +table.sortedindexonly=sortedindexonly table.sortedhashkeys=sortedhashkeys local function nothing() end local function sortedhash(t,cmp) @@ -1228,10 +1333,13 @@ local function sortedhash(t,cmp) s=sortedkeys(t) end local n=0 + local m=#s local function kv(s) - n=n+1 - local k=s[n] - return k,t[k] + if n<m then + n=n+1 + local k=s[n] + return k,t[k] + end end return kv,s else @@ -1382,6 +1490,7 @@ local noquotes,hexify,handle,reduce,compact,inline,functions local reserved=table.tohash { 'and','break','do','else','elseif','end','false','for','function','if', 'in','local','nil','not','or','repeat','return','then','true','until','while', + 'NaN','goto', } local function simple_table(t) if #t>0 then @@ -1401,12 +1510,12 @@ local function simple_table(t) else tt[nt]=tostring(v) end - elseif tv=="boolean" then - nt=nt+1 - tt[nt]=tostring(v) elseif tv=="string" then nt=nt+1 tt[nt]=format("%q",v) + elseif tv=="boolean" then + nt=nt+1 + tt[nt]=v and "true" or "false" else tt=nil break @@ -1439,7 +1548,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s[%q]={",depth,name)) end elseif tn=="boolean" then - handle(format("%s[%s]={",depth,tostring(name))) + handle(format("%s[%s]={",depth,name and "true" or "false")) else handle(format("%s{",depth)) end @@ -1463,21 +1572,21 @@ local function do_serialize(root,name,depth,level,indexed) for i=1,#sk do local k=sk[i] local v=root[k] - local t,tk=type(v),type(k) + local tv,tk=type(v),type(k) if compact and first and tk=="number" and k>=first and k<=last then - if t=="number" then + if tv=="number" then if hexify then handle(format("%s 0x%04X,",depth,v)) else handle(format("%s %s,",depth,v)) end - elseif t=="string" then + elseif tv=="string" then if reduce and tonumber(v) then handle(format("%s %s,",depth,v)) else handle(format("%s %q,",depth,v)) end - elseif t=="table" then + elseif tv=="table" then if not next(v) then handle(format("%s {},",depth)) elseif inline then @@ -1490,11 +1599,11 @@ local function do_serialize(root,name,depth,level,indexed) else do_serialize(v,k,depth,level+1,true) end - elseif t=="boolean" then - handle(format("%s %s,",depth,tostring(v))) - elseif t=="function" then + elseif tv=="boolean" then + handle(format("%s %s,",depth,v and "true" or "false")) + elseif tv=="function" then if functions then - handle(format('%s load(%q),',depth,dump(v))) + handle(format('%s load(%q),',depth,dump(v))) else handle(format('%s "function",',depth)) end @@ -1505,7 +1614,7 @@ local function do_serialize(root,name,depth,level,indexed) if false then handle(format("%s __p__=nil,",depth)) end - elseif t=="number" then + elseif tv=="number" then if tk=="number" then if hexify then handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) @@ -1514,9 +1623,9 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk=="boolean" then if hexify then - handle(format("%s [%s]=0x%04X,",depth,tostring(k),v)) + handle(format("%s [%s]=0x%04X,",depth,k and "true" or "false",v)) else - handle(format("%s [%s]=%s,",depth,tostring(k),v)) + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) end elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then @@ -1531,7 +1640,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%q]=%s,",depth,k,v)) end end - elseif t=="string" then + elseif tv=="string" then if reduce and tonumber(v) then if tk=="number" then if hexify then @@ -1540,7 +1649,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%s]=%s,",depth,k,v)) end elseif tk=="boolean" then - handle(format("%s [%s]=%s,",depth,tostring(k),v)) + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%s,",depth,k,v)) else @@ -1554,14 +1663,14 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%s]=%q,",depth,k,v)) end elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,tostring(k),v)) + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%q,",depth,k,v)) else handle(format("%s [%q]=%q,",depth,k,v)) end end - elseif t=="table" then + elseif tv=="table" then if not next(v) then if tk=="number" then if hexify then @@ -1570,7 +1679,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%s]={},",depth,k)) end elseif tk=="boolean" then - handle(format("%s [%s]={},",depth,tostring(k))) + handle(format("%s [%s]={},",depth,k and "true" or "false")) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s={},",depth,k)) else @@ -1586,7 +1695,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) end elseif tk=="boolean" then - handle(format("%s [%s]={ %s },",depth,tostring(k),concat(st,", "))) + handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s={ %s },",depth,k,concat(st,", "))) else @@ -1598,21 +1707,21 @@ local function do_serialize(root,name,depth,level,indexed) else do_serialize(v,k,depth,level+1) end - elseif t=="boolean" then + elseif tv=="boolean" then if tk=="number" then if hexify then - handle(format("%s [0x%04X]=%s,",depth,k,tostring(v))) + handle(format("%s [0x%04X]=%s,",depth,k,v and "true" or "false")) else - handle(format("%s [%s]=%s,",depth,k,tostring(v))) + handle(format("%s [%s]=%s,",depth,k,v and "true" or "false")) end elseif tk=="boolean" then - handle(format("%s [%s]=%s,",depth,tostring(k),tostring(v))) + handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false")) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,tostring(v))) + handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else - handle(format("%s [%q]=%s,",depth,k,tostring(v))) + handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) end - elseif t=="function" then + elseif tv=="function" then if functions then local f=getinfo(v).what=="C" and dump(dummy) or dump(v) if tk=="number" then @@ -1622,7 +1731,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%s]=load(%q),",depth,k,f)) end elseif tk=="boolean" then - handle(format("%s [%s]=load(%q),",depth,tostring(k),f)) + handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=load(%q),",depth,k,f)) else @@ -1637,7 +1746,7 @@ local function do_serialize(root,name,depth,level,indexed) handle(format("%s [%s]=%q,",depth,k,tostring(v))) end elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,tostring(k),tostring(v))) + handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%q,",depth,k,tostring(v))) else @@ -1938,7 +2047,9 @@ function table.print(t,...) serialize(print,t,...) end end -setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) +if setinspector then + setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) +end function table.sub(t,i,j) return { unpack(t,i,j) } end @@ -1973,6 +2084,24 @@ function table.sorted(t,...) sort(t,...) return t end +function table.values(t,s) + if t then + local values,keys,v={},{},0 + for key,value in next,t do + if not keys[value] then + v=v+1 + values[v]=value + keys[k]=key + end + end + if s then + sort(values) + end + return values + else + return {} + end +end end -- of closure @@ -1981,7 +2110,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-io"] = package.loaded["l-io"] or true --- original size: 8799, stripped down to: 6325 +-- original size: 8824, stripped down to: 6347 if not modules then modules={} end modules ['l-io']={ version=1.001, @@ -1995,7 +2124,7 @@ local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local floor=math.floor local type=type -if string.find(os.getenv("PATH"),";") then +if string.find(os.getenv("PATH"),";",1,true) then io.fileseparator,io.pathseparator="\\",";" else io.fileseparator,io.pathseparator="/",":" @@ -2012,6 +2141,7 @@ local function readall(f) return f:read('*all') else local done=f:seek("set",0) + local step if size<1024*1024 then step=1024*1024 elseif size>16*1024*1024 then @@ -2515,7 +2645,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-os"] = package.loaded["l-os"] or true --- original size: 14017, stripped down to: 8504 +-- original size: 16093, stripped down to: 9704 if not modules then modules={} end modules ['l-os']={ version=1.001, @@ -2596,10 +2726,16 @@ function os.exec (...) ioflush() return exec (...) end function io.popen (...) ioflush() return iopopen(...) end function os.resultof(command) local handle=io.popen(command,"r") - return handle and handle:read("*all") or "" + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + else + return "" + end end if not io.fileseparator then - if find(os.getenv("PATH"),";") then + if find(os.getenv("PATH"),";",1,true) then io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "mswin" else io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" @@ -2630,13 +2766,14 @@ if not os.times then } end end -os.gettimeofday=os.gettimeofday or os.clock -local startuptime=os.gettimeofday() +local gettimeofday=os.gettimeofday or os.clock +os.gettimeofday=gettimeofday +local startuptime=gettimeofday() function os.runtime() - return os.gettimeofday()-startuptime + return gettimeofday()-startuptime end -os.resolvers=os.resolvers or {} -local resolvers=os.resolvers +local resolvers=os.resolvers or {} +os.resolvers=resolvers setmetatable(os,{ __index=function(t,k) local r=resolvers[k] return r and r(t,k) or nil @@ -2656,10 +2793,10 @@ end if platform~="" then os.platform=platform elseif os.type=="windows" then - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or "" - if find(architecture,"AMD64") then - platform="mswin-64" + if find(architecture,"AMD64",1,true) then + platform="win64" else platform="mswin" end @@ -2668,11 +2805,11 @@ elseif os.type=="windows" then return platform end elseif name=="linux" then - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform,architecture="",os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" - if find(architecture,"x86_64") then + if find(architecture,"x86_64",1,true) then platform="linux-64" - elseif find(architecture,"ppc") then + elseif find(architecture,"ppc",1,true) then platform="linux-ppc" else platform="linux" @@ -2682,13 +2819,13 @@ elseif name=="linux" then return platform end elseif name=="macosx" then - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform,architecture="",os.resultof("echo $HOSTTYPE") or "" if architecture=="" then platform="osx-intel" - elseif find(architecture,"i386") then + elseif find(architecture,"i386",1,true) then platform="osx-intel" - elseif find(architecture,"x86_64") then + elseif find(architecture,"x86_64",1,true) then platform="osx-64" else platform="osx-ppc" @@ -2698,9 +2835,9 @@ elseif name=="macosx" then return platform end elseif name=="sunos" then - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform,architecture="",os.resultof("uname -m") or "" - if find(architecture,"sparc") then + if find(architecture,"sparc",1,true) then platform="solaris-sparc" else platform="solaris-intel" @@ -2710,9 +2847,9 @@ elseif name=="sunos" then return platform end elseif name=="freebsd" then - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform,architecture="",os.resultof("uname -m") or "" - if find(architecture,"amd64") then + if find(architecture,"amd64",1,true) then platform="freebsd-amd64" else platform="freebsd" @@ -2722,9 +2859,9 @@ elseif name=="freebsd" then return platform end elseif name=="kfreebsd" then - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform,architecture="",os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" - if find(architecture,"x86_64") then + if find(architecture,"x86_64",1,true) then platform="kfreebsd-amd64" else platform="kfreebsd-i386" @@ -2734,13 +2871,18 @@ elseif name=="kfreebsd" then return platform end else - function os.resolvers.platform(t,k) + function resolvers.platform(t,k) local platform="linux" os.setenv("MTX_PLATFORM",platform) os.platform=platform return platform end end +function resolvers.bits(t,k) + local bits=find(os.platform,"64",1,true) and 64 or 32 + os.bits=bits + return bits +end local t={ 8,9,"a","b" } function os.uuid() return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", @@ -2766,26 +2908,38 @@ function os.timezone(delta) end local timeformat=format("%%s%s",os.timezone(true)) local dateformat="!%Y-%m-%d %H:%M:%S" +local lasttime=nil +local lastdate=nil function os.fulltime(t,default) - t=tonumber(t) or 0 + t=t and tonumber(t) or 0 if t>0 then elseif default then return default else - t=nil + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=format(timeformat,date(dateformat)) end - return format(timeformat,date(dateformat,t)) + return lastdate end local dateformat="%Y-%m-%d %H:%M:%S" +local lasttime=nil +local lastdate=nil function os.localtime(t,default) - t=tonumber(t) or 0 + t=t and tonumber(t) or 0 if t>0 then elseif default then return default else - t=nil + t=time() end - return date(dateformat,t) + if t~=lasttime then + lasttime=t + lastdate=date(dateformat,t) + end + return lastdate end function os.converttime(t,default) local t=tonumber(t) @@ -2835,6 +2989,38 @@ if not os.sleep then socket.sleep(n) end end +local function isleapyear(year) + return (year%400==0) or ((year%100~=0) and (year%4==0)) +end +os.isleapyear=isleapyear +local days={ 31,28,31,30,31,30,31,31,30,31,30,31 } +local function nofdays(year,month) + if not month then + return isleapyear(year) and 365 or 364 + else + return month==2 and isleapyear(year) and 29 or days[month] + end +end +os.nofdays=nofdays +function os.weekday(day,month,year) + return date("%w",time { year=year,month=month,day=day })+1 +end +function os.validdate(year,month,day) + if month<1 then + month=1 + elseif month>12 then + month=12 + end + if day<1 then + day=1 + else + local max=nofdays(year,month) + if day>max then + day=max + end + end + return year,month,day +end end -- of closure @@ -2843,7 +3029,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-file"] = package.loaded["l-file"] or true --- original size: 17777, stripped down to: 9653 +-- original size: 18308, stripped down to: 9948 if not modules then modules={} end modules ['l-file']={ version=1.001, @@ -3086,17 +3272,24 @@ end function file.joinpath(tab,separator) return tab and concat(tab,separator or io.pathseparator) end +local someslash=S("\\/") local stripper=Cs(P(fwslash)^0/""*reslasher) -local isnetwork=fwslash*fwslash*(1-fwslash)+(1-fwslash-colon)^1*colon +local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon local isroot=fwslash^1*-1 local hasroot=fwslash^1 +local reslasher=lpeg.replacer(S("\\/"),"/") local deslasher=lpeg.replacer(S("\\/")^1,"/") function file.join(...) local lst={... } local one=lst[1] if lpegmatch(isnetwork,one) then + local one=lpegmatch(reslasher,one) local two=lpegmatch(deslasher,concat(lst,"/",2)) - return one.."/"..two + if lpegmatch(hasroot,two) then + return one..two + else + return one.."/"..two + end elseif lpegmatch(isroot,one) then local two=lpegmatch(deslasher,concat(lst,"/",2)) if lpegmatch(hasroot,two) then @@ -3113,7 +3306,9 @@ end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec local untouched=periods+(1-period)^1*P(-1) -local splitstarter=(Cs(drivespec*(bwslash/"/"+fwslash)^0)+Cc(false))*Ct(lpeg.splitat(S("/\\")^1)) +local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0) +local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//") +local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1)) local absolute=fwslash function file.collapsepath(str,anchor) if not str then @@ -3361,7 +3556,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-url"] = package.loaded["l-url"] or true --- original size: 11806, stripped down to: 5417 +-- original size: 12292, stripped down to: 5585 if not modules then modules={} end modules ['l-url']={ version=1.001, @@ -3388,7 +3583,7 @@ local hexdigit=R("09","AF","af") local plus=P("+") local nothing=Cc("") local escapedchar=(percent*C(hexdigit*hexdigit))/tochar -local escaped=(plus/" ")+escapedchar +local escaped=(plus/" ")+escapedchar local noslash=P("/")/"" local schemestr=Cs((escaped+(1-colon-slash-qmark-hash))^2) local authoritystr=Cs((escaped+(1- slash-qmark-hash))^0) @@ -3412,9 +3607,14 @@ setmetatable(escapes,{ __index=function(t,k) end }) local escaper=Cs((R("09","AZ","az")^1+P(" ")/"%%20"+S("-./_")^1+P(1)/escapes)^0) local unescaper=Cs((escapedchar+1)^0) +local getcleaner=Cs((P("+++")/"%%2B"+P("+")/"%%20"+P(1))^1) lpegpatterns.urlunescaped=escapedchar lpegpatterns.urlescaper=escaper lpegpatterns.urlunescaper=unescaper +lpegpatterns.urlgetcleaner=getcleaner +function url.unescapeget(str) + return lpegmatch(getcleaner,str) +end local function split(str) return (type(str)=="string" and lpegmatch(parser,str)) or str end @@ -3567,7 +3767,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 13738, stripped down to: 8560 +-- original size: 14788, stripped down to: 9096 if not modules then modules={} end modules ['l-dir']={ version=1.001, @@ -3590,6 +3790,8 @@ local isdir=lfs.isdir local isfile=lfs.isfile local currentdir=lfs.currentdir local chdir=lfs.chdir +local mkdir=lfs.mkdir +local onwindows=os.type=="windows" or find(os.getenv("PATH"),";",1,true) if not isdir then function isdir(name) local a=attributes(name) @@ -3661,11 +3863,21 @@ local function collectpattern(path,patt,recurse,result) return result end dir.collectpattern=collectpattern -local pattern=Ct { - [1]=(C(P(".")+P("/")^1)+C(R("az","AZ")*P(":")*P("/")^0)+Cc("./"))*V(2)*V(3), - [2]=C(((1-S("*?/"))^0*P("/"))^0), - [3]=C(P(1)^0) -} +local separator +if onwindows then + local slash=S("/\\")/"/" + pattern=Ct { + [1]=(Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3), + [2]=Cs(((1-S("*?/\\"))^0*slash)^0), + [3]=Cs(P(1)^0) + } +else + pattern=Ct { + [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), + [2]=C(((1-S("*?/"))^0*P("/"))^0), + [3]=C(P(1)^0) + } +end local filter=Cs (( P("**")/".*"+P("*")/"[^/]*"+P("?")/"[^/]"+P(".")/"%%."+P("+")/"%%+"+P("-")/"%%-"+P(1) )^0 ) @@ -3681,7 +3893,7 @@ local function glob(str,t) local split=lpegmatch(pattern,str) if split then local root,path,base=split[1],split[2],split[3] - local recurse=find(base,"%*%*") + local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) globpattern(start,result,recurse,t) @@ -3707,7 +3919,7 @@ local function glob(str,t) local t=t or {} local action=action or function(name) t[#t+1]=name end local root,path,base=split[1],split[2],split[3] - local recurse=find(base,"%*%*") + local recurse=find(base,"**",1,true) local start=root..path local result=lpegmatch(filter,start..base) globpattern(start,result,recurse,action) @@ -3749,22 +3961,30 @@ function dir.ls(pattern) return concat(glob(pattern),"\n") end local make_indeed=true -local onwindows=os.type=="windows" or find(os.getenv("PATH"),";") if onwindows then function dir.mkdirs(...) - local str,pth="","" - for i=1,select("#",...) do - local s=select(i,...) - if s=="" then - elseif str=="" then - str=s - else - str=str.."/"..s + local n=select("#",...) + local str + if n==1 then + str=select(1,...) + if isdir(str) then + return str,true + end + else + str="" + for i=1,n do + local s=select(i,...) + if s=="" then + elseif str=="" then + str=s + else + str=str.."/"..s + end end end - local first,middle,last + local pth="" local drive=false - first,middle,last=match(str,"^(//)(//*)(.*)$") + local first,middle,last=match(str,"^(//)(//*)(.*)$") if first then else first,last=match(str,"^(//)/*(.-)$") @@ -3797,21 +4017,30 @@ if onwindows then pth=pth.."/"..s end if make_indeed and not isdir(pth) then - lfs.mkdir(pth) + mkdir(pth) end end return pth,(isdir(pth)==true) end else function dir.mkdirs(...) - local str,pth="","" - for i=1,select("#",...) do - local s=select(i,...) - if s and s~="" then - if str~="" then - str=str.."/"..s - else - str=s + local n=select("#",...) + local str,pth + if n==1 then + str=select(1,...) + if isdir(str) then + return str,true + end + else + str="" + for i=1,n do + local s=select(i,...) + if s and s~="" then + if str~="" then + str=str.."/"..s + else + str=s + end end end end @@ -3826,7 +4055,7 @@ else pth=pth.."/"..s end if make_indeed and not first and not isdir(pth) then - lfs.mkdir(pth) + mkdir(pth) end end else @@ -3834,7 +4063,7 @@ else for s in gmatch(str,"[^/]+") do pth=pth.."/"..s if make_indeed and not isdir(pth) then - lfs.mkdir(pth) + mkdir(pth) end end end @@ -3925,7 +4154,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-boolean"] = package.loaded["l-boolean"] or true --- original size: 1781, stripped down to: 1503 +-- original size: 1809, stripped down to: 1527 if not modules then modules={} end modules ['l-boolean']={ version=1.001, @@ -3981,9 +4210,9 @@ function string.booleanstring(str) end function string.is_boolean(str,default) if type(str)=="string" then - if str=="true" or str=="yes" or str=="on" or str=="t" then + if str=="true" or str=="yes" or str=="on" or str=="t" or str=="1" then return true - elseif str=="false" or str=="no" or str=="off" or str=="f" then + elseif str=="false" or str=="no" or str=="off" or str=="f" or str=="0" then return false end end @@ -3997,7 +4226,7 @@ do -- create closure to overcome 200 locals limit package.loaded["l-unicode"] = package.loaded["l-unicode"] or true --- original size: 26810, stripped down to: 11943 +-- original size: 33706, stripped down to: 14938 if not modules then modules={} end modules ['l-unicode']={ version=1.001, @@ -4010,7 +4239,7 @@ utf=utf or (unicode and unicode.utf8) or {} utf.characters=utf.characters or string.utfcharacters utf.values=utf.values or string.utfvalues local type=type -local char,byte,format,sub=string.char,string.byte,string.format,string.sub +local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch local concat=table.concat local P,C,R,Cs,Ct,Cmt,Cc,Carg,Cp=lpeg.P,lpeg.C,lpeg.R,lpeg.Cs,lpeg.Ct,lpeg.Cmt,lpeg.Cc,lpeg.Carg,lpeg.Cp local lpegmatch,patterns=lpeg.match,lpeg.patterns @@ -4020,6 +4249,7 @@ local replacer=lpeg.replacer local utfvalues=utf.values local utfgmatch=utf.gmatch local p_utftype=patterns.utftype +local p_utfstricttype=patterns.utfstricttype local p_utfoffset=patterns.utfoffset local p_utf8char=patterns.utf8char local p_utf8byte=patterns.utf8byte @@ -4276,112 +4506,181 @@ function utf.magic(f) end return lpegmatch(p_utftype,str) end -local function utf16_to_utf8_be(t) - if type(t)=="string" then - t=lpegmatch(utflinesplitter,t) - end - local result={} - for i=1,#t do - local r,more=0,0 - for left,right in bytepairs(t[i]) do - if right then - local now=256*left+right - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - r=r+1 - result[r]=utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - else - r=r+1 - result[r]=utfchar(now) +local utf16_to_utf8_be,utf16_to_utf8_le +local utf32_to_utf8_be,utf32_to_utf8_le +local utf_16_be_linesplitter=patterns.utfbom_16_be^-1*lpeg.tsplitat(patterns.utf_16_be_nl) +local utf_16_le_linesplitter=patterns.utfbom_16_le^-1*lpeg.tsplitat(patterns.utf_16_le_nl) +if bytepairs then + utf16_to_utf8_be=function(t) + if type(t)=="string" then + t=lpegmatch(utf_16_be_linesplitter,t) + end + local result={} + for i=1,#t do + local r,more=0,0 + for left,right in bytepairs(t[i]) do + if right then + local now=256*left+right + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + r=r+1 + result[r]=utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + else + r=r+1 + result[r]=utfchar(now) + end end end + t[i]=concat(result,"",1,r) end - t[i]=concat(result,"",1,r) + return t end - return t -end -local function utf16_to_utf8_le(t) - if type(t)=="string" then - t=lpegmatch(utflinesplitter,t) + utf16_to_utf8_le=function(t) + if type(t)=="string" then + t=lpegmatch(utf_16_le_linesplitter,t) + end + local result={} + for i=1,#t do + local r,more=0,0 + for left,right in bytepairs(t[i]) do + if right then + local now=256*right+left + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + r=r+1 + result[r]=utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + else + r=r+1 + result[r]=utfchar(now) + end + end + end + t[i]=concat(result,"",1,r) + end + return t end - local result={} - for i=1,#t do - local r,more=0,0 - for left,right in bytepairs(t[i]) do - if right then - local now=256*right+left - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - r=r+1 - result[r]=utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now + utf32_to_utf8_be=function(t) + if type(t)=="string" then + t=lpegmatch(utflinesplitter,t) + end + local result={} + for i=1,#t do + local r,more=0,-1 + for a,b in bytepairs(t[i]) do + if a and b then + if more<0 then + more=256*256*256*a+256*256*b + else + r=r+1 + result[t]=utfchar(more+256*a+b) + more=-1 + end else - r=r+1 - result[r]=utfchar(now) + break end end + t[i]=concat(result,"",1,r) end - t[i]=concat(result,"",1,r) - end - return t -end -local function utf32_to_utf8_be(t) - if type(t)=="string" then - t=lpegmatch(utflinesplitter,t) + return t end - local result={} - for i=1,#t do - local r,more=0,-1 - for a,b in bytepairs(t[i]) do - if a and b then - if more<0 then - more=256*256*256*a+256*256*b + utf32_to_utf8_le=function(t) + if type(t)=="string" then + t=lpegmatch(utflinesplitter,t) + end + local result={} + for i=1,#t do + local r,more=0,-1 + for a,b in bytepairs(t[i]) do + if a and b then + if more<0 then + more=256*b+a + else + r=r+1 + result[t]=utfchar(more+256*256*256*b+256*256*a) + more=-1 + end else - r=r+1 - result[t]=utfchar(more+256*a+b) - more=-1 + break end - else - break end + t[i]=concat(result,"",1,r) end - t[i]=concat(result,"",1,r) + return t end - return t -end -local function utf32_to_utf8_le(t) - if type(t)=="string" then - t=lpegmatch(utflinesplitter,t) +else + utf16_to_utf8_be=function(t) + if type(t)=="string" then + t=lpegmatch(utf_16_be_linesplitter,t) + end + local result={} + for i=1,#t do + local r,more=0,0 + for left,right in gmatch(t[i],"(.)(.)") do + if left=="\000" then + r=r+1 + result[r]=utfchar(byte(right)) + elseif right then + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + r=r+1 + result[r]=utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + else + r=r+1 + result[r]=utfchar(now) + end + end + end + t[i]=concat(result,"",1,r) + end + return t end - local result={} - for i=1,#t do - local r,more=0,-1 - for a,b in bytepairs(t[i]) do - if a and b then - if more<0 then - more=256*b+a - else + utf16_to_utf8_le=function(t) + if type(t)=="string" then + t=lpegmatch(utf_16_le_linesplitter,t) + end + local result={} + for i=1,#t do + local r,more=0,0 + for left,right in gmatch(t[i],"(.)(.)") do + if right=="\000" then r=r+1 - result[t]=utfchar(more+256*256*256*b+256*256*a) - more=-1 + result[r]=utfchar(byte(left)) + elseif right then + local now=256*byte(right)+byte(left) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + r=r+1 + result[r]=utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + else + r=r+1 + result[r]=utfchar(now) + end end - else - break end + t[i]=concat(result,"",1,r) end - t[i]=concat(result,"",1,r) + return t end - return t + utf32_to_utf8_le=function() return {} end + utf32_to_utf8_be=function() return {} end end -utf.utf32_to_utf8_be=utf32_to_utf8_be -utf.utf32_to_utf8_le=utf32_to_utf8_le -utf.utf16_to_utf8_be=utf16_to_utf8_be utf.utf16_to_utf8_le=utf16_to_utf8_le +utf.utf16_to_utf8_be=utf16_to_utf8_be +utf.utf32_to_utf8_le=utf32_to_utf8_le +utf.utf32_to_utf8_be=utf32_to_utf8_be function utf.utf8_to_utf8(t) return type(t)=="string" and lpegmatch(utflinesplitter,t) or t end @@ -4413,13 +4712,27 @@ local function big(c) end local _,l_remap=utf.remapper(little) local _,b_remap=utf.remapper(big) -function utf.utf8_to_utf16(str,littleendian) - if littleendian then - return char(255,254)..lpegmatch(l_remap,str) +function utf.utf8_to_utf16_be(str,nobom) + if nobom then + return lpegmatch(b_remap,str) else return char(254,255)..lpegmatch(b_remap,str) end end +function utf.utf8_to_utf16_le(str,nobom) + if nobom then + return lpegmatch(l_remap,str) + else + return char(255,254)..lpegmatch(l_remap,str) + end +end +function utf.utf8_to_utf16(str,littleendian,nobom) + if littleendian then + return utf.utf8_to_utf16_le(str,nobom) + else + return utf.utf8_to_utf16_be(str,nobom) + end +end local pattern=Cs ( (p_utf8byte/function(unicode ) return format("0x%04X",unicode) end)*(p_utf8byte*Carg(1)/function(unicode,separator) return format("%s0x%04X",separator,unicode) end)^0 ) @@ -4432,6 +4745,21 @@ end function utf.xstring(s) return format("0x%05X",type(s)=="number" and s or utfbyte(s)) end +function utf.toeight(str) + if not str then + return nil + end + local utftype=lpegmatch(p_utfstricttype,str) + if utftype=="utf-8" then + return sub(str,4) + elseif utftype=="utf-16-le" then + return utf16_to_utf8_le(str) + elseif utftype=="utf-16-be" then + return utf16_to_utf8_ne(str) + else + return str + end +end local p_nany=p_utf8char/"" if utfgmatch then function utf.count(str,what) @@ -4489,6 +4817,15 @@ if not utf.values then end string.utfvalues=utf.values end +function utf.chrlen(u) + return + (u<0x80 and 1) or + (u<0xE0 and 2) or + (u<0xF0 and 3) or + (u<0xF8 and 4) or + (u<0xFC and 5) or + (u<0xFE and 6) or 0 +end end -- of closure @@ -4534,7 +4871,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 22834, stripped down to: 12570 +-- original size: 32843, stripped down to: 18226 if not modules then modules={} end modules ['util-str']={ version=1.001, @@ -4553,15 +4890,28 @@ local unpack,concat=table.unpack,table.concat local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc local patterns,lpegmatch=lpeg.patterns,lpeg.match local utfchar,utfbyte=utf.char,utf.byte -local loadstripped=_LUAVERSION<5.2 and load or function(str) - return load(dump(load(str),true)) +local loadstripped=nil +if _LUAVERSION<5.2 then + loadstripped=function(str,shortcuts) + return load(str) + end +else + loadstripped=function(str,shortcuts) + if shortcuts then + return load(dump(load(str),true),nil,nil,shortcuts) + else + return load(dump(load(str),true)) + end + end end if not number then number={} end local stripper=patterns.stripzeros local function points(n) + n=tonumber(n) return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) end local function basepoints(n) + n=tonumber(n) return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536)) end number.points=points @@ -4624,11 +4974,39 @@ local pattern=Carg(1)/function(t) function strings.tabtospace(str,tab) return lpegmatch(pattern,str,1,tab or 7) end -function strings.striplong(str) - str=gsub(str,"^%s*","") - str=gsub(str,"[\n\r]+ *","\n") - return str +local newline=patterns.newline +local endofstring=patterns.endofstring +local whitespace=patterns.whitespace +local spacer=patterns.spacer +local space=spacer^0 +local nospace=space/"" +local endofline=nospace*newline +local stripend=(whitespace^1*endofstring)/"" +local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) +local stripempty=endofline^1/"" +local normalempty=endofline^1 +local singleempty=endofline*(endofline^0/"") +local doubleempty=endofline*endofline^-1*(endofline^0/"") +local stripstart=stripempty^0 +local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 ) +local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 ) +local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 ) +local p_retain_normal=Cs ((normalline+normalempty )^0 ) +local p_retain_collapse=Cs ((normalline+doubleempty )^0 ) +local p_retain_noempty=Cs ((normalline+singleempty )^0 ) +local striplinepatterns={ + ["prune"]=p_prune_normal, + ["prune and collapse"]=p_prune_collapse, + ["prune and no empty"]=p_prune_noempty, + ["retain"]=p_retain_normal, + ["retain and collapse"]=p_retain_collapse, + ["retain and no empty"]=p_retain_noempty, +} +strings.striplinepatterns=striplinepatterns +function strings.striplines(str,how) + return str and lpegmatch(how and striplinepatterns[how] or p_prune_collapse,str) or str end +strings.striplong=strings.striplines function strings.nice(str) str=gsub(str,"[:%-+_]+"," ") return str @@ -4679,29 +5057,83 @@ function number.signed(i) return "-",-i end end -local preamble=[[ -local type = type -local tostring = tostring -local tonumber = tonumber -local format = string.format -local concat = table.concat -local signed = number.signed -local points = number.points -local basepoints = number.basepoints -local utfchar = utf.char -local utfbyte = utf.byte -local lpegmatch = lpeg.match -local nspaces = string.nspaces -local tracedchar = string.tracedchar -local autosingle = string.autosingle -local autodouble = string.autodouble -local sequenced = table.sequenced -]] +local zero=P("0")^1/"" +local plus=P("+")/"" +local minus=P("-") +local separator=S(".") +local digit=R("09") +local trailing=zero^1*#S("eE") +local exponent=(S("eE")*(plus+Cs((minus*zero^0*P(-1))/"")+minus)*zero^0*(P(-1)*Cc("0")+P(1)^1)) +local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) +local pattern_b=Cs((exponent+P(1))^0) +function number.sparseexponent(f,n) + if not n then + n=f + f="%e" + end + local tn=type(n) + if tn=="string" then + local m=tonumber(n) + if m then + return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,m)) + end + elseif tn=="number" then + return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,n)) + end + return tostring(n) +end local template=[[ %s %s return function(%s) return %s end ]] +local preamble,environment="",{} +if _LUAVERSION<5.2 then + preamble=[[ +local lpeg=lpeg +local type=type +local tostring=tostring +local tonumber=tonumber +local format=string.format +local concat=table.concat +local signed=number.signed +local points=number.points +local basepoints= number.basepoints +local utfchar=utf.char +local utfbyte=utf.byte +local lpegmatch=lpeg.match +local nspaces=string.nspaces +local tracedchar=string.tracedchar +local autosingle=string.autosingle +local autodouble=string.autodouble +local sequenced=table.sequenced +local formattednumber=number.formatted +local sparseexponent=number.sparseexponent + ]] +else + environment={ + global=global or _G, + lpeg=lpeg, + type=type, + tostring=tostring, + tonumber=tonumber, + format=string.format, + concat=table.concat, + signed=number.signed, + points=number.points, + basepoints=number.basepoints, + utfchar=utf.char, + utfbyte=utf.byte, + lpegmatch=lpeg.match, + nspaces=string.nspaces, + tracedchar=string.tracedchar, + autosingle=string.autosingle, + autodouble=string.autodouble, + sequenced=table.sequenced, + formattednumber=number.formatted, + sparseexponent=number.sparseexponent, + } +end local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) local v=t[k-1]..",a"..k @@ -4710,7 +5142,7 @@ setmetatable(arguments,{ __index=function(t,k) end }) local prefix_any=C((S("+- .")+R("09"))^0) -local prefix_tab=C((1-R("az","AZ","09","%%"))^0) +local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0) local format_s=function(f) n=n+1 if f and f~="" then @@ -4740,7 +5172,7 @@ local format_i=function(f) if f and f~="" then return format("format('%%%si',a%s)",f,n) else - return format("a%s",n) + return format("format('%%i',a%s)",n) end end local format_d=format_i @@ -4752,6 +5184,10 @@ local format_f=function(f) n=n+1 return format("format('%%%sf',a%s)",f,n) end +local format_F=function(f) + n=n+1 + return format("((a%s == 0 and '0') or (a%s == 1 and '1') or format('%%%sf',a%s))",n,n,f,n) +end local format_g=function(f) n=n+1 return format("format('%%%sg',a%s)",f,n) @@ -4768,6 +5204,14 @@ local format_E=function(f) n=n+1 return format("format('%%%sE',a%s)",f,n) end +local format_j=function(f) + n=n+1 + return format("sparseexponent('%%%se',a%s)",f,n) +end +local format_J=function(f) + n=n+1 + return format("sparseexponent('%%%sE',a%s)",f,n) +end local format_x=function(f) n=n+1 return format("format('%%%sx',a%s)",f,n) @@ -4892,6 +5336,43 @@ end local format_W=function(f) return format("nspaces[%s]",tonumber(f) or 0) end +local digit=patterns.digit +local period=patterns.period +local three=digit*digit*digit +local splitter=Cs ( + (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2) +) +patterns.formattednumber=splitter +function number.formatted(n,sep1,sep2) + local s=type(s)=="string" and n or format("%0.2f",n) + if sep1==true then + return lpegmatch(splitter,s,1,".",",") + elseif sep1=="." then + return lpegmatch(splitter,s,1,sep1,sep2 or ",") + elseif sep1=="," then + return lpegmatch(splitter,s,1,sep1,sep2 or ".") + else + return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") + end +end +local format_m=function(f) + n=n+1 + if not f or f=="" then + f="," + end + return format([[formattednumber(a%s,%q,".")]],n,f) +end +local format_M=function(f) + n=n+1 + if not f or f=="" then + f="." + end + return format([[formattednumber(a%s,%q,",")]],n,f) +end +local format_z=function(f) + n=n+(tonumber(f) or 1) + return "''" +end local format_rest=function(s) return format("%q",s) end @@ -4921,15 +5402,17 @@ local builder=Cs { "start", ( P("%")/""*( V("!") -+V("s")+V("q")+V("i")+V("d")+V("f")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o") ++V("s")+V("q")+V("i")+V("d")+V("f")+V("F")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o") +V("c")+V("C")+V("S") +V("Q") +V("N") -+V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("b")+V("t")+V("T")+V("l")+V("L")+V("I")+V("h") -+V("w") ++V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("b")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w") +V("W") +V("a") -+V("A") ++V("A") ++V("j")+V("J") ++V("m")+V("M") ++V("z") +V("*") )+V("*") )*(P(-1)+Carg(1)) @@ -4939,6 +5422,7 @@ local builder=Cs { "start", ["i"]=(prefix_any*P("i"))/format_i, ["d"]=(prefix_any*P("d"))/format_d, ["f"]=(prefix_any*P("f"))/format_f, + ["F"]=(prefix_any*P("F"))/format_F, ["g"]=(prefix_any*P("g"))/format_g, ["G"]=(prefix_any*P("G"))/format_G, ["e"]=(prefix_any*P("e"))/format_e, @@ -4960,19 +5444,24 @@ local builder=Cs { "start", ["b"]=(prefix_any*P("b"))/format_b, ["t"]=(prefix_tab*P("t"))/format_t, ["T"]=(prefix_tab*P("T"))/format_T, - ["l"]=(prefix_tab*P("l"))/format_l, - ["L"]=(prefix_tab*P("L"))/format_L, + ["l"]=(prefix_any*P("l"))/format_l, + ["L"]=(prefix_any*P("L"))/format_L, ["I"]=(prefix_any*P("I"))/format_I, ["w"]=(prefix_any*P("w"))/format_w, ["W"]=(prefix_any*P("W"))/format_W, + ["j"]=(prefix_any*P("j"))/format_j, + ["J"]=(prefix_any*P("J"))/format_J, + ["m"]=(prefix_tab*P("m"))/format_m, + ["M"]=(prefix_tab*P("M"))/format_M, + ["z"]=(prefix_any*P("z"))/format_z, ["a"]=(prefix_any*P("a"))/format_a, ["A"]=(prefix_any*P("A"))/format_A, - ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%%%")^1)/format_rest, + ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } local direct=Cs ( - P("%")/""*Cc([[local format = string.format return function(str) return format("%]])*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*Cc([[",str) end]])*P(-1) - ) + P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] +) local function make(t,str) local f local p @@ -4981,10 +5470,10 @@ local function make(t,str) f=loadstripped(p)() else n=0 - p=lpegmatch(builder,str,1,"..",t._extensions_) + p=lpegmatch(builder,str,1,t._connector_,t._extensions_) if n>0 then p=format(template,preamble,t._preamble_,arguments[n],p) - f=loadstripped(p)() + f=loadstripped(p,t._environment_)() else f=function() return str end end @@ -4996,10 +5485,22 @@ local function use(t,fmt,...) return t[fmt](...) end strings.formatters={} -function strings.formatters.new() - local t={ _extensions_={},_preamble_="",_type_="formatter" } - setmetatable(t,{ __index=make,__call=use }) - return t +if _LUAVERSION<5.2 then + function strings.formatters.new(noconcat) + local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_=preamble,_environment_={} } + setmetatable(t,{ __index=make,__call=use }) + return t + end +else + function strings.formatters.new(noconcat) + local e={} + for k,v in next,environment do + e[k]=v + end + local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_="",_environment_=e } + setmetatable(t,{ __index=make,__call=use }) + return t + end end local formatters=strings.formatters.new() string.formatters=formatters @@ -5007,16 +5508,29 @@ string.formatter=function(str,...) return formatters[str](...) end local function add(t,name,template,preamble) if type(t)=="table" and t._type_=="formatter" then t._extensions_[name]=template or "%s" - if preamble then + if type(preamble)=="string" then t._preamble_=preamble.."\n"..t._preamble_ + elseif type(preamble)=="table" then + for k,v in next,preamble do + t._environment_[k]=v + end end end end strings.formatters.add=add -lpeg.patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) -lpeg.patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],[[local xmlescape = lpeg.patterns.xmlescape]]) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],[[local texescape = lpeg.patterns.texescape]]) +patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) +patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) +patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) +patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"')) +if _LUAVERSION<5.2 then + add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape") + add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape") + add(formatters,"lua",[[lpegmatch(luaescape,%s)]],"local luaescape = lpeg.patterns.luaescape") +else + add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape }) + add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) + add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) +end end -- of closure @@ -5025,7 +5539,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tab"] = package.loaded["util-tab"] or true --- original size: 14510, stripped down to: 8531 +-- original size: 23985, stripped down to: 16069 if not modules then modules={} end modules ['util-tab']={ version=1.001, @@ -5037,35 +5551,38 @@ if not modules then modules={} end modules ['util-tab']={ utilities=utilities or {} utilities.tables=utilities.tables or {} local tables=utilities.tables -local format,gmatch,gsub=string.format,string.gmatch,string.gsub +local format,gmatch,gsub,sub=string.format,string.gmatch,string.gsub,string.sub local concat,insert,remove=table.concat,table.insert,table.remove local setmetatable,getmetatable,tonumber,tostring=setmetatable,getmetatable,tonumber,tostring local type,next,rawset,tonumber,tostring,load,select=type,next,rawset,tonumber,tostring,load,select local lpegmatch,P,Cs,Cc=lpeg.match,lpeg.P,lpeg.Cs,lpeg.Cc -local serialize,sortedkeys,sortedpairs=table.serialize,table.sortedkeys,table.sortedpairs +local sortedkeys,sortedpairs=table.sortedkeys,table.sortedpairs local formatters=string.formatters +local utftoeight=utf.toeight local splitter=lpeg.tsplitat(".") -function tables.definetable(target,nofirst,nolast) - local composed,shortcut,t=nil,nil,{} +function utilities.tables.definetable(target,nofirst,nolast) + local composed,t=nil,{} local snippets=lpegmatch(splitter,target) for i=1,#snippets-(nolast and 1 or 0) do local name=snippets[i] if composed then - composed=shortcut.."."..name - shortcut=shortcut.."_"..name - t[#t+1]=formatters["local %s = %s if not %s then %s = { } %s = %s end"](shortcut,composed,shortcut,shortcut,composed,shortcut) + composed=composed.."."..name + t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) else composed=name - shortcut=name if not nofirst then t[#t+1]=formatters["%s = %s or { }"](composed,composed) end end end - if nolast then - composed=shortcut.."."..snippets[#snippets] + if composed then + if nolast then + composed=composed.."."..snippets[#snippets] + end + return concat(t,"\n"),composed + else + return "",target end - return concat(t,"\n"),composed end function tables.definedtable(...) local t=_G @@ -5092,7 +5609,7 @@ function tables.accesstable(target,root) end function tables.migratetable(target,v,root) local t=root or _G - local names=string.split(target,".") + local names=lpegmatch(splitter,target) for i=1,#names-1 do local name=names[i] t[name]=t[name] or {} @@ -5247,47 +5764,78 @@ function tables.encapsulate(core,capsule,protect) } ) end end -local function fastserialize(t,r,outer) - r[#r+1]="{" - local n=#t - if n>0 then - for i=1,n do - local v=t[i] - local tv=type(v) - if tv=="string" then - r[#r+1]=formatters["%q,"](v) - elseif tv=="number" then - r[#r+1]=formatters["%s,"](v) - elseif tv=="table" then - fastserialize(v,r) - elseif tv=="boolean" then - r[#r+1]=formatters["%S,"](v) +local f_hashed_string=formatters["[%q]=%q,"] +local f_hashed_number=formatters["[%q]=%s,"] +local f_hashed_boolean=formatters["[%q]=%l,"] +local f_hashed_table=formatters["[%q]="] +local f_indexed_string=formatters["[%s]=%q,"] +local f_indexed_number=formatters["[%s]=%s,"] +local f_indexed_boolean=formatters["[%s]=%l,"] +local f_indexed_table=formatters["[%s]="] +local f_ordered_string=formatters["%q,"] +local f_ordered_number=formatters["%s,"] +local f_ordered_boolean=formatters["%l,"] +function table.fastserialize(t,prefix) + local r={ type(prefix)=="string" and prefix or "return" } + local m=1 + local function fastserialize(t,outer) + local n=#t + m=m+1 + r[m]="{" + if n>0 then + for i=0,n do + local v=t[i] + local tv=type(v) + if tv=="string" then + m=m+1 r[m]=f_ordered_string(v) + elseif tv=="number" then + m=m+1 r[m]=f_ordered_number(v) + elseif tv=="table" then + fastserialize(v) + elseif tv=="boolean" then + m=m+1 r[m]=f_ordered_boolean(v) + end end end - else for k,v in next,t do - local tv=type(v) - if tv=="string" then - r[#r+1]=formatters["[%q]=%q,"](k,v) - elseif tv=="number" then - r[#r+1]=formatters["[%q]=%s,"](k,v) - elseif tv=="table" then - r[#r+1]=formatters["[%q]="](k) - fastserialize(v,r) - elseif tv=="boolean" then - r[#r+1]=formatters["[%q]=%S,"](k,v) + local tk=type(k) + if tk=="number" then + if k>n or k<0 then + local tv=type(v) + if tv=="string" then + m=m+1 r[m]=f_indexed_string(k,v) + elseif tv=="number" then + m=m+1 r[m]=f_indexed_number(k,v) + elseif tv=="table" then + m=m+1 r[m]=f_indexed_table(k) + fastserialize(v) + elseif tv=="boolean" then + m=m+1 r[m]=f_indexed_boolean(k,v) + end + end + else + local tv=type(v) + if tv=="string" then + m=m+1 r[m]=f_hashed_string(k,v) + elseif tv=="number" then + m=m+1 r[m]=f_hashed_number(k,v) + elseif tv=="table" then + m=m+1 r[m]=f_hashed_table(k) + fastserialize(v) + elseif tv=="boolean" then + m=m+1 r[m]=f_hashed_boolean(k,v) + end end end + m=m+1 + if outer then + r[m]="}" + else + r[m]="}," + end + return r end - if outer then - r[#r+1]="}" - else - r[#r+1]="}," - end - return r -end -function table.fastserialize(t,prefix) - return concat(fastserialize(t,{ prefix or "return" },true)) + return concat(fastserialize(t,true)) end function table.deserialize(str) if not str or str=="" then @@ -5307,6 +5855,7 @@ function table.load(filename,loader) if filename then local t=(loader or io.loaddata)(filename) if t and t~="" then + local t=utftoeight(t) t=load(t) if type(t)=="function" then t=t() @@ -5318,9 +5867,12 @@ function table.load(filename,loader) end end function table.save(filename,t,n,...) - io.savedata(filename,serialize(t,n==nil and true or n,...)) + io.savedata(filename,table.serialize(t,n==nil and true or n,...)) end -local function slowdrop(t) +local f_key_value=formatters["%s=%q"] +local f_add_table=formatters[" {%t},\n"] +local f_return_table=formatters["return {\n%t}"] +local function slowdrop(t) local r={} local l={} for i=1,#t do @@ -5328,23 +5880,25 @@ local function slowdrop(t) local j=0 for k,v in next,ti do j=j+1 - l[j]=formatters["%s=%q"](k,v) + l[j]=f_key_value(k,v) end - r[i]=formatters[" {%t},\n"](l) + r[i]=f_add_table(l) end - return formatters["return {\n%st}"](r) + return f_return_table(r) end local function fastdrop(t) local r={ "return {\n" } + local m=1 for i=1,#t do local ti=t[i] - r[#r+1]=" {" + m=m+1 r[m]=" {" for k,v in next,ti do - r[#r+1]=formatters["%s=%q"](k,v) + m=m+1 r[m]=f_key_value(k,v) end - r[#r+1]="},\n" + m=m+1 r[m]="},\n" end - r[#r+1]="}" + m=m+1 + r[m]="}" return concat(r) end function table.drop(t,slow) @@ -5379,6 +5933,216 @@ function table.twowaymapper(t) setmetatable(t,selfmapper) return t end +local f_start_key_idx=formatters["%w{"] +local f_start_key_num=formatters["%w[%s]={"] +local f_start_key_str=formatters["%w[%q]={"] +local f_start_key_boo=formatters["%w[%l]={"] +local f_start_key_nop=formatters["%w{"] +local f_stop=formatters["%w},"] +local f_key_num_value_num=formatters["%w[%s]=%s,"] +local f_key_str_value_num=formatters["%w[%q]=%s,"] +local f_key_boo_value_num=formatters["%w[%l]=%s,"] +local f_key_num_value_str=formatters["%w[%s]=%q,"] +local f_key_str_value_str=formatters["%w[%q]=%q,"] +local f_key_boo_value_str=formatters["%w[%l]=%q,"] +local f_key_num_value_boo=formatters["%w[%s]=%l,"] +local f_key_str_value_boo=formatters["%w[%q]=%l,"] +local f_key_boo_value_boo=formatters["%w[%l]=%l,"] +local f_key_num_value_not=formatters["%w[%s]={},"] +local f_key_str_value_not=formatters["%w[%q]={},"] +local f_key_boo_value_not=formatters["%w[%l]={},"] +local f_key_num_value_seq=formatters["%w[%s]={ %, t },"] +local f_key_str_value_seq=formatters["%w[%q]={ %, t },"] +local f_key_boo_value_seq=formatters["%w[%l]={ %, t },"] +local f_val_num=formatters["%w%s,"] +local f_val_str=formatters["%w%q,"] +local f_val_boo=formatters["%w%l,"] +local f_val_not=formatters["%w{},"] +local f_val_seq=formatters["%w{ %, t },"] +local f_table_return=formatters["return {"] +local f_table_name=formatters["%s={"] +local f_table_direct=formatters["{"] +local f_table_entry=formatters["[%q]={"] +local f_table_finish=formatters["}"] +local spaces=utilities.strings.newrepeater(" ") +local serialize=table.serialize +function table.serialize(root,name,specification) + if type(specification)=="table" then + return serialize(root,name,specification) + end + local t + local n=1 + local function simple_table(t) + if #t>0 then + local n=0 + for _,v in next,t do + n=n+1 + if type(v)=="table" then + return nil + end + end + if n==#t then + local tt={} + local nt=0 + for i=1,#t do + local v=t[i] + local tv=type(v) + nt=nt+1 + if tv=="number" then + tt[nt]=v + elseif tv=="string" then + tt[nt]=format("%q",v) + elseif tv=="boolean" then + tt[nt]=v and "true" or "false" + else + return nil + end + end + return tt + end + end + return nil + end + local function do_serialize(root,name,depth,level,indexed) + if level>0 then + n=n+1 + if indexed then + t[n]=f_start_key_idx(depth) + else + local tn=type(name) + if tn=="number" then + t[n]=f_start_key_num(depth,name) + elseif tn=="string" then + t[n]=f_start_key_str(depth,name) + elseif tn=="boolean" then + t[n]=f_start_key_boo(depth,name) + else + t[n]=f_start_key_nop(depth) + end + end + depth=depth+1 + end + if root and next(root) then + local first=nil + local last=0 + last=#root + for k=1,last do + if root[k]==nil then + last=k-1 + break + end + end + if last>0 then + first=1 + end + local sk=sortedkeys(root) + for i=1,#sk do + local k=sk[i] + local v=root[k] + local tv=type(v) + local tk=type(k) + if first and tk=="number" and k>=first and k<=last then + if tv=="number" then + n=n+1 t[n]=f_val_num(depth,v) + elseif tv=="string" then + n=n+1 t[n]=f_val_str(depth,v) + elseif tv=="table" then + if not next(v) then + n=n+1 t[n]=f_val_not(depth) + else + local st=simple_table(v) + if st then + n=n+1 t[n]=f_val_seq(depth,st) + else + do_serialize(v,k,depth,level+1,true) + end + end + elseif tv=="boolean" then + n=n+1 t[n]=f_val_boo(depth,v) + end + elseif tv=="number" then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_num(depth,k,v) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_num(depth,k,v) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_num(depth,k,v) + end + elseif tv=="string" then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_str(depth,k,v) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_str(depth,k,v) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_str(depth,k,v) + end + elseif tv=="table" then + if not next(v) then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_not(depth,k,v) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_not(depth,k,v) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_not(depth,k,v) + end + else + local st=simple_table(v) + if not st then + do_serialize(v,k,depth,level+1) + elseif tk=="number" then + n=n+1 t[n]=f_key_num_value_seq(depth,k,st) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_seq(depth,k,st) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_seq(depth,k,st) + end + end + elseif tv=="boolean" then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_boo(depth,k,v) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_boo(depth,k,v) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_boo(depth,k,v) + end + end + end + end + if level>0 then + n=n+1 t[n]=f_stop(depth-1) + end + end + local tname=type(name) + if tname=="string" then + if name=="return" then + t={ f_table_return() } + else + t={ f_table_name(name) } + end + elseif tname=="number" then + t={ f_table_entry(name) } + elseif tname=="boolean" then + if name then + t={ f_table_return() } + else + t={ f_table_direct() } + end + else + t={ f_table_name("t") } + end + if root then + if getmetatable(root) then + local dummy=root._w_h_a_t_e_v_e_r_ + root._w_h_a_t_e_v_e_r_=nil + end + if next(root) then + do_serialize(root,name,1,0) + end + end + n=n+1 + t[n]=f_table_finish() + return concat(t,"\n") +end end -- of closure @@ -5387,7 +6151,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sto"] = package.loaded["util-sto"] or true --- original size: 4432, stripped down to: 3123 +-- original size: 4172, stripped down to: 2953 if not modules then modules={} end modules ['util-sto']={ version=1.001, @@ -5457,56 +6221,47 @@ end local function f_empty () return "" end local function f_self (t,k) t[k]=k return k end local function f_table (t,k) local v={} t[k]=v return v end +local function f_number(t,k) t[k]=0 return 0 end local function f_ignore() end -local t_empty={ __index=f_empty } -local t_self={ __index=f_self } -local t_table={ __index=f_table } -local t_ignore={ __newindex=f_ignore } +local f_index={ + ["empty"]=f_empty, + ["self"]=f_self, + ["table"]=f_table, + ["number"]=f_number, +} +local t_index={ + ["empty"]={ __index=f_empty }, + ["self"]={ __index=f_self }, + ["table"]={ __index=f_table }, + ["number"]={ __index=f_number }, +} function table.setmetatableindex(t,f) if type(t)~="table" then f,t=t,{} end local m=getmetatable(t) if m then - if f=="empty" then - m.__index=f_empty - elseif f=="key" then - m.__index=f_self - elseif f=="table" then - m.__index=f_table - else - m.__index=f - end + m.__index=f_index[f] or f else - if f=="empty" then - setmetatable(t,t_empty) - elseif f=="key" then - setmetatable(t,t_self) - elseif f=="table" then - setmetatable(t,t_table) - else - setmetatable(t,{ __index=f }) - end + setmetatable(t,t_index[f] or { __index=f }) end return t end +local f_index={ + ["ignore"]=f_ignore, +} +local t_index={ + ["ignore"]={ __newindex=f_ignore }, +} function table.setmetatablenewindex(t,f) if type(t)~="table" then f,t=t,{} end local m=getmetatable(t) if m then - if f=="ignore" then - m.__newindex=f_ignore - else - m.__newindex=f - end + m.__newindex=f_index[f] or f else - if f=="ignore" then - setmetatable(t,t_ignore) - else - setmetatable(t,{ __newindex=f }) - end + setmetatable(t,t_index[f] or { __newindex=f }) end return t end @@ -5543,7 +6298,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-prs"] = package.loaded["util-prs"] or true --- original size: 17827, stripped down to: 12722 +-- original size: 19618, stripped down to: 14012 if not modules then modules={} end modules ['util-prs']={ version=1.001, @@ -5555,8 +6310,9 @@ if not modules then modules={} end modules ['util-prs']={ local lpeg,table,string=lpeg,table,string local P,R,V,S,C,Ct,Cs,Carg,Cc,Cg,Cf,Cp=lpeg.P,lpeg.R,lpeg.V,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cc,lpeg.Cg,lpeg.Cf,lpeg.Cp local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns -local concat,format,gmatch,find=table.concat,string.format,string.gmatch,string.find +local concat,gmatch,find=table.concat,string.gmatch,string.find local tostring,type,next,rawset=tostring,type,next,rawset +local mod,div=math.mod,math.div utilities=utilities or {} local parsers=utilities.parsers or {} utilities.parsers=parsers @@ -5687,13 +6443,34 @@ function parsers.settings_to_array(str,strict) elseif not str or str=="" then return {} elseif strict then - if find(str,"{") then + if find(str,"{",1,true) then return lpegmatch(pattern,str) else return { str } end - else + elseif find(str,",",1,true) then return lpegmatch(pattern,str) + else + return { str } + end +end +local separator=space^0*comma*space^0 +local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(comma+P(-1)))))^0) +local withvalue=Carg(1)*value/function(f,s) return f(s) end +local pattern_a=spaces*Ct(value*(separator*value)^0) +local pattern_b=spaces*withvalue*(separator*withvalue)^0 +function parsers.stripped_settings_to_array(str) + if not str or str=="" then + return {} + else + return lpegmatch(pattern_a,str) + end +end +function parsers.process_stripped_settings(str,action) + if not str or str=="" then + return {} + else + return lpegmatch(pattern_b,str,1,action) end end local function set(t,v) @@ -5760,6 +6537,12 @@ function parsers.simple_hash_to_string(h,separator) end return concat(t,separator or ",") end +local str=C((1-whitespace-equal)^1) +local setting=Cf(Carg(1)*(whitespace^0*Cg(str*whitespace^0*(equal*whitespace^0*str+Cc(""))))^1,rawset) +local splitter=setting^1 +function utilities.parsers.options_to_hash(str,target) + return str and lpegmatch(splitter,str,1,target or {}) or {} +end local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C(digit^1*lparent*(noparent+nestedparents)^1*rparent)+C((nestedbraces+(1-comma))^1) local pattern_a=spaces*Ct(value*(separator*value)^0) local function repeater(n,str) @@ -5864,7 +6647,7 @@ function parsers.csvsplitter(specification) end whatever=quotedata+whatever end - local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r"))^0 ) + local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) return function(data) return lpegmatch(parser,data) end @@ -5878,8 +6661,8 @@ function parsers.rfc4180splitter(specification) local separator=S(separator~="" and separator or ",") local escaped=quotechar*Cs((dquotechar+(1-quotechar))^0)*quotechar local non_escaped=C((1-quotechar-newline-separator)^1) - local field=escaped+non_escaped - local record=Ct((field*separator^-1)^1) + local field=escaped+non_escaped+Cc("") + local record=Ct(field*(separator*field)^1) local headerline=record*Cp() local wholeblob=Ct((newline^-1*record)^0) return function(data,getheader) @@ -5972,7 +6755,7 @@ end local function fetch(t,name) return t[name] or {} end -function process(result,more) +local function process(result,more) for k,v in next,more do result[k]=v end @@ -5984,6 +6767,18 @@ local merge=Cf(parser,process) function utilities.parsers.mergehashes(hash,list) return lpegmatch(merge,list,1,hash) end +function utilities.parsers.runtime(time) + if not time then + time=os.runtime() + end + local days=div(time,24*60*60) + time=mod(time,24*60*60) + local hours=div(time,60*60) + time=mod(time,60*60) + local minutes=div(time,60) + local seconds=mod(time,60) + return days,hours,minutes,seconds +end end -- of closure @@ -6385,7 +7180,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-log"] = package.loaded["trac-log"] or true --- original size: 21914, stripped down to: 14287 +-- original size: 25607, stripped down to: 16617 if not modules then modules={} end modules ['trac-log']={ version=1.001, @@ -6398,11 +7193,11 @@ local write_nl,write=texio and texio.write_nl or print,texio and texio.write or local format,gmatch,find=string.format,string.gmatch,string.find local concat,insert,remove=table.concat,table.insert,table.remove local topattern=string.topattern -local texcount=tex and tex.count local next,type,select=next,type,select local utfchar=utf.char local setmetatableindex=table.setmetatableindex local formatters=string.formatters +local texgetcount=tex and tex.getcount logs=logs or {} local logs=logs local moreinfo=[[ @@ -6423,7 +7218,7 @@ utilities.strings.formatters.add ( local function ignore() end setmetatableindex(logs,function(t,k) t[k]=ignore;return ignore end) local report,subreport,status,settarget,setformats,settranslations -local direct,subdirect,writer,pushtarget,poptarget +local direct,subdirect,writer,pushtarget,poptarget,setlogfile,settimedlog,setprocessor,setformatters if tex and (tex.jobname or tex.formatname) then local valueiskey={ __index=function(t,k) t[k]=k return k end } local target="term and log" @@ -6436,67 +7231,67 @@ if tex and (tex.jobname or tex.formatname) then newline=function() write_nl(target,"\n") end - local f_one=formatters["%-15s > %s\n"] - local f_two=formatters["%-15s >\n"] + local report_yes=formatters["%-15s > %s\n"] + local report_nop=formatters["%-15s >\n"] report=function(a,b,c,...) if c then - write_nl(target,f_one(translations[a],formatters[formats[b]](c,...))) + write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) elseif b then - write_nl(target,f_one(translations[a],formats[b])) + write_nl(target,report_yes(translations[a],formats[b])) elseif a then - write_nl(target,f_two(translations[a])) + write_nl(target,report_nop(translations[a])) else write_nl(target,"\n") end end - local f_one=formatters["%-15s > %s"] - local f_two=formatters["%-15s >"] + local direct_yes=formatters["%-15s > %s"] + local direct_nop=formatters["%-15s >"] direct=function(a,b,c,...) if c then - return f_one(translations[a],formatters[formats[b]](c,...)) + return direct_yes(translations[a],formatters[formats[b]](c,...)) elseif b then - return f_one(translations[a],formats[b]) + return direct_yes(translations[a],formats[b]) elseif a then - return f_two(translations[a]) + return direct_nop(translations[a]) else return "" end end - local f_one=formatters["%-15s > %s > %s\n"] - local f_two=formatters["%-15s > %s >\n"] + local subreport_yes=formatters["%-15s > %s > %s\n"] + local subreport_nop=formatters["%-15s > %s >\n"] subreport=function(a,s,b,c,...) if c then - write_nl(target,f_one(translations[a],translations[s],formatters[formats[b]](c,...))) + write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) elseif b then - write_nl(target,f_one(translations[a],translations[s],formats[b])) + write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) elseif a then - write_nl(target,f_two(translations[a],translations[s])) + write_nl(target,subreport_nop(translations[a],translations[s])) else write_nl(target,"\n") end end - local f_one=formatters["%-15s > %s > %s"] - local f_two=formatters["%-15s > %s >"] + local subdirect_yes=formatters["%-15s > %s > %s"] + local subdirect_nop=formatters["%-15s > %s >"] subdirect=function(a,s,b,c,...) if c then - return f_one(translations[a],translations[s],formatters[formats[b]](c,...)) + return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) elseif b then - return f_one(translations[a],translations[s],formats[b]) + return subdirect_yes(translations[a],translations[s],formats[b]) elseif a then - return f_two(translations[a],translations[s]) + return subdirect_nop(translations[a],translations[s]) else return "" end end - local f_one=formatters["%-15s : %s\n"] - local f_two=formatters["%-15s :\n"] + local status_yes=formatters["%-15s : %s\n"] + local status_nop=formatters["%-15s :\n"] status=function(a,b,c,...) if c then - write_nl(target,f_one(translations[a],formatters[formats[b]](c,...))) + write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) elseif b then - write_nl(target,f_one(translations[a],formats[b])) + write_nl(target,status_yes(translations[a],formats[b])) elseif a then - write_nl(target,f_two(translations[a])) + write_nl(target,status_nop(translations[a])) else write_nl(target,"\n") end @@ -6533,47 +7328,69 @@ if tex and (tex.jobname or tex.formatname) then settranslations=function(t) translations=t end + setprocessor=function(f) + local writeline=write_nl + write_nl=function(target,...) + writeline(target,f(...)) + end + end + setformatters=function(f) + report_yes=f.report_yes or report_yes + report_nop=f.report_nop or report_nop + subreport_yes=f.subreport_yes or subreport_yes + subreport_nop=f.subreport_nop or subreport_nop + direct_yes=f.direct_yes or direct_yes + direct_nop=f.direct_nop or direct_nop + subdirect_yes=f.subdirect_yes or subdirect_yes + subdirect_nop=f.subdirect_nop or subdirect_nop + status_yes=f.status_yes or status_yes + status_nop=f.status_nop or status_nop + end + setlogfile=ignore + settimedlog=ignore else logs.flush=ignore - writer=write_nl + writer=function(s) + write_nl(s) + end newline=function() write_nl("\n") end - local f_one=formatters["%-15s | %s"] - local f_two=formatters["%-15s |"] + local report_yes=formatters["%-15s | %s"] + local report_nop=formatters["%-15s |"] report=function(a,b,c,...) if c then - write_nl(f_one(a,formatters[b](c,...))) + write_nl(report_yes(a,formatters[b](c,...))) elseif b then - write_nl(f_one(a,b)) + write_nl(report_yes(a,b)) elseif a then - write_nl(f_two(a)) + write_nl(report_nop(a)) else write_nl("") end end - local f_one=formatters["%-15s | %s | %s"] - local f_two=formatters["%-15s | %s |"] + local subreport_yes=formatters["%-15s | %s | %s"] + local subreport_nop=formatters["%-15s | %s |"] subreport=function(a,sub,b,c,...) if c then - write_nl(f_one(a,sub,formatters[b](c,...))) + write_nl(subreport_yes(a,sub,formatters[b](c,...))) elseif b then - write_nl(f_one(a,sub,b)) + write_nl(subreport_yes(a,sub,b)) elseif a then - write_nl(f_two(a,sub)) + write_nl(subreport_nop(a,sub)) else write_nl("") end end - local f_one=formatters["%-15s : %s\n"] - local f_two=formatters["%-15s :\n"] + local status_yes=formatters["%-15s : %s\n"] + local status_nop=formatters["%-15s :\n"] status=function(a,b,c,...) if c then - write_nl(f_one(a,formatters[b](c,...))) + write_nl(status_yes(a,formatters[b](c,...))) elseif b then - write_nl(f_one(a,b)) + write_nl(status_yes(a,b)) elseif a then - write_nl(f_two(a)) + write_nl(status_nop(a)) else write_nl("\n") end @@ -6585,6 +7402,49 @@ else poptarget=ignore setformats=ignore settranslations=ignore + setprocessor=function(f) + local writeline=write_nl + write_nl=function(s) + writeline(f(s)) + end + end + setformatters=function(f) + report_yes=f.report_yes or report_yes + report_nop=f.report_nop or report_nop + subreport_yes=f.subreport_yes or subreport_yes + subreport_nop=f.subreport_nop or subreport_nop + status_yes=f.status_yes or status_yes + status_nop=f.status_nop or status_nop + end + setlogfile=function(name,keepopen) + if name and name~="" then + local localtime=os.localtime + local writeline=write_nl + if keepopen then + local f=io.open(name,"ab") + write_nl=function(s) + writeline(s) + f:write(localtime()," | ",s,"\n") + end + else + write_nl=function(s) + writeline(s) + local f=io.open(name,"ab") + f:write(localtime()," | ",s,"\n") + f:close() + end + end + end + setlogfile=ignore + end + settimedlog=function() + local localtime=os.localtime + local writeline=write_nl + write_nl=function(s) + writeline(localtime().." | "..s) + end + settimedlog=ignore + end end logs.report=report logs.subreport=subreport @@ -6594,6 +7454,10 @@ logs.pushtarget=pushtarget logs.poptarget=poptarget logs.setformats=setformats logs.settranslations=settranslations +logs.setlogfile=setlogfile +logs.settimedlog=settimedlog +logs.setprocessor=setprocessor +logs.setformatters=setformatters logs.direct=direct logs.subdirect=subdirect logs.writer=writer @@ -6670,9 +7534,10 @@ local function setblocked(category,value) v.state=value end else - states=utilities.parsers.settings_to_hash(category) + states=utilities.parsers.settings_to_hash(category,type(states)=="table" and states or nil) for c,_ in next,states do - if data[c] then + local v=data[c] + if v then v.state=value else c=topattern(c,true,true) @@ -6744,7 +7609,9 @@ end) local report_pages=logs.reporter("pages") local real,user,sub function logs.start_page_number() - real,user,sub=texcount.realpageno,texcount.userpageno,texcount.subpageno + real=texgetcount("realpageno") + user=texgetcount("userpageno") + sub=texgetcount("subpageno") end local timing=false local starttime=nil @@ -6949,7 +7816,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 5678, stripped down to: 4448 +-- original size: 7011, stripped down to: 5590 if not modules then modules={} end modules ['trac-inf']={ version=1.001, @@ -6958,16 +7825,19 @@ if not modules then modules={} end modules ['trac-inf']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local type,tonumber=type,tonumber -local format,lower=string.format,string.lower +local type,tonumber,select=type,tonumber,select +local format,lower,find=string.format,string.lower,string.find local concat=table.concat local clock=os.gettimeofday or os.clock +local setmetatableindex=table.setmetatableindex +local serialize=table.serialize +local formatters=string.formatters statistics=statistics or {} local statistics=statistics statistics.enable=true statistics.threshold=0.01 local statusinfo,n,registered,timers={},0,{},{} -table.setmetatableindex(timers,function(t,k) +setmetatableindex(timers,function(t,k) local v={ timing=0,loadtime=0 } t[k]=v return v @@ -7046,6 +7916,10 @@ local report=logs.reporter("mkiv lua stats") function statistics.show() if statistics.enable then local register=statistics.register + register("used platform",function() + return format("%s, type: %s, binary subtree: %s", + os.platform or "unknown",os.type or "unknown",environment.texos or "unknown") + end) register("luatex banner",function() return lower(status.banner) end) @@ -7057,14 +7931,23 @@ function statistics.show() return format("%s direct, %s indirect, %s total",total-indirect,indirect,total) end) if jit then - local status={ jit.status() } - if status[1] then - register("luajit status",function() - return concat(status," ",2) - end) - end - end - register("current memory usage",statistics.memused) + local jitstatus={ jit.status() } + if jitstatus[1] then + register("luajit options",concat(jitstatus," ",2)) + end + end + register("lua properties",function() + local list=status.list() + local hashchar=tonumber(list.luatex_hashchars) + local mask=lua.mask or "ascii" + return format("engine: %s, used memory: %s, hash type: %s, hash chars: min(%s,40), symbol mask: %s (%s)", + jit and "luajit" or "lua", + statistics.memused(), + list.luatex_hashtype or "default", + hashchar and 2^hashchar or "unknown", + mask, + mask=="utf" and "τεχ" or "tex") + end) register("runtime",statistics.runtime) logs.newline() for i=1,#statusinfo do @@ -7094,7 +7977,17 @@ function statistics.timed(action) starttiming("run") action() stoptiming("run") - report("total runtime: %s",elapsedtime("run")) + report("total runtime: %s seconds",elapsedtime("run")) +end +function statistics.tracefunction(base,tag,...) + for i=1,select("#",...) do + local name=select(i,...) + local stat={} + local func=base[name] + setmetatableindex(stat,function(t,k) t[k]=0 return 0 end) + base[name]=function(n,k,v) stat[k]=stat[k]+1 return func(n,k,v) end + statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end) + end end commands=commands or {} function commands.resettimer(name) @@ -7113,7 +8006,7 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-pro"] = package.loaded["trac-pro"] or true --- original size: 5773, stripped down to: 3453 +-- original size: 5829, stripped down to: 3501 if not modules then modules={} end modules ['trac-pro']={ version=1.001, @@ -7130,14 +8023,16 @@ local namespaces=namespaces local registered={} local function report_index(k,name) if trace_namespaces then - report_system("reference to %a in protected namespace %a: %s",k,name,debug.traceback()) + report_system("reference to %a in protected namespace %a: %s",k,name) + debugger.showtraceback(report_system) else report_system("reference to %a in protected namespace %a",k,name) end end local function report_newindex(k,name) if trace_namespaces then - report_system("assignment to %a in protected namespace %a: %s",k,name,debug.traceback()) + report_system("assignment to %a in protected namespace %a: %s",k,name) + debugger.showtraceback(report_system) else report_system("assignment to %a in protected namespace %a",k,name) end @@ -7258,7 +8153,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lua"] = package.loaded["util-lua"] or true --- original size: 12575, stripped down to: 8700 +-- original size: 4982, stripped down to: 3511 if not modules then modules={} end modules ['util-lua']={ version=1.001, @@ -7293,251 +8188,92 @@ luautilities.suffixes={ tua="tua", tuc="tuc", } -if jit or status.luatex_version>=74 then - local function register(name) - if tracestripping then - report_lua("stripped bytecode from %a",name or "unknown") - end - strippedchunks[#strippedchunks+1]=name - luautilities.nofstrippedchunks=luautilities.nofstrippedchunks+1 - end - local function stupidcompile(luafile,lucfile,strip) - local code=io.loaddata(luafile) - if code and code~="" then - code=load(code) - if code then - code=dump(code,strip and luautilities.stripcode or luautilities.alwaysstripcode) - if code and code~="" then - register(name) - io.savedata(lucfile,code) - return true,0 - end - else - report_lua("fatal error %a in file %a",1,luafile) - end - else - report_lua("fatal error %a in file %a",2,luafile) - end - return false,0 +local function register(name) + if tracestripping then + report_lua("stripped bytecode from %a",name or "unknown") end - function luautilities.loadedluacode(fullname,forcestrip,name) - name=name or fullname - local code=environment.loadpreprocessedfile and environment.loadpreprocessedfile(fullname) or loadfile(fullname) + strippedchunks[#strippedchunks+1]=name + luautilities.nofstrippedchunks=luautilities.nofstrippedchunks+1 +end +local function stupidcompile(luafile,lucfile,strip) + local code=io.loaddata(luafile) + if code and code~="" then + code=load(code) if code then - code() - end - if forcestrip and luautilities.stripcode then - if type(forcestrip)=="function" then - forcestrip=forcestrip(fullname) - end - if forcestrip or luautilities.alwaysstripcode then + code=dump(code,strip and luautilities.stripcode or luautilities.alwaysstripcode) + if code and code~="" then register(name) - return load(dump(code,true)),0 - else - return code,0 + io.savedata(lucfile,code) + return true,0 end - elseif luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 else - return code,0 - end - end - function luautilities.strippedloadstring(code,forcestrip,name) - if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then - code=load(code) - if not code then - report_lua("fatal error %a in file %a",3,name) - end - register(name) - code=dump(code,true) - end - return load(code),0 - end - function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) - report_lua("compiling %a into %a",luafile,lucfile) - os.remove(lucfile) - local done=stupidcompile(luafile,lucfile,strip~=false) - if done then - report_lua("dumping %a into %a stripped",luafile,lucfile) - if cleanup==true and lfs.isfile(lucfile) and lfs.isfile(luafile) then - report_lua("removing %a",luafile) - os.remove(luafile) - end + report_lua("fatal error %a in file %a",1,luafile) end - return done + else + report_lua("fatal error %a in file %a",2,luafile) end - function luautilities.loadstripped(...) - local l=load(...) - if l then - return load(dump(l,true)) - end + return false,0 +end +function luautilities.loadedluacode(fullname,forcestrip,name) + name=name or fullname + local code,message + if environment.loadpreprocessedfile then + code,message=environment.loadpreprocessedfile(fullname) + else + code,message=loadfile(fullname) end -else - local function register(name,before,after) - local delta=before-after - if tracestripping then - report_lua("bytecodes stripped from %a, # before %s, # after %s, delta %s",name,before,after,delta) - end - strippedchunks[#strippedchunks+1]=name - luautilities.nofstrippedchunks=luautilities.nofstrippedchunks+1 - luautilities.nofstrippedbytes=luautilities.nofstrippedbytes+delta - return delta - end - local strip_code_pc - if _MAJORVERSION==5 and _MINORVERSION==1 then - strip_code_pc=function(dump,name) - local before=#dump - local version,format,endian,int,size,ins,num=byte(dump,5,11) - local subint - if endian==1 then - subint=function(dump,i,l) - local val=0 - for n=l,1,-1 do - val=val*256+byte(dump,i+n-1) - end - return val,i+l - end - else - subint=function(dump,i,l) - local val=0 - for n=1,l,1 do - val=val*256+byte(dump,i+n-1) - end - return val,i+l - end - end - local strip_function - strip_function=function(dump) - local count,offset=subint(dump,1,size) - local stripped,dirty=rep("\0",size),offset+count - offset=offset+count+int*2+4 - offset=offset+int+subint(dump,offset,int)*ins - count,offset=subint(dump,offset,int) - for n=1,count do - local t - t,offset=subint(dump,offset,1) - if t==1 then - offset=offset+1 - elseif t==4 then - offset=offset+size+subint(dump,offset,size) - elseif t==3 then - offset=offset+num - end - end - count,offset=subint(dump,offset,int) - stripped=stripped..sub(dump,dirty,offset-1) - for n=1,count do - local proto,off=strip_function(sub(dump,offset,-1)) - stripped,offset=stripped..proto,offset+off-1 - end - offset=offset+subint(dump,offset,int)*int+int - count,offset=subint(dump,offset,int) - for n=1,count do - offset=offset+subint(dump,offset,size)+size+int*2 - end - count,offset=subint(dump,offset,int) - for n=1,count do - offset=offset+subint(dump,offset,size)+size - end - stripped=stripped..rep("\0",int*3) - return stripped,offset - end - dump=sub(dump,1,12)..strip_function(sub(dump,13,-1)) - local after=#dump - local delta=register(name,before,after) - return dump,delta - end + if code then + code() else - strip_code_pc=function(dump,name) - return dump,0 - end + report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") end - function luautilities.loadedluacode(fullname,forcestrip,name) - local code=environment.loadpreprocessedfile and environment.preprocessedloadfile(fullname) or loadfile(fullname) - if code then - code() + if forcestrip and luautilities.stripcode then + if type(forcestrip)=="function" then + forcestrip=forcestrip(fullname) end - if forcestrip and luautilities.stripcode then - if type(forcestrip)=="function" then - forcestrip=forcestrip(fullname) - end - if forcestrip then - local code,n=strip_code_pc(dump(code),name) - return load(code),n - elseif luautilities.alwaysstripcode then - return load(strip_code_pc(dump(code),name)) - else - return code,0 - end - elseif luautilities.alwaysstripcode then - return load(strip_code_pc(dump(code),name)) + if forcestrip or luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 else return code,0 end + elseif luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 + else + return code,0 end - function luautilities.strippedloadstring(code,forcestrip,name) - local n=0 - if (forcestrip and luautilities.stripcode) or luautilities.alwaysstripcode then - code=load(code) - if not code then - report_lua("fatal error in file %a",name) - end - code,n=strip_code_pc(dump(code),name) - end - return load(code),n +end +function luautilities.strippedloadstring(code,forcestrip,name) + local code,message=load(code) + if not code then + report_lua("loading of file %a failed:\n\t%s",name,message or "no message") end - local function stupidcompile(luafile,lucfile,strip) - local code=io.loaddata(luafile) - local n=0 - if code and code~="" then - code=load(code) - if not code then - report_lua("fatal error in file %a",luafile) - end - code=dump(code) - if strip then - code,n=strip_code_pc(code,luautilities.stripcode or luautilities.alwaysstripcode,luafile) - end - if code and code~="" then - io.savedata(lucfile,code) - end - end - return n + if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 + else + return code,0 end - local luac_normal="texluac -o %q %q" - local luac_strip="texluac -s -o %q %q" - function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) - report_lua("compiling %a into %a",luafile,lucfile) - os.remove(lucfile) - local done=false - if strip~=false then - strip=true - end - if forcestupidcompile then - fallback=true - elseif strip then - done=os.spawn(format(luac_strip,lucfile,luafile))==0 - else - done=os.spawn(format(luac_normal,lucfile,luafile))==0 - end - if not done and fallback then - local n=stupidcompile(luafile,lucfile,strip) - if n>0 then - report_lua("%a dumped into %a (%i bytes stripped)",luafile,lucfile,n) - else - report_lua("%a dumped into %a (unstripped)",luafile,lucfile) - end - cleanup=false - done=true - end - if done and cleanup==true and lfs.isfile(lucfile) and lfs.isfile(luafile) then +end +function luautilities.compile(luafile,lucfile,cleanup,strip,fallback) + report_lua("compiling %a into %a",luafile,lucfile) + os.remove(lucfile) + local done=stupidcompile(luafile,lucfile,strip~=false) + if done then + report_lua("dumping %a into %a stripped",luafile,lucfile) + if cleanup==true and lfs.isfile(lucfile) and lfs.isfile(luafile) then report_lua("removing %a",luafile) os.remove(luafile) end - return done end - luautilities.loadstripped=loadstring + return done +end +function luautilities.loadstripped(...) + local l=load(...) + if l then + return load(dump(l,true)) + end end @@ -7547,7 +8283,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-deb"] = package.loaded["util-deb"] or true --- original size: 3708, stripped down to: 2568 +-- original size: 3898, stripped down to: 2644 if not modules then modules={} end modules ['util-deb']={ version=1.001, @@ -7627,20 +8363,22 @@ end function debugger.disable() debug.sethook() end -function traceback() - local level=1 +local function showtraceback(rep) + local level=2 + local reporter=rep or report while true do - local info=debug.getinfo(level,"Sl") + local info=getinfo(level,"Sl") if not info then break elseif info.what=="C" then - print(format("%3i : C function",level)) + reporter("%2i : %s",level-1,"C function") else - print(format("%3i : [%s]:%d",level,info.short_src,info.currentline)) + reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) end level=level+1 end end +debugger.showtraceback=showtraceback end -- of closure @@ -7826,7 +8564,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tpl"] = package.loaded["util-tpl"] or true --- original size: 5655, stripped down to: 3242 +-- original size: 6251, stripped down to: 3488 if not modules then modules={} end modules ['util-tpl']={ version=1.001, @@ -7840,8 +8578,8 @@ local templates=utilities.templates local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) local report_template=logs.reporter("template") local tostring=tostring -local format,sub=string.format,string.sub -local P,C,Cs,Carg,lpegmatch=lpeg.P,lpeg.C,lpeg.Cs,lpeg.Carg,lpeg.match +local format,sub,byte=string.format,string.sub,string.byte +local P,C,R,Cs,Cc,Carg,lpegmatch,lpegpatterns=lpeg.P,lpeg.C,lpeg.R,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.match,lpeg.patterns local replacer local function replacekey(k,t,how,recursive) local v=t[k] @@ -7868,10 +8606,13 @@ local sqlescape=lpeg.replacer { { "\r\n","\\n" }, { "\r","\\n" }, } -local sqlquotedescape=lpeg.Cs(lpeg.Cc("'")*sqlescape*lpeg.Cc("'")) +local sqlquoted=lpeg.Cs(lpeg.Cc("'")*sqlescape*lpeg.Cc("'")) +lpegpatterns.sqlescape=sqlescape +lpegpatterns.sqlquoted=sqlquoted +local luaescape=lpegpatterns.luaescape local escapers={ lua=function(s) - return sub(format("%q",s),2,-2) + return lpegmatch(luaescape,s) end, sql=function(s) return lpegmatch(sqlescape,s) @@ -7882,11 +8623,9 @@ local quotedescapers={ return format("%q",s) end, sql=function(s) - return lpegmatch(sqlquotedescape,s) + return lpegmatch(sqlquoted,s) end, } -lpeg.patterns.sqlescape=sqlescape -lpeg.patterns.sqlescape=sqlquotedescape local luaescaper=escapers.lua local quotedluaescaper=quotedescapers.lua local function replacekeyunquoted(s,t,how,recurse) @@ -7923,6 +8662,11 @@ local function replace(str,mapping,how,recurse) end end templates.replace=replace +function templates.replacer(str,how,recurse) + return function(mapping) + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + end +end function templates.load(filename,mapping,how,recurse) local data=io.loaddata(filename) or "" if mapping and next(mapping) then @@ -7948,7 +8692,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 8722, stripped down to: 5050 +-- original size: 8814, stripped down to: 5092 if not modules then modules={} end modules ['util-env']={ version=1.001, @@ -7984,6 +8728,7 @@ local luaengines=allocate { environment.validengines=validengines environment.basicengines=basicengines if not arg then + environment.used_as_library=true elseif luaengines[file.removesuffix(arg[-1])] then elseif validengines[file.removesuffix(arg[0])] then if arg[1]=="--luaonly" then @@ -8084,7 +8829,7 @@ function environment.reconstructcommandline(arg,noquote) a=resolvers.resolve(a) a=unquoted(a) a=gsub(a,'"','\\"') - if find(a," ") then + if find(a," ",1,true) then result[#result+1]=quoted(a) else result[#result+1]=a @@ -8144,7 +8889,7 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-env"] = package.loaded["luat-env"] or true --- original size: 5874, stripped down to: 4184 +-- original size: 6174, stripped down to: 4141 if not modules then modules={} end modules ['luat-env']={ version=1.001, @@ -8158,12 +8903,13 @@ local trace_locating=false trackers.register("resolvers.locating",function(v) tr local report_lua=logs.reporter("resolvers","lua") local luautilities=utilities.lua local luasuffixes=luautilities.suffixes +local texgettoks=tex and tex.gettoks environment=environment or {} local environment=environment local mt={ __index=function(_,k) if k=="version" then - local version=tex.toks and tex.toks.contextversiontoks + local version=texgettoks and texgettoks("contextversiontoks") if version and version~="" then rawset(environment,"version",version) return version @@ -8171,7 +8917,7 @@ local mt={ return "unknown" end elseif k=="kind" then - local kind=tex.toks and tex.toks.contextkindtoks + local kind=texgettoks and texgettoks("contextkindtoks") if kind and kind~="" then rawset(environment,"kind",kind) return kind @@ -8221,15 +8967,13 @@ function environment.luafilechunk(filename,silent) filename=file.replacesuffix(filename,"lua") local fullname=environment.luafile(filename) if fullname and fullname~="" then - local data=luautilities.loadedluacode(fullname,strippable,filename) - if trace_locating then + local data=luautilities.loadedluacode(fullname,strippable,filename) + if not silent then report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") - elseif not silent then - texio.write("<",data and "+ " or "- ",fullname,">") end return data else - if trace_locating then + if not silent then report_lua("unknown file %a",filename) end return nil @@ -8298,7 +9042,7 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true --- original size: 42495, stripped down to: 26647 +-- original size: 42614, stripped down to: 26694 if not modules then modules={} end modules ['lxml-tab']={ version=1.001, @@ -8309,6 +9053,7 @@ if not modules then modules={} end modules ['lxml-tab']={ } local trace_entities=false trackers.register("xml.entities",function(v) trace_entities=v end) local report_xml=logs and logs.reporter("xml","core") or function(...) print(string.format(...)) end +if lpeg.setmaxstack then lpeg.setmaxstack(1000) end xml=xml or {} local xml=xml local concat,remove,insert=table.concat,table.remove,table.insert @@ -8728,7 +9473,6 @@ local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace* local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset local simpledoctype=(1-close)^1 local somedoctype=C((somespace*(publicdoctype+systemdoctype+definitiondoctype+simpledoctype)*optionalspace)^0) -local somedoctype=C((somespace*(publicdoctype+systemdoctype+definitiondoctype+simpledoctype)*optionalspace)^0) local instruction=(spacing*begininstruction*someinstruction*endinstruction)/function(...) add_special("@pi@",...) end local comment=(spacing*begincomment*somecomment*endcomment )/function(...) add_special("@cm@",...) end local cdata=(spacing*begincdata*somecdata*endcdata )/function(...) add_special("@cd@",...) end @@ -8824,8 +9568,11 @@ local function _xmlconvert_(data,settings) end if errorstr and errorstr~="" then result.error=true + else + errorstr=nil end result.statistics={ + errormessage=errorstr, entities={ decimals=dcache, hexadecimals=hcache, @@ -9023,23 +9770,25 @@ local function verbose_document(e,handlers) end end local function serialize(e,handlers,...) - local initialize=handlers.initialize - local finalize=handlers.finalize - local functions=handlers.functions - if initialize then - local state=initialize(...) - if not state==true then - return state + if e then + local initialize=handlers.initialize + local finalize=handlers.finalize + local functions=handlers.functions + if initialize then + local state=initialize(...) + if not state==true then + return state + end + end + local etg=e.tg + if etg then + (functions[etg] or functions["@el@"])(e,handlers) + else + functions["@dc@"](e,handlers) + end + if finalize then + return finalize() end - end - local etg=e.tg - if etg then - (functions[etg] or functions["@el@"])(e,handlers) - else - functions["@dc@"](e,handlers) - end - if finalize then - return finalize() end end local function xserialize(e,handlers) @@ -9280,7 +10029,7 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true --- original size: 48956, stripped down to: 30516 +-- original size: 48030, stripped down to: 30595 if not modules then modules={} end modules ['lxml-lpt']={ version=1.001, @@ -10261,8 +11010,13 @@ function xml.elements(root,pattern,reverse) local collected=applylpath(root,pattern) if not collected then return dummy - elseif reverse then - local c=#collected+1 + end + local n=#collected + if n==0 then + return dummy + end + if reverse then + local c=n+1 return function() if c>1 then c=c-1 @@ -10272,7 +11026,7 @@ function xml.elements(root,pattern,reverse) end end else - local n,c=#collected,0 + local c=0 return function() if c<n then c=c+1 @@ -10287,8 +11041,13 @@ function xml.collected(root,pattern,reverse) local collected=applylpath(root,pattern) if not collected then return dummy - elseif reverse then - local c=#collected+1 + end + local n=#collected + if n==0 then + return dummy + end + if reverse then + local c=n+1 return function() if c>1 then c=c-1 @@ -10296,7 +11055,7 @@ function xml.collected(root,pattern,reverse) end end else - local n,c=#collected,0 + local c=0 return function() if c<n then c=c+1 @@ -10311,7 +11070,7 @@ function xml.inspect(collection,pattern) report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) end end -local function split(e) +local function split(e) local dt=e.dt if dt then for i=1,#dt do @@ -11651,7 +12410,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 7898, stripped down to: 5501 +-- original size: 7927, stripped down to: 5528 if not modules then modules={} end modules ['data-ini']={ version=1.001, @@ -11795,7 +12554,7 @@ if not texroot or texroot=="" then ossetenv('TEXROOT',texroot) end environment.texroot=file.collapsepath(texroot) -if profiler then +if type(profiler)=="table" and not jit then directives.register("system.profile",function() profiler.start("luatex-profile.log") end) @@ -11813,7 +12572,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 14654, stripped down to: 9517 +-- original size: 15317, stripped down to: 9723 if not modules then modules={} end modules ['data-exp']={ version=1.001, @@ -11825,7 +12584,7 @@ if not modules then modules={} end modules ['data-exp']={ 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 +local Ct,Cs,Cc,Carg,P,C,S=lpeg.Ct,lpeg.Cs,lpeg.Cc,lpeg.Carg,lpeg.P,lpeg.C,lpeg.S local type,next=type,next local ostype=os.type local collapsepath=file.collapsepath @@ -11833,20 +12592,6 @@ local trace_locating=false trackers.register("resolvers.locating",function(v) tr local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_expansions=logs.reporter("resolvers","expansions") local resolvers=resolvers -local function f_first(a,b) - local t,n={},0 - for s in gmatch(b,"[^,]+") do - n=n+1;t[n]=a..s - end - return concat(t,",") -end -local function f_second(a,b) - local t,n={},0 - for s in gmatch(a,"[^,]+") do - n=n+1;t[n]=s..b - end - return concat(t,",") -end local function f_both(a,b) local t,n={},0 for sb in gmatch(b,"[^,]+") do @@ -11856,6 +12601,15 @@ local function f_both(a,b) end return concat(t,",") end +local comma=P(",") +local nocomma=(1-comma)^1 +local docomma=comma^1/"," +local before=Cs((nocomma*Carg(1)+docomma)^0) +local after=Cs((Carg(1)*nocomma+docomma)^0) +local both=Cs(((C(nocomma)*Carg(1))/function(a,b) return lpegmatch(before,b,1,a) end+docomma)^0) +local function f_first (a,b) return lpegmatch(after,b,1,a) end +local function f_second(a,b) return lpegmatch(before,a,1,b) end +local function f_both (a,b) return lpegmatch(both,b,1,a) end local left=P("{") local right=P("}") local var=P((1-S("{}" ))^0) @@ -11940,7 +12694,7 @@ function resolvers.cleanpath(str) report_expansions("no home dir set, ignoring dependent paths") end function resolvers.cleanpath(str) - if not str or find(str,"~") then + if not str or find(str,"~",1,true) then return "" else return lpegmatch(cleanup,str) @@ -12175,7 +12929,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-env"] = package.loaded["data-env"] or true --- original size: 8762, stripped down to: 6484 +-- original size: 8769, stripped down to: 6490 if not modules then modules={} end modules ['data-env']={ version=1.001, @@ -12278,7 +13032,7 @@ local relations=allocate { texmfscripts={ names={ "texmfscript","texmfscripts","script","scripts" }, variable='TEXMFSCRIPTS', - suffixes={ 'rb','pl','py' }, + suffixes={ 'lua','rb','pl','py' }, }, lua={ names={ "lua" }, @@ -12443,7 +13197,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 14615, stripped down to: 11208 +-- original size: 15532, stripped down to: 11648 if not modules then modules={} end modules ['data-tmp']={ version=1.100, @@ -12657,6 +13411,22 @@ function caches.getfirstreadablefile(filename,...) end return caches.setfirstwritablefile(filename,...) end +function caches.getfirstreadablefile_TEST_ME_FIRST(filename,...) + local fullname,path=caches.setfirstwritablefile(filename,...) + if is_readable(fullname) then + return fullname,path + end + local rd=getreadablepaths(...) + for i=1,#rd do + local path=rd[i] + local fullname=file.join(path,filename) + if is_readable(fullname) then + usedreadables[i]=true + return fullname,path + end + end + return fullname,path +end function caches.setfirstwritablefile(filename,...) local wr=getwritablepath(...) local fullname=file.join(wr,filename) @@ -12802,7 +13572,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5137, stripped down to: 4007 +-- original size: 5460, stripped down to: 4014 if not modules then modules={} end modules ['data-met']={ version=1.100, @@ -12831,7 +13601,7 @@ local function splitmethod(filename) return filename end filename=file.collapsepath(filename,".") - if not find(filename,"://") then + if not find(filename,"://",1,true) then return { scheme="file",path=filename,original=filename,filename=filename } end local specification=url.hashed(filename) @@ -12921,7 +13691,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 61759, stripped down to: 42959 +-- original size: 61824, stripped down to: 42982 if not modules then modules={} end modules ['data-res']={ version=1.001, @@ -13152,7 +13922,7 @@ local function identify_configuration_files() local realname=resolvers.resolve(filename) if trace_locating then local fullpath=gsub(resolvers.resolve(collapsepath(filepath)),"//","/") - local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c") + local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) report_resolving("looking for %a on %s path %a from specification %a",luacnfname,weirdpath and "weird" or "given",fullpath,filepath) end if lfs.isfile(realname) then @@ -13741,7 +14511,7 @@ local function find_direct(filename,allresults) end end local function find_wildcard(filename,allresults) - if find(filename,'%*') then + if find(filename,'*',1,true) then if trace_locating then report_resolving("checking wildcard %a",filename) end @@ -13887,7 +14657,7 @@ local function find_intree(filename,filetype,wantedfiles,allresults) local scheme=url.hasscheme(pathname) if not scheme or scheme=="file" then local pname=gsub(pathname,"%.%*$",'') - if not find(pname,"%*") then + if not find(pname,"*",1,true) then if can_be_dir(pname) then for k=1,#wantedfiles do local w=wantedfiles[k] @@ -14156,7 +14926,7 @@ local function findwildcardfiles(filename,allresults,result) local path=lower(lpegmatch(makewildcard,dirn) or dirn) local name=lower(lpegmatch(makewildcard,base) or base) local files,done=instance.files,false - if find(name,"%*") then + if find(name,"*",1,true) then local hashes=instance.hashes for k=1,#hashes do local hash=hashes[k] @@ -14175,7 +14945,7 @@ local function findwildcardfiles(filename,allresults,result) for k=1,#hashes do local hash=hashes[k] local hashname,hashtype=hash.name,hash.type - if doit(path,files[hashname][bname],bname,hashname,hashtype,result,allresults) then done=true end + if doit(path,files[hashname][base],base,hashname,hashtype,result,allresults) then done=true end if done and not allresults then break end end end @@ -14799,7 +15569,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-use"] = package.loaded["data-use"] or true --- original size: 3913, stripped down to: 2998 +-- original size: 3899, stripped down to: 2984 if not modules then modules={} end modules ['data-use']={ version=1.001, @@ -14845,7 +15615,7 @@ end statistics.register("used config file",function() return caches.configfiles() end) statistics.register("used cache path",function() return caches.usedpaths() end) function statistics.savefmtstatus(texname,formatbanner,sourcefile) - local enginebanner=status.list().banner + local enginebanner=status.banner if formatbanner and enginebanner and sourcefile then local luvname=file.replacesuffix(texname,"luv") local luvdata={ @@ -14858,7 +15628,7 @@ function statistics.savefmtstatus(texname,formatbanner,sourcefile) end end function statistics.checkfmtstatus(texname) - local enginebanner=status.list().banner + local enginebanner=status.banner if enginebanner and texname then local luvname=file.replacesuffix(texname,"luv") if lfs.isfile(luvname) then @@ -15199,7 +15969,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-sch"] = package.loaded["data-sch"] or true --- original size: 6202, stripped down to: 5149 +-- original size: 6213, stripped down to: 5160 if not modules then modules={} end modules ['data-sch']={ version=1.001, @@ -15242,7 +16012,7 @@ function resolvers.schemes.cleanname(specification) end local cached,loaded,reused,thresholds,handlers={},{},{},{},{} local function runcurl(name,cachename) - local command="curl --silent --create-dirs --output "..cachename.." "..name + local command="curl --silent --insecure --create-dirs --output "..cachename.." "..name os.spawn(command) end local function fetch(specification) @@ -15482,7 +16252,7 @@ do -- create closure to overcome 200 locals limit package.loaded["data-aux"] = package.loaded["data-aux"] or true --- original size: 2394, stripped down to: 2005 +-- original size: 2431, stripped down to: 1996 if not modules then modules={} end modules ['data-aux']={ version=1.001, @@ -15496,8 +16266,8 @@ local type,next=type,next local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local resolvers=resolvers local report_scripts=logs.reporter("resolvers","scripts") -function resolvers.updatescript(oldname,newname) - local scriptpath="scripts/context/lua" +function resolvers.updatescript(oldname,newname) + local scriptpath="context/lua" newname=file.addsuffix(newname,"lua") local oldscript=resolvers.cleanpath(oldname) if trace_locating then @@ -15682,7 +16452,7 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lib"] = package.loaded["util-lib"] or true --- original size: 11136, stripped down to: 5549 +-- original size: 11549, stripped down to: 5905 if not modules then modules={} end modules ['util-lib']={ version=1.001, @@ -15702,6 +16472,9 @@ local function requireswiglib(required,version) local trace_swiglib=trace_swiglib or package.helpers.trace local library=loaded[required] if library==nil then + if trace_swiglib then + report_swiglib("requiring library %a with version %a",required,version or "any") + end local required_full=gsub(required,"%.","/") local required_path=pathpart(required_full) local required_base=nameonly(required_full) @@ -15808,7 +16581,7 @@ local function requireswiglib(required,version) if libtype=="function" then library=library() else - report_swiglib("load error: %a returns %a, message %a",opener,libtype,message or "no message") + report_swiglib("load error: %a returns %a, message %a, library %a",opener,libtype,(string.gsub(message or "no message","[%s]+$","")),found_library or "no library") library=false end dir.pop() @@ -15833,6 +16606,7 @@ function require(name,version) end end local swiglibs={} +local initializer="core" function swiglib(name,version) local library=swiglibs[name] if not library then @@ -15840,7 +16614,12 @@ function swiglib(name,version) if trace_swiglib then report_swiglib("loading %a",name) end - library=requireswiglib("swiglib."..name,version) + if not find(name,"%."..initializer.."$") then + fullname="swiglib."..name.."."..initializer + else + fullname="swiglib."..name + end + library=requireswiglib(fullname,version) swiglibs[name]=library statistics.stoptiming(swiglibs) end @@ -16096,8 +16875,8 @@ end -- of closure -- used libraries : l-lua.lua l-package.lua l-lpeg.lua l-function.lua l-string.lua l-table.lua l-io.lua l-number.lua l-set.lua l-os.lua l-file.lua l-gzip.lua l-md5.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-sto.lua util-prs.lua util-fmt.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-mrg.lua util-tpl.lua util-env.lua luat-env.lua lxml-tab.lua lxml-lpt.lua lxml-mis.lua lxml-aux.lua lxml-xml.lua trac-xml.lua data-ini.lua data-exp.lua data-env.lua data-tmp.lua data-met.lua data-res.lua data-pre.lua data-inp.lua data-out.lua data-fil.lua data-con.lua data-use.lua data-zip.lua data-tre.lua data-sch.lua data-lua.lua data-aux.lua data-tmf.lua data-lst.lua util-lib.lua luat-sta.lua luat-fmt.lua -- skipped libraries : - --- original bytes : 670212 --- stripped bytes : 245255 +-- original bytes : 694558 +-- stripped bytes : 246497 -- end library merge @@ -16196,17 +16975,18 @@ local ownlibs = { -- order can be made better } +-- c:/data/develop/tex-context/tex/texmf-win64/bin/../../texmf-context/tex/context/base/data-tmf.lua +-- c:/data/develop/context/sources/data-tmf.lua + local ownlist = { - '.', - ownpath , - ownpath .. "/../sources", -- HH's development path + -- '.', + -- ownpath , + owntree .. "/../../../../context/sources", -- HH's development path owntree .. "/../../texmf-local/tex/context/base", owntree .. "/../../texmf-context/tex/context/base", - owntree .. "/../../texmf-dist/tex/context/base", owntree .. "/../../texmf/tex/context/base", owntree .. "/../../../texmf-local/tex/context/base", owntree .. "/../../../texmf-context/tex/context/base", - owntree .. "/../../../texmf-dist/tex/context/base", owntree .. "/../../../texmf/tex/context/base", } @@ -16265,11 +17045,9 @@ end -- verbosity -local e_verbose = environment.arguments["verbose"] +----- e_verbose = environment.arguments["verbose"] -if e_verbose then - trackers.enable("resolvers.locating") -end +local e_verbose = false -- some common flags (also passed through environment) @@ -16916,10 +17694,22 @@ function runners.execute_ctx_script(filename,...) local scriptbase = match(scriptname,".*mtx%-([^%-]-)%.lua") if scriptbase then local data = io.loaddata(scriptname) - local banner, version = match(data,"[\n\r]logs%.extendbanner%s*%(%s*[\"\']([^\n\r]+)%s*(%d+%.%d+)") - if banner then - valid[#valid+1] = { scriptbase, version, banner } - end +local application = match(data,"local application.-=.-(%{.-%})") +if application then + application = loadstring("return " .. application) + if application then + application = application() + local banner = application.banner + if banner then + local description, version = match(banner,"^(.-) ([%d.]+)$") + if description then + valid[#valid+1] = { scriptbase, version, description } + else + valid[#valid+1] = { scriptbase, "", banner } + end + end + end +end end end if #valid > 0 then @@ -16990,12 +17780,22 @@ environment.initializearguments(before) instance.lsrmode = environment.argument("lsr") or false +e_verbose = environment.arguments["verbose"] -- delayed till here (we need the ones before script) + +if e_verbose then + trackers.enable("resolvers.locating") +end + -- maybe the unset has to go to this level local is_mkii_stub = runners.registered[file.removesuffix(file.basename(filename))] local e_argument = environment.argument +if e_argument("timedlog") then + logs.settimedlog() +end + if e_argument("usekpse") or e_argument("forcekpse") or is_mkii_stub then resolvers.load_tree(e_argument('tree'),true) -- force resolve of TEXMFCNF @@ -17078,11 +17878,38 @@ else end +-- joke .. reminds me of messing with gigi terminals + +if e_argument("ansi") then + + local formatters = string.formatters + + logs.setformatters { + report_yes = formatters["[1;32m%-15s [0;1m|[0m %s"], + report_nop = formatters["[1;32m%-15s [0;1m|[0m"], + subreport_yes = formatters["[1;32m%-15s [0;1m|[1;31m %s [0;1m|[0m %s"], + subreport_nop = formatters["[1;32m%-15s [0;1m|[1;31m %s [0;1m|[0m"], + status_yes = formatters["[1;32m%-15s [0;1m:[0m %s\n"], + status_nop = formatters["[1;32m%-15s [0;1m:[0m\n"], + } + + local script = e_argument("script") or e_argument("scripts") + + if type(script) == "string" then + logs.writer("]0;"..script.."") -- for Alan to test + end + +end + if e_argument("script") or e_argument("scripts") then -- run a script by loading it (using libs), pass args - runners.loadbase() + if e_argument("nofiledatabase") then + -- handy for mtx-update + else + runners.loadbase() + end if is_mkii_stub then ok = runners.execute_script(filename,false,true) else @@ -17095,8 +17922,16 @@ elseif e_argument("selfmerge") then runners.loadbase() local found = locate_libs() + if found then - utilities.merger.selfmerge(own.name,own.libs,{ found }) + local mtxrun = resolvers.findfile("mtxrun.lua") -- includes local name + if lfs.isfile(mtxrun) then + utilities.merger.selfmerge(mtxrun,own.libs,{ found }) + application.report("runner updated on resolved path: %s",mtxrun) + else + utilities.merger.selfmerge(own.name,own.libs,{ found }) + application.report("runner updated on relative path: %s",own.name) + end end elseif e_argument("selfclean") then @@ -17104,7 +17939,15 @@ elseif e_argument("selfclean") then -- remove embedded libraries runners.loadbase() - utilities.merger.selfclean(own.name) + + local mtxrun = resolvers.findfile("mtxrun.lua") -- includes local name + if lfs.isfile(mtxrun) then + utilities.merger.selfclean(mtxrun) + application.report("runner cleaned on resolved path: %s",mtxrun) + else + utilities.merger.selfclean(own.name) + application.report("runner cleaned on relative path: %s",own.name) + end elseif e_argument("selfupdate") then @@ -17346,6 +18189,8 @@ elseif e_argument("version") then application.version() + application.report("source path",environment.ownbin) + elseif e_argument("directives") then directives.show() @@ -17400,7 +18245,7 @@ end if e_verbose then report() - report("runtime: %0.3f seconds",os.runtime()) + report("elapsed lua time: %0.3f seconds",os.runtime()) end if os.type ~= "windows" then |