diff options
Diffstat (limited to 'scripts')
26 files changed, 76208 insertions, 61467 deletions
diff --git a/scripts/context/lua/mtx-colors.lua b/scripts/context/lua/mtx-colors.lua index 7dd1b4ac4..1c3f8cf82 100644 --- a/scripts/context/lua/mtx-colors.lua +++ b/scripts/context/lua/mtx-colors.lua @@ -61,7 +61,14 @@ function scripts.colors.table() end end else - report("no file(s) given" ) + local files = resolvers.findfiles("*.icc") + if #files > 0 then + for i=1,#files do + report(files[i]) + end + else + report("no file(s) given" ) + end end end diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index f380dc6ff..0288d686c 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -40,49 +40,49 @@ local application = logs.application { } -- local luatexflags = { --- ["8bit"] = true, -- ignored, input is assumed to be in UTF-8 encoding --- ["default-translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding --- ["translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding --- ["etex"] = true, -- ignored, the etex extensions are always active --- ["parse-first-line"] = true, -- ignored, enable parsing of the first line of the input file --- ["no-parse-first-line"] = true, -- ignored, disable parsing of the first line of the input file +-- ["8bit"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["default-translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["translate-file"] = true, -- ignored, input is assumed to be in UTF-8 encoding +-- ["etex"] = true, -- ignored, the etex extensions are always active +-- ["parse-first-line"] = true, -- ignored, enable parsing of the first line of the input file +-- ["no-parse-first-line"] = true, -- ignored, disable parsing of the first line of the input file -- --- ["credits"] = true, -- display credits and exit --- ["debug-format"] = true, -- enable format debugging --- ["disable-write18"] = true, -- disable \write18{SHELL COMMAND} --- ["draftmode"] = true, -- switch on draft mode (generates no output PDF) --- ["enable-write18"] = true, -- enable \write18{SHELL COMMAND} --- ["file-line-error"] = true, -- enable file:line:error style messages --- ["file-line-error-style"] = true, -- aliases of --file-line-error --- ["no-file-line-error"] = true, -- disable file:line:error style messages --- ["no-file-line-error-style"] = true, -- aliases of --no-file-line-error --- ["fmt"] = true, -- load the format file FORMAT --- ["halt-on-error"] = true, -- stop processing at the first error --- ["help"] = true, -- display help and exit --- ["ini"] = true, -- be iniluatex, for dumping formats --- ["interaction"] = true, -- set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode) --- ["jobname"] = true, -- set the job name to STRING --- ["kpathsea-debug"] = true, -- set path searching debugging flags according to the bits of NUMBER --- ["lua"] = true, -- load and execute a lua initialization script --- ["mktex"] = true, -- enable mktexFMT generation (FMT=tex/tfm) --- ["no-mktex"] = true, -- disable mktexFMT generation (FMT=tex/tfm) --- ["nosocket"] = true, -- disable the lua socket library --- ["output-comment"] = true, -- use STRING for DVI file comment instead of date (no effect for PDF) --- ["output-directory"] = true, -- use existing DIR as the directory to write files in --- ["output-format"] = true, -- use FORMAT for job output; FORMAT is 'dvi' or 'pdf' --- ["progname"] = true, -- set the program name to STRING --- ["recorder"] = true, -- enable filename recorder --- ["safer"] = true, -- disable easily exploitable lua commands --- ["shell-escape"] = true, -- enable \write18{SHELL COMMAND} --- ["no-shell-escape"] = true, -- disable \write18{SHELL COMMAND} --- ["shell-restricted"] = true, -- restrict \write18 to a list of commands given in texmf.cnf --- ["nodates"] = true, -- no production dates in pdf file --- ["trailerid"] = true, -- alternative trailer id --- ["synctex"] = true, -- enable synctex --- ["version"] = true, -- display version and exit --- ["luaonly"] = true, -- run a lua file, then exit --- ["luaconly"] = true, -- byte-compile a lua file, then exit --- ["jiton"] = false, +-- ["credits"] = true, -- display credits and exit +-- ["debug-format"] = true, -- enable format debugging +-- ["disable-write18"] = true, -- disable \write18{SHELL COMMAND} +-- ["draftmode"] = true, -- switch on draft mode (generates no output PDF) +-- ["enable-write18"] = true, -- enable \write18{SHELL COMMAND} +-- ["file-line-error"] = true, -- enable file:line:error style messages +-- ["file-line-error-style"] = true, -- aliases of --file-line-error +-- ["no-file-line-error"] = true, -- disable file:line:error style messages +-- ["no-file-line-error-style"] = true, -- aliases of --no-file-line-error +-- ["fmt"] = true, -- load the format file FORMAT +-- ["halt-on-error"] = true, -- stop processing at the first error +-- ["help"] = true, -- display help and exit +-- ["ini"] = true, -- be iniluatex, for dumping formats +-- ["interaction"] = true, -- set interaction mode (STRING=batchmode/nonstopmode/scrollmode/errorstopmode) +-- ["jobname"] = true, -- set the job name to STRING +-- ["kpathsea-debug"] = true, -- set path searching debugging flags according to the bits of NUMBER +-- ["lua"] = true, -- load and execute a lua initialization script +-- ["mktex"] = true, -- enable mktexFMT generation (FMT=tex/tfm) +-- ["no-mktex"] = true, -- disable mktexFMT generation (FMT=tex/tfm) +-- ["nosocket"] = true, -- disable the lua socket library +-- ["output-comment"] = true, -- use STRING for DVI file comment instead of date (no effect for PDF) +-- ["output-directory"] = true, -- use existing DIR as the directory to write files in +-- ["output-format"] = true, -- use FORMAT for job output; FORMAT is 'dvi' or 'pdf' +-- ["progname"] = true, -- set the program name to STRING +-- ["recorder"] = true, -- enable filename recorder +-- ["safer"] = true, -- disable easily exploitable lua commands +-- ["shell-escape"] = true, -- enable \write18{SHELL COMMAND} +-- ["no-shell-escape"] = true, -- disable \write18{SHELL COMMAND} +-- ["shell-restricted"] = true, -- restrict \write18 to a list of commands given in texmf.cnf +-- ["nodates"] = true, -- no production dates in pdf file +-- ["trailerid"] = true, -- alternative trailer id +-- ["synctex"] = true, -- enable synctex +-- ["version"] = true, -- display version and exit +-- ["luaonly"] = true, -- run a lua file, then exit +-- ["luaconly"] = true, -- byte-compile a lua file, then exit +-- ["jiton"] = false, -- not supported (makes no sense, slower) -- } local report = application.report @@ -95,12 +95,15 @@ scripts.context = scripts.context or { } 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 +elseif getargument("jit") then -- relaunch luajittex + -- bonus shortcut, we assume that --jit also indicates the engine -- although --jit and --engine=luajittex are independent setargument("engine","luajittex") end +-- -- The way we use stubs will change in a bit in 2019 (mtxrun and context). We also normalize +-- -- the platforms to use a similar approach to this. + local engine_new = file.nameonly(getargument("engine") or directives.value("system.engine")) local engine_old = file.nameonly(environment.ownbin) @@ -111,15 +114,15 @@ local function restart(engine_old,engine_new) os.exit(result == 0 and 0 or 1) end -if getargument("redirected") then - setargument("engine",engine_old) -- later on we need this -elseif engine_new == engine_old then - setargument("engine",engine_new) -- later on we need this -elseif environment.validengines[engine_new] and engine_new ~= environment.basicengines[engine_old] then - restart(engine_old,engine_new) -else - setargument("engine",engine_new) -- later on we need this -end +-- if getargument("redirected") then +-- setargument("engine",engine_old) -- later on we need this +-- elseif engine_new == engine_old then +-- setargument("engine",engine_new) -- later on we need this +-- elseif environment.validengines[engine_new] and engine_new ~= environment.basicengines[engine_old] then +-- restart(engine_old,engine_new) +-- else +-- setargument("engine",engine_new) -- later on we need this +-- end -- so far @@ -433,6 +436,7 @@ end local pdfview -- delayed local function pdf_open(name,method) + statistics.starttiming("pdfview") pdfview = pdfview or dofile(resolvers.findfile("l-pdfview.lua","tex")) pdfview.setmethod(method) report(pdfview.status()) @@ -441,9 +445,12 @@ local function pdf_open(name,method) pdfname = name .. ".pdf" -- agressive end pdfview.open(pdfname) + statistics.stoptiming("pdfview") + report("pdfview overhead: %s seconds",statistics.elapsedtime("pdfview")) end local function pdf_close(name,method) + statistics.starttiming("pdfview") pdfview = pdfview or dofile(resolvers.findfile("l-pdfview.lua","tex")) pdfview.setmethod(method) local pdfname = filenewsuffix(name,"pdf") @@ -452,6 +459,7 @@ local function pdf_close(name,method) end pdfname = name .. ".pdf" -- agressive pdfview.close(pdfname) + statistics.stoptiming("pdfview") end -- result file handling @@ -596,7 +604,7 @@ function scripts.context.run(ctxdata,filename) local a_nofile = getargument("nofile") local a_engine = getargument("engine") -- - local files = environment.files or { } + local files = environment.filenames or { } -- local filelist, mainfile -- @@ -651,7 +659,6 @@ function scripts.context.run(ctxdata,filename) local a_backend = getargument("backend") 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") local a_keeptuc = getargument("keeptuc") @@ -665,11 +672,11 @@ function scripts.context.run(ctxdata,filename) -- side effects (so no bug reports please) .. we provide --sandbox that -- does similar things but tries to ensure that context works as expected - local a_safer = getargument("safer") - - if a_safer then - report("warning: using the luatex safer options, processing is not guaranteed") - end + -- local a_safer = getargument("safer") + -- + -- if a_safer then + -- report("warning: using the luatex safer options, processing is not guaranteed") + -- end -- a_batchmode = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or (a_scrollmode and "scrollmode") or nil @@ -688,7 +695,7 @@ function scripts.context.run(ctxdata,filename) -- if pathname == "" and not a_global and filename ~= usedfiles.nop then filename = "./" .. filename - if not validfile(filename) then + if not validfile(filename) and not validfile(filename..".tex") then report("warning: no (local) file %a, proceeding",filename) end end @@ -709,7 +716,6 @@ 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_jithash = validstring(a_jithash or analysis.jithash) or nil -- if not formatfile or not scriptfile then @@ -795,6 +801,7 @@ function scripts.context.run(ctxdata,filename) ctx = validstring(ctxname), export = a_export and true or nil, nocompression = a_nocompression and true or nil, + texmfbinpath = os.selfdir, } -- for k, v in next, environment.arguments do @@ -809,14 +816,13 @@ function scripts.context.run(ctxdata,filename) local l_flags = { ["interaction"] = a_batchmode, -- ["synctex"] = false, -- context has its own way - ["no-parse-first-line"] = true, -- obsolete - ["safer"] = a_safer, -- better use --sandbox + -- ["no-parse-first-line"] = true, -- obsolete + -- ["safer"] = a_safer, -- better use --sandbox -- ["no-mktex"] = true, -- ["file-line-error-style"] = true, ["fmt"] = formatfile, ["lua"] = scriptfile, ["jobname"] = jobname, - ["jiton"] = a_jiton, ["jithash"] = a_jithash, } -- @@ -1185,9 +1191,9 @@ function scripts.context.make(name) if not getargument("fast") then -- as in texexec scripts.context.generate() end - local list = (name and { name }) or (environment.files[1] and environment.files) or defaultformats + local list = (name and { name }) or (environment.filenames[1] and environment.filenames) or defaultformats local engine = getargument("engine") or "luatex" - if getargument("jit") or getargument("jiton") then + if getargument("jit") then engine = "luajittex" end for i=1,#list do @@ -1205,7 +1211,7 @@ end function scripts.context.ctx() local ctxdata = ctxrunner.new() - ctxdata.jobname = environment.files[1] + ctxdata.jobname = environment.filenames[1] ctxrunner.checkfile(ctxdata,getargument("ctx")) ctxrunner.checkflags(ctxdata) scripts.context.run(ctxdata) @@ -1213,7 +1219,7 @@ end function scripts.context.autoctx() local ctxdata = nil - local files = environment.files + local files = environment.filenames local firstfile = #files > 0 and files[1] if firstfile then local suffix = filesuffix(firstfile) @@ -1248,7 +1254,7 @@ end -- local loaded = false -- -- function scripts.context.metapost() --- local filename = environment.files[1] or "" +-- local filename = environment.filenames[1] or "" -- if not loaded then -- dofile(resolvers.findfile("mlib-run.lua")) -- loaded = true @@ -1265,7 +1271,7 @@ end -- local jobname = "mtx-context-metapost" -- local tempname = fileaddsuffix(jobname,"tex") -- io.savedata(tempname,format(template,"metafun",filename)) --- environment.files[1] = tempname +-- environment.filenames[1] = tempname -- setargument("result",resultname) -- setargument("once",true) -- scripts.context.run() @@ -1583,7 +1589,7 @@ end -- updating (often one will use mtx-update instead) function scripts.context.timed(action) - statistics.timed(action) + statistics.timed(action,true) end local zipname = "cont-tmf.zip" @@ -1792,14 +1798,14 @@ elseif getargument("expert") then elseif getargument("showmodules") or getargument("modules") then scripts.context.modules() elseif getargument("showextras") or getargument("extras") then - scripts.context.extras(environment.files[1] or getargument("extras")) + scripts.context.extras(environment.filenames[1] or getargument("extras")) elseif getargument("extra") then scripts.context.extra() elseif getargument("exporthelp") then - -- application.export(getargument("exporthelp"),environment.files[1]) + -- application.export(getargument("exporthelp"),environment.filenames[1]) application.export() elseif getargument("help") then - if environment.files[1] == "extras" then + if environment.filenames[1] == "extras" then scripts.context.extras() else application.help("basic") @@ -1810,7 +1816,7 @@ elseif getargument("showdirectives") or getargument("directives") == true then scripts.context.directives() elseif getargument("showlogcategories") then scripts.context.logcategories() -elseif environment.files[1] or getargument("nofile") then +elseif environment.filenames[1] or getargument("nofile") then scripts.context.timed(scripts.context.autoctx) elseif getargument("pipe") then scripts.context.timed(scripts.context.pipe) diff --git a/scripts/context/lua/mtx-context.xml b/scripts/context/lua/mtx-context.xml index 9003b549a..8c21eaa8c 100644 --- a/scripts/context/lua/mtx-context.xml +++ b/scripts/context/lua/mtx-context.xml @@ -70,6 +70,9 @@ <flag name="silent" value="list"> <short>disable logcatgories (show list with <ref name="showlogcategories"/>)</short> </flag> + <flag name="strip"> + <short>strip Lua code (only meant for production where no errors are expected)</short> + </flag> <flag name="errors" value="list"> <short>show errors at the end of a run, quit when in list (also when <ref name="--silent"/>)</short> </flag> @@ -187,6 +190,9 @@ <flag name="keeplog"> <short>keep previous log files (jobname-log-[run].tmp)</short> </flag> + <flag name="lmtx"> + <short>force lmtx mode (when available)</short> + </flag> </subcategory> <subcategory> <flag name="extra=name"> diff --git a/scripts/context/lua/mtx-evohome.lua b/scripts/context/lua/mtx-evohome.lua index 7fd8612ec..83f87abdf 100644 --- a/scripts/context/lua/mtx-evohome.lua +++ b/scripts/context/lua/mtx-evohome.lua @@ -24,6 +24,7 @@ local helpinfo = [[ <category name="basic"> <subcategory> <flag name="collect"><short>collect data from device</short></flag> + <flag name="update"><short>update data from device</short></flag> <flag name="presets"><short>file with authenciation data</short></flag> <flag name="auto"><short>fetch temperature data every hour</short></flag> <flag name="port"><short>server port when running the service, default: 8068</short></flag> diff --git a/scripts/context/lua/mtx-fonts.lua b/scripts/context/lua/mtx-fonts.lua index 9b23f55c4..5fab67082 100644 --- a/scripts/context/lua/mtx-fonts.lua +++ b/scripts/context/lua/mtx-fonts.lua @@ -16,7 +16,7 @@ local lower = string.lower local concat = table.concat local write_nl = texio.write_nl -local otlversion = 3.103 +local otlversion = 3.106 local helpinfo = [[ <?xml version="1.0"?> diff --git a/scripts/context/lua/mtx-metatex.lua b/scripts/context/lua/mtx-metatex.lua deleted file mode 100644 index 455ecbd52..000000000 --- a/scripts/context/lua/mtx-metatex.lua +++ /dev/null @@ -1,80 +0,0 @@ -if not modules then modules = { } end modules ['mtx-metatex'] = { - version = 1.001, - comment = "companion to mtxrun.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- future versions will deal with specific variants of metatex - -local helpinfo = [[ -<?xml version="1.0"?> -<application> - <metadata> - <entry name="name">mtx-metatex</entry> - <entry name="detail">MetaTeX Process Management</entry> - <entry name="version">0.10</entry> - </metadata> - <flags> - <category name="basic"> - <subcategory> - <flag name="run"><short>process (one or more) files (default action)</short></flag> - <flag name="make"><short>create metatex format(s)</short></flag> - </subcategory> - </category> - </flags> -</application> -]] - -local application = logs.application { - name = "mtx-metatex", - banner = "MetaTeX Process Management 0.10", - helpinfo = helpinfo, -} - -local report = application.report - -scripts = scripts or { } -scripts.metatex = scripts.metatex or { } - --- metatex - -function scripts.metatex.make() - environment.make_format("metatex") -end - -function scripts.metatex.run(ctxdata,filename) - local filename = environment.files[1] or "" - if filename ~= "" then - local formatfile, scriptfile = resolvers.locateformat("metatex") - if formatfile and scriptfile then - local command = string.format("luatex --fmt=%s --lua=%s %s", - string.quote(formatfile), string.quote(scriptfile), string.quote(filename)) - report("running command: %s",command) - os.spawn(command) - elseif formatname then - report("error, no format found with name: %s",formatname) - else - report("error, no format found (provide formatname or interface)") - end - end -end - -function scripts.metatex.timed(action) - statistics.timed(action) -end - -if environment.argument("run") then - scripts.metatex.timed(scripts.metatex.run) -elseif environment.argument("make") then - scripts.metatex.timed(scripts.metatex.make) -elseif environment.argument("help") then - logs.help(messages.help,false) -elseif environment.argument("exporthelp") then - application.export(environment.argument("exporthelp"),environment.files[1]) -elseif environment.files[1] then - scripts.metatex.timed(scripts.metatex.run) -else - application.help() -end diff --git a/scripts/context/lua/mtx-package.lua b/scripts/context/lua/mtx-package.lua index 23da30bf2..cf60a444e 100644 --- a/scripts/context/lua/mtx-package.lua +++ b/scripts/context/lua/mtx-package.lua @@ -69,8 +69,25 @@ function scripts.package.merge_luatex_files(name) end end end - report("saving %q",newname) - io.savedata(newname,table.concat(collected)) + collected = table.concat(collected) + if environment.argument("stripcontext") then + local stripped = 0 + local eol = lpeg.patterns.eol + local space = lpeg.patterns.space^0 + local start = eol * lpeg.P("if context then") * space * eol + local stop = eol * (lpeg.P("else") + lpeg.P("end")) * space * eol + local noppes = function() + stripped = stripped + 1 + return "\n--removed\n" + end + local pattern = lpeg.Cs((start * ((1-stop)^1/noppes) * stop + lpeg.P(1))^0) + collected = lpeg.match(pattern,collected) + if stripped > 0 then + report("%i context specific sections stripped",stripped) + end + end + report("saving %q (%i bytes)",newname,#collected) + io.savedata(newname,collected) end end end diff --git a/scripts/context/lua/mtx-patterns.lua b/scripts/context/lua/mtx-patterns.lua index d16912e4f..4eb571117 100644 --- a/scripts/context/lua/mtx-patterns.lua +++ b/scripts/context/lua/mtx-patterns.lua @@ -691,6 +691,7 @@ end -- mtxrun --script pattern --check hyph-*.tex -- mtxrun --script pattern --check --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns -- mtxrun --script pattern --convert --path=c:/data/develop/svn-hyphen/trunk/hyph-utf8/tex/generic/hyph-utf8/patterns/tex --destination=e:/tmp/patterns +-- mtxrun --script pattern --convert --path=c:/data/repositories/tex-hyphen/hyph-utf8/tex/generic/hyph-utf8/patterns/tex --destination=e:/tmp/patterns -- -- use this call: -- diff --git a/scripts/context/lua/mtx-pdf.lua b/scripts/context/lua/mtx-pdf.lua index 371b7f319..2e73fa841 100644 --- a/scripts/context/lua/mtx-pdf.lua +++ b/scripts/context/lua/mtx-pdf.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['mtx-pdf'] = { } local tonumber = tonumber -local format, gmatch = string.format, string.gmatch +local format, gmatch, gsub = string.format, string.gmatch, string.gsub local utfchar = utf.char local concat = table.concat local setmetatableindex, sortedhash, sortedkeys = table.setmetatableindex, table.sortedhash, table.sortedkeys @@ -25,8 +25,13 @@ local helpinfo = [[ <subcategory> <flag name="info"><short>show some info about the given file</short></flag> <flag name="metadata"><short>show metadata xml blob</short></flag> + <flag name="pretty"><short>replace newlines in metadata</short></flag> <flag name="fonts"><short>show used fonts (<ref name="detail)"/></short></flag> - <flag name="linearize"><short>linearize given file</short></flag> + </subcategory> + <subcategory> + <example><command>mtxrun --script pdf --info foo.pdf</command></example> + <example><command>mtxrun --script pdf --metadata foo.pdf</command></example> + <example><command>mtxrun --script pdf --metadata --pretty foo.pdf</command></example> </subcategory> </category> </flags> @@ -41,11 +46,17 @@ local application = logs.application { local report = application.report -dofile(resolvers.findfile("lpdf-epd.lua","tex")) +if pdfe then + dofile(resolvers.findfile("lpdf-pde.lua","tex")) +else + dofile(resolvers.findfile("lpdf-epd.lua","tex")) +end scripts = scripts or { } scripts.pdf = scripts.pdf or { } +local details = environment.argument("detail") or environment.argument("details") + local function loadpdffile(filename) if not filename or filename == "" then report("no filename given") @@ -64,60 +75,134 @@ end function scripts.pdf.info(filename) local pdffile = loadpdffile(filename) if pdffile then - local catalog = pdffile.Catalog - local info = pdffile.Info - local pages = pdffile.pages - local nofpages = pages.n -- no # yet. will be in 5.2 + local catalog = pdffile.Catalog + local info = pdffile.Info + local pages = pdffile.pages + local nofpages = pdffile.nofpages + + local unset = "<unset>" - report("filename > %s",filename) - report("pdf version > %s",catalog.Version) - report("number of pages > %s",nofpages) - report("title > %s",info.Title) - report("creator > %s",info.Creator) - report("producer > %s",info.Producer) - report("creation date > %s",info.CreationDate) - report("modification date > %s",info.ModDate) + report("%-17s > %s","filename", filename) + report("%-17s > %s","pdf version", catalog.Version or unset) + report("%-17s > %s","major version", pdffile.majorversion or unset) + report("%-17s > %s","minor version", pdffile.minorversion or unset) + report("%-17s > %s","number of pages", nofpages or 0) + report("%-17s > %s","title", info.Title or unset) + report("%-17s > %s","creator", info.Creator or unset) + report("%-17s > %s","producer", info.Producer or unset) + report("%-17s > %s","creation date", info.CreationDate or unset) + report("%-17s > %s","modification date", info.ModDate or unset) - local width, height, start - for i=1, nofpages do - local page = pages[i] - local bbox = page.CropBox or page.MediaBox - local w, h = bbox[4]-bbox[2],bbox[3]-bbox[1] - if w ~= width or h ~= height then - if start then - report("cropbox > pages: %s-%s, width: %s, height: %s",start,i-1,width,height) + local function somebox(what) + local box = string.lower(what) + local width, height, start + for i=1, nofpages do + local page = pages[i] + local bbox = page[what] or page.MediaBox or { 0, 0, 0, 0 } + local w, h = bbox[4]-bbox[2],bbox[3]-bbox[1] + if w ~= width or h ~= height then + if start then + report("%-17s > pages: %s-%s, width: %s, height: %s",box,start,i-1,width,height) + end + width, height, start = w, h, i end - width, height, start = w, h, i end + report("%-17s > pages: %s-%s, width: %s, height: %s",box,start,nofpages,width,height) end - report("cropbox > pages: %s-%s, width: %s, height: %s",start,nofpages,width,height) + + if details then + somebox("MediaBox") + somebox("ArtBox") + somebox("BleedBox") + somebox("CropBox") + somebox("TrimBox") + else + somebox("CropBox") + end + + -- if details then + local annotations = 0 + for i=1, nofpages do + local page = pages[i] + local a = page.Annots + if a then + annotations = annotations + #a + end + end + if annotations > 0 then + report("%-17s > %s", "annotations",annotations) + end + -- end + + -- if details then + local d = pdffile.destinations + local k = d and sortedkeys(d) + if k and #k > 0 then + report("%-17s > %s", "destinations",#k) + end + local d = pdffile.javascripts + local k = d and sortedkeys(d) + if k and #k > 0 then + report("%-17s > %s", "javascripts",#k) + end + local d = pdffile.widgets + if d and #d > 0 then + report("%-17s > %s", "widgets",#d) + end + local d = pdffile.embeddedfiles + local k = d and sortedkeys(d) + if k and #k > 0 then + report("%-17s > %s", "embeddedfiles",#k) + end + -- end + end end -function scripts.pdf.metadata(filename) +function scripts.pdf.metadata(filename,pretty) local pdffile = loadpdffile(filename) if pdffile then local catalog = pdffile.Catalog local metadata = catalog.Metadata if metadata then - report("metadata > \n\n%s\n",metadata()) + metadata = metadata() + if pretty then + metadata = gsub(metadata,"\r","\n") + end + report("metadata > \n\n%s\n",metadata) else report("no metadata") end end end +local expanded = lpdf.epdf.expanded + local function getfonts(pdffile) local usedfonts = { } - for i=1,pdffile.pages.n do - local page = pdffile.pages[i] - local fontlist = page.Resources.Font - if fontlist then - for k, v in next, lpdf.epdf.expand(fontlist) do - usedfonts[k] = lpdf.epdf.expand(v) + + local function collect(where,tag) + local resources = where.Resources + if resources then + local fontlist = resources.Font + if fontlist then + for k, v in expanded(fontlist) do + usedfonts[tag and (tag .. "." .. k) or k] = v + end + end + local objects = resources.XObject + if objects then + for k, v in expanded(objects) do + collect(v,tag and (tag .. "." .. k) or k) + end end end end + + for i=1,pdffile.nofpages do + collect(pdffile.pages[i]) + end + return usedfonts end @@ -125,7 +210,8 @@ local function getunicodes(font) local cid = font.ToUnicode if cid then cid = cid() - local counts = { } + local counts = { } + local indices = { } -- for s in gmatch(cid,"begincodespacerange%s*(.-)%s*endcodespacerange") do -- for a, b in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do -- print(a,b) @@ -141,18 +227,20 @@ local function getunicodes(font) for i=first,last do local c = i + offset counts[c] = counts[c] + 1 + indices[i] = true end end end for s in gmatch(cid,"beginbfchar%s*(.-)%s*endbfchar") do for old, new in gmatch(s,"<([^>]+)>%s+<([^>]+)>") do + indices[tonumber(old,16)] = true for n in gmatch(new,"....") do local c = tonumber(n,16) counts[c] = counts[c] + 1 end end end - return counts + return counts, indices end end @@ -161,49 +249,93 @@ function scripts.pdf.fonts(filename) if pdffile then local usedfonts = getfonts(pdffile) local found = { } + local common = table.setmetatableindex("table") for k, v in table.sortedhash(usedfonts) do - local counts = getunicodes(v) - local codes = { } - local chars = { } - local freqs = { } + local basefont = v.BaseFont + local encoding = v.Encoding + local subtype = v.Subtype + local unicode = v.ToUnicode + local counts, + indices = getunicodes(v) + local codes = { } + local chars = { } + local freqs = { } + local names = { } if counts then codes = sortedkeys(counts) for i=1,#codes do local k = codes[i] - local c = utfchar(k) - chars[i] = c - freqs[i] = format("U+%05X %s %s",k,counts[k] > 1 and "+" or " ", c) + if k > 32 then + local c = utfchar(k) + chars[i] = c + freqs[i] = format("U+%05X %s %s",k,counts[k] > 1 and "+" or " ", c) + else + freqs[i] = format("U+%05X %s --",k,counts[k] > 1 and "+" or " ") + end + end + if basefont and unicode then + local b = gsub(basefont,"^.*%+","") + local c = common[b] + for k in next, indices do + c[k] = true + end end for i=1,#codes do codes[i] = format("U+%05X",codes[i]) end end + local d = encoding and encoding.Differences + if d then + for i=1,#d do + local di = d[i] + if type(di) == "string" then + names[#names+1] = di + end + end + end found[k] = { - basefont = v.BaseFont or "no basefont", - encoding = v.Encoding or "no encoding", - subtype = v.Subtype or "no subtype", - unicode = v.ToUnicode and "unicode" or "no unicode", + basefont = basefont or "no basefont", + encoding = (d and "custom n=" .. #d) or "no encoding", + subtype = subtype or "no subtype", + unicode = tounicode and "unicode" or "no vector", chars = chars, codes = codes, freqs = freqs, + names = names, } end - if environment.argument("detail") then + if details then for k, v in sortedhash(found) do - report("id : %s",k) - report("basefont : %s",v.basefont) - report("encoding : %s",v.encoding) - report("subtype : %s",v.subtype) - report("unicode : %s",v.unicode) - report("characters : %s", concat(v.chars," ")) - report("codepoints : %s", concat(v.codes," ")) + report("id : %s", k) + report("basefont : %s", v.basefont) + report("encoding : % t", v.names) + report("subtype : %s", v.subtype) + report("unicode : %s", v.unicode) + if #v.chars > 0 then + report("characters : % t", v.chars) + end + if #v.codes > 0 then + report("codepoints : % t", v.codes) + end + report("") + end + for k, v in sortedhash(common) do + report("basefont : %s",k) + report("indices : % t", sortedkeys(v)) report("") end else - local results = { { "id", "basefont", "encoding", "subtype", "unicode", "characters" } } + local haschar = false for k, v in sortedhash(found) do - results[#results+1] = { k, v.basefont, v.encoding, v.subtype, v.unicode, concat(v.chars," ") } + if #v.chars > 0 then + haschar = true + break + end + end + local results = { { "id", "basefont", "encoding", "subtype", "unicode", haschar and "characters" or nil } } + for k, v in sortedhash(found) do + results[#results+1] = { k, v.basefont, v.encoding, v.subtype, v.unicode, haschar and concat(v.chars," ") or nil } end utilities.formatters.formatcolumns(results) report(results[1]) @@ -216,46 +348,6 @@ function scripts.pdf.fonts(filename) end end --- this is a quick hack ... proof of concept .. will change (derived from luigi's example) ... --- i will make a ctx wrapper - -local qpdf -- just call qpdf, no need for a lib here - -function scripts.pdf.linearize(filename) - qpdf = qpdf or swiglib("qpdf.core") - local oldfile = filename or environment.files[1] - if not oldfile then - return - end - file.addsuffix(oldfile,"pdf") - if not lfs.isfile(oldfile) then - return - end - local newfile = environment.files[2] - if not newfile or file.removesuffix(oldfile) == file.removesuffix(newfile)then - newfile = file.addsuffix(file.removesuffix(oldfile) .. "-linearized","pdf") - end - local password = environment.arguments.password - local instance = qpdf.qpdf_init() - if bit32.band(qpdf.qpdf_read(instance,oldfile,password),qpdf.QPDF_ERRORS) ~= 0 then - report("unable to open input file") - elseif bit32.band(qpdf.qpdf_init_write(instance,newfile),qpdf.QPDF_ERRORS) ~= 0 then - report("unable to open output file") - else - report("linearizing %a into %a",oldfile,newfile) - qpdf.qpdf_set_static_ID(instance,qpdf.QPDF_TRUE) - qpdf.qpdf_set_linearization(instance,qpdf.QPDF_TRUE) - qpdf.qpdf_write(instance) - end - while qpdf.qpdf_more_warnings(instance) ~= 0 do - report("warning: %s",qpdf.qpdf_get_error_full_text(instance,qpdf.qpdf_next_warning(qpdf))) - end - if qpdf.qpdf_has_error(instance) ~= 0 then - report("error: %s",qpdf.qpdf_get_error_full_text(instance,qpdf.qpdf_get_error(qpdf))) - end - qpdf.qpdf_cleanup_p(instance) -end - -- scripts.pdf.info("e:/tmp/oeps.pdf") -- scripts.pdf.metadata("e:/tmp/oeps.pdf") -- scripts.pdf.fonts("e:/tmp/oeps.pdf") @@ -268,11 +360,9 @@ if filename == "" then elseif environment.argument("info") then scripts.pdf.info(filename) elseif environment.argument("metadata") then - scripts.pdf.metadata(filename) + scripts.pdf.metadata(filename,environment.argument("pretty")) elseif environment.argument("fonts") then scripts.pdf.fonts(filename) -elseif environment.argument("linearize") then - scripts.pdf.linearize(filename) elseif environment.argument("exporthelp") then application.export(environment.argument("exporthelp"),filename) else diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua index 448b20ac5..4f7b9b591 100644 --- a/scripts/context/lua/mtx-server.lua +++ b/scripts/context/lua/mtx-server.lua @@ -48,8 +48,6 @@ local gettime = os.gettimeofday or os.clock scripts = scripts or { } scripts.webserver = scripts.webserver or { } -dofile(resolvers.findfile("luat-soc.lua","tex")) - local socket = socket or require("socket") ----- http = http or require("socket.http") -- not needed diff --git a/scripts/context/lua/mtx-tools.lua b/scripts/context/lua/mtx-tools.lua index 69064c640..146c46f36 100644 --- a/scripts/context/lua/mtx-tools.lua +++ b/scripts/context/lua/mtx-tools.lua @@ -103,12 +103,18 @@ function scripts.tools.downcase() local basename = file.basename(name) if lower(basename) ~= basename then n = n + 1 + local low = lower(name) + if n == 1 then + report() + end + report("%a renamed to %a",name,low) if force then - os.rename(name,lower(name)) + os.rename(name,low) end end end) if n > 0 then + report() if force then report("%s files renamed",n) else diff --git a/scripts/context/lua/mtx-unicode.lua b/scripts/context/lua/mtx-unicode.lua index 7d59bd1ca..fd6576646 100644 --- a/scripts/context/lua/mtx-unicode.lua +++ b/scripts/context/lua/mtx-unicode.lua @@ -14,9 +14,54 @@ if not modules then modules = { } end modules ['mtx-unicode'] = { -- -- e:/tex-context/tex/texmf-local/data/unicode/blocks.txt -- --- last checked: +-- curl -o arabicshaping.txt http://www.unicode.org/Public/UNIDATA/ArabicShaping.txt +-- curl -o bidibrackets.txt http://www.unicode.org/Public/UNIDATA/BidiBrackets.txt +-- curl -o bidicharactertest.txt http://www.unicode.org/Public/UNIDATA/BidiCharacterTest.txt +-- curl -o bidimirroring.txt http://www.unicode.org/Public/UNIDATA/BidiMirroring.txt +-- curl -o biditest.txt http://www.unicode.org/Public/UNIDATA/BidiTest.txt +-- curl -o blocks.txt http://www.unicode.org/Public/UNIDATA/Blocks.txt +-- curl -o cjkradicals.txt http://www.unicode.org/Public/UNIDATA/CJKRadicals.txt +-- curl -o casefolding.txt http://www.unicode.org/Public/UNIDATA/CaseFolding.txt +-- curl -o compositionexclusions.txt http://www.unicode.org/Public/UNIDATA/CompositionExclusions.txt +-- curl -o derivedage.txt http://www.unicode.org/Public/UNIDATA/DerivedAge.txt +-- curl -o derivedcoreproperties.txt http://www.unicode.org/Public/UNIDATA/DerivedCoreProperties.txt +-- curl -o derivednormalizationprops.txt http://www.unicode.org/Public/UNIDATA/DerivedNormalizationProps.txt +-- curl -o eastasianwidth.txt http://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt +-- curl -o emojisources.txt http://www.unicode.org/Public/UNIDATA/EmojiSources.txt +-- curl -o hangulsyllabletype.txt http://www.unicode.org/Public/UNIDATA/HangulSyllableType.txt +-- curl -o index.txt http://www.unicode.org/Public/UNIDATA/Index.txt +-- curl -o indicpositionalcategory.txt http://www.unicode.org/Public/UNIDATA/IndicPositionalCategory.txt +-- curl -o indicsyllabiccategory.txt http://www.unicode.org/Public/UNIDATA/IndicSyllabicCategory.txt +-- curl -o jamo.txt http://www.unicode.org/Public/UNIDATA/Jamo.txt +-- curl -o linebreak.txt http://www.unicode.org/Public/UNIDATA/LineBreak.txt +-- curl -o namealiases.txt http://www.unicode.org/Public/UNIDATA/NameAliases.txt +-- curl -o namedsequences.txt http://www.unicode.org/Public/UNIDATA/NamedSequences.txt +-- curl -o namedsequencesprov.txt http://www.unicode.org/Public/UNIDATA/NamedSequencesProv.txt +-- curl -o nameslist.html http://www.unicode.org/Public/UNIDATA/NamesList.html +-- curl -o nameslist.txt http://www.unicode.org/Public/UNIDATA/NamesList.txt +-- curl -o normalizationcorrections.txt http://www.unicode.org/Public/UNIDATA/NormalizationCorrections.txt +-- curl -o normalizationtest.txt http://www.unicode.org/Public/UNIDATA/NormalizationTest.txt +-- curl -o proplist.txt http://www.unicode.org/Public/UNIDATA/PropList.txt +-- curl -o propertyaliases.txt http://www.unicode.org/Public/UNIDATA/PropertyAliases.txt +-- curl -o propertyvaluealiases.txt http://www.unicode.org/Public/UNIDATA/PropertyValueAliases.txt +-- curl -o readme.txt http://www.unicode.org/Public/UNIDATA/ReadMe.txt +-- curl -o scriptextensions.txt http://www.unicode.org/Public/UNIDATA/ScriptExtensions.txt +-- curl -o scripts.txt http://www.unicode.org/Public/UNIDATA/Scripts.txt +-- curl -o specialcasing.txt http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt +-- curl -o standardizedvariants.html http://www.unicode.org/Public/UNIDATA/StandardizedVariants.html +-- curl -o standardizedvariants.txt http://www.unicode.org/Public/UNIDATA/StandardizedVariants.txt +-- curl -o tangutsources.txt http://www.unicode.org/Public/UNIDATA/TangutSources.txt +-- curl -o ucd.zip http://www.unicode.org/Public/UNIDATA/UCD.zip +-- curl -o usourcedata.txt http://www.unicode.org/Public/UNIDATA/USourceData.txt +-- curl -o usourceglyphs.pdf http://www.unicode.org/Public/UNIDATA/USourceGlyphs.pdf +-- curl -o unicodedata.txt http://www.unicode.org/Public/UNIDATA/UnicodeData.txt +-- curl -o unihan.zip http://www.unicode.org/Public/UNIDATA/Unihan.zip -- --- code freeze tl 2014 / unicode 7 +-- curl -o emoji-data.txt http://unicode.org/Public/emoji/11.0/emoji-data.txt +-- curl -o emoji-sequences.txt http://unicode.org/Public/emoji/11.0/emoji-sequences.txt +-- curl -o emoji-variation-sequences.txt http://unicode.org/Public/emoji/11.0/emoji-variation-sequences.txt +-- curl -o emoji-zwj-sequences.txt http://unicode.org/Public/emoji/11.0/emoji-zwj-sequences.txt +-- curl -o emoji-test.txt http://unicode.org/Public/emoji/11.0/emoji-test.txt -- -- todo: -- diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua index 6663be7a2..d9deb1b36 100644 --- a/scripts/context/lua/mtx-update.lua +++ b/scripts/context/lua/mtx-update.lua @@ -220,6 +220,8 @@ update.platforms = { -- ["solaris-sparc"] = "solaris-sparc", ["solaris"] = "solaris-sparc", + -- + ["unknown"] = "unknown", } local windowsplatform = { diff --git a/scripts/context/lua/mtx-youless.lua b/scripts/context/lua/mtx-youless.lua index 32e1bd870..ecab30580 100644 --- a/scripts/context/lua/mtx-youless.lua +++ b/scripts/context/lua/mtx-youless.lua @@ -54,7 +54,7 @@ local helpinfo = [[ local application = logs.application { name = "mtx-youless", - banner = "YouLess Fetcher 1.100", + banner = "YouLess Fetcher 1.10", helpinfo = helpinfo, } diff --git a/scripts/context/lua/mtxlibs.lua b/scripts/context/lua/mtxlibs.lua index f6839eb9d..94dc658f3 100644 --- a/scripts/context/lua/mtxlibs.lua +++ b/scripts/context/lua/mtxlibs.lua @@ -67,6 +67,7 @@ local owntree = ownpath local ownlibs = { + "l-bit32.lua", "l-lua.lua", "l-macro.lua", "l-sandbox.lua", @@ -82,6 +83,7 @@ local ownlibs = { "l-file.lua", -- limited functionality when no lfs -- "l-gzip.lua", "l-md5.lua", -- not loaded when no md5 library + "l-sha.lua", -- not loaded when no sha2 library "l-url.lua", "l-dir.lua", -- limited functionality when no lfs "l-boolean.lua", @@ -98,6 +100,19 @@ local ownlibs = { -- "util-fmt.lua", -- no need for table formatters -- "util-deb.lua", -- no need for debugging (and tracing) + "util-soc-imp-reset", + "util-soc-imp-socket", + "util-soc-imp-copas", + "util-soc-imp-ltn12", + -- "util-soc-imp-mbox", + "util-soc-imp-mime", + "util-soc-imp-url", + "util-soc-imp-headers", + "util-soc-imp-tp", + "util-soc-imp-http", + "util-soc-imp-ftp", + "util-soc-imp-smtp", + "trac-set.lua", "trac-log.lua", -- "trac-pro.lua", -- not relevant outside context diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 0f4767d91..569a7f2e1 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1,16 +1,5 @@ #!/usr/bin/env texlua --- for k, v in next, _G.string do --- local tv = type(v) --- if tv == "table" then --- for kk, vv in next, v do --- print(k,kk,vv) --- end --- else --- print(tv,k,v) --- end --- end - if not modules then modules = { } end modules ['mtxrun'] = { version = 1.001, comment = "runner, lua replacement for texmfstart.rb", @@ -20,25 +9,43 @@ if not modules then modules = { } end modules ['mtxrun'] = { } -- one can make a stub: + +-- mtxrun : -- -- #!/bin/sh -- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@" +-- mtxrun.cmd : +-- +-- @luatex --luaonly %~d0%~p0mtxrun.lua %* + -- filename : mtxrun.lua -- comment : companion to context.tex -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files --- This script is based on texmfstart.rb but does not use kpsewhich to --- locate files. Although kpse is a library it never came to opening up --- its interface to other programs (esp scripting languages) and so we --- do it ourselves. The lua variant evolved out of an experimental ruby --- one. Interesting is that using a scripting language instead of c does --- not have a speed penalty. Actually the lua variant is more efficient, --- especially when multiple calls to kpsewhich are involved. The lua +-- This script is based on texmfstart.rb but does not use kpsewhich to locate files. +-- Although kpse is a library it never came to opening up its interface to other +-- programs (esp scripting languages) and so we do it ourselves. The lua variant +-- evolved out of an experimental ruby one. Interesting is that using a scripting +-- language instead of c does not have a speed penalty. Actually the lua variant is +-- more efficient, especially when multiple calls to kpsewhich are involved. The lua -- library also gives way more control. +-- When libraries used here are updates you can run +-- +-- mtxrun --selfmerge +-- +-- to update the embedded code. After that you might need to run +-- +-- mtxrun --selfupdate +-- +-- to copy the new script (from scripts/context/lua) to location where +-- binaries are expected. If you want to remove the embedded code you can run +-- +-- mtxxun --selfclean + -- to be done / considered -- -- support for --exec or make it default @@ -54,16 +61,147 @@ if not modules then modules = { } end modules ['mtxrun'] = { do -- create closure to overcome 200 locals limit +package.loaded["l-bit32"] = package.loaded["l-bit32"] or true + +-- original size: 3607, stripped down to: 3009 + +if not modules then modules={} end modules ['l-bit32']={ + version=1.001, + license="the same as regular Lua", + source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto", + comment="drop-in for bit32, adapted a bit by Hans Hagen", +} +if bit32 then +elseif utf8 then + load ([[ +local select = select -- instead of: arg = { ... } +bit32 = { + bnot = function (a) + return ~a & 0xFFFFFFFF + end, + band = function (x, y, z, ...) + if not z then + return ((x or -1) & (y or -1)) & 0xFFFFFFFF + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bor = function (x, y, z, ...) + if not z then + return ((x or 0) | (y or 0)) & 0xFFFFFFFF + else + local res = x | y | z + for i=1,select("#",...) do + res = res | select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bxor = function (x, y, z, ...) + if not z then + return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF + else + local res = x ~ y ~ z + for i=1,select("#",...) do + res = res ~ select(i,...) + end + return res & 0xFFFFFFFF + end + end, + btest = function (x, y, z, ...) + if not z then + return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0 + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return (res & 0xFFFFFFFF) ~= 0 + end + end, + lshift = function (a, b) + return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF + end, + rshift = function (a, b) + return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF + end, + arshift = function (a, b) + a = a & 0xFFFFFFFF + if b <= 0 or (a & 0x80000000) == 0 then + return (a >> b) & 0xFFFFFFFF + else + return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF + end + end, + lrotate = function (a ,b) + b = b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + rrotate = function (a, b) + b = -b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + extract = function (a, f, w) + return (a >> f) & ~(-1 << (w or 1)) + end, + replace = function (a, v, f, w) + local mask = ~(-1 << (w or 1)) + return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF + end, +} + ]] ) () +elseif bit then + load ([[ +local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift +bit32 = { + arshift = bit.arshift, + band = band, + bnot = bnot, + bor = bit.bor, + bxor = bit.bxor, + btest = function(...) + return band(...) ~= 0 + end, + extract = function(a,f,w) + return band(rshift(a,f),2^(w or 1)-1) + end, + lrotate = bit.rol, + lshift = lshift, + replace = function(a,v,f,w) + local mask = 2^(w or 1)-1 + return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f) + end, + rrotate = bit.ror, + rshift = rshift, +} + ]] ) () +else + xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end) +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + package.loaded["l-lua"] = package.loaded["l-lua"] or true --- original size: 6230, stripped down to: 3662 +-- original size: 6281, stripped down to: 2863 if not modules then modules={} end modules ['l-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,tonumber=next,type,tonumber LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$") @@ -71,122 +209,111 @@ LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5 LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1 LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10 if LUAVERSION<5.2 and jit then - MINORVERSION=2 - LUAVERSION=5.2 + MINORVERSION=2 + LUAVERSION=5.2 end -_LUAVERSION=LUAVERSION if not lpeg then - lpeg=require("lpeg") + lpeg=require("lpeg") end if loadstring then - local loadnormal=load - function load(first,...) - if type(first)=="string" then - return loadstring(first,...) - else - return loadnormal(first,...) - end + local loadnormal=load + function load(first,...) + if type(first)=="string" then + return loadstring(first,...) + else + return loadnormal(first,...) end + end else - loadstring=load + loadstring=load end if not ipairs then - local function iterate(a,i) - i=i+1 - local v=a[i] - if v~=nil then - return i,v - end - end - function ipairs(a) - return iterate,a,0 + local function iterate(a,i) + i=i+1 + local v=a[i] + if v~=nil then + return i,v end + end + function ipairs(a) + return iterate,a,0 + end end if not pairs then - function pairs(t) - return next,t - end + function pairs(t) + return next,t + end end if not table.unpack then - table.unpack=_G.unpack + table.unpack=_G.unpack elseif not unpack then - _G.unpack=table.unpack + _G.unpack=table.unpack end if not package.loaders then - package.loaders=package.searchers + package.loaders=package.searchers end local print,select,tostring=print,select,tostring local inspectors={} function setinspector(kind,inspector) - inspectors[kind]=inspector + inspectors[kind]=inspector end function inspect(...) - for s=1,select("#",...) do - local value=select(s,...) - if value==nil then - print("nil") - else - local done=false - local kind=type(value) - local inspector=inspectors[kind] - if inspector then - done=inspector(value) - if done then - break - end - end - for kind,inspector in next,inspectors do - done=inspector(value) - if done then - break - end - end - if not done then - print(tostring(value)) - end + for s=1,select("#",...) do + local value=select(s,...) + if value==nil then + print("nil") + else + local done=false + local kind=type(value) + local inspector=inspectors[kind] + if inspector then + done=inspector(value) + if done then + break + end + end + for kind,inspector in next,inspectors do + done=inspector(value) + if done then + break end + end + if not done then + print(tostring(value)) + end end + end end local dummy=function() end function optionalrequire(...) - local ok,result=xpcall(require,dummy,...) - if ok then - return result - end + local ok,result=xpcall(require,dummy,...) + if ok then + return result + end end if lua then - lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" + lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" end local flush=io.flush if flush then - local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end - local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end - local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end - local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end + local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end + local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end + local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end + local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end end FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load if not FFISUPPORTED then - local okay;okay,ffi=pcall(require,"ffi") - FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load + local okay;okay,ffi=pcall(require,"ffi") + FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load end if not FFISUPPORTED then - ffi=nil + ffi=nil elseif not ffi.number then - ffi.number=tonumber + ffi.number=tonumber end -if not bit32 then - bit32=require("l-bit32") +if LUAVERSION>5.3 then + collectgarbage("generational") end -local loaded=package.loaded -if not loaded["socket"] then loaded["socket"]=loaded["socket.core"] end -if not loaded["mime"] then loaded["mime"]=loaded["mime.core"] end -if not socket.mime then socket.mime=package.loaded["mime"] end -if not loaded["socket.mime"] then loaded["socket.mime"]=socket.mime end -if not loaded["socket.http"] then loaded["socket.http"]=socket.http end -if not loaded["socket.ftp"] then loaded["socket.ftp"]=socket.ftp end -if not loaded["socket.smtp"] then loaded["socket.smtp"]=socket.smtp end -if not loaded["socket.tp"] then loaded["socket.tp"]=socket.tp end -if not loaded["socket.url"] then loaded["socket.url"]=socket.url end end -- of closure @@ -195,25 +322,27 @@ do -- create closure to overcome 200 locals limit package.loaded["l-macro"] = package.loaded["l-macro"] or true --- original size: 8260, stripped down to: 5213 +-- original size: 10131, stripped down to: 5991 if not modules then modules={} end modules ['l-macros']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg local lpegmatch=lpeg.match local concat=table.concat -local format,sub=string.format,string.sub +local format,sub,match=string.format,string.sub,string.match local next,load,type=next,load,type local newline=S("\n\r")^1 local continue=P("\\")*newline +local whitespace=S(" \t\n\r") local spaces=S(" \t")+continue -local name=R("az","AZ","__","09")^1 -local body=((1+continue/"")-newline)^1 +local nametoken=R("az","AZ","__","09") +local name=nametoken^1 +local body=((continue/""+1)-newline)^1 local lparent=P("(") local rparent=P(")") local noparent=1-(lparent+rparent) @@ -230,172 +359,214 @@ local definitions={} local resolve local subparser local report_lua=function(...) - if logs and logs.reporter then - report_lua=logs.reporter("system","lua") - report_lua(...) - else - print(format(...)) - end -end -resolve=C(C(name)*arguments^-1)/function(raw,s,a) - local d=definitions[s] - if d then - if a then - local n=#a - local p=patterns[s][n] - if p then - local d=d[n] - for i=1,n do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return lpegmatch(p,d,1,a) or d - else - return raw - end - else - return d[0] or raw - end - elseif a then - for i=1,#a do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return s.."("..concat(a,",")..")" - else - return raw - end -end -subparser=Cs((resolve+P(1))^1) -local enddefine=P("#enddefine")/"" -local beginregister=(C(name)*spaces^0*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) - local n=0 + if logs and logs.reporter then + report_lua=logs.reporter("system","lua") + report_lua(...) + else + print(format(...)) + end +end +local safeguard=P("local")*whitespace^1*name*(whitespace+P("=")) +resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a) + local d=definitions[s] + if d then if a then - n=#a - local pattern=P(false) + local n=#a + local p=patterns[s][n] + if p then + local d=d[n] for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p + a[i]=lpegmatch(subparser,a[i]) or a[i] end - p[n]=pattern + return lpegmatch(p,d,1,a) or d + else + return raw + end + else + return d[0] or raw end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d + elseif a then + for i=1,#a do + a[i]=lpegmatch(subparser,a[i]) or a[i] end - d[n]=lpegmatch(subparser,v) or v - return "" + return s.."("..concat(a,",")..")" + else + return raw + end end -local register=(C(name)*spaces^0*(arguments+Cc(false))*spaces^0*C(body))/function(k,a,v) - local n=0 - if a then - n=#a - local pattern=P(false) - for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p - end - p[n]=pattern - end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d - end - d[n]=lpegmatch(subparser,v) or v - return "" +subparser=Cs((resolve+P(1))^1) +local enddefine=P("#enddefine")/"" +local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" +end +local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" end local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a) - local n=0 - if a then - n=#a - local p=patterns[k] - if p then - p[n]=false - end - end - local d=definitions[k] - if d then - d[n]=false + local n=0 + if a then + n=#a + local p=patterns[k] + if p then + p[n]=false end - return "" + end + local d=definitions[k] + if d then + d[n]=false + end + return "" end local begindefine=(P("begindefine")*spaces^0/"")*beginregister -local define=(P("define" )*spaces^0/"")*register -local undefine=(P("undefine" )*spaces^0/"")*unregister +local define=(P("define" )*spaces^0/"")*register +local undefine=(P("undefine" )*spaces^0/"")*unregister local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 ) function macros.reset() - definitions={} - patterns={} + definitions={} + patterns={} +end +function macros.showdefinitions() + for name,list in table.sortedhash(definitions) do + local arguments=list.a + if arguments then + arguments="("..concat(arguments,",")..")" + else + arguments="" + end + print("macro: "..name..arguments) + for i=0,#list do + local l=list[i] + if l then + print(" "..l) + end + end + end end function macros.resolvestring(str) - return lpegmatch(parser,str) or str + return lpegmatch(parser,str) or str end function macros.resolving() - return next(patterns) -end -local function loaded(name,trace,detail) - local f=io.open(name,"rb") - if not f then - return false,format("file '%s' not found",name) - end - local c=f:read("*a") - if not c then - return false,format("file '%s' is invalid",name) - end + return next(patterns) +end +local function reload(path,name,data) + local only=match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only + local f=io.open(name,"wb") + f:write(data) f:close() - local n=lpegmatch(parser,c) - if trace then - if #n~=#c then - report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) - if detail then - report_lua() - report_lua(n) - report_lua() - end - elseif detail then - report_lua("no macros expanded in '%s'",name) - end + local f=loadfile(name) + os.remove(name) + return f + end +end +local function reload(path,name,data) + if path and path~="" then + local only=string.match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only.."-macro.lua" + local f=io.open(name,"wb") + if f then + f:write(data) + f:close() + local l=loadfile(name) + os.remove(name) + return l + end end - if #name>30 then - n="--[["..sub(name,-30).."]] "..n - else - n="--[["..name.."]] "..n + end + return load(data,name) +end +local function loaded(name,trace,detail) + local f=io.open(name,"rb") + if not f then + return false,format("file '%s' not found",name) + end + local c=f:read("*a") + if not c then + return false,format("file '%s' is invalid",name) + end + f:close() + local n=lpegmatch(parser,c) + if trace then + if #n~=#c then + report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) + if detail then + report_lua() + report_lua(n) + report_lua() + end + elseif detail then + report_lua("no macros expanded in '%s'",name) end - return load(n) + end + return reload(lfs and lfs.currentdir(),name,n) end macros.loaded=loaded function required(name,trace) - local filename=file.addsuffix(name,"lua") - local fullname=resolvers and resolvers.find_file(filename) or filename - if not fullname or fullname=="" then - return false - end - local codeblob=package.loaded[fullname] - if codeblob then - return codeblob - end - local code,message=loaded(fullname,macros,trace,trace) - if type(code)=="function" then - code=code() - else - report_lua("error when loading '%s'",fullname) - return false,message - end - if code==nil then - code=false - end - package.loaded[fullname]=code - return code + local filename=file.addsuffix(name,"lua") + local fullname=resolvers and resolvers.find_file(filename) or filename + if not fullname or fullname=="" then + return false + end + local codeblob=package.loaded[fullname] + if codeblob then + return codeblob + end + local code,message=loaded(fullname,macros,trace,trace) + if type(code)=="function" then + code=code() + else + report_lua("error when loading '%s'",fullname) + return false,message + end + if code==nil then + code=false + end + package.loaded[fullname]=code + return code end macros.required=required @@ -406,14 +577,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true --- original size: 9678, stripped down to: 6688 +-- original size: 9747, stripped down to: 6313 if not modules then modules={} end modules ['l-sandbox']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local global=_G local next=next @@ -439,231 +610,234 @@ local trace=false local logger=false local blocked={} local function report(...) - tprint("sandbox ! "..format(...)) + tprint("sandbox ! "..format(...)) end sandbox.report=report function sandbox.setreporter(r) - report=r - sandbox.report=r + report=r + sandbox.report=r end function sandbox.settrace(v) - trace=v + trace=v end function sandbox.setlogger(l) - logger=type(l)=="function" and l or false + logger=type(l)=="function" and l or false end local function register(func,overload,comment) - if type(func)=="function" then - if type(overload)=="string" then - comment=overload - overload=nil - end - local function f(...) - if sandboxed then - local overload=overloads[f] - if overload then - if logger then - local result={ overload(func,...) } - logger { - comment=comments[f] or tostring(f), - arguments={... }, - result=result[1] and true or false, - } - return unpack(result) - else - return overload(func,...) - end - else - end - else - return func(...) - end - end - if comment then - comments[f]=comment - if trace then - report("registering function: %s",comment) - end + if type(func)=="function" then + if type(overload)=="string" then + comment=overload + overload=nil + end + local function f(...) + if sandboxed then + local overload=overloads[f] + if overload then + if logger then + local result={ overload(func,...) } + logger { + comment=comments[f] or tostring(f), + arguments={... }, + result=result[1] and true or false, + } + return unpack(result) + else + return overload(func,...) + end + else end - overloads[f]=overload or false - originals[f]=func - return f + else + return func(...) + end end + if comment then + comments[f]=comment + if trace then + report("registering function: %s",comment) + end + end + overloads[f]=overload or false + originals[f]=func + return f + end end local function redefine(func,comment) - if type(func)=="function" then - skiploads[func]=comment or comments[func] or "unknown" - if overloads[func]==false then - overloads[func]=nil - end + if type(func)=="function" then + skiploads[func]=comment or comments[func] or "unknown" + if overloads[func]==false then + overloads[func]=nil end + end end sandbox.register=register sandbox.redefine=redefine function sandbox.original(func) - return originals and originals[func] or func + return originals and originals[func] or func end function sandbox.overload(func,overload,comment) - comment=comment or comments[func] or "?" - if type(func)~="function" then - if trace then - report("overloading unknown function: %s",comment) - end - elseif type(overload)~="function" then - if trace then - report("overloading function with bad overload: %s",comment) - end - elseif overloads[func]==nil then - if trace then - report("function is not registered: %s",comment) - end - elseif skiploads[func] then - if trace then - report("function is not skipped: %s",comment) - end - else - if trace then - report("overloading function: %s",comment) - end - overloads[func]=overload + comment=comment or comments[func] or "?" + if type(func)~="function" then + if trace then + report("overloading unknown function: %s",comment) + end + elseif type(overload)~="function" then + if trace then + report("overloading function with bad overload: %s",comment) + end + elseif overloads[func]==nil then + if trace then + report("function is not registered: %s",comment) + end + elseif skiploads[func] then + if trace then + report("function is not skipped: %s",comment) end - return func + else + if trace then + report("overloading function: %s",comment) + end + overloads[func]=overload + end + return func end local function whatever(specification,what,target) - if type(specification)~="table" then - report("%s needs a specification",what) - elseif type(specification.category)~="string" or type(specification.action)~="function" then - report("%s needs a category and action",what) - elseif not sandboxed then - target[#target+1]=specification - elseif trace then - report("already enabled, discarding %s",what) - end + if type(specification)~="table" then + report("%s needs a specification",what) + elseif type(specification.category)~="string" or type(specification.action)~="function" then + report("%s needs a category and action",what) + elseif not sandboxed then + target[#target+1]=specification + elseif trace then + report("already enabled, discarding %s",what) + end end function sandbox.initializer(specification) - whatever(specification,"initializer",initializers) + whatever(specification,"initializer",initializers) end function sandbox.finalizer(specification) - whatever(specification,"finalizer",finalizers) + whatever(specification,"finalizer",finalizers) end function require(name) - local n=gsub(name,"^.*[\\/]","") - local n=gsub(n,"[%.].*$","") - local b=blocked[n] - if b==false then - return nil - elseif b then - if trace then - report("using blocked: %s",n) - end - return b - else - if trace then - report("requiring: %s",name) - end - return requiem(name) + local n=gsub(name,"^.*[\\/]","") + local n=gsub(n,"[%.].*$","") + local b=blocked[n] + if b==false then + return nil + elseif b then + if trace then + report("using blocked: %s",n) end -end -function blockrequire(name,lib) + return b + else if trace then - report("preventing reload of: %s",name) + report("requiring: %s",name) end - blocked[name]=lib or _G[name] or false + return requiem(name) + end +end +function blockrequire(name,lib) + if trace then + report("preventing reload of: %s",name) + end + blocked[name]=lib or _G[name] or false end function sandbox.enable() - if not sandboxed then - for i=1,#initializers do - initializers[i].action() - end - for i=1,#finalizers do - finalizers[i].action() - end - local nnot=0 - local nyes=0 - local cnot={} - local cyes={} - local skip={} - for k,v in next,overloads do - local c=comments[k] - if v then - if c then - cyes[#cyes+1]=c - else - nyes=nyes+1 - end - else - if c then - cnot[#cnot+1]=c - else - nnot=nnot+1 - end - end - end - for k,v in next,skiploads do - skip[#skip+1]=v - end - if #cyes>0 then - sort(cyes) - report("overloaded known: %s",concat(cyes," | ")) - end - if nyes>0 then - report("overloaded unknown: %s",nyes) - end - if #cnot>0 then - sort(cnot) - report("not overloaded known: %s",concat(cnot," | ")) - end - if nnot>0 then - report("not overloaded unknown: %s",nnot) + if not sandboxed then + debug={ + traceback=debug.traceback, + } + for i=1,#initializers do + initializers[i].action() + end + for i=1,#finalizers do + finalizers[i].action() + end + local nnot=0 + local nyes=0 + local cnot={} + local cyes={} + local skip={} + for k,v in next,overloads do + local c=comments[k] + if v then + if c then + cyes[#cyes+1]=c + else + nyes=nyes+1 end - if #skip>0 then - sort(skip) - report("not overloaded redefined: %s",concat(skip," | ")) + else + if c then + cnot[#cnot+1]=c + else + nnot=nnot+1 end - initializers=nil - finalizers=nil - originals=nil - sandboxed=true + end + end + for k,v in next,skiploads do + skip[#skip+1]=v + end + if #cyes>0 then + sort(cyes) + report("overloaded known: %s",concat(cyes," | ")) + end + if nyes>0 then + report("overloaded unknown: %s",nyes) end + if #cnot>0 then + sort(cnot) + report("not overloaded known: %s",concat(cnot," | ")) + end + if nnot>0 then + report("not overloaded unknown: %s",nnot) + end + if #skip>0 then + sort(skip) + report("not overloaded redefined: %s",concat(skip," | ")) + end + initializers=nil + finalizers=nil + originals=nil + sandboxed=true + end end blockrequire("lfs",lfs) blockrequire("io",io) blockrequire("os",os) blockrequire("ffi",ffi) local function supported(library) - local l=_G[library] - return l + local l=_G[library] + return l end loadfile=register(loadfile,"loadfile") if supported("io") then - io.open=register(io.open,"io.open") - io.popen=register(io.popen,"io.popen") - io.lines=register(io.lines,"io.lines") - io.output=register(io.output,"io.output") - io.input=register(io.input,"io.input") + io.open=register(io.open,"io.open") + io.popen=register(io.popen,"io.popen") + io.lines=register(io.lines,"io.lines") + io.output=register(io.output,"io.output") + io.input=register(io.input,"io.input") end if supported("os") then - os.execute=register(os.execute,"os.execute") - os.spawn=register(os.spawn,"os.spawn") - os.exec=register(os.exec,"os.exec") - os.rename=register(os.rename,"os.rename") - os.remove=register(os.remove,"os.remove") + os.execute=register(os.execute,"os.execute") + os.spawn=register(os.spawn,"os.spawn") + os.exec=register(os.exec,"os.exec") + os.rename=register(os.rename,"os.rename") + os.remove=register(os.remove,"os.remove") end if supported("lfs") then - lfs.chdir=register(lfs.chdir,"lfs.chdir") - lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") - lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") - lfs.isfile=register(lfs.isfile,"lfs.isfile") - lfs.isdir=register(lfs.isdir,"lfs.isdir") - lfs.attributes=register(lfs.attributes,"lfs.attributes") - lfs.dir=register(lfs.dir,"lfs.dir") - lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") - lfs.touch=register(lfs.touch,"lfs.touch") - lfs.link=register(lfs.link,"lfs.link") - lfs.setmode=register(lfs.setmode,"lfs.setmode") - lfs.readlink=register(lfs.readlink,"lfs.readlink") - lfs.shortname=register(lfs.shortname,"lfs.shortname") - lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") + lfs.chdir=register(lfs.chdir,"lfs.chdir") + lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") + lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") + lfs.isfile=register(lfs.isfile,"lfs.isfile") + lfs.isdir=register(lfs.isdir,"lfs.isdir") + lfs.attributes=register(lfs.attributes,"lfs.attributes") + lfs.dir=register(lfs.dir,"lfs.dir") + lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") + lfs.touch=register(lfs.touch,"lfs.touch") + lfs.link=register(lfs.link,"lfs.link") + lfs.setmode=register(lfs.setmode,"lfs.setmode") + lfs.readlink=register(lfs.readlink,"lfs.readlink") + lfs.shortname=register(lfs.shortname,"lfs.shortname") + lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") end @@ -673,14 +847,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-package"] = package.loaded["l-package"] or true --- original size: 11562, stripped down to: 8625 +-- original size: 11605, stripped down to: 8299 if not modules then modules={} end modules ['l-package']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local gsub,format,find=string.gsub,string.format,string.find @@ -688,40 +862,40 @@ local insert,remove=table.insert,table.remove local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match local package=package local searchers=package.searchers or package.loaders -local filejoin=file and file.join or function(path,name) return path.."/"..name end -local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end -local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end +local filejoin=file and file.join or function(path,name) return path.."/"..name end +local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end +local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end local function cleanpath(path) - return path + return path end local pattern=Cs((((1-S("\\/"))^0*(S("\\/")^1/"/"))^0*(P(".")^1/"/"+P(1))^1)*-1) local function lualibfile(name) - return lpegmatch(pattern,name) or name + return lpegmatch(pattern,name) or name end local offset=luarocks and 1 or 0 local helpers=package.helpers or { - cleanpath=cleanpath, - lualibfile=lualibfile, - trace=false, - report=function(...) print(format(...)) end, - builtin={ - ["preload table"]=searchers[1+offset], - ["path specification"]=searchers[2+offset], - ["cpath specification"]=searchers[3+offset], - ["all in one fallback"]=searchers[4+offset], - }, - methods={}, - sequence={ - "already loaded", - "preload table", - "qualified path", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", - } + cleanpath=cleanpath, + lualibfile=lualibfile, + trace=false, + report=function(...) print(format(...)) end, + builtin={ + ["preload table"]=searchers[1+offset], + ["path specification"]=searchers[2+offset], + ["cpath specification"]=searchers[3+offset], + ["all in one fallback"]=searchers[4+offset], + }, + methods={}, + sequence={ + "already loaded", + "preload table", + "qualified path", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", + } } package.helpers=helpers local methods=helpers.methods @@ -737,253 +911,256 @@ local nofextralib=-1 local nofpathlua=-1 local nofpathlib=-1 local function listpaths(what,paths) - local nofpaths=#paths - if nofpaths>0 then - for i=1,nofpaths do - helpers.report("using %s path %i: %s",what,i,paths[i]) - end - else - helpers.report("no %s paths defined",what) + local nofpaths=#paths + if nofpaths>0 then + for i=1,nofpaths do + helpers.report("using %s path %i: %s",what,i,paths[i]) end - return nofpaths + else + helpers.report("no %s paths defined",what) + end + return nofpaths end local function getextraluapaths() - if helpers.trace and #extraluapaths~=nofextralua then - nofextralua=listpaths("extra lua",extraluapaths) - end - return extraluapaths + if helpers.trace and #extraluapaths~=nofextralua then + nofextralua=listpaths("extra lua",extraluapaths) + end + return extraluapaths end local function getextralibpaths() - if helpers.trace and #extralibpaths~=nofextralib then - nofextralib=listpaths("extra lib",extralibpaths) - end - return extralibpaths + if helpers.trace and #extralibpaths~=nofextralib then + nofextralib=listpaths("extra lib",extralibpaths) + end + return extralibpaths end local function getluapaths() - local luapath=package.path or "" - if oldluapath~=luapath then - luapaths=file.splitpath(luapath,";") - oldluapath=luapath - nofpathlua=-1 - end - if helpers.trace and #luapaths~=nofpathlua then - nofpathlua=listpaths("builtin lua",luapaths) - end - return luapaths + local luapath=package.path or "" + if oldluapath~=luapath then + luapaths=file.splitpath(luapath,";") + oldluapath=luapath + nofpathlua=-1 + end + if helpers.trace and #luapaths~=nofpathlua then + nofpathlua=listpaths("builtin lua",luapaths) + end + return luapaths end local function getlibpaths() - local libpath=package.cpath or "" - if oldlibpath~=libpath then - libpaths=file.splitpath(libpath,";") - oldlibpath=libpath - nofpathlib=-1 - end - if helpers.trace and #libpaths~=nofpathlib then - nofpathlib=listpaths("builtin lib",libpaths) - end - return libpaths + local libpath=package.cpath or "" + if oldlibpath~=libpath then + libpaths=file.splitpath(libpath,";") + oldlibpath=libpath + nofpathlib=-1 + end + if helpers.trace and #libpaths~=nofpathlib then + nofpathlib=listpaths("builtin lib",libpaths) + end + return libpaths end package.luapaths=getluapaths package.libpaths=getlibpaths package.extraluapaths=getextraluapaths package.extralibpaths=getextralibpaths local hashes={ - lua={}, - lib={}, + lua={}, + lib={}, } local function registerpath(tag,what,target,...) - local pathlist={... } - local cleanpath=helpers.cleanpath - local trace=helpers.trace - local report=helpers.report - local hash=hashes[what] - local function add(path) - local path=cleanpath(path) - if not hash[path] then - target[#target+1]=path - hash[path]=true - if trace then - report("registered %s path %s: %s",tag,#target,path) - end - else - if trace then - report("duplicate %s path: %s",tag,path) - end - end + local pathlist={... } + local cleanpath=helpers.cleanpath + local trace=helpers.trace + local report=helpers.report + local hash=hashes[what] + local function add(path) + local path=cleanpath(path) + if not hash[path] then + target[#target+1]=path + hash[path]=true + if trace then + report("registered %s path %s: %s",tag,#target,path) + end + else + if trace then + report("duplicate %s path: %s",tag,path) + end end - for p=1,#pathlist do - local path=pathlist[p] - if type(path)=="table" then - for i=1,#path do - add(path[i]) - end - else - add(path) - end + end + for p=1,#pathlist do + local path=pathlist[p] + if type(path)=="table" then + for i=1,#path do + add(path[i]) + end + else + add(path) end + end end local function pushpath(tag,what,target,path) - local path=helpers.cleanpath(path) - insert(target,1,path) - if helpers.trace then - helpers.report("pushing %s path in front: %s",tag,path) - end + local path=helpers.cleanpath(path) + insert(target,1,path) + if helpers.trace then + helpers.report("pushing %s path in front: %s",tag,path) + end end local function poppath(tag,what,target) - local path=remove(target,1) - if helpers.trace then - if path then - helpers.report("popping %s path from front: %s",tag,path) - else - helpers.report("no %s path to pop",tag) - end + local path=remove(target,1) + if helpers.trace then + if path then + helpers.report("popping %s path from front: %s",tag,path) + else + helpers.report("no %s path to pop",tag) end + end end helpers.registerpath=registerpath function package.extraluapath(...) - registerpath("extra lua","lua",extraluapaths,...) + registerpath("extra lua","lua",extraluapaths,...) end function package.pushluapath(path) - pushpath("extra lua","lua",extraluapaths,path) + pushpath("extra lua","lua",extraluapaths,path) end function package.popluapath() - poppath("extra lua","lua",extraluapaths) + poppath("extra lua","lua",extraluapaths) end function package.extralibpath(...) - registerpath("extra lib","lib",extralibpaths,...) + registerpath("extra lib","lib",extralibpaths,...) end function package.pushlibpath(path) - pushpath("extra lib","lib",extralibpaths,path) + pushpath("extra lib","lib",extralibpaths,path) end function package.poplibpath() - poppath("extra lib","lua",extralibpaths) + poppath("extra lib","lua",extralibpaths) end local function loadedaslib(resolved,rawname) - local base=gsub(rawname,"%.","_") - local init="luaopen_"..gsub(base,"%.","_") - if helpers.trace then - helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) - end - return package.loadlib(resolved,init) + local base=gsub(rawname,"%.","_") + local init="luaopen_"..gsub(base,"%.","_") + if helpers.trace then + helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) + end + return package.loadlib(resolved,init) end helpers.loadedaslib=loadedaslib local function loadedbypath(name,rawname,paths,islib,what) - local trace=helpers.trace - for p=1,#paths do - local path=paths[p] - local resolved=filejoin(path,name) - if trace then - helpers.report("%s path, identifying '%s' on '%s'",what,name,path) - end - if isreadable(resolved) then - if trace then - helpers.report("%s path, '%s' found on '%s'",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + for p=1,#paths do + local path=paths[p] + local resolved=filejoin(path,name) + if trace then + helpers.report("%s path, identifying '%s' on '%s'",what,name,path) + end + if isreadable(resolved) then + if trace then + helpers.report("%s path, '%s' found on '%s'",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + 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 + 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] + return package.loaded[name] end methods["preload table"]=function(name) - return builtin["preload table"](name) + return builtin["preload table"](name) end methods["qualified path"]=function(name) - return loadedbyname(addsuffix(lualibfile(name),"lua"),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") + return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib") end methods["path specification"]=function(name) - getluapaths() - return builtin["path specification"](name) + getluapaths() + return builtin["path specification"](name) end methods["cpath specification"]=function(name) - getlibpaths() - return builtin["cpath specification"](name) + getlibpaths() + return builtin["cpath specification"](name) end methods["all in one fallback"]=function(name) - return builtin["all in one fallback"](name) + return builtin["all in one fallback"](name) end methods["not loaded"]=function(name) - if helpers.trace then - helpers.report("unable to locate '%s'",name or "?") - end - return nil + if helpers.trace then + helpers.report("unable to locate '%s'",name or "?") + end + return nil end local level=0 local used={} helpers.traceused=false function helpers.loaded(name) - local sequence=helpers.sequence - level=level+1 - for i=1,#sequence do - local method=sequence[i] - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) - end - local result,rest=methods[method](name) - if type(result)=="function" then - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) - end - if helpers.traceused then - used[#used+1]={ level=level,name=name } - end - level=level-1 - return result,rest - end + local sequence=helpers.sequence + level=level+1 + for i=1,#sequence do + local method=sequence[i] + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) end - level=level-1 - return nil + local result,rest=methods[method](name) + if type(result)=="function" then + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) + end + if helpers.traceused then + used[#used+1]={ level=level,name=name } + end + level=level-1 + return result,rest + end + end + level=level-1 + return nil end function helpers.showused() - local n=#used - if n>0 then - helpers.report("%s libraries loaded:",n) - helpers.report() - for i=1,n do - local u=used[i] - helpers.report("%i %a",u.level,u.name) - end - helpers.report() - end + local n=#used + if n>0 then + helpers.report("%s libraries loaded:",n) + helpers.report() + for i=1,n do + local u=used[i] + helpers.report("%i %a",u.level,u.name) + end + helpers.report() + end end function helpers.unload(name) - if helpers.trace then - if package.loaded[name] then - helpers.report("unloading, name '%s', %s",name,"done") - else - helpers.report("unloading, name '%s', %s",name,"not loaded") - end + if helpers.trace then + if package.loaded[name] then + helpers.report("unloading, name '%s', %s",name,"done") + else + helpers.report("unloading, name '%s', %s",name,"not loaded") end - package.loaded[name]=nil + end + package.loaded[name]=nil end table.insert(searchers,1,helpers.loaded) +if context then + package.path="" +end end -- of closure @@ -992,14 +1169,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true --- original size: 38582, stripped down to: 20518 +-- original size: 38434, stripped down to: 19310 if not modules then modules={} end modules ['l-lpeg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } lpeg=require("lpeg") local lpeg=lpeg @@ -1010,7 +1187,7 @@ 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 if setinspector then - setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) + setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns @@ -1033,7 +1210,7 @@ local underscore=P("_") local hexdigit=digit+lowercase+uppercase local hexdigits=hexdigit^1 local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") -local newline=P("\r")*(P("\n")+P(true))+P("\n") +local newline=P("\r")*(P("\n")+P(true))+P("\n") local escaped=P("\\")*anything local squote=P("'") local dquote=P('"') @@ -1042,9 +1219,9 @@ 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_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") @@ -1076,7 +1253,7 @@ patterns.utf8character=utf8character patterns.validutf8=validutf8char patterns.validutf8char=validutf8char local eol=S("\n\r") -local spacer=S(" \t\f\v") +local spacer=S(" \t\f\v") local whitespace=eol+spacer local nonspacer=1-spacer local nonwhitespace=1-whitespace @@ -1085,15 +1262,15 @@ 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)) local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0) local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0) -local e_collapser=Cs((whitespace^1*P(-1)/""+nonwhitespace^1+whitespace^1/" ")^0) +local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0) local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0) local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0) -local e_stripper=Cs((spacer^1*P(-1)/""+nonspacer^1+spacer^1/" ")^0) +local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0) local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0) patterns.stripper=stripper patterns.fullstripper=fullstripper @@ -1150,7 +1327,7 @@ patterns.cpfloat=sign^-1*patterns.cpunsigned patterns.number=patterns.float+patterns.integer patterns.cnumber=patterns.cfloat+patterns.integer patterns.cpnumber=patterns.cpfloat+patterns.integer -patterns.oct=zero*octdigits +patterns.oct=zero*octdigits patterns.octal=patterns.oct patterns.HEX=zero*P("X")*(digit+uppercase)^1 patterns.hex=zero*P("x")*(digit+lowercase)^1 @@ -1160,76 +1337,84 @@ patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)* 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/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) -local function anywhere(pattern) - return P { P(pattern)+1*V(1) } +patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0)) +function anywhere(pattern) + return (1-P(pattern))^0*P(pattern) end lpeg.anywhere=anywhere function lpeg.instringchecker(p) - p=anywhere(p) - return function(str) - return lpegmatch(p,str) and true or false - end + p=anywhere(p) + return function(str) + return lpegmatch(p,str) and true or false + end end function lpeg.splitter(pattern,action) + if action then return (((1-P(pattern))^1)/action+1)^0 + else + return (Cs((1-P(pattern))^1)+1)^0 + end end function lpeg.tsplitter(pattern,action) + if action then return Ct((((1-P(pattern))^1)/action+1)^0) + else + return Ct((Cs((1-P(pattern))^1)+1)^0) + end end local splitters_s,splitters_m,splitters_t={},{},{} local function splitat(separator,single) - local splitter=(single and splitters_s[separator]) or splitters_m[separator] - if not splitter then - separator=P(separator) - local other=C((1-separator)^0) - if single then - local any=anything - splitter=other*(separator*C(any^0)+"") - splitters_s[separator]=splitter - else - splitter=other*(separator*other)^0 - splitters_m[separator]=splitter - end + local splitter=(single and splitters_s[separator]) or splitters_m[separator] + if not splitter then + separator=P(separator) + local other=C((1-separator)^0) + if single then + local any=anything + splitter=other*(separator*C(any^0)+"") + splitters_s[separator]=splitter + else + splitter=other*(separator*other)^0 + splitters_m[separator]=splitter end - return splitter + end + return splitter end local function tsplitat(separator) - local splitter=splitters_t[separator] - if not splitter then - splitter=Ct(splitat(separator)) - splitters_t[separator]=splitter - end - return splitter + local splitter=splitters_t[separator] + if not splitter then + splitter=Ct(splitat(separator)) + splitters_t[separator]=splitter + end + return splitter end lpeg.splitat=splitat lpeg.tsplitat=tsplitat function string.splitup(str,separator) - if not separator then - separator="," - end - return lpegmatch(splitters_m[separator] or splitat(separator),str) + if not separator then + separator="," + end + return lpegmatch(splitters_m[separator] or splitat(separator),str) end local cache={} function lpeg.split(separator,str) + local c=cache[separator] + if not c then + c=tsplitat(separator) + cache[separator]=c + end + return lpegmatch(c,str) +end +function string.split(str,separator) + if separator then local c=cache[separator] if not c then - c=tsplitat(separator) - cache[separator]=c + c=tsplitat(separator) + cache[separator]=c end return lpegmatch(c,str) -end -function string.split(str,separator) - if separator then - local c=cache[separator] - if not c then - c=tsplitat(separator) - cache[separator]=c - end - return lpegmatch(c,str) - else - return { str } - end + else + return { str } + end end local spacing=patterns.spacer^0*newline local empty=spacing*Cc("") @@ -1239,505 +1424,463 @@ patterns.textline=content local linesplitter=tsplitat(newline) patterns.linesplitter=linesplitter function string.splitlines(str) - return lpegmatch(linesplitter,str) + return lpegmatch(linesplitter,str) end local cache={} function lpeg.checkedsplit(separator,str) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) end function string.checkedsplit(str,separator) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) -end -local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end -local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) +end +local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end +local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4 patterns.utf8byte=utf8byte local cache={} function lpeg.stripper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs(((S(str)^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs(((str^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs(((S(str)^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs(((str^1)/""+1)^0) + end end local cache={} function lpeg.keeper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs((((1-S(str))^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs((((1-str)^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs((((1-S(str))^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs((((1-str)^1)/""+1)^0) + end end function lpeg.frontstripper(str) - return (P(str)+P(true))*Cs(anything^0) + return (P(str)+P(true))*Cs(anything^0) end function lpeg.endstripper(str) - return Cs((1-P(str)*endofstring)^0) + return Cs((1-P(str)*endofstring)^0) end function lpeg.replacer(one,two,makefunction,isutf) - local pattern - local u=isutf and utf8char or 1 - if type(one)=="table" then - local no=#one - local p=P(false) - if no==0 then - for k,v in next,one do - p=p+P(k)/v - end - pattern=Cs((p+u)^0) - elseif no==1 then - local o=one[1] - one,two=P(o[1]),o[2] - pattern=Cs((one/two+u)^0) - else - for i=1,no do - local o=one[i] - p=p+P(o[1])/o[2] - end - pattern=Cs((p+u)^0) - end - else - pattern=Cs((P(one)/(two or "")+u)^0) + local pattern + local u=isutf and utf8char or 1 + if type(one)=="table" then + local no=#one + local p=P(false) + if no==0 then + for k,v in next,one do + p=p+P(k)/v + end + pattern=Cs((p+u)^0) + elseif no==1 then + local o=one[1] + one,two=P(o[1]),o[2] + pattern=Cs((one/two+u)^0) + else + for i=1,no do + local o=one[i] + p=p+P(o[1])/o[2] + end + pattern=Cs((p+u)^0) end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=Cs((P(one)/(two or "")+u)^0) + end + if makefunction then + return function(str) + return lpegmatch(pattern,str) end + else + return pattern + end end function lpeg.finder(lst,makefunction,isutf) - local pattern - if type(lst)=="table" then - pattern=P(false) - if #lst==0 then - for k,v in next,lst do - pattern=pattern+P(k) - end - else - for i=1,#lst do - pattern=pattern+P(lst[i]) - end - end - else - pattern=P(lst) - end - if isutf then - pattern=((utf8char or 1)-pattern)^0*pattern + local pattern + if type(lst)=="table" then + pattern=P(false) + if #lst==0 then + for k,v in next,lst do + pattern=pattern+P(k) + end else - pattern=(1-pattern)^0*pattern + for i=1,#lst do + pattern=pattern+P(lst[i]) + end end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=P(lst) + end + 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) end + else + return pattern + end end local splitters_f,splitters_s={},{} function lpeg.firstofsplit(separator) - local splitter=splitters_f[separator] - if not splitter then - local pattern=P(separator) - splitter=C((1-pattern)^0) - splitters_f[separator]=splitter - end - return splitter + local splitter=splitters_f[separator] + if not splitter then + local pattern=P(separator) + splitter=C((1-pattern)^0) + splitters_f[separator]=splitter + end + return splitter end function lpeg.secondofsplit(separator) - local splitter=splitters_s[separator] - if not splitter then - local pattern=P(separator) - splitter=(1-pattern)^0*pattern*C(anything^0) - splitters_s[separator]=splitter - end - return splitter + local splitter=splitters_s[separator] + if not splitter then + 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 + 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 + 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 } + left,right=P(left),P(right) + return P { left*((1-left-right)+V(1))^0*right } end function lpeg.counter(pattern,action) - local n=0 - local pattern=(P(pattern)/function() n=n+1 end+anything)^0 - if action then - return function(str) n=0;lpegmatch(pattern,str);action(n) end - else - return function(str) n=0;lpegmatch(pattern,str);return n end - end -end -utf=utf or (unicode and unicode.utf8) or {} -local utfcharacters=utf and utf.characters or string.utfcharacters -local utfgmatch=utf and utf.gmatch -local utfchar=utf and utf.char -lpeg.UP=lpeg.P -if utfcharacters then - function lpeg.US(str) - local p=P(false) - for uc in utfcharacters(str) do - p=p+P(uc) - end - return p - end -elseif utfgmatch then - function lpeg.US(str) - local p=P(false) - for uc in utfgmatch(str,".") do - p=p+P(uc) - end - return p - end -else - function lpeg.US(str) - local p=P(false) - local f=function(uc) - p=p+P(uc) - end - lpegmatch((utf8char/f)^0,str) - return p - end -end -local range=utf8byte*utf8byte+Cc(false) -function lpeg.UR(str,more) - local first,last - if type(str)=="number" then - first=str - last=more or first - else - first,last=lpegmatch(range,str) - if not last then - return P(str) - end - end - if first==last then - return P(str) - elseif utfchar and (last-first<8) then - local p=P(false) - for i=first,last do - p=p+P(utfchar(i)) - end - return p - else - local f=function(b) - return b>=first and b<=last - end - return utf8byte/f - end + local n=0 + local pattern=(P(pattern)/function() n=n+1 end+anything)^0 + if action then + return function(str) n=0;lpegmatch(pattern,str);action(n) end + else + return function(str) n=0;lpegmatch(pattern,str);return n end + end end function lpeg.is_lpeg(p) - return p and lpegtype(p)=="pattern" + return p and lpegtype(p)=="pattern" end function lpeg.oneof(list,...) - if type(list)~="table" then - list={ list,... } - end - local p=P(list[1]) - for l=2,#list do - p=p+P(list[l]) - end - return p + if type(list)~="table" then + list={ list,... } + end + local p=P(list[1]) + for l=2,#list do + p=p+P(list[l]) + end + return p end local sort=table.sort local function copyindexed(old) - local new={} - for i=1,#old do - new[i]=old - end - return new + local new={} + for i=1,#old do + new[i]=old + end + return new end local function sortedkeys(tab) - local keys,s={},0 - for key,_ in next,tab do - s=s+1 - keys[s]=key - end - sort(keys) - return keys + local keys,s={},0 + for key,_ in next,tab do + s=s+1 + keys[s]=key + end + sort(keys) + return keys end function lpeg.append(list,pp,delayed,checked) - local p=pp - if #list>0 then - local keys=copyindexed(list) - sort(keys) - for i=#keys,1,-1 do - local k=keys[i] - if p then - p=P(k)+p - else - p=P(k) - end - end - elseif delayed then - local keys=sortedkeys(list) + local p=pp + if #list>0 then + local keys=copyindexed(list) + sort(keys) + for i=#keys,1,-1 do + local k=keys[i] + if p then + p=P(k)+p + else + p=P(k) + end + end + elseif delayed then + local keys=sortedkeys(list) + if p then + for i=1,#keys,1 do + local k=keys[i] + local v=list[k] + p=P(k)/list+p + end + else + for i=1,#keys do + local k=keys[i] + local v=list[k] if p then - for i=1,#keys,1 do - local k=keys[i] - local v=list[k] - p=P(k)/list+p - end + p=P(k)+p else - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)+p - else - p=P(k) - end - end - if p then - p=p/list - end + p=P(k) end - elseif checked then - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - if k==v then - p=P(k)+p - else - p=P(k)/v+p - end - else - if k==v then - p=P(k) - else - p=P(k)/v - end - end + end + if p then + p=p/list + end + end + elseif checked then + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + if k==v then + p=P(k)+p + else + p=P(k)/v+p end - else - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)/v+p - else - p=P(k)/v - end + else + if k==v then + p=P(k) + else + p=P(k)/v end + end end - return p + else + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + p=P(k)/v+p + else + p=P(k)/v + end + end + end + return p end local p_false=P(false) local p_true=P(true) local lower=utf and utf.lower or string.lower local upper=utf and utf.upper or string.upper function lpeg.setutfcasers(l,u) - lower=l or lower - upper=u or upper + lower=l or lower + upper=u or upper end local function make1(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+P(k)*p_true - elseif v==false then - else - p=p+P(k)*make1(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+P(k)*p_true + elseif v==false then + else + p=p+P(k)*make1(v,v[""]) + end end - return p + end + if rest then + p=p+p_true + end + return p end local function make2(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+(P(lower(k))+P(upper(k)))*p_true - elseif v==false then - else - p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+(P(lower(k))+P(upper(k)))*p_true + elseif v==false then + else + p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) + end end - return p -end -function lpeg.utfchartabletopattern(list,insensitive) - local tree={} - local n=#list - if n==0 then - for s in next,list do - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + end + if rest then + p=p+p_true + end + return p +end +local function utfchartabletopattern(list,insensitive) + local tree={} + local n=#list + if n==0 then + for s in next,list do + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end - else - for i=1,n do - local s=list[i] - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end + end + else + for i=1,n do + local s=list[i] + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end end - return (insensitive and make2 or make1)(tree) + end + return (insensitive and make2 or make1)(tree) +end +lpeg.utfchartabletopattern=utfchartabletopattern +function lpeg.utfreplacer(list,insensitive) + local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0) + return function(str) + return lpegmatch(pattern,str) or str + end end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) - local m=n%step - local d=floor(n/step) - if d>0 then - local v=V(tostring(step)) - local s=result.start - for i=1,d do - if s then - s=v*s - else - s=v - end - end - result.start=s - end - if step>1 and result.start then - local v=V(tostring(step/2)) - result[tostring(step)]=v*v - end - if step>0 then - return nextstep(m,step/2,result) - else - return result + local m=n%step + local d=floor(n/step) + if d>0 then + local v=V(tostring(step)) + local s=result.start + for i=1,d do + if s then + s=v*s + else + s=v + end end + result.start=s + end + if step>1 and result.start then + local v=V(tostring(step/2)) + result[tostring(step)]=v*v + end + if step>0 then + return nextstep(m,step/2,result) + else + return result + end end function lpeg.times(pattern,n) - return P(nextstep(n,2^16,{ "start",["1"]=pattern })) -end -local trailingzeros=zero^0*-digit -local case_1=period*trailingzeros/"" -local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"") -local number=digits*(case_1+case_2) -local stripper=Cs((number+1)^0) -lpeg.patterns.stripzeros=stripper + return P(nextstep(n,2^16,{ "start",["1"]=pattern })) +end +do + local trailingzeros=zero^0*-digit + local stripper=Cs(( + digits*( + period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"") + )+1 + )^0) + lpeg.patterns.stripzeros=stripper + local nonzero=digit-zero + local trailingzeros=zero^1*endofstring + local stripper=Cs((1-period)^0*( + period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring + )) + lpeg.patterns.stripzero=stripper +end local byte_to_HEX={} local byte_to_hex={} local byte_to_dec={} local hex_to_byte={} for i=0,255 do - local H=format("%02X",i) - local h=format("%02x",i) - local d=format("%03i",i) - local c=char(i) - byte_to_HEX[c]=H - byte_to_hex[c]=h - byte_to_dec[c]=d - hex_to_byte[h]=c - hex_to_byte[H]=c + local H=format("%02X",i) + local h=format("%02x",i) + local d=format("%03i",i) + local c=char(i) + byte_to_HEX[c]=H + byte_to_hex[c]=h + byte_to_dec[c]=d + hex_to_byte[h]=c + hex_to_byte[H]=c end local hextobyte=P(2)/hex_to_byte local bytetoHEX=P(1)/byte_to_HEX @@ -1756,32 +1899,47 @@ patterns.bytestoHEX=bytestoHEX patterns.bytestohex=bytestohex patterns.bytestodec=bytestodec function string.toHEX(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestoHEX,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestoHEX,s) + end end function string.tohex(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestohex,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestohex,s) + end end function string.todec(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestodec,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestodec,s) + end end function string.tobytes(s) - if not s or s=="" then - return s - else - return lpegmatch(hextobytes,s) - end + if not s or s=="" then + return s + else + return lpegmatch(hextobytes,s) + end +end +local patterns={} +local function containsws(what) + local p=patterns[what] + if not p then + local p1=P(what)*(whitespace+endofstring)*Cc(true) + local p2=whitespace*P(p1) + p=P(p1)+P(1-p2)^0*p2+Cc(false) + patterns[what]=p + end + return p +end +lpeg.containsws=containsws +function string.containsws(str,what) + return lpegmatch(patterns[what] or containsws(what),str) end @@ -1791,14 +1949,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-function"] = package.loaded["l-function"] or true --- original size: 361, stripped down to: 322 +-- original size: 361, stripped down to: 317 if not modules then modules={} end modules ['l-functions']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } functions=functions or {} function functions.dummy() end @@ -1810,14 +1968,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-string"] = package.loaded["l-string"] or true --- original size: 6461, stripped down to: 3341 +-- original size: 6461, stripped down to: 3255 if not modules then modules={} end modules ['l-string']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local string=string local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower @@ -1825,25 +1983,25 @@ local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote function string.unquoted(str) - return lpegmatch(unquoted,str) or str + return lpegmatch(unquoted,str) or str end function string.quoted(str) - return format("%q",str) + return format("%q",str) end function string.count(str,pattern) - local n=0 - for _ in gmatch(str,pattern) do - n=n+1 - end - return n + local n=0 + for _ in gmatch(str,pattern) do + n=n+1 + end + return n end function string.limit(str,n,sentinel) - if #str>n then - sentinel=sentinel or "..." - return sub(str,1,(n-#sentinel))..sentinel - else - return str - end + if #str>n then + sentinel=sentinel or "..." + return sub(str,1,(n-#sentinel))..sentinel + else + return str + end end local stripper=patterns.stripper local fullstripper=patterns.fullstripper @@ -1851,81 +2009,81 @@ local collapser=patterns.collapser local nospacer=patterns.nospacer local longtostring=patterns.longtostring function string.strip(str) - return str and lpegmatch(stripper,str) or "" + return str and lpegmatch(stripper,str) or "" end function string.fullstrip(str) - return str and lpegmatch(fullstripper,str) or "" + return str and lpegmatch(fullstripper,str) or "" end function string.collapsespaces(str) - return str and lpegmatch(collapser,str) or "" + return str and lpegmatch(collapser,str) or "" end function string.nospaces(str) - return str and lpegmatch(nospacer,str) or "" + return str and lpegmatch(nospacer,str) or "" end function string.longtostring(str) - return str and lpegmatch(longtostring,str) or "" + return str and lpegmatch(longtostring,str) or "" end local pattern=P(" ")^0*P(-1) function string.is_empty(str) - if not str or str=="" then - return true - else - return lpegmatch(pattern,str) and true or false - end + if not str or str=="" then + return true + else + return lpegmatch(pattern,str) and true or false + end end local anything=patterns.anything local allescapes=Cc("%")*S(".-+%?()[]*") -local someescapes=Cc("%")*S(".-+%()[]") -local matchescapes=Cc(".")*S("*?") +local someescapes=Cc("%")*S(".-+%()[]") +local matchescapes=Cc(".")*S("*?") local pattern_a=Cs ((allescapes+anything )^0 ) local pattern_b=Cs ((someescapes+matchescapes+anything )^0 ) local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") ) function string.escapedpattern(str,simple) - return lpegmatch(simple and pattern_b or pattern_a,str) + return lpegmatch(simple and pattern_b or pattern_a,str) end function string.topattern(str,lowercase,strict) - if str=="" or type(str)~="string" then - return ".*" - elseif strict then - str=lpegmatch(pattern_c,str) - else - str=lpegmatch(pattern_b,str) - end - if lowercase then - return lower(str) - else - return str - end + if str=="" or type(str)~="string" then + return ".*" + elseif strict then + str=lpegmatch(pattern_c,str) + else + str=lpegmatch(pattern_b,str) + end + if lowercase then + return lower(str) + else + return str + end end function string.valid(str,default) - return (type(str)=="string" and str~="" and str) or default or nil + return (type(str)=="string" and str~="" and str) or default or nil end string.itself=function(s) return s end local pattern_c=Ct(C(1)^0) local pattern_b=Ct((C(1)/byte)^0) function string.totable(str,bytes) - return lpegmatch(bytes and pattern_b or pattern_c,str) + return lpegmatch(bytes and pattern_b or pattern_c,str) end local replacer=lpeg.replacer("@","%%") function string.tformat(fmt,...) - return format(lpegmatch(replacer,fmt),...) + return format(lpegmatch(replacer,fmt),...) end string.quote=string.quoted string.unquote=string.unquoted if not string.bytetable then - local limit=5000 - function string.bytetable(str) - local n=#str - if n>limit then - local t={ byte(str,1,limit) } - for i=limit+1,n do - t[i]=byte(str,i) - end - return t - else - return { byte(str,1,n) } - end + local limit=5000 + function string.bytetable(str) + local n=#str + if n>limit then + local t={ byte(str,1,limit) } + for i=limit+1,n do + t[i]=byte(str,i) + end + return t + else + return { byte(str,1,n) } end + end end @@ -1935,166 +2093,172 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 40197, stripped down to: 23561 +-- original size: 41298, stripped down to: 21498 if not modules then modules={} end modules ['l-table']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select local table,string=table,string -local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove +local concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable -local getinfo=debug.getinfo local lpegmatch,patterns=lpeg.match,lpeg.patterns local floor=math.floor local stripper=patterns.stripper function table.getn(t) - return t and #t + return t and #t end function table.strip(tab) - local lst,l={},0 - for i=1,#tab do - local s=lpegmatch(stripper,tab[i]) or "" - if s=="" then - else - l=l+1 - lst[l]=s - end + local lst={} + local l=0 + for i=1,#tab do + local s=lpegmatch(stripper,tab[i]) or "" + if s=="" then + else + l=l+1 + lst[l]=s end - return lst + end + return lst end function table.keys(t) - if t then - local keys,k={},0 - for key in next,t do - k=k+1 - keys[k]=key - end - return keys - else - return {} + if t then + local keys={} + local k=0 + for key in next,t do + k=k+1 + keys[k]=key end + return keys + else + return {} + end end local function compare(a,b) - local ta=type(a) - if ta=="number" then - local tb=type(b) - if ta==tb then - return a<b - elseif tb=="string" then - return tostring(a)<b - end - elseif ta=="string" then - local tb=type(b) - if ta==tb then - return a<b - else - return a<tostring(b) - end + local ta=type(a) + if ta=="number" then + local tb=type(b) + if ta==tb then + return a<b + elseif tb=="string" then + return tostring(a)<b end - return tostring(a)<tostring(b) + elseif ta=="string" then + local tb=type(b) + if ta==tb then + return a<b + else + return a<tostring(b) + end + end + return tostring(a)<tostring(b) end local function sortedkeys(tab) - if tab then - local srt,category,s={},0,0 - for key in next,tab do - s=s+1 - srt[s]=key - if category==3 then - elseif category==1 then - if type(key)~="string" then - category=3 - end - elseif category==2 then - if type(key)~="number" then - category=3 - end - else - local tkey=type(key) - if tkey=="string" then - category=1 - elseif tkey=="number" then - category=2 - else - category=3 - end - end - end - if s<2 then - elseif category==3 then - sort(srt,compare) + if tab then + local srt={} + local category=0 + local s=0 + for key in next,tab do + s=s+1 + srt[s]=key + if category==3 then + elseif category==1 then + if type(key)~="string" then + category=3 + end + elseif category==2 then + if type(key)~="number" then + category=3 + end + else + local tkey=type(key) + if tkey=="string" then + category=1 + elseif tkey=="number" then + category=2 else - sort(srt) + category=3 end - return srt + end + end + if s<2 then + elseif category==3 then + sort(srt,compare) else - return {} + sort(srt) end + return srt + else + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="string" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="number" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + return srt + else + return {} + end end local function sortedhashkeys(tab,cmp) - if tab then - local srt,s={},0 - for key in next,tab do - if key then - s=s+1 - srt[s]=key - end - end - if s>1 then - sort(srt,cmp) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if key then + s=s+1 + srt[s]=key + end + end + if s>1 then + sort(srt,cmp) end + return srt + else + return {} + end end function table.allkeys(t) - local keys={} - for k,v in next,t do - for k in next,v do - keys[k]=true - end + local keys={} + for k,v in next,t do + for k in next,v do + keys[k]=true end - return sortedkeys(keys) + end + return sortedkeys(keys) end table.sortedkeys=sortedkeys table.sortedhashonly=sortedhashonly @@ -2102,907 +2266,944 @@ table.sortedindexonly=sortedindexonly table.sortedhashkeys=sortedhashkeys local function nothing() end local function sortedhash(t,cmp) - if t then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local m=#s - if m==1 then - return next,t - elseif m>0 then - local n=0 - return function() - if n<m then - n=n+1 - local k=s[n] - return k,t[k] - end - end + if t then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local m=#s + if m==1 then + return next,t + elseif m>0 then + local n=0 + return function() + if n<m then + n=n+1 + local k=s[n] + return k,t[k] end + end end - return nothing + end + return nothing end table.sortedhash=sortedhash table.sortedpairs=sortedhash function table.append(t,list) - local n=#t - for i=1,#list do - n=n+1 - t[n]=list[i] - end - return t + local n=#t + for i=1,#list do + n=n+1 + t[n]=list[i] + end + return t end function table.prepend(t,list) - local nl=#list - local nt=nl+#t - for i=#t,1,-1 do - t[nt]=t[i] - nt=nt-1 - end - for i=1,#list do - t[i]=list[i] - end - return t + local nl=#list + local nt=nl+#t + for i=#t,1,-1 do + t[nt]=t[i] + nt=nt-1 + end + for i=1,#list do + t[i]=list[i] + end + return t end function table.merge(t,...) - t=t or {} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + if not t then + t={} + end + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.merged(...) - local t={} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + local t={} + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.imerge(t,...) - local nt=#t - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - nt=nt+1 - t[nt]=nst[j] - end + local nt=#t + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + nt=nt+1 + t[nt]=nst[j] end - return t + end + return t end function table.imerged(...) - local tmp,ntmp={},0 - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - ntmp=ntmp+1 - tmp[ntmp]=nst[j] - end + local tmp={} + local ntmp=0 + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + ntmp=ntmp+1 + tmp[ntmp]=nst[j] end - return tmp + end + return tmp end local function fastcopy(old,metatabletoo) - if old then - local new={} - for k,v in next,old do - if type(v)=="table" then - new[k]=fastcopy(v,metatabletoo) - else - new[k]=v - end - end - if metatabletoo then - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + if type(v)=="table" then + new[k]=fastcopy(v,metatabletoo) + else + new[k]=v + end + end + if metatabletoo then + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end end + return new + else + return {} + end end local function copy(t,tables) - tables=tables or {} - local tcopy={} - if not tables[t] then - tables[t]=tcopy - end - for i,v in next,t do - if type(i)=="table" then - if tables[i] then - i=tables[i] - else - i=copy(i,tables) - end - end - if type(v)~="table" then - tcopy[i]=v - elseif tables[v] then - tcopy[i]=tables[v] - else - tcopy[i]=copy(v,tables) - end + if not tables then + tables={} + end + local tcopy={} + if not tables[t] then + tables[t]=tcopy + end + for i,v in next,t do + if type(i)=="table" then + if tables[i] then + i=tables[i] + else + i=copy(i,tables) + end end - local mt=getmetatable(t) - if mt then - setmetatable(tcopy,mt) + if type(v)~="table" then + tcopy[i]=v + elseif tables[v] then + tcopy[i]=tables[v] + else + tcopy[i]=copy(v,tables) end - return tcopy + end + local mt=getmetatable(t) + if mt then + setmetatable(tcopy,mt) + end + return tcopy end table.fastcopy=fastcopy table.copy=copy function table.derive(parent) - local child={} - if parent then - setmetatable(child,{ __index=parent }) - end - return child + local child={} + if parent then + setmetatable(child,{ __index=parent }) + end + return child end function table.tohash(t,value) - local h={} - if t then - if value==nil then value=true end - for _,v in next,t do - h[v]=value - end + local h={} + if t then + if value==nil then value=true end + for _,v in next,t do + h[v]=value end - return h + end + return h end function table.fromhash(t) - local hsh,h={},0 - for k,v in next,t do - if v then - h=h+1 - hsh[h]=k - end + local hsh={} + local h=0 + for k,v in next,t do + if v then + h=h+1 + hsh[h]=k end - return hsh + end + return hsh end local noquotes,hexify,handle,compact,inline,functions,metacheck 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', + '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 is_simple_table(t,hexify) - local nt=#t - if nt>0 then - local n=0 - for _,v in next,t do - n=n+1 - if type(v)=="table" then - return nil - end + local nt=#t + if nt>0 then + local n=0 + for _,v in next,t do + n=n+1 + if type(v)=="table" then + return nil + end + end + local haszero=rawget(t,0) + if n==nt then + local tt={} + for i=1,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i]=format("0x%X",v) + else + tt[i]=v + end + elseif tv=="string" then + tt[i]=format("%q",v) + elseif tv=="boolean" then + tt[i]=v and "true" or "false" + else + return nil end - local haszero=rawget(t,0) - if n==nt then - local tt={} - for i=1,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i]=format("0x%X",v) - else - tt[i]=v - end - elseif tv=="string" then - tt[i]=format("%q",v) - elseif tv=="boolean" then - tt[i]=v and "true" or "false" - else - return nil - end - end - return tt - elseif haszero and (n==nt+1) then - local tt={} - for i=0,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i+1]=format("0x%X",v) - else - tt[i+1]=v - end - elseif tv=="string" then - tt[i+1]=format("%q",v) - elseif tv=="boolean" then - tt[i+1]=v and "true" or "false" - else - return nil - end - end - tt[1]="[0] = "..tt[1] - return tt + end + return tt + elseif haszero and (n==nt+1) then + local tt={} + for i=0,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i+1]=format("0x%X",v) + else + tt[i+1]=v + end + elseif tv=="string" then + tt[i+1]=format("%q",v) + elseif tv=="boolean" then + tt[i+1]=v and "true" or "false" + else + return nil end + end + tt[1]="[0] = "..tt[1] + return tt end - return nil + end + return nil end table.is_simple_table=is_simple_table local propername=patterns.propername local function dummy() end local function do_serialize(root,name,depth,level,indexed) - if level>0 then - depth=depth.." " - if indexed then - handle(format("%s{",depth)) + if level>0 then + depth=depth.." " + if indexed then + handle(format("%s{",depth)) + else + local tn=type(name) + if tn=="number" then + if hexify then + handle(format("%s[0x%X]={",depth,name)) else - local tn=type(name) - if tn=="number" then - if hexify then - handle(format("%s[0x%X]={",depth,name)) - else - handle(format("%s[%s]={",depth,name)) - end - elseif tn=="string" then - if noquotes and not reserved[name] and lpegmatch(propername,name) then - handle(format("%s%s={",depth,name)) - else - handle(format("%s[%q]={",depth,name)) - end - elseif tn=="boolean" then - handle(format("%s[%s]={",depth,name and "true" or "false")) - else - handle(format("%s{",depth)) - end + handle(format("%s[%s]={",depth,name)) end + elseif tn=="string" then + if noquotes and not reserved[name] and lpegmatch(propername,name) then + handle(format("%s%s={",depth,name)) + else + handle(format("%s[%q]={",depth,name)) + end + elseif tn=="boolean" then + handle(format("%s[%s]={",depth,name and "true" or "false")) + else + handle(format("%s{",depth)) + end end - if root and next(root)~=nil then - local first,last=nil,0 - if compact then - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end - end - if last>0 then - first=1 - end + end + if root and next(root)~=nil then + local first=nil + local last=0 + if compact then + last=#root + for k=1,last do + if rawget(root,k)==nil then + last=k-1 + break 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 compact and first and tk=="number" and k>=first and k<=last then - if tv=="number" then - if hexify then - handle(format("%s 0x%X,",depth,v)) - else - handle(format("%s %s,",depth,v)) - end - elseif tv=="string" then - handle(format("%s %q,",depth,v)) - elseif tv=="table" then - if next(v)==nil then - handle(format("%s {},",depth)) - elseif inline then - local st=is_simple_table(v,hexify) - if st then - handle(format("%s { %s },",depth,concat(st,", "))) - else - do_serialize(v,k,depth,level+1,true) - end - else - do_serialize(v,k,depth,level+1,true) - end - 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))) - else - handle(format('%s "function",',depth)) - end - else - handle(format("%s %q,",depth,tostring(v))) - end - elseif k=="__p__" then - if false then - handle(format("%s __p__=nil,",depth)) - end - elseif tv=="number" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=0x%X,",depth,k,v)) - else - handle(format("%s [%s]=%s,",depth,k,v)) - end - elseif tk=="boolean" then - if hexify then - handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) - else - handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) - end - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - if hexify then - handle(format("%s %s=0x%X,",depth,k,v)) - else - handle(format("%s %s=%s,",depth,k,v)) - end - else - if hexify then - handle(format("%s [%q]=0x%X,",depth,k,v)) - else - handle(format("%s [%q]=%s,",depth,k,v)) - end - end - elseif tv=="string" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,v)) - else - handle(format("%s [%s]=%q,",depth,k,v)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) - elseif tk~="string" then - 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 - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={},",depth,k)) - else - handle(format("%s [%s]={},",depth,k)) - end - elseif tk=="boolean" then - handle(format("%s [%s]={},",depth,k and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={},",depth,k)) - else - handle(format("%s [%q]={},",depth,k)) - end - elseif inline then - local st=is_simple_table(v,hexify) - if st then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) - end - elseif tk=="boolean" then - handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) - end - else - do_serialize(v,k,depth,level+1) - end - else - do_serialize(v,k,depth,level+1) - end - elseif tv=="boolean" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) - else - 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),v and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,v and "true" or "false")) - else - handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) - end - elseif tv=="function" then - if functions then - local f=getinfo(v).what=="C" and dump(dummy) or dump(v) - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=load(%q),",depth,k,f)) - else - handle(format("%s [%s]=load(%q),",depth,k,f)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=load(%q),",depth,k,f)) - else - handle(format("%s [%q]=load(%q),",depth,k,f)) - end - end + end + if last>0 then + first=1 + end + 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 compact and first and tk=="number" and k>=first and k<=last then + if tv=="number" then + if hexify then + handle(format("%s 0x%X,",depth,v)) + else + handle(format("%s %s,",depth,v)) + end + elseif tv=="string" then + handle(format("%s %q,",depth,v)) + elseif tv=="table" then + if next(v)==nil then + handle(format("%s {},",depth)) + elseif inline then + local st=is_simple_table(v,hexify) + if st then + handle(format("%s { %s },",depth,concat(st,", "))) else - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) - else - handle(format("%s [%s]=%q,",depth,k,tostring(v))) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%q,",depth,k,tostring(v))) - else - handle(format("%s [%q]=%q,",depth,k,tostring(v))) - end + do_serialize(v,k,depth,level+1,true) end + else + do_serialize(v,k,depth,level+1,true) + end + 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))) + else + handle(format('%s "function",',depth)) + end + else + handle(format("%s %q,",depth,tostring(v))) end - end - if level>0 then - handle(format("%s},",depth)) - end -end -local function serialize(_handle,root,name,specification) - local tname=type(name) - if type(specification)=="table" then - noquotes=specification.noquotes - hexify=specification.hexify - handle=_handle or specification.handle or print - functions=specification.functions - compact=specification.compact - inline=specification.inline and compact - metacheck=specification.metacheck - if functions==nil then - functions=true - end - if compact==nil then - compact=true - end - if inline==nil then - inline=compact - end - if metacheck==nil then - metacheck=true + elseif k=="__p__" then + if false then + handle(format("%s __p__=nil,",depth)) end - else - noquotes=false - hexify=false - handle=_handle or print - compact=true - inline=true - functions=true - metacheck=true - end - if tname=="string" then - if name=="return" then - handle("return {") + elseif tv=="number" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=0x%X,",depth,k,v)) + else + handle(format("%s [%s]=%s,",depth,k,v)) + end + elseif tk=="boolean" then + if hexify then + handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + else + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) + end + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + if hexify then + handle(format("%s %s=0x%X,",depth,k,v)) + else + handle(format("%s %s=%s,",depth,k,v)) + end + else + if hexify then + handle(format("%s [%q]=0x%X,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end + end + elseif tv=="string" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,v)) + else + handle(format("%s [%s]=%q,",depth,k,v)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) else - handle(name.."={") + handle(format("%s [%q]=%q,",depth,k,v)) end - elseif tname=="number" then - if hexify then - handle(format("[0x%X]={",name)) + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={},",depth,k)) + else + handle(format("%s [%s]={},",depth,k)) + end + elseif tk=="boolean" then + handle(format("%s [%s]={},",depth,k and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={},",depth,k)) + else + handle(format("%s [%q]={},",depth,k)) + end + elseif inline then + local st=is_simple_table(v,hexify) + if st then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) + end + elseif tk=="boolean" then + handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) + end + else + do_serialize(v,k,depth,level+1) + end else - handle("["..name.."]={") + do_serialize(v,k,depth,level+1) end - elseif tname=="boolean" then - if name then - handle("return {") + elseif tv=="boolean" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) + else + 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),v and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else - handle("{") + handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) end - else - handle("t={") - end - if root then - if metacheck and getmetatable(root) then - local dummy=root._w_h_a_t_e_v_e_r_ - root._w_h_a_t_e_v_e_r_=nil + elseif tv=="function" then + if functions then + local getinfo=debug and debug.getinfo + if getinfo then + local f=getinfo(v).what=="C" and dump(dummy) or dump(v) + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=load(%q),",depth,k,f)) + else + handle(format("%s [%s]=load(%q),",depth,k,f)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=load(%q),",depth,k,f)) + else + handle(format("%s [%q]=load(%q),",depth,k,f)) + end + end end - if next(root)~=nil then - do_serialize(root,name,"",0) + else + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) + else + handle(format("%s [%s]=%q,",depth,k,tostring(v))) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,tostring(v))) + else + handle(format("%s [%q]=%q,",depth,k,tostring(v))) end + end end - handle("}") + end + if level>0 then + handle(format("%s},",depth)) + end end -function table.serialize(root,name,specification) - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s +local function serialize(_handle,root,name,specification) + local tname=type(name) + if type(specification)=="table" then + noquotes=specification.noquotes + hexify=specification.hexify + handle=_handle or specification.handle or print + functions=specification.functions + compact=specification.compact + inline=specification.inline and compact + metacheck=specification.metacheck + if functions==nil then + functions=true + end + if compact==nil then + compact=true + end + if inline==nil then + inline=compact + end + if metacheck==nil then + metacheck=true + end + else + noquotes=false + hexify=false + handle=_handle or print + compact=true + inline=true + functions=true + metacheck=true + end + if tname=="string" then + if name=="return" then + handle("return {") + else + handle(name.."={") + end + elseif tname=="number" then + if hexify then + handle(format("[0x%X]={",name)) + else + handle("["..name.."]={") + end + elseif tname=="boolean" then + if name then + handle("return {") + else + handle("{") + end + else + handle("t={") + end + if root then + if metacheck and 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)~=nil then + do_serialize(root,name,"",0) end - serialize(flush,root,name,specification) - return concat(t,"\n") + end + handle("}") +end +function table.serialize(root,name,specification) + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + end + serialize(flush,root,name,specification) + return concat(t,"\n") end table.tohandle=serialize local maxtab=2*1024 function table.tofile(filename,root,name,specification) - local f=io.open(filename,'w') - if f then - if maxtab>1 then - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s - if n>maxtab then - f:write(concat(t,"\n"),"\n") - t,n={},0 - end - end - serialize(flush,root,name,specification) - f:write(concat(t,"\n"),"\n") - else - local function flush(s) - f:write(s,"\n") - end - serialize(flush,root,name,specification) + local f=io.open(filename,'w') + if f then + if maxtab>1 then + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + if n>maxtab then + f:write(concat(t,"\n"),"\n") + t={} + n=0 end - f:close() - io.flush() + end + serialize(flush,root,name,specification) + f:write(concat(t,"\n"),"\n") + else + local function flush(s) + f:write(s,"\n") + end + serialize(flush,root,name,specification) end + f:close() + io.flush() + end end local function flattened(t,f,depth) - if f==nil then - f={} - depth=0xFFFF - elseif tonumber(f) then - depth=f - f={} - elseif not depth then - depth=0xFFFF - end - for k,v in next,t do - if type(k)~="number" then - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end - end + if f==nil then + f={} + depth=0xFFFF + elseif tonumber(f) then + depth=f + f={} + elseif not depth then + depth=0xFFFF + end + for k,v in next,t do + if type(k)~="number" then + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v + end end - for k=1,#t do - local v=t[k] - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end + end + for k=1,#t do + local v=t[k] + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v end - return f + end + return f end table.flattened=flattened local function collapsed(t,f,h) - if f==nil then - f={} - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsed(v,f,h) - elseif not h[v] then - f[#f+1]=v - h[v]=true - end + if f==nil then + f={} + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsed(v,f,h) + elseif not h[v] then + f[#f+1]=v + h[v]=true end - return f + end + return f end local function collapsedhash(t,h) - if h==nil then - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsedhash(v,h) - else - h[v]=true - end + if h==nil then + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsedhash(v,h) + else + h[v]=true end - return h + end + return h end -table.collapsed=collapsed +table.collapsed=collapsed table.collapsedhash=collapsedhash local function unnest(t,f) - if not f then - f={} - end - for i=1,#t do - local v=t[i] - if type(v)=="table" then - if type(v[1])=="table" then - unnest(v,f) - else - f[#f+1]=v - end - else - f[#f+1]=v - end + if not f then + f={} + end + for i=1,#t do + local v=t[i] + if type(v)=="table" then + if type(v[1])=="table" then + unnest(v,f) + else + f[#f+1]=v + end + else + f[#f+1]=v end - return f + end + return f end function table.unnest(t) - return unnest(t) + return unnest(t) end local function are_equal(a,b,n,m) - if a==b then - return true - elseif a and b and #a==#b then - n=n or 1 - m=m or #a - for i=n,m do - local ai,bi=a[i],b[i] - if ai==bi then - elseif type(ai)=="table" and type(bi)=="table" then - if not are_equal(ai,bi) then - return false - end - else - return false - end + if a==b then + return true + elseif a and b and #a==#b then + if not n then + n=1 + end + if not m then + m=#a + end + for i=n,m do + local ai,bi=a[i],b[i] + if ai==bi then + elseif type(ai)=="table" and type(bi)=="table" then + if not are_equal(ai,bi) then + return false end - return true - else + else return false + end end + return true + else + return false + end end local function identical(a,b) - if a~=b then - for ka,va in next,a do - local vb=b[ka] - if va==vb then - elseif type(va)=="table" and type(vb)=="table" then - if not identical(va,vb) then - return false - end - else - return false - end - end + if a~=b then + for ka,va in next,a do + local vb=b[ka] + if va==vb then + elseif type(va)=="table" and type(vb)=="table" then + if not identical(va,vb) then + return false + end + else + return false + end end - return true + end + return true end table.identical=identical table.are_equal=are_equal local function sparse(old,nest,keeptables) - local new={} - for k,v in next,old do - if not (v=="" or v==false) then - if nest and type(v)=="table" then - v=sparse(v,nest) - if keeptables or next(v)~=nil then - new[k]=v - end - else - new[k]=v - end - end + local new={} + for k,v in next,old do + if not (v=="" or v==false) then + if nest and type(v)=="table" then + v=sparse(v,nest) + if keeptables or next(v)~=nil then + new[k]=v + end + else + new[k]=v + end end - return new + end + return new end table.sparse=sparse function table.compact(t) - return sparse(t,true,true) + return sparse(t,true,true) end function table.contains(t,v) - if t then - for i=1,#t do - if t[i]==v then - return i - end - end + if t then + for i=1,#t do + if t[i]==v then + return i + end end - return false + end + return false end function table.count(t) - local n=0 - for k,v in next,t do - n=n+1 - end - return n + local n=0 + for k,v in next,t do + n=n+1 + end + return n end function table.swapped(t,s) - local n={} - if s then - for k,v in next,s do - n[k]=v - end + local n={} + if s then + for k,v in next,s do + n[k]=v end - for k,v in next,t do - n[v]=k - end - return n + end + for k,v in next,t do + n[v]=k + end + return n end function table.hashed(t) - for i=1,#t do - t[t[i]]=i - end - return t + for i=1,#t do + t[t[i]]=i + end + return t end function table.mirrored(t) - local n={} - for k,v in next,t do - n[v]=k - n[k]=v - end - return n + local n={} + for k,v in next,t do + n[v]=k + n[k]=v + end + return n end function table.reversed(t) - if t then - local tt,tn={},#t - if tn>0 then - local ttn=0 - for i=tn,1,-1 do - ttn=ttn+1 - tt[ttn]=t[i] - end - end - return tt + if t then + local tt={} + local tn=#t + if tn>0 then + local ttn=0 + for i=tn,1,-1 do + ttn=ttn+1 + tt[ttn]=t[i] + end end + return tt + end end function table.reverse(t) - if t then - local n=#t - for i=1,floor(n/2) do - local j=n-i+1 - t[i],t[j]=t[j],t[i] - end - return t + if t then + local n=#t + local m=n+1 + for i=1,floor(n/2) do + local j=m-i + t[i],t[j]=t[j],t[i] end + return t + end end -function table.sequenced(t,sep,simple) - if not t then - return "" +local function sequenced(t,sep,simple) + if not t then + return "" + elseif type(t)=="string" then + return t + end + local n=#t + local s={} + if n>0 then + for i=1,n do + local v=t[i] + if type(v)=="table" then + s[i]="{"..sequenced(v,sep,simple).."}" + else + s[i]=tostring(t[i]) + end end - local n=#t - local s={} - if n>0 then - for i=1,n do - s[i]=tostring(t[i]) + else + n=0 + for k,v in sortedhash(t) do + if simple then + if v==true then + n=n+1 + s[n]=k + elseif v and v~="" then + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) + end end - else - n=0 - for k,v in sortedhash(t) do - if simple then - if v==true then - n=n+1 - s[n]=k - elseif v and v~="" then - n=n+1 - s[n]=k.."="..tostring(v) - end - else - n=n+1 - s[n]=k.."="..tostring(v) - end + else + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) end + end end - return concat(s,sep or " | ") + end + return concat(s,sep or " | ") end +table.sequenced=sequenced function table.print(t,...) - if type(t)~="table" then - print(tostring(t)) - else - serialize(print,t,...) - end + if type(t)~="table" then + print(tostring(t)) + else + serialize(print,t,...) + end end if setinspector then - setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) + setinspector("table",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) } + return { unpack(t,i,j) } end function table.is_empty(t) - return not t or next(t)==nil + return not t or next(t)==nil end function table.has_one_entry(t) - return t and next(t,next(t))==nil + return t and next(t,next(t))==nil end function table.loweredkeys(t) - local l={} - for k,v in next,t do - l[lower(k)]=v - end - return l + local l={} + for k,v in next,t do + l[lower(k)]=v + end + return l end function table.unique(old) - local hash={} - local new={} - local n=0 - for i=1,#old do - local oi=old[i] - if not hash[oi] then - n=n+1 - new[n]=oi - hash[oi]=true - end - end - return new + local hash={} + local new={} + local n=0 + for i=1,#old do + local oi=old[i] + if not hash[oi] then + n=n+1 + new[n]=oi + hash[oi]=true + end + end + return new end function table.sorted(t,...) - sort(t,...) - return 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 {} + if t then + local values={} + local keys={} + local 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 function table.filtered(t,pattern,sort,cmp) - if t and type(pattern)=="string" then - if sort then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local n=0 - local m=#s - local function kv(s) - while n<m do - n=n+1 - local k=s[n] - if find(k,pattern) then - return k,t[k] - end - end - end - return kv,s - else - local n=next(t) - local function iterator() - while n~=nil do - local k=n - n=next(t,k) - if find(k,pattern) then - return k,t[k] - end - end - end - return iterator,t + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end end - else - return nothing + end + return kv,s + else + local n=next(t) + local function iterator() + while n~=nil do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t end + else + return nothing + end end if not table.move then - function table.move(a1,f,e,t,a2) - if a2 and a1~=a2 then - for i=f,e do - a2[t]=a1[i] - t=t+1 - end - return a2 - else - t=t+e-f - for i=e,f,-1 do - a1[t]=a1[i] - t=t-1 - end - return a1 - end + function table.move(a1,f,e,t,a2) + if a2 and a1~=a2 then + for i=f,e do + a2[t]=a1[i] + t=t+1 + end + return a2 + else + t=t+e-f + for i=e,f,-1 do + a1[t]=a1[i] + t=t-1 + end + return a1 end + end end @@ -3012,14 +3213,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-io"] = package.loaded["l-io"] or true --- original size: 11823, stripped down to: 6945 +-- original size: 11823, stripped down to: 6325 if not modules then modules={} end modules ['l-io']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local io=io local open,flush,write,read=io.open,io.flush,io.write,io.read @@ -3027,334 +3228,334 @@ local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local type=type if string.find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator="\\",";" + io.fileseparator,io.pathseparator="\\",";" else - io.fileseparator,io.pathseparator="/",":" + io.fileseparator,io.pathseparator="/",":" end local large=0x01000000 local medium=0x00100000 local small=0x00020000 local function readall(f) - local size=f:seek("end") - if size>0 then - f:seek("set",0) - return f:read(size) - else - return "" - end + local size=f:seek("end") + if size>0 then + f:seek("set",0) + return f:read(size) + else + return "" + end end io.readall=readall function io.loaddata(filename,textmode) - local f=open(filename,(textmode and 'r') or 'rb') - if f then - local size=f:seek("end") - local data=nil - if size>0 then - f:seek("set",0) - data=f:read(size) - end - f:close() - return data + local f=open(filename,(textmode and 'r') or 'rb') + if f then + local size=f:seek("end") + local data=nil + if size>0 then + f:seek("set",0) + data=f:read(size) end + f:close() + return data + end end function io.copydata(source,target,action) - local f=open(source,"rb") - if f then - local g=open(target,"wb") - if g then - local size=f:seek("end") - if size>0 then - f:seek("set",0) - local data=f:read(size) - if action then - data=action(data) - end - if data then - g:write(data) - end - end - g:close() + local f=open(source,"rb") + if f then + local g=open(target,"wb") + if g then + local size=f:seek("end") + if size>0 then + f:seek("set",0) + local data=f:read(size) + if action then + data=action(data) end - f:close() - flush() + if data then + g:write(data) + end + end + g:close() end + f:close() + flush() + end end function io.savedata(filename,data,joiner) - local f=open(filename,"wb") - if f then - if type(data)=="table" then - f:write(concat(data,joiner or "")) - elseif type(data)=="function" then - data(f) - else - f:write(data or "") - end - f:close() - flush() - return true + local f=open(filename,"wb") + if f then + if type(data)=="table" then + f:write(concat(data,joiner or "")) + elseif type(data)=="function" then + data(f) else - return false + f:write(data or "") end + f:close() + flush() + return true + else + return false + end end if fio and fio.readline then - local readline=fio.readline - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=readline(f) - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + local readline=fio.readline + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=readline(f) + if line then + lines[i]=line else - local line=readline(f) - f:close() - if line and #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=readline(f) + f:close() + if line and #line>0 then + return line + end end + end else - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=f:read("*lines") - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=f:read("*lines") + if line then + lines[i]=line else - local line=f:read("*line") or "" - f:close() - if #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=f:read("*line") or "" + f:close() + if #line>0 then + return line + end end + end end function io.loadchunk(filename,n) - local f=open(filename,'rb') - if f then - local data=f:read(n or 1024) - f:close() - if #data>0 then - return data - end + local f=open(filename,'rb') + if f then + local data=f:read(n or 1024) + f:close() + if #data>0 then + return data end + end end function io.exists(filename) - local f=open(filename) - if f==nil then - return false - else - f:close() - return true - end + local f=open(filename) + if f==nil then + return false + else + f:close() + return true + end end function io.size(filename) - local f=open(filename) - if f==nil then - return 0 - else - local s=f:seek("end") - f:close() - return s - end + local f=open(filename) + if f==nil then + return 0 + else + local s=f:seek("end") + f:close() + return s + end end local function noflines(f) - if type(f)=="string" then - local f=open(filename) - if f then - local n=f and noflines(f) or 0 - f:close() - return n - else - return 0 - end + if type(f)=="string" then + local f=open(filename) + if f then + local n=f and noflines(f) or 0 + f:close() + return n else - local n=0 - for _ in f:lines() do - n=n+1 - end - f:seek('set',0) - return n + return 0 + end + else + local n=0 + for _ in f:lines() do + n=n+1 end + f:seek('set',0) + return n + end end io.noflines=noflines local nextchar={ - [ 4]=function(f) - return f:read(1,1,1,1) - end, - [ 2]=function(f) - return f:read(1,1) - end, - [ 1]=function(f) - return f:read(1) - end, - [-2]=function(f) - local a,b=f:read(1,1) - return b,a - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - return d,c,b,a - end + [ 4]=function(f) + return f:read(1,1,1,1) + end, + [ 2]=function(f) + return f:read(1,1) + end, + [ 1]=function(f) + return f:read(1) + end, + [-2]=function(f) + local a,b=f:read(1,1) + return b,a + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + return d,c,b,a + end } function io.characters(f,n) - if f then - return nextchar[n or 1],f - end + if f then + return nextchar[n or 1],f + end end local nextbyte={ - [4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(a),byte(b),byte(c),byte(d) - end - end, - [3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(a),byte(b),byte(c) - end - end, - [2]=function(f) - local a,b=f:read(1,1) - if b then - return byte(a),byte(b) - end - end, - [1]=function (f) - local a=f:read(1) - if a then - return byte(a) - end - end, - [-2]=function (f) - local a,b=f:read(1,1) - if b then - return byte(b),byte(a) - end - end, - [-3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(c),byte(b),byte(a) - end - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(d),byte(c),byte(b),byte(a) - end + [4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(a),byte(b),byte(c),byte(d) + end + end, + [3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(a),byte(b),byte(c) + end + end, + [2]=function(f) + local a,b=f:read(1,1) + if b then + return byte(a),byte(b) + end + end, + [1]=function (f) + local a=f:read(1) + if a then + return byte(a) + end + end, + [-2]=function (f) + local a,b=f:read(1,1) + if b then + return byte(b),byte(a) + end + end, + [-3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(c),byte(b),byte(a) + end + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(d),byte(c),byte(b),byte(a) end + end } function io.bytes(f,n) - if f then - return nextbyte[n or 1],f - else - return nil,nil - end + if f then + return nextbyte[n or 1],f + else + return nil,nil + end end function io.ask(question,default,options) - while true do - write(question) - if options then - write(format(" [%s]",concat(options,"|"))) - end - if default then - write(format(" [%s]",default)) - end - write(format(" ")) - flush() - local answer=read() - answer=gsub(answer,"^%s*(.*)%s*$","%1") - if answer=="" and default then - return default - elseif not options then - return answer - else - for k=1,#options do - if options[k]==answer then - return answer - end - end - local pattern="^"..answer - for k=1,#options do - local v=options[k] - if find(v,pattern) then - return v - end - end + while true do + write(question) + if options then + write(format(" [%s]",concat(options,"|"))) + end + if default then + write(format(" [%s]",default)) + end + write(format(" ")) + flush() + local answer=read() + answer=gsub(answer,"^%s*(.*)%s*$","%1") + if answer=="" and default then + return default + elseif not options then + return answer + else + for k=1,#options do + if options[k]==answer then + return answer end + end + local pattern="^"..answer + for k=1,#options do + local v=options[k] + if find(v,pattern) then + return v + end + end end + end end local function readnumber(f,n,m) - if m then - f:seek("set",n) - n=m - end - if n==1 then - return byte(f:read(1)) - elseif n==2 then - local a,b=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==3 then - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==4 then - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==8 then - local a,b=readnumber(f,4),readnumber(f,4) - return 0x100*a+b - elseif n==12 then - local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) - return 0x10000*a+0x100*b+c - elseif n==-2 then - local b,a=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==-3 then - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==-4 then - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==-8 then - local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) - return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h - else - return 0 - end + if m then + f:seek("set",n) + n=m + end + if n==1 then + return byte(f:read(1)) + elseif n==2 then + local a,b=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==3 then + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==4 then + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==8 then + local a,b=readnumber(f,4),readnumber(f,4) + return 0x100*a+b + elseif n==12 then + local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) + return 0x10000*a+0x100*b+c + elseif n==-2 then + local b,a=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==-3 then + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==-4 then + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==-8 then + local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) + return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h + else + return 0 + end end io.readnumber=readnumber function io.readstring(f,n,m) - if m then - f:seek("set",n) - n=m - end - local str=gsub(f:read(n),"\000","") - return str + if m then + f:seek("set",n) + n=m + end + local str=gsub(f:read(n),"\000","") + return str end @@ -3364,14 +3565,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-number"] = package.loaded["l-number"] or true --- original size: 5645, stripped down to: 2253 +-- original size: 5720, stripped down to: 2176 if not modules then modules={} end modules ['l-number']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tostring,tonumber=tostring,tonumber local format,floor,match,rep=string.format,math.floor,string.match,string.rep @@ -3381,99 +3582,107 @@ local floor=math.floor number=number or {} local number=number if bit32 then - local bextract=bit32.extract - local t={ - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - } - function number.tobitstring(b,m) - local n=32 - for i=0,31 do - local v=bextract(b,i) - local k=32-i - if v==1 then - n=k - t[k]="1" - else - t[k]="0" - end - end - if m then - m=33-m*8 - if m<1 then - m=1 - end - return concat(t,"",m) - elseif n<8 then - return concat(t) - elseif n<16 then - return concat(t,"",9) - elseif n<24 then - return concat(t,"",17) - else - return concat(t,"",25) - end + local bextract=bit32.extract + local t={ + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + } + function number.tobitstring(b,m,w) + if not w then + w=32 + end + local n=w + for i=0,w-1 do + local v=bextract(b,i) + local k=w-i + if v==1 then + n=k + t[k]="1" + else + t[k]="0" + end + end + if w then + return concat(t,"",1,w) + elseif m then + m=33-m*8 + if m<1 then + m=1 + end + return concat(t,"",1,m) + elseif n<8 then + return concat(t) + elseif n<16 then + return concat(t,"",9) + elseif n<24 then + return concat(t,"",17) + else + return concat(t,"",25) end + end else - function number.tobitstring(n,m) - if n>0 then - local t={} - while n>0 do - insert(t,1,n%2>0 and 1 or 0) - n=floor(n/2) - end - local nn=8-#t%8 - if nn>0 and nn<8 then - for i=1,nn do - insert(t,1,0) - end - end - if m then - m=m*8-#t - if m>0 then - insert(t,1,rep("0",m)) - end - end - return concat(t) - elseif m then - rep("00000000",m) - else - return "00000000" + function number.tobitstring(n,m) + if n>0 then + local t={} + while n>0 do + insert(t,1,n%2>0 and 1 or 0) + n=floor(n/2) + end + local nn=8-#t%8 + if nn>0 and nn<8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m=m*8-#t + if m>0 then + insert(t,1,rep("0",m)) end + end + return concat(t) + elseif m then + rep("00000000",m) + else + return "00000000" end + end end function number.valid(str,default) - return tonumber(str) or default or nil + return tonumber(str) or default or nil end function number.toevenhex(n) - local s=format("%X",n) - if #s%2==0 then - return s - else - return "0"..s - end + local s=format("%X",n) + if #s%2==0 then + return s + else + return "0"..s + end end function number.bytetodecimal(b) - local d=floor(b*100/255+0.5) - if d>100 then - return 100 - elseif d<-100 then - return -100 - else - return d - end + local d=floor(b*100/255+0.5) + if d>100 then + return 100 + elseif d<-100 then + return -100 + else + return d + end end function number.decimaltobyte(d) - local b=floor(d*255/100+0.5) - if b>255 then - return 255 - elseif b<-255 then - return -255 - else - return b - end + local b=floor(d*255/100+0.5) + if b>255 then + return 255 + elseif b<-255 then + return -255 + else + return b + end +end +function number.idiv(i,d) + return floor(i/d) end @@ -3483,14 +3692,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-set"] = package.loaded["l-set"] or true --- original size: 1923, stripped down to: 1133 +-- original size: 1923, stripped down to: 1044 if not modules then modules={} end modules ['l-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } set=set or {} local nums={} @@ -3499,54 +3708,54 @@ local concat=table.concat local next,type=next,type set.create=table.tohash function set.tonumber(t) - if next(t) then - local s="" - for k,v in next,t do - if v then - s=s.." "..k - end - end - local n=nums[s] - if not n then - n=#tabs+1 - tabs[n]=t - nums[s]=n - end - return n - else - return 0 + if next(t) then + local s="" + for k,v in next,t do + if v then + s=s.." "..k + end end + local n=nums[s] + if not n then + n=#tabs+1 + tabs[n]=t + nums[s]=n + end + return n + else + return 0 + end end function set.totable(n) - if n==0 then - return {} - else - return tabs[n] or {} - end + if n==0 then + return {} + else + return tabs[n] or {} + end end function set.tolist(n) - if n==0 or not tabs[n] then - return "" - else - local t,n={},0 - for k,v in next,tabs[n] do - if v then - n=n+1 - t[n]=k - end - end - return concat(t," ") + if n==0 or not tabs[n] then + return "" + else + local t,n={},0 + for k,v in next,tabs[n] do + if v then + n=n+1 + t[n]=k + end end + return concat(t," ") + end end function set.contains(n,s) - if type(n)=="table" then - return n[s] - elseif n==0 then - return false - else - local t=tabs[n] - return t and t[s] - end + if type(n)=="table" then + return n[s] + elseif n==0 then + return false + else + local t=tabs[n] + return t and t[s] + end end @@ -3556,14 +3765,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-os"] = package.loaded["l-os"] or true --- original size: 16268, stripped down to: 9246 +-- original size: 19347, stripped down to: 10258 if not modules then modules={} end modules ['l-os']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local os=os local date,time=os.date,os.time @@ -3571,357 +3780,434 @@ local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string local concat=table.concat local random,ceil,randomseed=math.random,math.ceil,math.randomseed local rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring=rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring -math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) -randomseed(math.initialseed) -if not os.__getenv__ then - os.__getenv__=os.getenv - os.__setenv__=os.setenv - if os.env then - local osgetenv=os.getenv - local ossetenv=os.setenv - local osenv=os.env local _=osenv.PATH - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - if type(v)=="table" then - v=concat(v,";") - end - ossetenv(K,v) - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v - end +do + local selfdir=os.selfdir + if selfdir=="" then + selfdir=nil + end + if not selfdir then + if arg then + for i=1,#arg do + local a=arg[i] + if find(a,"^%-%-[c:]*texmfbinpath=") then + selfdir=gsub(a,"^.-=","") + break end - else - local ossetenv=os.setenv - local osgetenv=os.getenv - local osenv={} - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v + end + end + if not selfdir then + selfdir=os.selfbin or "luatex" + if find(selfdir,"[/\\]") then + selfdir=gsub(selfdir,"[/\\][^/\\]*$","") + elseif os.getenv then + local path=os.getenv("PATH") + local name=gsub(selfdir,"^.*[/\\][^/\\]","") + local patt="[^:]+" + if os.type=="windows" then + patt="[^;]+" + name=name..".exe" + end + local isfile + if lfs then + local attributes=lfs.attributes + isfile=function(name) + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil + end + else + local open=io.open + isfile=function(name) + local f=open(name) + if f then + f:close() + return true end + end end - local function __index(t,k) - return os.getenv(k) - end - local function __newindex(t,k,v) - os.setenv(k,v) + for p in gmatch(path,patt) do + if isfile(p.."/"..name) then + selfdir=p + break + end end - os.env={} - setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end + os.selfdir=selfdir or "." + end +end +math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) +randomseed(math.initialseed) +if not os.__getenv__ then + os.__getenv__=os.getenv + os.__setenv__=os.setenv + if os.env then + local osgetenv=os.getenv + local ossetenv=os.setenv + local osenv=os.env local _=osenv.PATH + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + if type(v)=="table" then + v=concat(v,";") + end + ossetenv(K,v) + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + else + local ossetenv=os.setenv + local osgetenv=os.getenv + local osenv={} + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + local function __index(t,k) + return os.getenv(k) + end + local function __newindex(t,k,v) + os.setenv(k,v) + end + os.env={} + setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end local execute=os.execute local iopopen=io.popen local function resultof(command) - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - else - return "" - end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + else + return "" + end end os.resultof=resultof function os.pipeto(command) - return iopopen(command,"w") + return iopopen(command,"w") end if not io.fileseparator then - if find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" - else - io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" - end + if find(os.getenv("PATH"),";",1,true) then + io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" + else + io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" + end end os.type=os.type or (io.pathseparator==";" and "windows") or "unix" -os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" +os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" if os.type=="windows" then - os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } + os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } else - os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } + os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } end local launchers={ - windows="start %s", - macosx="open %s", - unix="$BROWSER %s &> /dev/null &", + windows="start %s", + macosx="open %s", + unix="xdg-open %s &> /dev/null &", } function os.launch(str) - execute(format(launchers[os.name] or launchers.unix,str)) + execute(format(launchers[os.name] or launchers.unix,str)) end if not os.times then - function os.times() - return { - utime=os.gettimeofday(), - stime=0, - cutime=0, - cstime=0, - } - end + function os.times() + return { + utime=os.gettimeofday(), + stime=0, + cutime=0, + cstime=0, + } + end end local gettimeofday=os.gettimeofday or os.clock os.gettimeofday=gettimeofday local startuptime=gettimeofday() function os.runtime() - return gettimeofday()-startuptime + return gettimeofday()-startuptime end 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 + local r=resolvers[k] + return r and r(t,k) or nil end }) local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or "" if platform~="" then - os.platform=platform + os.platform=platform elseif os.type=="windows" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or "" - if find(architecture,"AMD64",1,true) then - platform="win64" - else - platform="mswin" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("PROCESSOR_ARCHITECTURE") or "" + local platform="" + if find(architecture,"AMD64",1,true) then + platform="win64" + else + platform="mswin" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="linux" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="linux-64" - elseif find(architecture,"ppc",1,true) then - platform="linux-ppc" - else - platform="linux" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform=os.getenv("MTX_PLATFORM") or "" + local musl=find(os.selfdir or "","linuxmusl") + if platform~="" then + elseif find(architecture,"x86_64",1,true) then + platform=musl and "linuxmusl" or "linux-64" + elseif find(architecture,"ppc",1,true) then + platform="linux-ppc" + else + platform=musl and "linuxmusl" or "linux" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="macosx" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("echo $HOSTTYPE") or "" - if architecture=="" then - platform="osx-intel" - elseif find(architecture,"i386",1,true) then - platform="osx-intel" - elseif find(architecture,"x86_64",1,true) then - platform="osx-64" - else - platform="osx-ppc" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=resultof("echo $HOSTTYPE") or "" + local platform="" + if architecture=="" then + platform="osx-intel" + elseif find(architecture,"i386",1,true) then + platform="osx-intel" + elseif find(architecture,"x86_64",1,true) then + platform="osx-64" + else + platform="osx-ppc" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="sunos" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"sparc",1,true) then - platform="solaris-sparc" - else - platform="solaris-intel" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"sparc",1,true) then + platform="solaris-sparc" + else + platform="solaris-intel" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="freebsd" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"amd64",1,true) then - platform="freebsd-amd64" - else - platform="freebsd" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"amd64",1,true) then + platform="freebsd-amd64" + else + platform="freebsd" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="kfreebsd" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="kfreebsd-amd64" - else - platform="kfreebsd-i386" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform="" + if find(architecture,"x86_64",1,true) then + platform="kfreebsd-amd64" + else + platform="kfreebsd-i386" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end else - function resolvers.platform(t,k) - local platform="linux" - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local platform="linux" + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end end os.newline=name=="windows" and "\013\010" or "\010" function resolvers.bits(t,k) - local bits=find(os.platform,"64",1,true) and 64 or 32 - os.bits=bits - return bits + 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", - random(0xFFFF),random(0xFFFF), - random(0x0FFF), - t[ceil(random(4))] or 8,random(0x0FFF), - random(0xFFFF), - random(0xFFFF),random(0xFFFF),random(0xFFFF) - ) + return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", + random(0xFFFF),random(0xFFFF), + random(0x0FFF), + t[ceil(random(4))] or 8,random(0x0FFF), + random(0xFFFF), + random(0xFFFF),random(0xFFFF),random(0xFFFF) + ) end local d function os.timezone(delta) - d=d or tonumber(tonumber(date("%H")-date("!%H"))) - if delta then - if d>0 then - return format("+%02i:00",d) - else - return format("-%02i:00",-d) - end + d=d or tonumber(tonumber(date("%H")-date("!%H"))) + if delta then + if d>0 then + return format("+%02i:00",d) else - return 1 + return format("-%02i:00",-d) end + else + return 1 + end 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=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=format(timeformat,date(dateformat)) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=format(timeformat,date(dateformat)) + end + return lastdate end local dateformat="%Y-%m-%d %H:%M:%S" local lasttime=nil local lastdate=nil function os.localtime(t,default) - t=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=date(dateformat,t) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=date(dateformat,t) + end + return lastdate end function os.converttime(t,default) - local t=tonumber(t) - if t and t>0 then - return date(dateformat,t) - else - return default or "-" - end + local t=tonumber(t) + if t and t>0 then + return date(dateformat,t) + else + return default or "-" + end end local memory={} local function which(filename) - local fullname=memory[filename] - if fullname==nil then - local suffix=file.suffix(filename) - local suffixes=suffix=="" and os.binsuffixes or { suffix } - for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do - local df=file.join(directory,filename) - for i=1,#suffixes do - local dfs=file.addsuffix(df,suffixes[i]) - if io.exists(dfs) then - fullname=dfs - break - end - end - end - if not fullname then - fullname=false + local fullname=memory[filename] + if fullname==nil then + local suffix=file.suffix(filename) + local suffixes=suffix=="" and os.binsuffixes or { suffix } + for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local df=file.join(directory,filename) + for i=1,#suffixes do + local dfs=file.addsuffix(df,suffixes[i]) + if io.exists(dfs) then + fullname=dfs + break end - memory[filename]=fullname + end end - return fullname + if not fullname then + fullname=false + end + memory[filename]=fullname + end + return fullname end os.which=which os.where=which function os.today() - return date("!*t") + return date("!*t") end function os.now() - return date("!%Y-%m-%d %H:%M:%S") + return date("!%Y-%m-%d %H:%M:%S") end if not os.sleep then - local socket=socket - function os.sleep(n) - if not socket then - socket=require("socket") - end - socket.sleep(n) + local socket=socket + function os.sleep(n) + if not socket then + socket=require("socket") end + socket.sleep(n) + end end local function isleapyear(year) - return (year%4==0) and (year%100~=0 or year%400==0) + return (year%4==0) and (year%100~=0 or year%400==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 + 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 + 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 + 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 +local osexit=os.exit +local exitcode=nil +function os.setexitcode(code) + exitcode=code +end +function os.exit(c) + if exitcode~=nil then + return osexit(exitcode) + end + if c~=nil then + return osexit(c) + end + return osexit() end @@ -3931,19 +4217,19 @@ do -- create closure to overcome 200 locals limit package.loaded["l-file"] = package.loaded["l-file"] or true --- original size: 21616, stripped down to: 10359 +-- original size: 21804, stripped down to: 9980 if not modules then modules={} end modules ['l-file']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } file=file or {} local file=file if not lfs then - lfs=optionalrequire("lfs") + lfs=optionalrequire("lfs") end local insert,concat=table.insert,table.concat local match,find,gmatch=string.match,string.find,string.gmatch @@ -3951,24 +4237,22 @@ local lpegmatch=lpeg.match local getcurrentdir,attributes=lfs.currentdir,lfs.attributes local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct -local tricky=S("/\\")*P(-1) local attributes=lfs.attributes -if sandbox then - sandbox.redefine(lfs.isfile,"lfs.isfile") - sandbox.redefine(lfs.isdir,"lfs.isdir") -end function lfs.isdir(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end + return attributes(name,"mode")=="directory" end function lfs.isfile(name) - return attributes(name,"mode")=="file" + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil end function lfs.isfound(name) - return attributes(name,"mode")=="file" and name or nil + local a=attributes(name,"mode") + return (a=="file" or a=="link") and name or nil +end +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir,"lfs.isdir") + sandbox.redefine(lfs.isfound,"lfs.isfound") end local colon=P(":") local period=P(".") @@ -3982,27 +4266,27 @@ local name=noperiod^1 local suffix=period/""*(1-period-slashes)^1*-1 local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) local function pathpart(name,default) - return name and lpegmatch(pattern,name) or default or "" + return name and lpegmatch(pattern,name) or default or "" end local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1 local function basename(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0 local function nameonly(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1 local function suffixonly(name) - return name and lpegmatch(pattern,name) or "" + return name and lpegmatch(pattern,name) or "" end local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("") local function suffixesonly(name) - if name then - return lpegmatch(pattern,name) - else - return "" - end + if name then + return lpegmatch(pattern,name) + else + return "" + end end file.pathpart=pathpart file.basename=basename @@ -4011,7 +4295,7 @@ file.suffixonly=suffixonly file.suffix=suffixonly file.suffixesonly=suffixesonly file.suffixes=suffixesonly -file.dirname=pathpart +file.dirname=pathpart file.extname=suffixonly local drive=C(R("az","AZ"))*colon local path=C((noslashes^0*slashes)^0) @@ -4027,142 +4311,142 @@ local pattern_b=path*base*suffix local pattern_c=C(drive*path)*C(base*suffix) local pattern_d=path*rest function file.splitname(str,splitdrive) - if not str then - elseif splitdrive then - return lpegmatch(pattern_a,str) - else - return lpegmatch(pattern_b,str) - end + if not str then + elseif splitdrive then + return lpegmatch(pattern_a,str) + else + return lpegmatch(pattern_b,str) + end end function file.splitbase(str) - if str then - return lpegmatch(pattern_d,str) - else - return "",str - end + if str then + return lpegmatch(pattern_d,str) + else + return "",str + end end function file.nametotable(str,splitdrive) - if str then - local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) - if splitdrive then - return { - path=path, - drive=drive, - subpath=subpath, - name=name, - base=base, - suffix=suffix, - } - else - return { - path=path, - name=name, - base=base, - suffix=suffix, - } - end + if str then + local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) + if splitdrive then + return { + path=path, + drive=drive, + subpath=subpath, + name=name, + base=base, + suffix=suffix, + } + else + return { + path=path, + name=name, + base=base, + suffix=suffix, + } end + end end local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1) function file.removesuffix(name) - return name and lpegmatch(pattern,name) + return name and lpegmatch(pattern,name) end local suffix=period/""*(1-period-slashes)^1*-1 local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix) function file.addsuffix(filename,suffix,criterium) - if not filename or not suffix or suffix=="" then - return filename - elseif criterium==true then - return filename.."."..suffix - elseif not criterium then - local n,s=lpegmatch(pattern,filename) - if not s or s=="" then - return filename.."."..suffix - else + if not filename or not suffix or suffix=="" then + return filename + elseif criterium==true then + return filename.."."..suffix + elseif not criterium then + local n,s=lpegmatch(pattern,filename) + if not s or s=="" then + return filename.."."..suffix + else + return filename + end + else + local n,s=lpegmatch(pattern,filename) + if s and s~="" then + local t=type(criterium) + if t=="table" then + for i=1,#criterium do + if s==criterium[i] then return filename + end end - else - local n,s=lpegmatch(pattern,filename) - if s and s~="" then - local t=type(criterium) - if t=="table" then - for i=1,#criterium do - if s==criterium[i] then - return filename - end - end - elseif t=="string" then - if s==criterium then - return filename - end - end + elseif t=="string" then + if s==criterium then + return filename end - return (n or filename).."."..suffix + end end + return (n or filename).."."..suffix + end end local suffix=period*(1-period-slashes)^1*-1 local pattern=Cs((1-suffix)^0) function file.replacesuffix(name,suffix) - if name and suffix and suffix~="" then - return lpegmatch(pattern,name).."."..suffix - else - return name - end + if name and suffix and suffix~="" then + return lpegmatch(pattern,name).."."..suffix + else + return name + end end local reslasher=lpeg.replacer(P("\\"),"/") function file.reslash(str) - return str and lpegmatch(reslasher,str) + return str and lpegmatch(reslasher,str) end function file.is_writable(name) - if not name then - elseif lfs.isdir(name) then - name=name.."/m_t_x_t_e_s_t.tmp" - local f=io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f=io.open(name,"ab") - if f then - f:close() - return true - end - else - local f=io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true - end + if not name then + elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true end - return false + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end + end + return false end local readable=P("r")*Cc(true) function file.is_readable(name) - if name then - local a=attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else - return false - end + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end file.isreadable=file.is_readable file.iswritable=file.is_writable function file.size(name) - if name then - local a=attributes(name) - return a and a.size or 0 - else - return 0 - end + if name then + local a=attributes(name) + return a and a.size or 0 + else + return 0 + end end function file.splitpath(str,separator) - return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) + return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) end function file.joinpath(tab,separator) - return tab and concat(tab,separator or io.pathseparator) + return tab and concat(tab,separator or io.pathseparator) end local someslash=S("\\/") local stripper=Cs(P(fwslash)^0/""*reslasher) @@ -4172,30 +4456,30 @@ local hasroot=fwslash^1 local reslasher=lpeg.replacer(S("\\/"),"/") local deslasher=lpeg.replacer(S("\\/")^1,"/") function file.join(one,two,three,...) - if not two then - return one=="" and one or lpegmatch(reslasher,one) - end - if one=="" then - return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) - end - if lpegmatch(isnetwork,one) then - local one=lpegmatch(reslasher,one) - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return one..two - else - return one.."/"..two - end - elseif lpegmatch(isroot,one) then - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return two - else - return "/"..two - end - else - return lpegmatch(deslasher,concat({ one,two,three,... },"/")) - end + if not two then + return one=="" and one or lpegmatch(reslasher,one) + end + if one=="" then + return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) + end + if lpegmatch(isnetwork,one) then + local one=lpegmatch(reslasher,one) + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return one..two + else + return one.."/"..two + end + elseif lpegmatch(isroot,one) then + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return two + else + return "/"..two + end + else + return lpegmatch(deslasher,concat({ one,two,three,... },"/")) + end end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec @@ -4205,56 +4489,56 @@ 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 - return - end - if anchor==true and not lpegmatch(anchors,str) then - str=getcurrentdir().."/"..str - end - if str=="" or str=="." then - return "." - elseif lpegmatch(untouched,str) then - return lpegmatch(reslasher,str) - end - local starter,oldelements=lpegmatch(splitstarter,str) - local newelements={} - local i=#oldelements - while i>0 do - local element=oldelements[i] - if element=='.' then - elseif element=='..' then - local n=i-1 - while n>0 do - local element=oldelements[n] - if element~='..' and element~='.' then - oldelements[n]='.' - break - else - n=n-1 - end - end - if n<1 then - insert(newelements,1,'..') - end - elseif element~="" then - insert(newelements,1,element) - end - i=i-1 - end - if #newelements==0 then - return starter or "." - elseif starter then - return starter..concat(newelements,'/') - elseif lpegmatch(absolute,str) then - return "/"..concat(newelements,'/') - else - newelements=concat(newelements,'/') - if anchor=="." and find(str,"^%./") then - return "./"..newelements + if not str then + return + end + if anchor==true and not lpegmatch(anchors,str) then + str=getcurrentdir().."/"..str + end + if str=="" or str=="." then + return "." + elseif lpegmatch(untouched,str) then + return lpegmatch(reslasher,str) + end + local starter,oldelements=lpegmatch(splitstarter,str) + local newelements={} + local i=#oldelements + while i>0 do + local element=oldelements[i] + if element=='.' then + elseif element=='..' then + local n=i-1 + while n>0 do + local element=oldelements[n] + if element~='..' and element~='.' then + oldelements[n]='.' + break else - return newelements + n=n-1 end - end + end + if n<1 then + insert(newelements,1,'..') + end + elseif element~="" then + insert(newelements,1,element) + end + i=i-1 + end + if #newelements==0 then + return starter or "." + elseif starter then + return starter..concat(newelements,'/') + elseif lpegmatch(absolute,str) then + return "/"..concat(newelements,'/') + else + newelements=concat(newelements,'/') + if anchor=="." and find(str,"^%./") then + return "./"..newelements + else + return newelements + end + end end local validchars=R("az","09","AZ","--","..") local pattern_a=lpeg.replacer(1-validchars) @@ -4262,26 +4546,26 @@ local pattern_a=Cs((validchars+P(1)/"-")^1) local whatever=P("-")^0/"" local pattern_b=Cs(whatever*(1-whatever*-1)^1) function file.robustname(str,strict) - if str then - str=lpegmatch(pattern_a,str) or str - if strict then - return lpegmatch(pattern_b,str) or str - else - return str - end + if str then + str=lpegmatch(pattern_a,str) or str + if strict then + return lpegmatch(pattern_b,str) or str + else + return str end + end end local loaddata=io.loaddata local savedata=io.savedata file.readdata=loaddata file.savedata=savedata function file.copy(oldname,newname) - if oldname and newname then - local data=loaddata(oldname) - if data and data~="" then - savedata(newname,data) - end + if oldname and newname then + local data=loaddata(oldname) + if data and data~="" then + savedata(newname,data) end + end end local letter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4290,40 +4574,44 @@ local rootbased=fwslash+letter*colon lpeg.patterns.qualified=qualified lpeg.patterns.rootbased=rootbased function file.is_qualified_path(filename) - return filename and lpegmatch(qualified,filename)~=nil + return filename and lpegmatch(qualified,filename)~=nil end function file.is_rootbased_path(filename) - return filename and lpegmatch(rootbased,filename)~=nil + return filename and lpegmatch(rootbased,filename)~=nil end function file.strip(name,dir) - if name then - local b,a=match(name,"^(.-)"..dir.."(.*)$") - return a~="" and a or name - end + if name then + local b,a=match(name,"^(.-)"..dir.."(.*)$") + return a~="" and a or name + end end function lfs.mkdirs(path) - local full="" - for sub in gmatch(path,"(/*[^\\/]+)") do - full=full..sub - lfs.mkdir(full) - end + local full="" + for sub in gmatch(path,"(/*[^\\/]+)") do + full=full..sub + lfs.mkdir(full) + end end function file.withinbase(path) - local l=0 - if not find(path,"^/") then - path="/"..path + local l=0 + if not find(path,"^/") then + path="/"..path + end + for dir in gmatch(path,"/([^/]+)") do + if dir==".." then + l=l-1 + elseif dir~="." then + l=l+1 end - for dir in gmatch(path,"/([^/]+)") do - if dir==".." then - l=l-1 - elseif dir~="." then - l=l+1 - end - if l<0 then - return false - end + if l<0 then + return false end - return true + end + return true +end +local symlinkattributes=lfs.symlinkattributes +function lfs.readlink(name) + return symlinkattributes(name,"target") or nil end @@ -4333,51 +4621,51 @@ do -- create closure to overcome 200 locals limit package.loaded["l-gzip"] = package.loaded["l-gzip"] or true --- original size: 1211, stripped down to: 1002 +-- original size: 1211, stripped down to: 951 if not modules then modules={} end modules ['l-gzip']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not gzip then - return + return end local suffix,suffixes=file.suffix,file.suffixes function gzip.load(filename) - local f=io.open(filename,"rb") - if not f then - elseif suffix(filename)=="gz" then - f:close() - local g=gzip.open(filename,"rb") - if g then - local str=g:read("*all") - g:close() - return str - end - else - local str=f:read("*all") - f:close() - return str - end + local f=io.open(filename,"rb") + if not f then + elseif suffix(filename)=="gz" then + f:close() + local g=gzip.open(filename,"rb") + if g then + local str=g:read("*all") + g:close() + return str + end + else + local str=f:read("*all") + f:close() + return str + end end function gzip.save(filename,data) - if suffix(filename)~="gz" then - filename=filename..".gz" - end - local f=io.open(filename,"wb") - if f then - local s=zlib.compress(data or "",9,nil,15+16) - f:write(s) - f:close() - return #s - end + if suffix(filename)~="gz" then + filename=filename..".gz" + end + local f=io.open(filename,"wb") + if f then + local s=zlib.compress(data or "",9,nil,15+16) + f:write(s) + f:close() + return #s + end end function gzip.suffix(filename) - local suffix,extra=suffixes(filename) - local gzipped=extra=="gz" - return suffix,gzipped + local suffix,extra=suffixes(filename) + local gzipped=extra=="gz" + return suffix,gzipped end @@ -4387,87 +4675,119 @@ do -- create closure to overcome 200 locals limit package.loaded["l-md5"] = package.loaded["l-md5"] or true --- original size: 3309, stripped down to: 2314 +-- original size: 3309, stripped down to: 2218 if not modules then modules={} end modules ['l-md5']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not md5 then - md5=optionalrequire("md5") + md5=optionalrequire("md5") end if not md5 then - md5={ - sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, - sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, - } + md5={ + sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, + sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, + } end local md5,file=md5,file local gsub=string.gsub do - local patterns=lpeg and lpeg.patterns - if patterns then - local bytestoHEX=patterns.bytestoHEX - local bytestohex=patterns.bytestohex - local bytestodec=patterns.bytestodec - local lpegmatch=lpeg.match - local md5sum=md5.sum - if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end - if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end - if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end - md5.sumhexa=md5.hex - md5.sumHEXA=md5.HEX - end + local patterns=lpeg and lpeg.patterns + if patterns then + local bytestoHEX=patterns.bytestoHEX + local bytestohex=patterns.bytestohex + local bytestodec=patterns.bytestodec + local lpegmatch=lpeg.match + local md5sum=md5.sum + if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end + if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end + if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end + md5.sumhexa=md5.hex + md5.sumHEXA=md5.HEX + end end function file.needsupdating(oldname,newname,threshold) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime then - local newtime=lfs.attributes(newname,"modification") - if not newtime then - return true - elseif newtime>=oldtime then - return false - elseif oldtime-newtime<(threshold or 1) then - return false - else - return true - end - else - return false - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime then + local newtime=lfs.attributes(newname,"modification") + if not newtime then + return true + elseif newtime>=oldtime then + return false + elseif oldtime-newtime<(threshold or 1) then + return false + else + return true + end + else + return false + end end file.needs_updating=file.needsupdating function file.syncmtimes(oldname,newname) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime and lfs.isfile(newname) then - lfs.touch(newname,oldtime,oldtime) - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) + end end function file.checksum(name) - if md5 then - local data=io.loaddata(name) - if data then - return md5.HEX(data) - end + if md5 then + local data=io.loaddata(name) + if data then + return md5.HEX(data) end - return nil + end + return nil end function file.loadchecksum(name) - if md5 then - local data=io.loaddata(name..".md5") - return data and (gsub(data,"%s","")) - end - return nil + if md5 then + local data=io.loaddata(name..".md5") + return data and (gsub(data,"%s","")) + end + return nil end function file.savechecksum(name,checksum) - if not checksum then checksum=file.checksum(name) end - if checksum then - io.savedata(name..".md5",checksum) - return checksum - end - return nil + if not checksum then checksum=file.checksum(name) end + if checksum then + io.savedata(name..".md5",checksum) + return checksum + end + return nil +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["l-sha"] = package.loaded["l-sha"] or true + +-- original size: 1085, stripped down to: 969 + +if not modules then modules={} end modules ['l-sha']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +if sha2 then + local lpegmatch=lpeg.match + local lpegpatterns=lpeg.patterns + local bytestohex=lpegpatterns.bytestohex + local bytestoHEX=lpegpatterns.bytestoHEX + local digest256=sha2.digest256 + local digest384=sha2.digest384 + local digest512=sha2.digest512 + sha2.hash256=function(str) return lpegmatch(bytestohex,digest256(str)) end + sha2.hash384=function(str) return lpegmatch(bytestohex,digest384(str)) end + sha2.hash512=function(str) return lpegmatch(bytestohex,digest512(str)) end + sha2.HASH256=function(str) return lpegmatch(bytestoHEX,digest256(str)) end + sha2.HASH384=function(str) return lpegmatch(bytestoHEX,digest384(str)) end + sha2.HASH512=function(str) return lpegmatch(bytestoHEX,digest512(str)) end end @@ -4477,14 +4797,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-url"] = package.loaded["l-url"] or true --- original size: 14755, stripped down to: 7236 +-- original size: 14755, stripped down to: 6981 if not modules then modules={} end modules ['l-url']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local char,format,byte=string.char,string.format,string.byte local concat=table.concat @@ -4497,14 +4817,14 @@ local url=url local unescapes={} local escapes={} setmetatable(unescapes,{ __index=function(t,k) - local v=char(tonumber(k,16)) - t[k]=v - return v + local v=char(tonumber(k,16)) + t[k]=v + return v end }) setmetatable(escapes,{ __index=function(t,k) - local v=format("%%%02X",byte(k)) - t[k]=v - return v + local v=format("%%%02X",byte(k)) + t[k]=v + return v end }) local colon=P(":") local qmark=P("?") @@ -4523,21 +4843,21 @@ local escaped=(plus/" ")+escapedchar local noslash=P("/")/"" local plustospace=P("+")/" " local decoder=Cs(( - plustospace+escapedchar+P("\r\n")/"\n"+P(1) - )^0 ) + plustospace+escapedchar+P("\r\n")/"\n"+P(1) + )^0 ) local encoder=Cs(( - R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar - )^0 ) + R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar + )^0 ) lpegpatterns.urldecoder=decoder lpegpatterns.urlencoder=encoder -function url.decode (str) return str and lpegmatch(decoder,str) or str end -function url.encode (str) return str and lpegmatch(encoder,str) or str end +function url.decode (str) return str and lpegmatch(decoder,str) or str end +function url.encode (str) return str and lpegmatch(encoder,str) or str end function url.unescape(str) return str and lpegmatch(unescaper,str) or str end local schemestr=Cs((escaped+(1-colon-slash-qmark-hash))^2) local authoritystr=Cs((escaped+(1- slash-qmark-hash))^0) -local pathstr=Cs((escaped+(1- qmark-hash))^0) -local querystr=Cs(((1- hash))^0) -local fragmentstr=Cs((escaped+(1- endofstring))^0) +local pathstr=Cs((escaped+(1- qmark-hash))^0) +local querystr=Cs(((1- hash))^0) +local fragmentstr=Cs((escaped+(1- endofstring))^0) local scheme=schemestr*colon+nothing local authority=slash*slash*authoritystr+nothing local path=slash*pathstr+nothing @@ -4555,19 +4875,19 @@ lpegpatterns.urlescaper=escaper lpegpatterns.urlunescaper=unescaper lpegpatterns.urlgetcleaner=getcleaner function url.unescapeget(str) - return lpegmatch(getcleaner,str) + return lpegmatch(getcleaner,str) end local function split(str) - return (type(str)=="string" and lpegmatch(parser,str)) or str + return (type(str)=="string" and lpegmatch(parser,str)) or str end local isscheme=schemestr*colon*slash*slash local function hasscheme(str) - if str then - local scheme=lpegmatch(isscheme,str) - return scheme~="" and scheme or false - else - return false - end + if str then + local scheme=lpegmatch(isscheme,str) + return scheme~="" and scheme or false + else + return false + end end local rootletter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4577,161 +4897,161 @@ local barswapper=replacer("|",":") local backslashswapper=replacer("\\","/") local equal=P("=") local amp=P("&") -local key=Cs(((plustospace+escapedchar+1)-equal )^0) +local key=Cs(((plustospace+escapedchar+1)-equal )^0) local value=Cs(((plustospace+escapedchar+1)-amp-endofstring)^0) local splitquery=Cf (Ct("")*P { "sequence", - sequence=V("pair")*(amp*V("pair"))^0, - pair=Cg(key*equal*value), + sequence=V("pair")*(amp*V("pair"))^0, + pair=Cg(key*equal*value), },rawset) local userpart=(1-atsign-colon)^1 local serverpart=(1-colon)^1 local splitauthority=((Cs(userpart)*colon*Cs(userpart)+Cs(userpart)*Cc(nil))*atsign+Cc(nil)*Cc(nil))*Cs(serverpart)*(colon*(serverpart/tonumber)+Cc(nil)) local function hashed(str) - if not str or str=="" then - return { - scheme="invalid", - original=str, - } - end - local detailed=split(str) - local rawscheme="" - local rawquery="" - local somescheme=false - local somequery=false - if detailed then - rawscheme=detailed[1] - rawquery=detailed[4] - somescheme=rawscheme~="" - somequery=rawquery~="" - end - if not somescheme and not somequery then - return { - scheme="file", - authority="", - path=str, - query="", - fragment="", - original=str, - noscheme=true, - filename=str, - } - end - local authority=detailed[2] - local path=detailed[3] - local filename - local username - local password - local host - local port - if authority~="" then - username,password,host,port=lpegmatch(splitauthority,authority) - end - if authority=="" then - filename=path - elseif path=="" then - filename="" - else - filename=authority.."/"..path - end + if not str or str=="" then return { - scheme=rawscheme, - authority=authority, - path=path, - query=lpegmatch(unescaper,rawquery), - queries=lpegmatch(splitquery,rawquery), - fragment=detailed[5], - original=str, - noscheme=false, - filename=filename, - host=host, - port=port, + scheme="invalid", + original=str, } + end + local detailed=split(str) + local rawscheme="" + local rawquery="" + local somescheme=false + local somequery=false + if detailed then + rawscheme=detailed[1] + rawquery=detailed[4] + somescheme=rawscheme~="" + somequery=rawquery~="" + end + if not somescheme and not somequery then + return { + scheme="file", + authority="", + path=str, + query="", + fragment="", + original=str, + noscheme=true, + filename=str, + } + end + local authority=detailed[2] + local path=detailed[3] + local filename + local username + local password + local host + local port + if authority~="" then + username,password,host,port=lpegmatch(splitauthority,authority) + end + if authority=="" then + filename=path + elseif path=="" then + filename="" + else + filename=authority.."/"..path + end + return { + scheme=rawscheme, + authority=authority, + path=path, + query=lpegmatch(unescaper,rawquery), + queries=lpegmatch(splitquery,rawquery), + fragment=detailed[5], + original=str, + noscheme=false, + filename=filename, + host=host, + port=port, + } end url.split=split url.hasscheme=hasscheme url.hashed=hashed function url.addscheme(str,scheme) - if hasscheme(str) then - return str - elseif not scheme then - return "file:///"..str - else - return scheme..":///"..str - end + if hasscheme(str) then + return str + elseif not scheme then + return "file:///"..str + else + return scheme..":///"..str + end end function url.construct(hash) - local result,r={},0 - local scheme=hash.scheme - local authority=hash.authority - local path=hash.path - local queries=hash.queries - local fragment=hash.fragment - if scheme and scheme~="" then - r=r+1;result[r]=lpegmatch(escaper,scheme) - r=r+1;result[r]="://" - end - if authority and authority~="" then - r=r+1;result[r]=lpegmatch(escaper,authority) - end - if path and path~="" then - r=r+1;result[r]="/" - r=r+1;result[r]=lpegmatch(escaper,path) - end - if queries then - local done=false - for k,v in sortedhash(queries) do - r=r+1;result[r]=done and "&" or "?" - r=r+1;result[r]=lpegmatch(escaper,k) - r=r+1;result[r]="=" - r=r+1;result[r]=lpegmatch(escaper,v) - done=true - end - end - if fragment and fragment~="" then - r=r+1;result[r]="#" - r=r+1;result[r]=lpegmatch(escaper,fragment) - end - return concat(result) + local result,r={},0 + local scheme=hash.scheme + local authority=hash.authority + local path=hash.path + local queries=hash.queries + local fragment=hash.fragment + if scheme and scheme~="" then + r=r+1;result[r]=lpegmatch(escaper,scheme) + r=r+1;result[r]="://" + end + if authority and authority~="" then + r=r+1;result[r]=lpegmatch(escaper,authority) + end + if path and path~="" then + r=r+1;result[r]="/" + r=r+1;result[r]=lpegmatch(escaper,path) + end + if queries then + local done=false + for k,v in sortedhash(queries) do + r=r+1;result[r]=done and "&" or "?" + r=r+1;result[r]=lpegmatch(escaper,k) + r=r+1;result[r]="=" + r=r+1;result[r]=lpegmatch(escaper,v) + done=true + end + end + if fragment and fragment~="" then + r=r+1;result[r]="#" + r=r+1;result[r]=lpegmatch(escaper,fragment) + end + return concat(result) end local pattern=Cs(slash^-1/""*R("az","AZ")*((S(":|")/":")+P(":"))*slash*P(1)^0) function url.filename(filename) - local spec=hashed(filename) - local path=spec.path - return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename + local spec=hashed(filename) + local path=spec.path + return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename end local function escapestring(str) - return lpegmatch(escaper,str) + return lpegmatch(escaper,str) end url.escape=escapestring function url.query(str) - if type(str)=="string" then - return lpegmatch(splitquery,str) or "" - else - return str - end + if type(str)=="string" then + return lpegmatch(splitquery,str) or "" + else + return str + end end function url.toquery(data) - local td=type(data) - if td=="string" then - return #str and escape(data) or nil - elseif td=="table" then - if next(data) then - local t={} - for k,v in next,data do - t[#t+1]=format("%s=%s",k,escapestring(v)) - end - return concat(t,"&") - end - else + local td=type(data) + if td=="string" then + return #str and escape(data) or nil + elseif td=="table" then + if next(data) then + local t={} + for k,v in next,data do + t[#t+1]=format("%s=%s",k,escapestring(v)) + end + return concat(t,"&") end + else + end end local pattern=Cs(noslash^0*(1-noslash*P(-1))^0) function url.barepath(path) - if not path or path=="" then - return "" - else - return lpegmatch(pattern,path) - end + if not path or path=="" then + return "" + else + return lpegmatch(pattern,path) + end end @@ -4741,14 +5061,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 17703, stripped down to: 11691 +-- original size: 18002, stripped down to: 10681 if not modules then modules={} end modules ['l-dir']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,select=type,select local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub @@ -4760,471 +5080,478 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir +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 onwindows then - local tricky=S("/\\")*P(-1) - isdir=function(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end - end - isfile=function(name) - return attributes(name,"mode")=="file" + local tricky=S("/\\")*P(-1) + isdir=function(name) + if lpegmatch(tricky,name) then + return attributes(name,"mode")=="directory" + else + return attributes(name.."/.","mode")=="directory" end - lfs.isdir=isdir - lfs.isfile=isfile + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile else - isdir=function(name) - return attributes(name,"mode")=="directory" - end - isfile=function(name) - return attributes(name,"mode")=="file" - end - lfs.isdir=isdir - lfs.isfile=isfile + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile end function dir.current() - return (gsub(currentdir(),"\\","/")) + return (gsub(currentdir(),"\\","/")) end local function glob_pattern_function(path,patt,recurse,action) - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - action(full) - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end - if dirs then - for i=1,#dirs do - glob_pattern_function(dirs[i],patt,recurse,action) - end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if dirs then + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } + end end + end + end + if dirs then + for i=1,nofdirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end end + end end local function glob_pattern_table(path,patt,recurse,result) - if not result then - result={} - end - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - result[#result+1]=full - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end + if not result then + result={} + end + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + local noffiles=#result + for name,a in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + noffiles=noffiles+1 + result[noffiles]=full + end + elseif recurse and mode=="directory" then if dirs then - for i=1,#dirs do - glob_pattern_table(dirs[i],patt,recurse,result) - end + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } end + end end - return result + end + if dirs then + for i=1,nofdirs do + glob_pattern_table(dirs[i],patt,recurse,result) + end + end + return result end local function globpattern(path,patt,recurse,method) - local kind=type(method) - if patt and sub(patt,1,-3)==path then - patt=false - end - if kind=="function" then - return glob_pattern_function(path,patt,recurse,method) - elseif kind=="table" then - return glob_pattern_table(path,patt,recurse,method) - else - return glob_pattern_table(path,patt,recurse,{}) - end + local kind=type(method) + if patt and sub(patt,1,-3)==path then + patt=false + end + local okay=isdir(path) + if kind=="function" then + return okay and glob_pattern_function(path,patt,recurse,method) or {} + elseif kind=="table" then + return okay and glob_pattern_table(path,patt,recurse,method) or method + else + return okay and glob_pattern_table(path,patt,recurse,{}) or {} + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) - local ok,scanner - result=result or {} - if path=="/" then - ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) - else - ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) - end - if ok and type(scanner)=="function" then - if not find(path,"/$") then - path=path..'/' - end - for name in scanner,first do - if name=="." then - elseif name==".." then - else - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then - result[name]=attr - end - elseif recurse and mode=="directory" then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr - end - end + local ok,scanner + result=result or {} + if path=="/" then + ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) + else + ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) + end + if ok and type(scanner)=="function" then + if not find(path,"/$") then + path=path..'/' + end + for name in scanner,first do + if name=="." then + elseif name==".." then + else + local full=path..name + local attr=attributes(full) + local mode=attr.mode + if mode=='file' then + if find(full,patt) then + result[name]=attr + end + elseif recurse and mode=="directory" then + attr.list=collectpattern(full,patt,recurse) + result[name]=attr end + end end - return result + end + return result end dir.collectpattern=collectpattern local separator,pattern if onwindows then - local slash=S("/\\")/"/" - pattern={ - [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) - } + local slash=S("/\\")/"/" + pattern={ + [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={ - [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), - [2]=C(((1-S("*?/"))^0*P("/"))^0), - [3]=C(P(1)^0) - } + pattern={ + [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) + P("**")/".*"+P("*")/"[^/]*"+P("?")/"[^/]"+P(".")/"%%."+P("+")/"%%+"+P("-")/"%%-"+P(1) )^0 ) local function glob(str,t) - if type(t)=="function" then - if type(str)=="table" then - for s=1,#str do - glob(str[s],t) - end - elseif isfile(str) then - t(str) - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,t) - end - end + if type(t)=="function" then + if type(str)=="table" then + for s=1,#str do + glob(str[s],t) + end + elseif isfile(str) then + t(str) + else + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + globpattern(start,result,recurse,t) + end + end + else + if type(str)=="table" then + local t=t or {} + for s=1,#str do + glob(str[s],t) + end + return t + elseif isfile(str) then + if t then + t[#t+1]=str + return t + else + return { str } + end else - if type(str)=="table" then - local t=t or {} - for s=1,#str do - glob(str[s],t) - end - return t - elseif isfile(str) then - if t then - t[#t+1]=str - return t - else - return { str } - end - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - return globpattern(start,result,recurse,t) - else - return {} - end - end + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + return globpattern(start,result,recurse,t) + else + return {} + end end + end end dir.glob=glob local function globfiles(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if recurse then - globfiles(path.."/"..name,recurse,func,files) - end - elseif mode=="file" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if recurse then + globfiles(path.."/"..name,recurse,func,files) + end + elseif mode=="file" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name end + end end - return files + end + return files end dir.globfiles=globfiles local function globdirs(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - if recurse then - globdirs(path.."/"..name,recurse,func,files) - end - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name + if recurse then + globdirs(path.."/"..name,recurse,func,files) + end end + end end - return files + end + return files end dir.globdirs=globdirs function dir.ls(pattern) - return concat(glob(pattern),"\n") + return concat(glob(pattern),"\n") end local make_indeed=true if onwindows then - function dir.mkdirs(...) - local n=select("#",...) - local str - if n==1 then - str=select(1,...) - if isdir(str) then - return str,true - end + function dir.mkdirs(...) + 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="" - for i=1,n do - local s=select(i,...) - if s=="" then - elseif str=="" then - str=s - else - str=str.."/"..s - end - end + str=str.."/"..s end - local pth="" - local drive=false - local first,middle,last=match(str,"^(//)(//*)(.*)$") - if first then + end + end + local pth="" + local drive=false + local first,middle,last=match(str,"^(//)(//*)(.*)$") + if first then + else + first,last=match(str,"^(//)/*(.-)$") + if first then + middle,last=match(str,"([^/]+)/+(.-)$") + if middle then + pth="//"..middle else - first,last=match(str,"^(//)/*(.-)$") - if first then - middle,last=match(str,"([^/]+)/+(.-)$") - if middle then - pth="//"..middle - else - pth="//"..last - last="" - end - else - first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") - if first then - pth,drive=first..middle,true - else - middle,last=match(str,"^(/*)(.-)$") - if not middle then - last=str - end - end - end + pth="//"..last + last="" end - for s in gmatch(last,"[^/]+") do - if pth=="" then - pth=s - elseif drive then - pth,drive=pth..s,false - else - pth=pth.."/"..s - end - if make_indeed and not isdir(pth) then - mkdir(pth) - end + else + first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") + if first then + pth,drive=first..middle,true + else + middle,last=match(str,"^(/*)(.-)$") + if not middle then + last=str + end end - return pth,(isdir(pth)==true) + end end + for s in gmatch(last,"[^/]+") do + if pth=="" then + pth=s + elseif drive then + pth,drive=pth..s,false + else + pth=pth.."/"..s + end + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end + return pth,(isdir(pth)==true) + end else - function dir.mkdirs(...) - 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 + function dir.mkdirs(...) + 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 - str=gsub(str,"/+","/") - if find(str,"^/") then - pth="/" - for s in gmatch(str,"[^/]+") do - local first=(pth=="/") - if first then - pth=pth..s - else - pth=pth.."/"..s - end - if make_indeed and not first and not isdir(pth) then - mkdir(pth) - end - end + end + end + str=gsub(str,"/+","/") + if find(str,"^/") then + pth="/" + for s in gmatch(str,"[^/]+") do + local first=(pth=="/") + if first then + pth=pth..s else - pth="." - for s in gmatch(str,"[^/]+") do - pth=pth.."/"..s - if make_indeed and not isdir(pth) then - mkdir(pth) - end - end + pth=pth.."/"..s end - return pth,(isdir(pth)==true) + if make_indeed and not first and not isdir(pth) then + mkdir(pth) + end + end + else + pth="." + for s in gmatch(str,"[^/]+") do + pth=pth.."/"..s + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end end + return pth,(isdir(pth)==true) + end end dir.makedirs=dir.mkdirs do - local chdir=sandbox and sandbox.original(chdir) or chdir - if onwindows then - local xcurrentdir=dir.current - function dir.expandname(str) - local first,nothing,last=match(str,"^(//)(//*)(.*)$") - if first then - first=xcurrentdir().."/" - end - if not first then - first,last=match(str,"^(//)/*(.*)$") - end - if not first then - first,last=match(str,"^([a-zA-Z]:)(.*)$") - if first and not find(last,"^/") then - local d=currentdir() - if chdir(first) then - first=xcurrentdir() - end - chdir(d) - end - end - if not first then - first,last=xcurrentdir(),str - end - last=gsub(last,"//","/") - last=gsub(last,"/%./","/") - last=gsub(last,"^/*","") - first=gsub(first,"/*$","") - if last=="" or last=="." then - return first - else - return first.."/"..last - end - end - else - function dir.expandname(str) - if not find(str,"^/") then - str=currentdir().."/"..str - end - str=gsub(str,"//","/") - str=gsub(str,"/%./","/") - str=gsub(str,"(.)/%.$","%1") - return str + local chdir=sandbox and sandbox.original(chdir) or chdir + if onwindows then + local xcurrentdir=dir.current + function dir.expandname(str) + local first,nothing,last=match(str,"^(//)(//*)(.*)$") + if first then + first=xcurrentdir().."/" + end + if not first then + first,last=match(str,"^(//)/*(.*)$") + end + if not first then + first,last=match(str,"^([a-zA-Z]:)(.*)$") + if first and not find(last,"^/") then + local d=currentdir() + if chdir(first) then + first=xcurrentdir() + end + chdir(d) end + end + if not first then + first,last=xcurrentdir(),str + end + last=gsub(last,"//","/") + last=gsub(last,"/%./","/") + last=gsub(last,"^/*","") + first=gsub(first,"/*$","") + if last=="" or last=="." then + return first + else + return first.."/"..last + end end + else + function dir.expandname(str) + if not find(str,"^/") then + str=currentdir().."/"..str + end + str=gsub(str,"//","/") + str=gsub(str,"/%./","/") + str=gsub(str,"(.)/%.$","%1") + return str + end + end end file.expandname=dir.expandname local stack={} function dir.push(newdir) - local curdir=currentdir() - insert(stack,curdir) - if newdir and newdir~="" then - chdir(newdir) - return newdir - else - return curdir - end + local curdir=currentdir() + insert(stack,curdir) + if newdir and newdir~="" then + chdir(newdir) + return newdir + else + return curdir + end end function dir.pop() - local d=remove(stack) - if d then - chdir(d) - end - return d + local d=remove(stack) + if d then + chdir(d) + end + return d end local function found(...) - for i=1,select("#",...) do - local path=select(i,...) - local kind=type(path) - if kind=="string" then - if isdir(path) then - return path - end - elseif kind=="table" then - local path=found(unpack(path)) - if path then - return path - end - end + for i=1,select("#",...) do + local path=select(i,...) + local kind=type(path) + if kind=="string" then + if isdir(path) then + return path + end + elseif kind=="table" then + local path=found(unpack(path)) + if path then + return path + end end + end end dir.found=found @@ -5235,69 +5562,69 @@ do -- create closure to overcome 200 locals limit package.loaded["l-boolean"] = package.loaded["l-boolean"] or true --- original size: 1850, stripped down to: 1568 +-- original size: 1850, stripped down to: 1498 if not modules then modules={} end modules ['l-boolean']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber=type,tonumber boolean=boolean or {} local boolean=boolean function boolean.tonumber(b) - if b then return 1 else return 0 end + if b then return 1 else return 0 end end function toboolean(str,tolerant) - if str==nil then - return false - elseif str==false then - return false - elseif str==true then - return true - elseif str=="true" then - return true - elseif str=="false" then - return false - elseif not tolerant then - return false - elseif str==0 then - return false - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str==nil then + return false + elseif str==false then + return false + elseif str==true then + return true + elseif str=="true" then + return true + elseif str=="false" then + return false + elseif not tolerant then + return false + elseif str==0 then + return false + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end string.toboolean=toboolean function string.booleanstring(str) - if str=="0" then - return false - elseif str=="1" then - return true - elseif str=="" then - return false - elseif str=="false" then - return false - elseif str=="true" then - return true - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str=="0" then + return false + elseif str=="1" then + return true + elseif str=="" then + return false + elseif str=="false" then + return false + elseif str=="true" then + return true + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end function string.is_boolean(str,default,strict) - if type(str)=="string" then - if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then - return true - elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then - return false - end + if type(str)=="string" then + if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then + return true + elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then + return false end - return default + end + return default end @@ -5307,18 +5634,24 @@ do -- create closure to overcome 200 locals limit package.loaded["l-unicode"] = package.loaded["l-unicode"] or true --- original size: 40036, stripped down to: 17837 +-- original size: 41047, stripped down to: 17171 if not modules then modules={} end modules ['l-unicode']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -utf=utf or (unicode and unicode.utf8) or {} -utf.characters=utf.characters or string.utfcharacters -utf.values=utf.values or string.utfvalues +utf=utf or {} +unicode=nil +if not string.utfcharacters then + local gmatch=string.gmatch + function string.characters(str) + return gmatch(str,".[\128-\191]*") + end +end +utf.characters=string.utfcharacters local type=type local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch local concat=table.concat @@ -5329,345 +5662,340 @@ local tabletopattern=lpeg.utfchartabletopattern local bytepairs=string.bytepairs local finder=lpeg.finder 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.utf8character +local p_utf8character=patterns.utf8character +local p_utf8char=patterns.utf8char local p_utf8byte=patterns.utf8byte local p_utfbom=patterns.utfbom local p_newline=patterns.newline local p_whitespace=patterns.whitespace -if not unicode then - unicode={ utf=utf } -end if not utf.char then - utf.char=string.utfcharacter or (utf8 and utf8.char) - if not utf.char then - local char=string.char - if bit32 then - local rshift=bit32.rshift - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+rshift(n,6), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+rshift(n,12), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+rshift(n,18), - 0x80+(rshift(n,12)%0x40), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + utf.char=string.utfcharacter or (utf8 and utf8.char) + if not utf.char then + local char=string.char + if bit32 then + local rshift=bit32.rshift + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+rshift(n,6), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+rshift(n,12), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+rshift(n,18), + 0x80+(rshift(n,12)%0x40), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) else - local floor=math.floor - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+floor(n/0x40), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+floor(n/0x1000), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+floor(n/0x40000), - 0x80+(floor(n/0x1000)%0x40), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + return "" end + end + else + local floor=math.floor + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+floor(n/0x40), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+floor(n/0x1000), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+floor(n/0x40000), + 0x80+(floor(n/0x1000)%0x40), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + else + return "" + end + end end + end end if not utf.byte then - utf.byte=string.utfvalue or (utf8 and utf8.codepoint) - if not utf.byte then - local utf8byte=patterns.utf8byte - function utf.byte(c) - return lpegmatch(utf8byte,c) - end + utf.byte=string.utfvalue or (utf8 and utf8.codepoint) + if not utf.byte then + function utf.byte(c) + return lpegmatch(p_utf8byte,c) end + end end local utfchar,utfbyte=utf.char,utf.byte function utf.filetype(data) - return data and lpegmatch(p_utftype,data) or "unknown" + return data and lpegmatch(p_utftype,data) or "unknown" end local toentities=Cs ( - ( - patterns.utf8one+( - patterns.utf8two+patterns.utf8three+patterns.utf8four - )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end - )^0 + ( + patterns.utf8one+( + patterns.utf8two+patterns.utf8three+patterns.utf8four + )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end + )^0 ) patterns.toentities=toentities function utf.toentities(str) - return lpegmatch(toentities,str) + return lpegmatch(toentities,str) end local one=P(1) local two=C(1)*C(1) local four=C(R(utfchar(0xD8),utfchar(0xFF)))*C(1)*C(1)*C(1) local pattern=P("\254\255")*Cs(( - four/function(a,b,c,d) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(a,b) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 )+P("\255\254")*Cs(( - four/function(b,a,d,c) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(b,a) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 ) + four/function(a,b,c,d) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(a,b) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 )+P("\255\254")*Cs(( + four/function(b,a,d,c) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(b,a) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 ) function string.toutf(s) - return lpegmatch(pattern,s) or s + return lpegmatch(pattern,s) or s end local validatedutf=Cs ( - ( - patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" - )^0 + ( + patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" + )^0 ) patterns.validatedutf=validatedutf function utf.is_valid(str) - return type(str)=="string" and lpegmatch(validatedutf,str) or false + return type(str)=="string" and lpegmatch(validatedutf,str) or false end if not utf.len then - utf.len=string.utflength or (utf8 and utf8.len) - if not utf.len then - local n,f=0,1 - local utfcharcounter=patterns.utfbom^-1*Cmt ( - Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, - function(_,t,d) - n=n+(t-f)/d - f=t - return true - end - )^0 - function utf.len(str) - n,f=0,1 - lpegmatch(utfcharcounter,str or "") - return n - end + utf.len=string.utflength or (utf8 and utf8.len) + if not utf.len then + local n,f=0,1 + local utfcharcounter=patterns.utfbom^-1*Cmt ( + Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, + function(_,t,d) + n=n+(t-f)/d + f=t + return true + end + )^0 + function utf.len(str) + n,f=0,1 + lpegmatch(utfcharcounter,str or "") + return n end + end end utf.length=utf.len if not utf.sub then - local utflength=utf.length - local b,e,n,first,last=0,0,0,0,0 - local function slide_zero(s,p) - n=n+1 - if n>=last then - e=p-1 - else - return p - end + local utflength=utf.length + local b,e,n,first,last=0,0,0,0,0 + local function slide_zero(s,p) + n=n+1 + if n>=last then + e=p-1 + else + return p end - local function slide_one(s,p) - n=n+1 - if n==first then - b=p - end - if n>=last then - e=p-1 - else - return p - end + end + local function slide_one(s,p) + n=n+1 + if n==first then + b=p end - local function slide_two(s,p) - n=n+1 - if n==first then - b=p - else - return true - end + if n>=last then + e=p-1 + else + return p end - local pattern_zero=Cmt(p_utf8char,slide_zero)^0 - local pattern_one=Cmt(p_utf8char,slide_one )^0 - local pattern_two=Cmt(p_utf8char,slide_two )^0 - local pattern_first=C(patterns.utf8character) - function utf.sub(str,start,stop) - if not start then - return str - end - if start==0 then - start=1 - end - if not stop then - if start<0 then - local l=utflength(str) - start=l+start - else - start=start-1 - end - b,n,first=0,0,start - lpegmatch(pattern_two,str) - if n>=first then - return sub(str,b) - else - return "" - end - end - if start<0 or stop<0 then - local l=utf.length(str) - if start<0 then - start=l+start - if start<=0 then - start=1 - else - start=start+1 - end - end - if stop<0 then - stop=l+stop - if stop==0 then - stop=1 - else - stop=stop+1 - end - end + end + local function slide_two(s,p) + n=n+1 + if n==first then + b=p + else + return true + end + end + local pattern_zero=Cmt(p_utf8character,slide_zero)^0 + local pattern_one=Cmt(p_utf8character,slide_one )^0 + local pattern_two=Cmt(p_utf8character,slide_two )^0 + local pattern_first=C(p_utf8character) + function utf.sub(str,start,stop) + if not start then + return str + end + if start==0 then + start=1 + end + if not stop then + if start<0 then + local l=utflength(str) + start=l+start + else + start=start-1 + end + b,n,first=0,0,start + lpegmatch(pattern_two,str) + if n>=first then + return sub(str,b) + else + return "" + end + end + if start<0 or stop<0 then + local l=utf.length(str) + if start<0 then + start=l+start + if start<=0 then + start=1 + else + start=start+1 end - if start==1 and stop==1 then - return lpegmatch(pattern_first,str) or "" - elseif start>stop then - return "" - elseif start>1 then - b,e,n,first,last=0,0,0,start-1,stop - lpegmatch(pattern_one,str) - if n>=first and e==0 then - e=#str - end - return sub(str,b,e) + end + if stop<0 then + stop=l+stop + if stop==0 then + stop=1 else - b,e,n,last=1,0,0,stop - lpegmatch(pattern_zero,str) - if e==0 then - e=#str - end - return sub(str,b,e) + stop=stop+1 end + end end + if start==1 and stop==1 then + return lpegmatch(pattern_first,str) or "" + elseif start>stop then + return "" + elseif start>1 then + b,e,n,first,last=0,0,0,start-1,stop + lpegmatch(pattern_one,str) + if n>=first and e==0 then + e=#str + end + return sub(str,b,e) + else + b,e,n,last=1,0,0,stop + lpegmatch(pattern_zero,str) + if e==0 then + e=#str + end + return sub(str,b,e) + end + end end function utf.remapper(mapping,option,action) - local variant=type(mapping) - if variant=="table" then - action=action or mapping - if option=="dynamic" then - local pattern=false - table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) - return function(str) - if not str or str=="" then - return "" - else - if not pattern then - pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - end - return lpegmatch(pattern,str) - end - end - elseif option=="pattern" then - return Cs((tabletopattern(mapping)/action+p_utf8char)^0) + local variant=type(mapping) + if variant=="table" then + action=action or mapping + if option=="dynamic" then + local pattern=false + table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + if not pattern then + pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + end + return lpegmatch(pattern,str) end - elseif variant=="function" then - if option=="pattern" then - return Cs((p_utf8char/mapping+p_utf8char)^0) + end + elseif option=="pattern" then + return Cs((tabletopattern(mapping)/action+p_utf8character)^0) + else + local pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((p_utf8char/mapping+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + return lpegmatch(pattern,str) end + end,pattern + end + elseif variant=="function" then + if option=="pattern" then + return Cs((p_utf8character/mapping+p_utf8character)^0) else - return function(str) - return str or "" + local pattern=Cs((p_utf8character/mapping+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" + else + return lpegmatch(pattern,str) end + end,pattern end -end -function utf.replacer(t) - local r=replacer(t,false,false,true) + else return function(str) - return lpegmatch(r,str) + return str or "" end + end +end +function utf.replacer(t) + local r=replacer(t,false,false,true) + return function(str) + return lpegmatch(r,str) + end end function utf.subtituter(t) - local f=finder (t) - local r=replacer(t,false,false,true) - return function(str) - local i=lpegmatch(f,str) - if not i then - return str - elseif i>#str then - return str - else - return lpegmatch(r,str) - end + local f=finder (t) + local r=replacer(t,false,false,true) + return function(str) + local i=lpegmatch(f,str) + if not i then + return str + elseif i>#str then + return str + else + return lpegmatch(r,str) end + end end local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline) -local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0) -local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0) -local utfcharsplitter_raw=Ct(C(p_utf8char)^0) +local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8character)^0) +local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8character))^0) +local utfcharsplitter_raw=Ct(C(p_utf8character)^0) patterns.utflinesplitter=utflinesplitter function utf.splitlines(str) - return lpegmatch(utflinesplitter,str or "") + return lpegmatch(utflinesplitter,str or "") end function utf.split(str,ignorewhitespace) - if ignorewhitespace then - return lpegmatch(utfcharsplitter_iws,str or "") - else - return lpegmatch(utfcharsplitter_ows,str or "") - end + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end end function utf.totable(str) - return lpegmatch(utfcharsplitter_raw,str) + return lpegmatch(utfcharsplitter_raw,str) end function utf.magic(f) - local str=f:read(4) or "" - local off=lpegmatch(p_utfoffset,str) - if off<4 then - f:seek('set',off) - end - return lpegmatch(p_utftype,str) + local str=f:read(4) or "" + local off=lpegmatch(p_utfoffset,str) + if off<4 then + f:seek('set',off) + end + return lpegmatch(p_utftype,str) end local utf16_to_utf8_be,utf16_to_utf8_le local utf32_to_utf8_be,utf32_to_utf8_le @@ -5681,36 +6009,36 @@ local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_n local utf_32_le_linesplitter=utf_32_le_getbom*lpeg.tsplitat(patterns.utf_32_le_nl) local more=0 local p_utf16_to_utf8_be=C(1)*C(1)/function(left,right) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf16_to_utf8_le=C(1)*C(1)/function(right,left) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf32_to_utf8_be=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) + return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) end local p_utf32_to_utf8_le=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) + return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) end p_utf16_to_utf8_be=P(true)/function() more=0 end*utf_16_be_getbom*Cs(p_utf16_to_utf8_be^0) p_utf16_to_utf8_le=P(true)/function() more=0 end*utf_16_le_getbom*Cs(p_utf16_to_utf8_le^0) @@ -5721,88 +6049,88 @@ patterns.utf16_to_utf8_le=p_utf16_to_utf8_le patterns.utf32_to_utf8_be=p_utf32_to_utf8_be patterns.utf32_to_utf8_le=p_utf32_to_utf8_le utf16_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_be,s) + else + return s + end end local utf16_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_be,s) end - return t + end + return t end utf16_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_le,s) + else + return s + end end local utf16_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_le,s) end - return t + end + return t end utf32_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_be,s) + else + return s + end end local utf32_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_be,s) end - return t + end + return t end utf32_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_le,s) + else + return s + end end local utf32_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_le,s) end - return t + end + return t end utf.utf16_to_utf8_le_t=utf16_to_utf8_le_t utf.utf16_to_utf8_be_t=utf16_to_utf8_be_t @@ -5813,189 +6141,225 @@ 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(t) - return type(t)=="string" and lpegmatch(utflinesplitter,t) or t + return type(t)=="string" and lpegmatch(utflinesplitter,t) or t end function utf.utf16_to_utf8_t(t,endian) - return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t + return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t end function utf.utf32_to_utf8_t(t,endian) - return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t + return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t end local function little(b) - if b<0x10000 then - return char(b%256,rshift(b,8)) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) - end + if b<0x10000 then + return char(b%256,rshift(b,8)) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) + end end local function big(b) - if b<0x10000 then - return char(rshift(b,8),b%256) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) - end + if b<0x10000 then + return char(rshift(b,8),b%256) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) + end end local l_remap=Cs((p_utf8byte/little+P(1)/"")^0) local b_remap=Cs((p_utf8byte/big+P(1)/"")^0) local function utf8_to_utf16_be(str,nobom) - if nobom then - return lpegmatch(b_remap,str) - else - return char(254,255)..lpegmatch(b_remap,str) - end + if nobom then + return lpegmatch(b_remap,str) + else + return char(254,255)..lpegmatch(b_remap,str) + end end local function utf8_to_utf16_le(str,nobom) - if nobom then - return lpegmatch(l_remap,str) - else - return char(255,254)..lpegmatch(l_remap,str) - end + if nobom then + return lpegmatch(l_remap,str) + else + return char(255,254)..lpegmatch(l_remap,str) + end end utf.utf8_to_utf16_be=utf8_to_utf16_be utf.utf8_to_utf16_le=utf8_to_utf16_le function utf.utf8_to_utf16(str,littleendian,nobom) - if littleendian then - return utf8_to_utf16_le(str,nobom) - else - return utf8_to_utf16_be(str,nobom) - end + if littleendian then + return utf8_to_utf16_le(str,nobom) + else + return 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 + (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 ) function utf.tocodes(str,separator) - return lpegmatch(pattern,str,1,separator or " ") + return lpegmatch(pattern,str,1,separator or " ") end function utf.ustring(s) - return format("U+%05X",type(s)=="number" and s or utfbyte(s)) + return format("U+%05X",type(s)=="number" and s or utfbyte(s)) end function utf.xstring(s) - return format("0x%05X",type(s)=="number" and s or utfbyte(s)) + return format("0x%05X",type(s)=="number" and s or utfbyte(s)) end function utf.toeight(str) - if not str or str=="" then - return nil - end - local utftype=lpegmatch(p_utfstricttype,str) - if utftype=="utf-8" then - return sub(str,4) - elseif utftype=="utf-16-be" then - return utf16_to_utf8_be(str) - elseif utftype=="utf-16-le" then - return utf16_to_utf8_le(str) - else - return str - end -end -local p_nany=p_utf8char/"" -if utfgmatch then - function utf.count(str,what) - if type(what)=="string" then - local n=0 - for _ in utfgmatch(str,what) do - n=n+1 - end - return n - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end -else - local cache={} - function utf.count(str,what) - if type(what)=="string" then - local p=cache[what] - if not p then - p=Cs((P(what)/" "+p_nany)^0) - cache[p]=p - end - return #lpegmatch(p,str) - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end + if not str or str=="" then + return nil + end + local utftype=lpegmatch(p_utfstricttype,str) + if utftype=="utf-8" then + return sub(str,4) + elseif utftype=="utf-16-be" then + return utf16_to_utf8_be(str) + elseif utftype=="utf-16-le" then + return utf16_to_utf8_le(str) + else + return str + end end -if not utf.characters then - function utf.characters(str) - return gmatch(str,".[\128-\191]*") +do + local p_nany=p_utf8character/"" + local cache={} + function utf.count(str,what) + if type(what)=="string" then + local p=cache[what] + if not p then + p=Cs((P(what)/" "+p_nany)^0) + cache[p]=p + end + return #lpegmatch(p,str) + else + return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) end - string.utfcharacters=utf.characters + end end -if not utf.values then - local find=string.find - local dummy=function() - end - function utf.values(str) - local n=#str - if n==0 then - return dummy - elseif n==1 then - return function() return utfbyte(str) end - else - local p=1 - return function() - local b,e=find(str,".[\128-\191]*",p) - if b then - p=e+1 - return utfbyte(sub(str,b,e)) - end - end - end +if not string.utfvalues then + local find=string.find + local dummy=function() + end + function string.utfvalues(str) + local n=#str + if n==0 then + return dummy + elseif n==1 then + return function() return utfbyte(str) end + else + local p=1 + return function() + local b,e=find(str,".[\128-\191]*",p) + if b then + p=e+1 + return utfbyte(sub(str,b,e)) + end + end end - string.utfvalues=utf.values + end end +utf.values=string.utfvalues 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 + 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 if bit32 then - local extract=bit32.extract - local char=string.char - function unicode.toutf32string(n) - if n<=0xFF then - return - char(n).."\000\000\000" - elseif n<=0xFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" - elseif n<=0xFFFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" - else - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) - end - end + local extract=bit32.extract + local char=string.char + function utf.toutf32string(n) + if n<=0xFF then + return + char(n).."\000\000\000" + elseif n<=0xFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" + elseif n<=0xFFFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" + else + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) + end + end end local len=utf.len local rep=rep function string.utfpadd(s,n) - if n and n~=0 then - local l=len(s) - if n>0 then - local d=n-l - if d>0 then - return rep(c or " ",d)..s - end - else - local d=- n-l - if d>0 then - return s..rep(c or " ",d) - end - end + if n and n~=0 then + local l=len(s) + if n>0 then + local d=n-l + if d>0 then + return rep(c or " ",d)..s + end + else + local d=- n-l + if d>0 then + return s..rep(c or " ",d) + end end - return s + end + return s +end +do + local utfcharacters=utf.characters or string.utfcharacters + local utfchar=utf.char or string.utfcharacter + lpeg.UP=P + if utfcharacters then + function lpeg.US(str) + local p=P(false) + for uc in utfcharacters(str) do + p=p+P(uc) + end + return p + end + else + function lpeg.US(str) + local p=P(false) + local f=function(uc) + p=p+P(uc) + end + lpegmatch((p_utf8char/f)^0,str) + return p + end + end + local range=p_utf8byte*p_utf8byte+Cc(false) + function lpeg.UR(str,more) + local first,last + if type(str)=="number" then + first=str + last=more or first + else + first,last=lpegmatch(range,str) + if not last then + return P(str) + end + end + if first==last then + return P(str) + end + if not utfchar then + utfchar=utf.char + end + if utfchar and (last-first<8) then + local p=P(false) + for i=first,last do + p=p+P(utfchar(i)) + end + return p + else + local f=function(b) + return b>=first and b<=last + end + return p_utf8byte/f + end + end end @@ -6005,93 +6369,93 @@ do -- create closure to overcome 200 locals limit package.loaded["l-math"] = package.loaded["l-math"] or true --- original size: 2555, stripped down to: 1900 +-- original size: 2555, stripped down to: 1831 if not modules then modules={} end modules ['l-math']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not math.ceiling then - math.ceiling=math.ceil + math.ceiling=math.ceil end if not math.round then - local floor=math.floor - function math.round(x) return floor(x+0.5) end + local floor=math.floor + function math.round(x) return floor(x+0.5) end end if not math.div then - local floor=math.floor - function math.div(n,m) return floor(n/m) end + local floor=math.floor + function math.div(n,m) return floor(n/m) end end if not math.mod then - function math.mod(n,m) return n%m end + function math.mod(n,m) return n%m end end if not math.sind then - local sin,cos,tan=math.sin,math.cos,math.tan - local pipi=2*math.pi/360 - function math.sind(d) return sin(d*pipi) end - function math.cosd(d) return cos(d*pipi) end - function math.tand(d) return tan(d*pipi) end + local sin,cos,tan=math.sin,math.cos,math.tan + local pipi=2*math.pi/360 + function math.sind(d) return sin(d*pipi) end + function math.cosd(d) return cos(d*pipi) end + function math.tand(d) return tan(d*pipi) end end if not math.odd then - function math.odd (n) return n%2~=0 end - function math.even(n) return n%2==0 end + function math.odd (n) return n%2~=0 end + function math.even(n) return n%2==0 end end if not math.cosh then - local exp=math.exp - function math.cosh(x) - local xx=exp(x) - return (xx+1/xx)/2 - end - function math.sinh(x) - local xx=exp(x) - return (xx-1/xx)/2 - end - function math.tanh(x) - local xx=exp(x) - return (xx-1/xx)/(xx+1/xx) - end + local exp=math.exp + function math.cosh(x) + local xx=exp(x) + return (xx+1/xx)/2 + end + function math.sinh(x) + local xx=exp(x) + return (xx-1/xx)/2 + end + function math.tanh(x) + local xx=exp(x) + return (xx-1/xx)/(xx+1/xx) + end end if not math.pow then - function math.pow(x,y) - return x^y - end + function math.pow(x,y) + return x^y + end end if not math.atan2 then - math.atan2=math.atan + math.atan2=math.atan end if not math.ldexp then - function math.ldexp(x,e) - return x*2.0^e - end + function math.ldexp(x,e) + return x*2.0^e + end end if not math.log10 then - local log=math.log - function math.log10(x) - return log(x,10) - end + local log=math.log + function math.log10(x) + return log(x,10) + end end if not math.type then - function math.type() - return "float" - end + function math.type() + return "float" + end end if not math.tointeger then - math.mininteger=-0x4FFFFFFFFFFF - math.maxinteger=0x4FFFFFFFFFFF - local floor=math.floor - function math.tointeger(n) - local f=floor(n) - return f==n and f or nil - end + math.mininteger=-0x4FFFFFFFFFFF + math.maxinteger=0x4FFFFFFFFFFF + local floor=math.floor + function math.tointeger(n) + local f=floor(n) + return f==n and f or nil + end end if not math.ult then - local floor=math.floor - function math.tointeger(m,n) - return floor(m)<floor(n) - end + local floor=math.floor + function math.tointeger(m,n) + return floor(m)<floor(n) + end end @@ -6101,14 +6465,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 38734, stripped down to: 22142 +-- original size: 43539, stripped down to: 21641 if not modules then modules={} end modules ['util-str']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.strings=utilities.strings or {} @@ -6121,624 +6485,657 @@ 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,utflen=utf.char,utf.byte,utf.len -local loadstripped=nil -local oldfashioned=LUAVERSION<5.2 -if oldfashioned 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 +local 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 if not number then number={} end -local stripper=patterns.stripzeros +local stripzero=patterns.stripzero +local stripzeros=patterns.stripzeros local newline=patterns.newline local endofstring=patterns.endofstring +local anything=patterns.anything local whitespace=patterns.whitespace +local space=patterns.space local spacer=patterns.spacer local spaceortab=patterns.spaceortab +local digit=patterns.digit +local sign=patterns.sign +local period=patterns.period +local ptf=1/65536 +local bpf=(7200/7227)/65536 local function points(n) - n=tonumber(n) - return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*ptf + if n%1==0 then + return format("%ipt",n) + end + return lpegmatch(stripzeros,format("%.5fpt",n)) 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)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*bpf + if n%1==0 then + return format("%ibp",n) + end + return lpegmatch(stripzeros,format("%.5fbp",n)) end number.points=points number.basepoints=basepoints local rubish=spaceortab^0*newline local anyrubish=spaceortab+newline -local anything=patterns.anything local stripped=(spaceortab^1/"")*newline local leading=rubish^0/"" local trailing=(anyrubish^1*endofstring)/"" local redundant=rubish^3/"\n" local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) function strings.collapsecrlf(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local repeaters={} function strings.newrepeater(str,offset) - offset=offset or 0 - local s=repeaters[str] - if not s then - s={} - repeaters[str]=s - end - local t=s[offset] - if t then - return t - end - t={} - setmetatable(t,{ __index=function(t,k) - if not k then - return "" - end - local n=k+offset - local s=n>0 and rep(str,n) or "" - t[k]=s - return s - end }) - s[offset]=t + offset=offset or 0 + local s=repeaters[str] + if not s then + s={} + repeaters[str]=s + end + local t=s[offset] + if t then return t + end + t={} + setmetatable(t,{ __index=function(t,k) + if not k then + return "" + end + local n=k+offset + local s=n>0 and rep(str,n) or "" + t[k]=s + return s + end }) + s[offset]=t + return t end local extra,tab,start=0,0,4,0 local nspaces=strings.newrepeater(" ") string.nspaces=nspaces local pattern=Carg(1)/function(t) - extra,tab,start=0,t or 7,1 - end*Cs(( + extra,tab,start=0,t or 7,1 + end*Cs(( Cp()*patterns.tab/function(position) - local current=(position-start+1)+extra - local spaces=tab-(current-1)%tab - if spaces>0 then - extra=extra+spaces-1 - return nspaces[spaces] - else - return "" - end + local current=(position-start+1)+extra + local spaces=tab-(current-1)%tab + if spaces>0 then + extra=extra+spaces-1 + return nspaces[spaces] + else + return "" + end end+newline*Cp()/function(position) - extra,start=0,position - end+patterns.anything - )^1) + extra,start=0,position + end+anything + )^1) function strings.tabtospace(str,tab) - return lpegmatch(pattern,str,1,tab or 7) + return lpegmatch(pattern,str,1,tab or 7) end function string.utfpadding(s,n) - if not n or n==0 then - return "" - end - local l=utflen(s) - if n>0 then - return nspaces[n-l] - else - return nspaces[-n-l] - end -end -local space=spacer^0 -local nospace=space/"" + if not n or n==0 then + return "" + end + local l=utflen(s) + if n>0 then + return nspaces[n-l] + else + return nspaces[-n-l] + end +end +local optionalspace=spacer^0 +local nospace=optionalspace/"" local endofline=nospace*newline local stripend=(whitespace^1*endofstring)/"" -local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) +local normalline=(nospace*((1-optionalspace*(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 intospace=whitespace^1/" " +local noleading=whitespace^1/"" +local notrailing=noleading*endofstring 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_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^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, - ["collapse"]=patterns.collapser, + ["prune"]=p_prune_normal, + ["prune and collapse"]=p_prune_collapse, + ["prune and no empty"]=p_prune_noempty, + ["prune and to space"]=p_prune_intospace, + ["retain"]=p_retain_normal, + ["retain and collapse"]=p_retain_collapse, + ["retain and no empty"]=p_retain_noempty, + ["collapse"]=patterns.collapser, } setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end }) strings.striplinepatterns=striplinepatterns function strings.striplines(str,how) - return str and lpegmatch(striplinepatterns[how],str) or str + return str and lpegmatch(striplinepatterns[how],str) or str +end +function strings.collapse(str) + return str and lpegmatch(p_prune_intospace,str) or str end strings.striplong=strings.striplines function strings.nice(str) - str=gsub(str,"[:%-+_]+"," ") - return str + str=gsub(str,"[:%-+_]+"," ") + return str end local n=0 local sequenced=table.sequenced function string.autodouble(s,sep) - if s==nil then - return '""' - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ('"'..sequenced(s,sep or ",")..'"') - end - return ('"'..tostring(s)..'"') + if s==nil then + return '""' + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ('"'..sequenced(s,sep or ",")..'"') + end + return ('"'..tostring(s)..'"') end function string.autosingle(s,sep) - if s==nil then - return "''" - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ("'"..sequenced(s,sep or ",").."'") - end - return ("'"..tostring(s).."'") + if s==nil then + return "''" + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ("'"..sequenced(s,sep or ",").."'") + end + return ("'"..tostring(s).."'") end local tracedchars={ [0]= - "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", - "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", - "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", - "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", - "[space]", + "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", + "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", + "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", + "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", + "[space]", } string.tracedchars=tracedchars strings.tracers=tracedchars function string.tracedchar(b) - if type(b)=="number" then - return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") - else - local c=utfbyte(b) - return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") - end + if type(b)=="number" then + return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") + else + local c=utfbyte(b) + return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") + end end function number.signed(i) - if i>0 then - return "+",i - else - return "-",-i - end -end -local digit=patterns.digit -local period=patterns.period -local three=digit*digit*digit + if i>0 then + return "+",i + else + return "-",-i + end +end +local two=digit*digit +local three=two*digit +local prefix=(Carg(1)*three)^1 local splitter=Cs ( - (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2) + (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2) +) +local splitter3=Cs ( + three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit ) patterns.formattednumber=splitter function number.formatted(n,sep1,sep2) - local s=type(s)=="string" and n or format("%0.2f",n) + if sep1==false then + if type(n)=="number" then + n=tostring(n) + end + return lpegmatch(splitter3,n,1,sep2 or ".") + else + if type(n)=="number" then + n=format("%0.2f",n) + end if sep1==true then - return lpegmatch(splitter,s,1,".",",") + return lpegmatch(splitter,n,1,".",",") elseif sep1=="." then - return lpegmatch(splitter,s,1,sep1,sep2 or ",") + return lpegmatch(splitter,n,1,sep1,sep2 or ",") elseif sep1=="," then - return lpegmatch(splitter,s,1,sep1,sep2 or ".") + return lpegmatch(splitter,n,1,sep1,sep2 or ".") else - return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") + return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".") end + end end local p=Cs( - P("-")^0*(P("0")^1/"")^0*(1-P("."))^0*(P(".")*P("0")^1*P(-1)/""+P(".")^0)*P(1-P("0")^1*P(-1))^0 - ) + P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0 + ) function number.compactfloat(n,fmt) - if n==0 then - return "0" - elseif n==1 then - return "1" - end - n=lpegmatch(p,format(fmt or "%0.3f",n)) - if n=="." or n=="" or n=="-" then - return "0" - end - return n + if n==0 then + return "0" + elseif n==1 then + return "1" + end + n=lpegmatch(p,format(fmt or "%0.3f",n)) + if n=="." or n=="" or n=="-" then + return "0" + end + return n end local zero=P("0")^1/"" local plus=P("+")/"" local minus=P("-") -local separator=S(".") -local digit=R("09") +local separator=period 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 exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1)) local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) -local pattern_b=Cs((exponent+P(1))^0) +local pattern_b=Cs((exponent+anything)^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)) + 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 - return tostring(n) + 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 hf={} local hs={} setmetatable(hf,{ __index=function(t,k) - local v="%."..k.."f" - t[k]=v - return v + local v="%."..k.."f" + t[k]=v + return v end } ) setmetatable(hs,{ __index=function(t,k) - local v="%"..k.."s" - t[k]=v - return v + local v="%"..k.."s" + t[k]=v + return v end } ) function number.formattedfloat(n,b,a) - local s=format(hf[a],n) - local l=(b or 0)+(a or 0)+1 - if #s<l then - return format(hs[l],s) - else - return s - end + local s=format(hf[a],n) + local l=(b or 0)+(a or 0)+1 + if #s<l then + return format(hs[l],s) + else + return s + end end local template=[[ %s %s return function(%s) return %s end ]] -local preamble,environment="",{} -if oldfashioned 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 utfpadding=string.utfpadding -local tracedchar=string.tracedchar -local autosingle=string.autosingle -local autodouble=string.autodouble -local sequenced=table.sequenced -local formattednumber=number.formatted -local sparseexponent=number.sparseexponent -local formattedfloat=number.formattedfloat - ]] -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, - utfpadding=string.utfpadding, - tracedchar=string.tracedchar, - autosingle=string.autosingle, - autodouble=string.autodouble, - sequenced=table.sequenced, - formattednumber=number.formatted, - sparseexponent=number.sparseexponent, - formattedfloat=number.formattedfloat, - } -end +local preamble="" +local 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, + utfpadding=string.utfpadding, + tracedchar=string.tracedchar, + autosingle=string.autosingle, + autodouble=string.autodouble, + sequenced=table.sequenced, + formattednumber=number.formatted, + sparseexponent=number.sparseexponent, + formattedfloat=number.formattedfloat, + stripzero=lpeg.patterns.stripzero, + stripzeros=lpeg.patterns.stripzeros, + FORMAT=string.f9, +} local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) - local v=t[k-1]..",a"..k - t[k]=v - return v - end + local v=t[k-1]..",a"..k + t[k]=v + return v + end }) -local prefix_any=C((S("+- .")+R("09"))^0) -local prefix_sub=(C((S("+-")+R("09"))^0)+Cc(0))*P(".")*(C((S("+-")+R("09"))^0)+Cc(0)) +local prefix_any=C((sign+space+period+digit)^0) +local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(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 - return format("format('%%%ss',a%s)",f,n) - else - return format("(a%s or '')",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',a%s)",f,n) + else + return format("(a%s or '')",n) + end end local format_S=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%ss',tostring(a%s))",f,n) - else - return format("tostring(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',tostring(a%s))",f,n) + else + return format("tostring(a%s)",n) + end end local format_right=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - elseif f>0 then - return format("utfpadding(a%s,%i)..a%s",n,f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + elseif f>0 then + return format("utfpadding(a%s,%i)..a%s",n,f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,f) + end end local format_left=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - end - if f<0 then - return format("utfpadding(a%s,%i)..a%s",n,-f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,-f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + end + if f<0 then + return format("utfpadding(a%s,%i)..a%s",n,-f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,-f) + end end local format_q=function() - n=n+1 - return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) + n=n+1 + return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) end local format_Q=function() - n=n+1 - return format("format('%%q',tostring(a%s))",n) + n=n+1 + return format("format('%%q',tostring(a%s))",n) end local format_i=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%si',a%s)",f,n) - else - return format("format('%%i',a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%si',a%s)",f,n) + else + return format("format('%%i',a%s)",n) + end end local format_d=format_i local format_I=function(f) - n=n+1 - return format("format('%%s%%%si',signed(a%s))",f,n) + n=n+1 + return format("format('%%s%%%si',signed(a%s))",f,n) end local format_f=function(f) - n=n+1 - return format("format('%%%sf',a%s)",f,n) + n=n+1 + return format("format('%%%sf',a%s)",f,n) end local format_F=function(f) - n=n+1 - if not f or f=="" then - return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) - else - return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) - end + n=n+1 + if not f or f=="" then + return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) + else + return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) + end end local format_k=function(b,a) - n=n+1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) + n=n+1 + return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) end local format_g=function(f) - n=n+1 - return format("format('%%%sg',a%s)",f,n) + n=n+1 + return format("format('%%%sg',a%s)",f,n) end local format_G=function(f) - n=n+1 - return format("format('%%%sG',a%s)",f,n) + n=n+1 + return format("format('%%%sG',a%s)",f,n) end local format_e=function(f) - n=n+1 - return format("format('%%%se',a%s)",f,n) + n=n+1 + return format("format('%%%se',a%s)",f,n) end local format_E=function(f) - n=n+1 - return format("format('%%%sE',a%s)",f,n) + 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) + 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) + 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) + n=n+1 + return format("format('%%%sx',a%s)",f,n) end local format_X=function(f) - n=n+1 - return format("format('%%%sX',a%s)",f,n) + n=n+1 + return format("format('%%%sX',a%s)",f,n) end local format_o=function(f) - n=n+1 - return format("format('%%%so',a%s)",f,n) + n=n+1 + return format("format('%%%so',a%s)",f,n) end local format_c=function() - n=n+1 - return format("utfchar(a%s)",n) + n=n+1 + return format("utfchar(a%s)",n) end local format_C=function() - n=n+1 - return format("tracedchar(a%s)",n) + n=n+1 + return format("tracedchar(a%s)",n) end local format_r=function(f) - n=n+1 - return format("format('%%%s.0f',a%s)",f,n) + n=n+1 + return format("format('%%%s.0f',a%s)",f,n) end local format_h=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_H=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_u=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_U=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_p=function() - n=n+1 - return format("points(a%s)",n) + n=n+1 + return format("points(a%s)",n) end local format_b=function() - n=n+1 - return format("basepoints(a%s)",n) + n=n+1 + return format("basepoints(a%s)",n) end local format_t=function(f) - n=n+1 - if f and f~="" then - return format("concat(a%s,%q)",n,f) - else - return format("concat(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("concat(a%s,%q)",n,f) + else + return format("concat(a%s)",n) + end end local format_T=function(f) - n=n+1 - if f and f~="" then - return format("sequenced(a%s,%q)",n,f) - else - return format("sequenced(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("sequenced(a%s,%q)",n,f) + else + return format("sequenced(a%s)",n) + end end local format_l=function() - n=n+1 - return format("(a%s and 'true' or 'false')",n) + n=n+1 + return format("(a%s and 'true' or 'false')",n) end local format_L=function() - n=n+1 - return format("(a%s and 'TRUE' or 'FALSE')",n) + n=n+1 + return format("(a%s and 'TRUE' or 'FALSE')",n) end -local format_N=function() - n=n+1 - return format("tostring(tonumber(a%s) or a%s)",n,n) +local format_n=function() + n=n+1 + return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n) +end +local format_N=function(f) + n=n+1 + if not f or f=="" then + f=".9" + end + return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n) end local format_a=function(f) - n=n+1 - if f and f~="" then - return format("autosingle(a%s,%q)",n,f) - else - return format("autosingle(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autosingle(a%s,%q)",n,f) + else + return format("autosingle(a%s)",n) + end end local format_A=function(f) - n=n+1 - if f and f~="" then - return format("autodouble(a%s,%q)",n,f) - else - return format("autodouble(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autodouble(a%s,%q)",n,f) + else + return format("autodouble(a%s)",n) + end end local format_w=function(f) - n=n+1 - f=tonumber(f) - if f then - return format("nspaces[%s+a%s]",f,n) - else - return format("nspaces[a%s]",n) - end + n=n+1 + f=tonumber(f) + if f then + return format("nspaces[%s+a%s]",f,n) + else + return format("nspaces[a%s]",n) + end end local format_W=function(f) - return format("nspaces[%s]",tonumber(f) or 0) + return format("nspaces[%s]",tonumber(f) or 0) end local format_m=function(f) - n=n+1 - if not f or f=="" then - f="," - end + n=n+1 + if not f or f=="" then + f="," + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,".")]],n,f) + end end local format_M=function(f) - n=n+1 - if not f or f=="" then - f="." - end + n=n+1 + if not f or f=="" then + f="." + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,",")]],n,f) + end end local format_z=function(f) - n=n+(tonumber(f) or 1) - return "''" + n=n+(tonumber(f) or 1) + return "''" end local format_rest=function(s) - return format("%q",s) + return format("%q",s) end local format_extension=function(extensions,f,name) - local extension=extensions[name] or "tostring(%s)" - local f=tonumber(f) or 1 - local w=find(extension,"%.%.%.") + local extension=extensions[name] or "tostring(%s)" + local f=tonumber(f) or 1 + local w=find(extension,"%.%.%.") + if w then if f==0 then - if w then - extension=gsub(extension,"%.%.%.","") - end - return extension + extension=gsub(extension,"%.%.%.","") + return extension elseif f==1 then - if w then - extension=gsub(extension,"%.%.%.","%%s") - end - n=n+1 - local a="a"..n - return format(extension,a,a) + extension=gsub(extension,"%.%.%.","%%s") + n=n+1 + local a="a"..n + return format(extension,a,a) elseif f<0 then - local a="a"..(n+f+1) - return format(extension,a,a) + local a="a"..(n+f+1) + return format(extension,a,a) else - if w then - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - end - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + local t={} + for i=1,f do + n=n+1 + t[i]="a"..n + end + return format(extension,unpack(t)) end + else + extension=gsub(extension,"%%s",function() + n=n+1 + return "a"..n + end) + return extension + end end local builder=Cs { "start", - start=( - ( - P("%")/""*( - V("!") + start=( + ( + P("%")/""*( + V("!") +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("N") +V("k") +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") @@ -6750,160 +7147,156 @@ local builder=Cs { "start", +V("z") +V(">") +V("<") - )+V("*") - )*(P(-1)+Carg(1)) - )^0, - ["s"]=(prefix_any*P("s"))/format_s, - ["q"]=(prefix_any*P("q"))/format_q, - ["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, - ["E"]=(prefix_any*P("E"))/format_E, - ["x"]=(prefix_any*P("x"))/format_x, - ["X"]=(prefix_any*P("X"))/format_X, - ["o"]=(prefix_any*P("o"))/format_o, - ["S"]=(prefix_any*P("S"))/format_S, - ["Q"]=(prefix_any*P("Q"))/format_Q, - ["N"]=(prefix_any*P("N"))/format_N, - ["k"]=(prefix_sub*P("k"))/format_k, - ["c"]=(prefix_any*P("c"))/format_c, - ["C"]=(prefix_any*P("C"))/format_C, - ["r"]=(prefix_any*P("r"))/format_r, - ["h"]=(prefix_any*P("h"))/format_h, - ["H"]=(prefix_any*P("H"))/format_H, - ["u"]=(prefix_any*P("u"))/format_u, - ["U"]=(prefix_any*P("U"))/format_U, - ["p"]=(prefix_any*P("p"))/format_p, - ["b"]=(prefix_any*P("b"))/format_b, - ["t"]=(prefix_tab*P("t"))/format_t, - ["T"]=(prefix_tab*P("T"))/format_T, - ["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, - ["<"]=(prefix_any*P("<"))/format_left, - [">"]=(prefix_any*P(">"))/format_right, - ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, - ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, - ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, + )+V("*") + )*(endofstring+Carg(1)) + )^0, + ["s"]=(prefix_any*P("s"))/format_s, + ["q"]=(prefix_any*P("q"))/format_q, + ["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, + ["E"]=(prefix_any*P("E"))/format_E, + ["x"]=(prefix_any*P("x"))/format_x, + ["X"]=(prefix_any*P("X"))/format_X, + ["o"]=(prefix_any*P("o"))/format_o, + ["S"]=(prefix_any*P("S"))/format_S, + ["Q"]=(prefix_any*P("Q"))/format_Q, + ["n"]=(prefix_any*P("n"))/format_n, + ["N"]=(prefix_any*P("N"))/format_N, + ["k"]=(prefix_sub*P("k"))/format_k, + ["c"]=(prefix_any*P("c"))/format_c, + ["C"]=(prefix_any*P("C"))/format_C, + ["r"]=(prefix_any*P("r"))/format_r, + ["h"]=(prefix_any*P("h"))/format_h, + ["H"]=(prefix_any*P("H"))/format_H, + ["u"]=(prefix_any*P("u"))/format_u, + ["U"]=(prefix_any*P("U"))/format_U, + ["p"]=(prefix_any*P("p"))/format_p, + ["b"]=(prefix_any*P("b"))/format_b, + ["t"]=(prefix_tab*P("t"))/format_t, + ["T"]=(prefix_tab*P("T"))/format_T, + ["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_any*P("m"))/format_m, + ["M"]=(prefix_any*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, + ["<"]=(prefix_any*P("<"))/format_left, + [">"]=(prefix_any*P(">"))/format_right, + ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, + ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, + ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } local xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end }) local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end }) local preset={ - ["%02x"]=function(n) return xx[n] end, - ["%02X"]=function(n) return XX[n] end, + ["%02x"]=function(n) return xx[n] end, + ["%02X"]=function(n) return XX[n] end, } -local direct=P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] +local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]] local function make(t,str) - local f=preset[str] - if f then - return f - end - local p=lpegmatch(direct,str) - if p then - f=loadstripped(p)() + local f=preset[str] + if f then + return f + end + local p=lpegmatch(direct,str) + if p then + f=loadstripped(p)() + else + n=0 + 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,t._environment_)() else - n=0 - 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,t._environment_)() - else - f=function() return str end - end + f=function() return str end end - t[str]=f - return f + end + t[str]=f + return f end local function use(t,fmt,...) - return t[fmt](...) + return t[fmt](...) end strings.formatters={} -if oldfashioned 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 +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 local formatters=strings.formatters.new() string.formatters=formatters 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 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 + if type(t)=="table" and t._type_=="formatter" then + t._extensions_[name]=template or "%s" + 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 -patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) -patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) +patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+anything)^0) +patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^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 oldfashioned 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 +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 }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 -local space=patterns.space local cquote=Cc('"') -local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +Cs(cquote*(equote-space)^0*space*equote^0*cquote) function string.optionalquoted(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local pattern=Cs((newline/(os.newline or "\r")+1)^0) function string.replacenewlines(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function strings.newcollector() - local result,r={},0 - return - function(fmt,str,...) - r=r+1 - result[r]=str==nil and fmt or formatters[fmt](str,...) - end, - function(connector) - if result then - local str=concat(result,connector) - result,r={},0 - return str - end - end + local result,r={},0 + return + function(fmt,str,...) + r=r+1 + result[r]=str==nil and fmt or formatters[fmt](str,...) + end, + function(connector) + if result then + local str=concat(result,connector) + result,r={},0 + return str + end + end +end +local f_16_16=formatters["%0.5N"] +function number.to16dot16(n) + return f_16_16(n/65536.0) end @@ -6913,14 +7306,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tab"] = package.loaded["util-tab"] or true --- original size: 27741, stripped down to: 17085 +-- original size: 28772, stripped down to: 16111 if not modules then modules={} end modules ['util-tab']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.tables=utilities.tables or {} @@ -6935,219 +7328,220 @@ local formatters=string.formatters local utftoeight=utf.toeight local splitter=lpeg.tsplitat(".") 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=composed.."."..name - t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) - else - composed=name - if not nofirst then - t[#t+1]=formatters["%s = %s or { }"](composed,composed) - end - end - end + local composed=nil + local t={} + local snippets=lpegmatch(splitter,target) + for i=1,#snippets-(nolast and 1 or 0) do + local name=snippets[i] if composed then - if nolast then - composed=composed.."."..snippets[#snippets] - end - return concat(t,"\n"),composed + composed=composed.."."..name + t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) else - return "",target + composed=name + if not nofirst then + t[#t+1]=formatters["%s = %s or { }"](composed,composed) + end + end + end + if composed then + if nolast then + composed=composed.."."..snippets[#snippets] end + return concat(t,"\n"),composed + else + return "",target + end end function tables.definedtable(...) - local t=_G - for i=1,select("#",...) do - local li=select(i,...) - local tl=t[li] - if not tl then - tl={} - t[li]=tl - end - t=tl - end - return t + local t=_G + for i=1,select("#",...) do + local li=select(i,...) + local tl=t[li] + if not tl then + tl={} + t[li]=tl + end + t=tl + end + return t end function tables.accesstable(target,root) - local t=root or _G - for name in gmatch(target,"([^%.]+)") do - t=t[name] - if not t then - return - end + local t=root or _G + for name in gmatch(target,"([^%.]+)") do + t=t[name] + if not t then + return end - return t + end + return t end function tables.migratetable(target,v,root) - local t=root or _G - local names=lpegmatch(splitter,target) - for i=1,#names-1 do - local name=names[i] - t[name]=t[name] or {} - t=t[name] - if not t then - return - end + local t=root or _G + local names=lpegmatch(splitter,target) + for i=1,#names-1 do + local name=names[i] + t[name]=t[name] or {} + t=t[name] + if not t then + return end - t[names[#names]]=v + end + t[names[#names]]=v end function tables.removevalue(t,value) - if value then - for i=1,#t do - if t[i]==value then - remove(t,i) - end - end + if value then + for i=1,#t do + if t[i]==value then + remove(t,i) + end end + end end function tables.replacevalue(t,oldvalue,newvalue) - if oldvalue and newvalue then - for i=1,#t do - if t[i]==oldvalue then - t[i]=newvalue - end - end + if oldvalue and newvalue then + for i=1,#t do + if t[i]==oldvalue then + t[i]=newvalue + end end + end end function tables.insertbeforevalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i,extra) + return end - insert(t,1,extra) + end + insert(t,1,extra) end function tables.insertaftervalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i+1,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i+1,extra) + return end - insert(t,#t+1,extra) + end + insert(t,#t+1,extra) end local escape=Cs(Cc('"')*((P('"')/'""'+P(1))^0)*Cc('"')) function table.tocsv(t,specification) - if t and #t>0 then - local result={} - local r={} - specification=specification or {} - local fields=specification.fields - if type(fields)~="string" then - fields=sortedkeys(t[1]) - end - local separator=specification.separator or "," - local noffields=#fields - if specification.preamble==true then - for f=1,noffields do - r[f]=lpegmatch(escape,tostring(fields[f])) - end - result[1]=concat(r,separator) - end - for i=1,#t do - local ti=t[i] - for f=1,noffields do - local field=ti[fields[f]] - if type(field)=="string" then - r[f]=lpegmatch(escape,field) - else - r[f]=tostring(field) - end - end - result[i+1]=concat(r,separator) + if t and #t>0 then + local result={} + local r={} + specification=specification or {} + local fields=specification.fields + if type(fields)~="string" then + fields=sortedkeys(t[1]) + end + local separator=specification.separator or "," + local noffields=#fields + if specification.preamble==true then + for f=1,noffields do + r[f]=lpegmatch(escape,tostring(fields[f])) + end + result[1]=concat(r,separator) + end + for i=1,#t do + local ti=t[i] + for f=1,noffields do + local field=ti[fields[f]] + if type(field)=="string" then + r[f]=lpegmatch(escape,field) + else + r[f]=tostring(field) end - return concat(result,"\n") - else - return "" + end + result[i+1]=concat(r,separator) end + return concat(result,"\n") + else + return "" + end end local nspaces=utilities.strings.newrepeater(" ") local function toxml(t,d,result,step) - local r=#result - for k,v in sortedpairs(t) do - local s=nspaces[d] - local tk=type(k) - local tv=type(v) - if tv=="table" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</entry>"](s,k) - else - r=r+1 result[r]=formatters["%s<%s>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</%s>"](s,k) - end - elseif tv=="string" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) - end - elseif tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) - end + local r=#result + for k,v in sortedpairs(t) do + local s=nspaces[d] + local tk=type(k) + local tv=type(v) + if tv=="table" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</entry>"](s,k) + else + r=r+1 result[r]=formatters["%s<%s>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</%s>"](s,k) + end + elseif tv=="string" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) + end + elseif tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) end + end end function table.toxml(t,specification) - specification=specification or {} - local name=specification.name - local noroot=name==false - local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } - local indent=specification.indent or 0 - local spaces=specification.spaces or 1 - if noroot then - toxml(t,indent,result,spaces) - else - toxml({ [name or "data"]=t },indent,result,spaces) - end - return concat(result,"\n") + specification=specification or {} + local name=specification.name + local noroot=name==false + local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } + local indent=specification.indent or 0 + local spaces=specification.spaces or 1 + if noroot then + toxml(t,indent,result,spaces) + else + toxml({ [name or "data"]=t },indent,result,spaces) + end + return concat(result,"\n") end function tables.encapsulate(core,capsule,protect) - if type(capsule)~="table" then - protect=true - capsule={} - end + if type(capsule)~="table" then + protect=true + capsule={} + end + for key,value in next,core do + if capsule[key] then + print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) + os.exit() + else + capsule[key]=value + end + end + if protect then for key,value in next,core do + core[key]=nil + end + setmetatable(core,{ + __index=capsule, + __newindex=function(t,key,value) if capsule[key] then - print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) - os.exit() + print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) + os.exit() else - capsule[key]=value + rawset(t,key,value) end - end - if protect then - for key,value in next,core do - core[key]=nil - end - setmetatable(core,{ - __index=capsule, - __newindex=function(t,key,value) - if capsule[key] then - print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) - os.exit() - else - rawset(t,key,value) - end - end - } ) - end + end + } ) + end end local f_hashed_string=formatters["[%q]=%q,"] local f_hashed_number=formatters["[%q]=%s,"] @@ -7161,157 +7555,157 @@ 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 + 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 - for k,v in next,t do - 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 + end + for k,v in next,t do + 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 - m=m+1 - if outer then - r[m]="}" - else - r[m]="}," + 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 - return r + end end - return concat(fastserialize(t,true)) + m=m+1 + if outer then + r[m]="}" + else + r[m]="}," + end + return r + end + return concat(fastserialize(t,true)) end function table.deserialize(str) - if not str or str=="" then - return - end - local code=load(str) - if not code then - return - end - code=code() - if not code then - return - end - return code + if not str or str=="" then + return + end + local code=load(str) + if not code then + return + end + code=code() + if not code then + return + end + return code end 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() - if type(t)=="table" then - return t - end - end + 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() + if type(t)=="table" then + return t end + end end + end end function table.save(filename,t,n,...) - io.savedata(filename,table.serialize(t,n==nil and true or n,...)) + io.savedata(filename,table.serialize(t,n==nil and true or n,...)) end 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 - local ti=t[i] - local j=0 - for k,v in next,ti do - j=j+1 - l[j]=f_key_value(k,v) - end - r[i]=f_add_table(l) - end - return f_return_table(r) + local r={} + local l={} + for i=1,#t do + local ti=t[i] + local j=0 + for k,v in next,ti do + j=j+1 + l[j]=f_key_value(k,v) + end + r[i]=f_add_table(l) + end + 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] - m=m+1 r[m]=" {" - for k,v in next,ti do - m=m+1 r[m]=f_key_value(k,v) - end - m=m+1 r[m]="},\n" - end - m=m+1 - r[m]="}" - return concat(r) + local r={ "return {\n" } + local m=1 + for i=1,#t do + local ti=t[i] + m=m+1 r[m]=" {" + for k,v in next,ti do + m=m+1 r[m]=f_key_value(k,v) + end + m=m+1 r[m]="},\n" + end + m=m+1 + r[m]="}" + return concat(r) end function table.drop(t,slow) - if #t==0 then - return "return { }" - elseif slow==true then - return slowdrop(t) - else - return fastdrop(t) - end + if #t==0 then + return "return { }" + elseif slow==true then + return slowdrop(t) + else + return fastdrop(t) + end end local selfmapper={ __index=function(t,k) t[k]=k return k end } -function table.twowaymapper(t) - if not t then - t={} - else - local zero=rawget(t,0) - for i=zero and 0 or 1,#t do - local ti=t[i] - if ti then - local i=tostring(i) - t[i]=ti - t[ti]=i - end - end +function table.twowaymapper(t) + if not t then + t={} + else + local zero=rawget(t,0) + for i=zero and 0 or 1,#t do + local ti=t[i] + if ti then + local i=tostring(i) + t[i]=ti + t[ti]=i + end end - setmetatable(t,selfmapper) - return t + end + setmetatable(t,selfmapper) + return t end local f_start_key_idx=formatters["%w{"] local f_start_key_num=formatters["%w[%s]={"] @@ -7349,187 +7743,223 @@ local spaces=utilities.strings.newrepeater(" ") local original_serialize=table.serialize local is_simple_table=table.is_simple_table local function serialize(root,name,specification) - if type(specification)=="table" then - return original_serialize(root,name,specification) - end - local t - local n=1 - local unknown=false - 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) + if type(specification)=="table" then + return original_serialize(root,name,specification) + end + local t + local n=1 + local unknown=false + 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)~=nil then + local first=nil + local last=0 + last=#root + for k=1,last do + if rawget(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<=last and k>=first 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 next(v)==nil then + n=n+1 t[n]=f_val_not(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)~=nil then - local first=nil - local last=0 - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end + local st=is_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 - if last>0 then - first=1 + elseif tv=="boolean" then + n=n+1 t[n]=f_val_boo(depth,v) + elseif unknown then + n=n+1 t[n]=f_val_str(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) + end + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_not(depth,k) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_not(depth,k) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_not(depth,k) + elseif unknown then + n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) 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<=last and k>=first 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 next(v)==nil then - n=n+1 t[n]=f_val_not(depth) - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_val_str(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) - end - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - n=n+1 t[n]=f_key_num_value_not(depth,k) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_not(depth,k) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_not(depth,k) - elseif unknown then - n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) - end - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_seq(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) - end - else - if tk=="number" then - n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(v)) - end - end + else + local st=is_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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_seq(depth,tostring(k),st) 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() } + 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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) + end else - t={ f_table_direct() } + if tk=="number" then + n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(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("t") } + t={ f_table_name(name) } 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)~=nil then - local st=is_simple_table(root) - if st then - return t[1]..f_fin_seq(st) - else - do_serialize(root,name,1,0) - end - 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)~=nil then + local st=is_simple_table(root) + if st then + return t[1]..f_fin_seq(st) + else + do_serialize(root,name,1,0) + end end - n=n+1 - t[n]=f_table_finish() - return concat(t,"\n") + end + n=n+1 + t[n]=f_table_finish() + return concat(t,"\n") end table.serialize=serialize if setinspector then - setinspector("table",function(v) - if type(v)=="table" then - print(serialize(v,"table",{ metacheck=false })) - return true - end - end) + setinspector("table",function(v) + if type(v)=="table" then + print(serialize(v,"table",{ metacheck=false })) + return true + end + end) +end +local mt={ + __newindex=function(t,k,v) + local n=t.last+1 + t.last=n + t.list[n]=k + t.hash[k]=v + end, + __index=function(t,k) + return t.hash[k] + end, + __len=function(t) + return t.last + end, +} +function table.orderedhash() + return setmetatable({ list={},hash={},last=0 },mt) +end +function table.ordered(t) + local n=t.last + if n>0 then + local l=t.list + local i=1 + local h=t.hash + local f=function() + if i<=n then + local k=i + local v=h[l[k]] + i=i+1 + return k,v + end + end + return f,1,h[l[1]] + else + return function() end + end end @@ -7539,15 +7969,16 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7787, stripped down to: 5858 +-- original size: 8607, stripped down to: 6727 if not modules then modules={} end modules ['util-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } +local tonumber=tonumber local byte=string.byte local char=string.char utilities=utilities or {} @@ -7555,251 +7986,280 @@ local files={} utilities.files=files local zerobased={} function files.open(filename,zb) - local f=io.open(filename,"rb") - if f then - zerobased[f]=zb or false - end - return f + local f=io.open(filename,"rb") + if f then + zerobased[f]=zb or false + end + return f end function files.close(f) - zerobased[f]=nil - f:close() + zerobased[f]=nil + f:close() end function files.size(f) - local current=f:seek() - local size=f:seek("end") - f:seek("set",current) - return size + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) - if zerobased[f] then - f:seek("set",n) - else - f:seek("set",n-1) - end + if zerobased[f] then + f:seek("set",n) + else + f:seek("set",n-1) + end end function files.getposition(f) - if zerobased[f] then - return f:seek() - else - return f:seek()+1 - end + if zerobased[f] then + return f:seek() + else + return f:seek()+1 + end end function files.look(f,n,chars) - local p=f:seek() - local s=f:read(n) - f:seek("set",p) - if chars then - return s - else - return byte(s,1,#s) - end + local p=f:seek() + local s=f:read(n) + f:seek("set",p) + if chars then + return s + else + return byte(s,1,#s) + end end function files.skip(f,n) - if n==1 then - f:read(n) - else - f:seek("set",f:seek()+n) - end + if n==1 then + f:read(n) + else + f:seek("set",f:seek()+n) + end end function files.readbyte(f) - return byte(f:read(1)) + return byte(f:read(1)) end function files.readbytes(f,n) - return byte(f:read(n),1,n) + return byte(f:read(n),1,n) end function files.readbytetable(f,n) - local s=f:read(n or 1) - return { byte(s,1,#s) } + local s=f:read(n or 1) + return { byte(s,1,#s) } end function files.readchar(f) - return f:read(1) + return f:read(1) end function files.readstring(f,n) - return f:read(n or 1) + return f:read(n or 1) end -function files.readinteger1(f) - local n=byte(f:read(1)) - if n>=0x80 then - return n-0x100 - else - return n - end +function files.readinteger1(f) + local n=byte(f:read(1)) + if n>=0x80 then + return n-0x100 + else + return n + end end -files.readcardinal1=files.readbyte +files.readcardinal1=files.readbyte files.readcardinal=files.readcardinal1 files.readinteger=files.readinteger1 files.readsignedbyte=files.readinteger1 function files.readcardinal2(f) - local a,b=byte(f:read(2),1,2) - return 0x100*a+b + local a,b=byte(f:read(2),1,2) + return 0x100*a+b end function files.readcardinal2le(f) - local b,a=byte(f:read(2),1,2) - return 0x100*a+b + local b,a=byte(f:read(2),1,2) + return 0x100*a+b end function files.readinteger2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readinteger2le(f) - local b,a=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local b,a=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readcardinal3(f) - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readcardinal3le(f) - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readinteger3(f) - local a,b,c=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local a,b,c=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readinteger3le(f) - local c,b,a=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local c,b,a=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readcardinal4(f) - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readcardinal4le(f) - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readinteger4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readinteger4le(f) - local d,c,b,a=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local d,c,b,a=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readfixed2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return (a-0x100)+b/0x100 - else - return (a )+b/0x100 - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function files.readfixed4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end if bit32 then - local extract=bit32.extract - local band=bit32.band - function files.read2dot14(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local extract=bit32.extract + local band=bit32.band + function files.read2dot14(f) + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) + else + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function files.skipshort(f,n) - f:read(2*(n or 1)) + f:read(2*(n or 1)) end function files.skiplong(f,n) - f:read(4*(n or 1)) + f:read(4*(n or 1)) end if bit32 then - local rshift=bit32.rshift - function files.writecardinal2(f,n) - local a=char(n%256) - n=rshift(n,8) - local b=char(n%256) - f:write(b,a) - end -else - local floor=math.floor - function files.writecardinal2(f,n) - local a=char(n%256) - n=floor(n/256) - local b=char(n%256) - f:write(b,a) - end -end -function files.writecardinal4(f,n) + local rshift=bit32.rshift + function files.writecardinal2(f,n) local a=char(n%256) n=rshift(n,8) local b=char(n%256) - n=rshift(n,8) - local c=char(n%256) - n=rshift(n,8) - local d=char(n%256) - f:write(d,c,b,a) + f:write(b,a) + end +else + local floor=math.floor + function files.writecardinal2(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + f:write(b,a) + end +end +function files.writecardinal4(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(d,c,b,a) end function files.writestring(f,s) - f:write(char(byte(s,1,#s))) + f:write(char(byte(s,1,#s))) end function files.writebyte(f,b) - f:write(char(b)) + f:write(char(b)) end if fio and fio.readcardinal1 then - files.readcardinal1=fio.readcardinal1 - files.readcardinal2=fio.readcardinal2 - files.readcardinal3=fio.readcardinal3 - files.readcardinal4=fio.readcardinal4 - files.readinteger1=fio.readinteger1 - files.readinteger2=fio.readinteger2 - files.readinteger3=fio.readinteger3 - files.readinteger4=fio.readinteger4 - files.readfixed2=fio.readfixed2 - files.readfixed4=fio.readfixed4 - files.read2dot14=fio.read2dot14 - files.setposition=fio.setposition - files.getposition=fio.getposition - files.readbyte=files.readcardinal1 - files.readsignedbyte=files.readinteger1 - files.readcardinal=files.readcardinal1 - files.readinteger=files.readinteger1 - local skipposition=fio.skipposition - files.skipposition=skipposition - files.readbytes=fio.readbytes - files.readbytetable=fio.readbytetable - function files.skipshort(f,n) - skipposition(f,2*(n or 1)) - end - function files.skiplong(f,n) - skipposition(f,4*(n or 1)) - end + files.readcardinal1=fio.readcardinal1 + files.readcardinal2=fio.readcardinal2 + files.readcardinal3=fio.readcardinal3 + files.readcardinal4=fio.readcardinal4 + files.readinteger1=fio.readinteger1 + files.readinteger2=fio.readinteger2 + files.readinteger3=fio.readinteger3 + files.readinteger4=fio.readinteger4 + files.readfixed2=fio.readfixed2 + files.readfixed4=fio.readfixed4 + files.read2dot14=fio.read2dot14 + files.setposition=fio.setposition + files.getposition=fio.getposition + files.readbyte=files.readcardinal1 + files.readsignedbyte=files.readinteger1 + files.readcardinal=files.readcardinal1 + files.readinteger=files.readinteger1 + local skipposition=fio.skipposition + files.skipposition=skipposition + files.readbytes=fio.readbytes + files.readbytetable=fio.readbytetable + function files.skipshort(f,n) + skipposition(f,2*(n or 1)) + end + function files.skiplong(f,n) + skipposition(f,4*(n or 1)) + end +end +if fio and fio.readcardinaltable then + files.readcardinaltable=fio.readcardinaltable + files.readintegertable=fio.readintegertable +else + local readcardinal1=files.readcardinal1 + local readcardinal2=files.readcardinal2 + local readcardinal3=files.readcardinal3 + local readcardinal4=files.readcardinal4 + function files.readcardinaltable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end + return t + end + local readinteger1=files.readinteger1 + local readinteger2=files.readinteger2 + local readinteger3=files.readinteger3 + local readinteger4=files.readinteger4 + function files.readintegertable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end + return t + end end @@ -7809,338 +8269,412 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sac"] = package.loaded["util-sac"] or true --- original size: 8716, stripped down to: 6754 +-- original size: 11065, stripped down to: 8209 if not modules then modules={} end modules ['util-sac']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local byte,sub=string.byte,string.sub -local extract=bit32 and bit32.extract +local tonumber=tonumber utilities=utilities or {} local streams={} utilities.streams=streams function streams.open(filename,zerobased) - local f=io.loaddata(filename) + local f=filename and io.loaddata(filename) + if f then return { f,1,#f,zerobased or false } + end +end +function streams.openstring(f,zerobased) + if f then + return { f,1,#f,zerobased or false } + end end function streams.close() end function streams.size(f) - return f and f[3] or 0 + return f and f[3] or 0 end function streams.setposition(f,i) - if f[4] then - if i<=0 then - f[2]=1 - else - f[2]=i+1 - end + if f[4] then + if i<=0 then + f[2]=1 else - if i<=1 then - f[2]=1 - else - f[2]=i - end + f[2]=i+1 end -end -function streams.getposition(f) - if f[4] then - return f[2]-1 + else + if i<=1 then + f[2]=1 else - return f[2] + f[2]=i end + end +end +function streams.getposition(f) + if f[4] then + return f[2]-1 + else + return f[2] + end end function streams.look(f,n,chars) - local b=f[2] - local e=b+n-1 - if chars then - return sub(f[1],b,e) - else - return byte(f[1],b,e) - end + local b=f[2] + local e=b+n-1 + if chars then + return sub(f[1],b,e) + else + return byte(f[1],b,e) + end end function streams.skip(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readbyte(f) - local i=f[2] - f[2]=i+1 - return byte(f[1],i) + local i=f[2] + f[2]=i+1 + return byte(f[1],i) end function streams.readbytes(f,n) - local i=f[2] - local j=i+n - f[2]=j - return byte(f[1],i,j-1) + local i=f[2] + local j=i+n + f[2]=j + return byte(f[1],i,j-1) end function streams.readbytetable(f,n) - local i=f[2] - local j=i+n - f[2]=j - return { byte(f[1],i,j-1) } + local i=f[2] + local j=i+n + f[2]=j + return { byte(f[1],i,j-1) } end function streams.skipbytes(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readchar(f) - local i=f[2] - f[2]=i+1 - return sub(f[1],i,i) + local i=f[2] + f[2]=i+1 + return sub(f[1],i,i) end function streams.readstring(f,n) - local i=f[2] - local j=i+n - f[2]=j - return sub(f[1],i,j-1) -end -function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - local n=byte(f[1],i) - if n>=0x80 then - return n-0x100 - else - return n - end + local i=f[2] + local j=i+n + f[2]=j + return sub(f[1],i,j-1) +end +function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + local n=byte(f[1],i) + if n>=0x80 then + return n-0x100 + else + return n + end end -streams.readcardinal1=streams.readbyte +streams.readcardinal1=streams.readbyte streams.readcardinal=streams.readcardinal1 streams.readinteger=streams.readinteger1 function streams.readcardinal2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + return 0x100*a+b end function streams.readcardinal2LE(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + return 0x100*a+b end function streams.readinteger2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readinteger2le(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readcardinal3(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readcardinal3le(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readinteger3(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readinteger3le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readcardinal4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - return 0x1000000*a+0x10000*b+0x100*c+d + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + return 0x1000000*a+0x10000*b+0x100*c+d end function streams.readinteger4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function streams.readinteger4le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local d,c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local d,c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end +end +function streams.readfixed2(f) + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function streams.readfixed4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end -function streams.readfixed2(f) +if bit32 then + local extract=bit32.extract + local band=bit32.band + function streams.read2dot14(f) local i=f[2] local j=i+1 f[2]=j+1 local a,b=byte(f[1],i,j) if a>=0x80 then - return (a-0x100)+b/0x100 + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) else - return (a )+b/0x100 - end -end -if extract then - local extract=bit32.extract - local band=bit32.band - function streams.read2dot14(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function streams.skipshort(f,n) - f[2]=f[2]+2*(n or 1) + f[2]=f[2]+2*(n or 1) end function streams.skiplong(f,n) - f[2]=f[2]+4*(n or 1) + f[2]=f[2]+4*(n or 1) end if sio and sio.readcardinal2 then - local readcardinal1=sio.readcardinal1 - local readcardinal2=sio.readcardinal2 - local readcardinal3=sio.readcardinal3 - local readcardinal4=sio.readcardinal4 - local readinteger1=sio.readinteger1 - local readinteger2=sio.readinteger2 - local readinteger3=sio.readinteger3 - local readinteger4=sio.readinteger4 - local readfixed2=sio.readfixed2 - local readfixed4=sio.readfixed4 - local read2dot14=sio.read2dot14 - local readbytes=sio.readbytes - local readbytetable=sio.readbytetable - function streams.readcardinal1(f) - local i=f[2] - f[2]=i+1 - return readcardinal1(f[1],i) - end - function streams.readcardinal2(f) - local i=f[2] - f[2]=i+2 - return readcardinal2(f[1],i) - end - function streams.readcardinal3(f) - local i=f[2] - f[2]=i+3 - return readcardinal3(f[1],i) - end - function streams.readcardinal4(f) - local i=f[2] - f[2]=i+4 - return readcardinal4(f[1],i) - end - function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - return readinteger1(f[1],i) - end - function streams.readinteger2(f) - local i=f[2] - f[2]=i+2 - return readinteger2(f[1],i) - end - function streams.readinteger3(f) - local i=f[2] - f[2]=i+3 - return readinteger3(f[1],i) - end - function streams.readinteger4(f) - local i=f[2] - f[2]=i+4 - return readinteger4(f[1],i) - end - function streams.read2dot4(f) - local i=f[2] - f[2]=i+2 - return read2dot4(f[1],i) - end - function streams.readbytes(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytes(f[1],i,n) + local readcardinal1=sio.readcardinal1 + local readcardinal2=sio.readcardinal2 + local readcardinal3=sio.readcardinal3 + local readcardinal4=sio.readcardinal4 + local readinteger1=sio.readinteger1 + local readinteger2=sio.readinteger2 + local readinteger3=sio.readinteger3 + local readinteger4=sio.readinteger4 + local readfixed2=sio.readfixed2 + local readfixed4=sio.readfixed4 + local read2dot14=sio.read2dot14 + local readbytes=sio.readbytes + local readbytetable=sio.readbytetable + function streams.readcardinal1(f) + local i=f[2] + f[2]=i+1 + return readcardinal1(f[1],i) + end + function streams.readcardinal2(f) + local i=f[2] + f[2]=i+2 + return readcardinal2(f[1],i) + end + function streams.readcardinal3(f) + local i=f[2] + f[2]=i+3 + return readcardinal3(f[1],i) + end + function streams.readcardinal4(f) + local i=f[2] + f[2]=i+4 + return readcardinal4(f[1],i) + end + function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + return readinteger1(f[1],i) + end + function streams.readinteger2(f) + local i=f[2] + f[2]=i+2 + return readinteger2(f[1],i) + end + function streams.readinteger3(f) + local i=f[2] + f[2]=i+3 + return readinteger3(f[1],i) + end + function streams.readinteger4(f) + local i=f[2] + f[2]=i+4 + return readinteger4(f[1],i) + end + function streams.read2dot4(f) + local i=f[2] + f[2]=i+2 + return read2dot4(f[1],i) + end + function streams.readbytes(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p end - function streams.readbytetable(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytetable(f[1],i,n) + return readbytes(f[1],i,n) + end + function streams.readbytetable(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readbytetable(f[1],i,n) + end + streams.readbyte=streams.readcardinal1 + streams.readsignedbyte=streams.readinteger1 + streams.readcardinal=streams.readcardinal1 + streams.readinteger=streams.readinteger1 +end +if sio and sio.readcardinaltable then + local readcardinaltable=sio.readcardinaltable + local readintegertable=sio.readintegertable + function utilities.streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readcardinaltable(f[1],i,n,b) + end + function utilities.streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readintegertable(f[1],i,n,b) + end +else + local readcardinal1=streams.readcardinal1 + local readcardinal2=streams.readcardinal2 + local readcardinal3=streams.readcardinal3 + local readcardinal4=streams.readcardinal4 + function streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p end - streams.readbyte=streams.readcardinal1 - streams.readsignedbyte=streams.readinteger1 - streams.readcardinal=streams.readcardinal1 - streams.readinteger=streams.readinteger1 + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end + return t + end + local readinteger1=streams.readinteger1 + local readinteger2=streams.readinteger2 + local readinteger3=streams.readinteger3 + local readinteger4=streams.readinteger4 + function streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end + return t + end end @@ -8150,156 +8684,168 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sto"] = package.loaded["util-sto"] or true --- original size: 6449, stripped down to: 3069 +-- original size: 6661, stripped down to: 3074 if not modules then modules={} end modules ['util-sto']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local setmetatable,getmetatable,rawset,type=setmetatable,getmetatable,rawset,type utilities=utilities or {} utilities.storage=utilities.storage or {} local storage=utilities.storage function storage.mark(t) - if not t then - print("\nfatal error: storage cannot be marked\n") - os.exit() - return - end - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + if not t then + print("\nfatal error: storage cannot be marked\n") + os.exit() + return + end + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.allocate(t) - t=t or {} - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + t=t or {} + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.marked(t) - local m=getmetatable(t) - return m and m.__storage__ + local m=getmetatable(t) + return m and m.__storage__ end function storage.checked(t) - if not t then - report("\nfatal error: storage has not been allocated\n") - os.exit() - return - end - return t + if not t then + report("\nfatal error: storage has not been allocated\n") + os.exit() + return + end + return t end function storage.setinitializer(data,initialize) - local m=getmetatable(data) or {} - m.__index=function(data,k) - m.__index=nil - initialize() - return data[k] - end - setmetatable(data,m) + local m=getmetatable(data) or {} + m.__index=function(data,k) + m.__index=nil + initialize() + return data[k] + end + setmetatable(data,m) end local keyisvalue={ __index=function(t,k) - t[k]=k - return k + t[k]=k + return k end } function storage.sparse(t) - t=t or {} - setmetatable(t,keyisvalue) - return t -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 + t=t or {} + setmetatable(t,keyisvalue) + return t +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 f_index={ - ["empty"]=f_empty, - ["self"]=f_self, - ["table"]=f_table, - ["number"]=f_number, + ["empty"]=f_empty, + ["self"]=f_self, + ["table"]=f_table, + ["number"]=f_number, } function table.setmetatableindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - else - setmetatable(t,{ __index=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + else + setmetatable(t,{ __index=i }) + end + return t end local f_index={ - ["ignore"]=f_ignore, + ["ignore"]=f_ignore, } function table.setmetatablenewindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__newindex=i - else - setmetatable(t,{ __newindex=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__newindex=i + else + setmetatable(t,{ __newindex=i }) + end + return t end function table.setmetatablecall(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - if m then - m.__call=f - else - setmetatable(t,{ __call=f }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + if m then + m.__call=f + else + setmetatable(t,{ __call=f }) + end + return t end function table.setmetatableindices(t,f,n,c) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - m.__newindex=n - m.__call=c - else - setmetatable(t,{ - __index=i, - __newindex=n, - __call=c, - }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + m.__newindex=n + m.__call=c + else + setmetatable(t,{ + __index=i, + __newindex=n, + __call=c, + }) + end + return t end function table.setmetatablekey(t,key,value) - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m[key]=value - return t + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m[key]=value + return t end function table.getmetatablekey(t,key,value) - local m=getmetatable(t) - return m and m[key] + local m=getmetatable(t) + return m and m[key] +end +function table.makeweak(t) + if not t then + t={} + end + local m=getmetatable(t) + if m then + m.__mode="v" + else + setmetatable(t,{ __mode="v" }) + end + return t end @@ -8309,14 +8855,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-prs"] = package.loaded["util-prs"] or true --- original size: 22956, stripped down to: 16106 +-- original size: 23460, stripped down to: 15834 if not modules then modules={} end modules ['util-prs']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } 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 @@ -8338,6 +8884,7 @@ utilities.parsers.hashes=hashes local digit=R("09") local space=P(' ') local equal=P("=") +local colon=P(":") local comma=P(",") local lbrace=P("{") local rbrace=P("}") @@ -8357,8 +8904,8 @@ local noparent=1-(lparent+rparent) local nobracket=1-(lbracket+rbracket) local escape,left,right=P("\\"),P('{'),P('}') lpegpatterns.balanced=P { - [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, - [2]=left*V(1)*right + [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, + [2]=left*V(1)*right } local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace } local nestedparents=P { lparent*(noparent+V(1))^0*rparent } @@ -8366,311 +8913,329 @@ local nestedbrackets=P { lbracket*(nobracket+V(1))^0*rbracket } local spaces=space^0 local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/"")) local content=(1-endofstring)^0 -lpegpatterns.nestedbraces=nestedbraces +lpegpatterns.nestedbraces=nestedbraces lpegpatterns.nestedparents=nestedparents -lpegpatterns.nested=nestedbraces +lpegpatterns.nested=nestedbraces lpegpatterns.argument=argument lpegpatterns.content=content -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local key=C((1-equal-comma)^1) local pattern_a=(space+comma)^0*(key*equal*value+key*C("")) local pattern_c=(space+comma)^0*(key*equal*value) +local pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C("")) local key=C((1-space-equal-comma)^1) local pattern_b=spaces*comma^0*spaces*(key*((spaces*equal*spaces*value)+C(""))) local hash={} local function set(key,value) - hash[key]=value + hash[key]=value end local pattern_a_s=(pattern_a/set)^1 local pattern_b_s=(pattern_b/set)^1 local pattern_c_s=(pattern_c/set)^1 +local pattern_d_s=(pattern_d/set)^1 patterns.settings_to_hash_a=pattern_a_s patterns.settings_to_hash_b=pattern_b_s patterns.settings_to_hash_c=pattern_c_s +patterns.settings_to_hash_d=pattern_d_s function parsers.make_settings_to_hash_pattern(set,how) - if how=="strict" then - return (pattern_c/set)^1 - elseif how=="tolerant" then - return (pattern_b/set)^1 - else - return (pattern_a/set)^1 - end + if how=="strict" then + return (pattern_c/set)^1 + elseif how=="tolerant" then + return (pattern_b/set)^1 + else + return (pattern_a/set)^1 + end end function parsers.settings_to_hash(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_a_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_a_s,str) + return hash + end +end +function parsers.settings_to_hash_colon_too(str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + else + hash={} + lpegmatch(pattern_d_s,str) + return hash + end end function parsers.settings_to_hash_tolerant(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_b_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_b_s,str) + return hash + end end function parsers.settings_to_hash_strict(str,existing) - if not str or str=="" then - return nil - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end - elseif str and str~="" then - hash=existing or {} - lpegmatch(pattern_c_s,str) - return next(hash) and hash + if not str or str=="" then + return nil + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting + else + return str end + elseif str and str~="" then + hash=existing or {} + lpegmatch(pattern_c_s,str) + return next(hash) and hash + end end local separator=comma*space^0 -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) patterns.settings_to_array=pattern function parsers.settings_to_array(str,strict) - if not str or str=="" then - return {} - elseif type(str)=="table" then - return str - elseif strict then - if find(str,"{",1,true) then - return lpegmatch(pattern,str) - else - return { str } - end - elseif find(str,",",1,true) then - return lpegmatch(pattern,str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + elseif strict then + if find(str,"{",1,true) then + return lpegmatch(pattern,str) else - return { str } + return { str } end + elseif find(str,",",1,true) then + return lpegmatch(pattern,str) + else + return { str } + end end function parsers.settings_to_numbers(str) - if not str or str=="" then - return {} - end - if type(str)=="table" then - elseif find(str,",",1,true) then - str=lpegmatch(pattern,str) - else - return { tonumber(str) } - end - for i=1,#str do - str[i]=tonumber(str[i]) - end - return str -end -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) + if not str or str=="" then + return {} + end + if type(str)=="table" then + elseif find(str,",",1,true) then + str=lpegmatch(pattern,str) + else + return { tonumber(str) } + end + for i=1,#str do + str[i]=tonumber(str[i]) + end + return str +end +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_obey_fences(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache_a={} local cache_b={} function parsers.groupedsplitat(symbol,withaction) - if not symbol then - symbol="," - end - local pattern=(withaction and cache_b or cache_a)[symbol] - if not pattern then - local symbols=S(symbol) - local separator=space^0*symbols*space^0 - local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) - if withaction then - local withvalue=Carg(1)*value/function(f,s) return f(s) end - pattern=spaces*withvalue*(separator*withvalue)^0 - cache_b[symbol]=pattern - else - pattern=spaces*Ct(value*(separator*value)^0) - cache_a[symbol]=pattern - end - end - return pattern + if not symbol then + symbol="," + end + local pattern=(withaction and cache_b or cache_a)[symbol] + if not pattern then + local symbols=S(symbol) + local separator=space^0*symbols*space^0 + local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) + if withaction then + local withvalue=Carg(1)*value/function(f,s) return f(s) end + pattern=spaces*withvalue*(separator*withvalue)^0 + cache_b[symbol]=pattern + else + pattern=spaces*Ct(value*(separator*value)^0) + cache_a[symbol]=pattern + end + end + return pattern end local pattern_a=parsers.groupedsplitat(",",false) local pattern_b=parsers.groupedsplitat(",",true) function parsers.stripped_settings_to_array(str) - if not str or str=="" then - return {} - else - return lpegmatch(pattern_a,str) - end + 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 + if not str or str=="" then + return {} + else + return lpegmatch(pattern_b,str,1,action) + end end local function set(t,v) - t[#t+1]=v + t[#t+1]=v end local value=P(Carg(1)*value)/set local pattern=value*(separator*value)^0*Carg(1) function parsers.add_settings_to_array(t,str) - return lpegmatch(pattern,str,nil,t) + return lpegmatch(pattern,str,nil,t) end function parsers.hash_to_string(h,separator,yes,no,strict,omit) - if h then - local t,tn,s={},0,sortedkeys(h) - omit=omit and tohash(omit) - for i=1,#s do - local key=s[i] - if not omit or not omit[key] then - local value=h[key] - if type(value)=="boolean" then - if yes and no then - if value then - tn=tn+1 - t[tn]=key..'='..yes - elseif not strict then - tn=tn+1 - t[tn]=key..'='..no - end - elseif value or not strict then - tn=tn+1 - t[tn]=key..'='..tostring(value) - end - else - tn=tn+1 - t[tn]=key..'='..value - end - end + if h then + local t={} + local tn=0 + local s=sortedkeys(h) + omit=omit and tohash(omit) + for i=1,#s do + local key=s[i] + if not omit or not omit[key] then + local value=h[key] + if type(value)=="boolean" then + if yes and no then + if value then + tn=tn+1 + t[tn]=key..'='..yes + elseif not strict then + tn=tn+1 + t[tn]=key..'='..no + end + elseif value or not strict then + tn=tn+1 + t[tn]=key..'='..tostring(value) + end + else + tn=tn+1 + t[tn]=key..'='..value end - return concat(t,separator or ",") - else - return "" + end end + return concat(t,separator or ",") + else + return "" + end end function parsers.array_to_string(a,separator) - if a then - return concat(a,separator or ",") - else - return "" - end + if a then + return concat(a,separator or ",") + else + return "" + end end local pattern=Cf(Ct("")*Cg(C((1-S(", "))^1)*S(", ")^0*Cc(true))^1,rawset) function utilities.parsers.settings_to_set(str) - return str and lpegmatch(pattern,str) or {} + return str and lpegmatch(pattern,str) or {} end hashes.settings_to_set=table.setmetatableindex(function(t,k) - local v=k and lpegmatch(pattern,k) or {} - t[k]=v - return v + local v=k and lpegmatch(pattern,k) or {} + t[k]=v + return v end) getmetatable(hashes.settings_to_set).__mode="kv" function parsers.simple_hash_to_string(h,separator) - local t,tn={},0 - for k,v in sortedhash(h) do - if v then - tn=tn+1 - t[tn]=k - end + local t={} + local tn=0 + for k,v in sortedhash(h) do + if v then + tn=tn+1 + t[tn]=k end - return concat(t,separator or ",") + end + return concat(t,separator or ",") end local str=Cs(lpegpatterns.unquoted)+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 {} + return str and lpegmatch(splitter,str,1,target or {}) or {} end local splitter=lpeg.tsplitat(" ") function utilities.parsers.options_to_array(str) - return str and lpegmatch(splitter,str) or {} + return str and lpegmatch(splitter,str) 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) - if not n then - return str + if not n then + return str + else + local s=lpegmatch(pattern_a,str) + if n==1 then + return unpack(s) else - local s=lpegmatch(pattern_a,str) - if n==1 then - return unpack(s) - else - local t,tn={},0 - for i=1,n do - for j=1,#s do - tn=tn+1 - t[tn]=s[j] - end - end - return unpack(t) + local t={} + local tn=0 + for i=1,n do + for j=1,#s do + tn=tn+1 + t[tn]=s[j] end + end + return unpack(t) end + end end local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+(C(digit^1)/tonumber*lparent*Cs((noparent+nestedparents)^1)*rparent)/repeater+C((nestedbraces+(1-comma))^1) local pattern_b=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_with_repeat(str,expand) - if expand then - return lpegmatch(pattern_b,str) or {} - else - return lpegmatch(pattern_a,str) or {} - end + if expand then + return lpegmatch(pattern_b,str) or {} + else + return lpegmatch(pattern_a,str) or {} + end end local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace local pattern=Ct((space+value)^0) function parsers.arguments_to_table(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function parsers.getparameters(self,class,parentclass,settings) - local sc=self[class] - if not sc then - sc={} - self[class]=sc - if parentclass then - local sp=self[parentclass] - if not sp then - sp={} - self[parentclass]=sp - end - setmetatableindex(sc,sp) - end + local sc=self[class] + if not sc then + sc={} + self[class]=sc + if parentclass then + local sp=self[parentclass] + if not sp then + sp={} + self[parentclass]=sp + end + setmetatableindex(sc,sp) end - parsers.settings_to_hash(settings,sc) + end + parsers.settings_to_hash(settings,sc) end function parsers.listitem(str) - return gmatch(str,"[^, ]+") + return gmatch(str,"[^, ]+") end local pattern=Cs { "start", - start=V("one")+V("two")+V("three"), - rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, - thousand=digit*digit*digit, - one=digit*V("rest"), - two=digit*digit*V("rest"), - three=V("thousand")*V("rest"), + start=V("one")+V("two")+V("three"), + rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, + thousand=digit*digit*digit, + one=digit*V("rest"), + two=digit*digit*V("rest"), + three=V("thousand")*V("rest"), } lpegpatterns.splitthousands=pattern function parsers.splitthousands(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local optionalwhitespace=whitespace^0 lpegpatterns.words=Ct((Cs((1-punctuation-whitespace)^1)+anything)^1) @@ -8684,75 +9249,75 @@ local key=C((1-equal)^1) local value=dquote*C((1-dquote-escape*dquote)^0)*dquote local pattern=Cf(Ct("")*(Cg(key*equal*value)*separator^0)^1,rawset)^0*P(-1) function parsers.keq_to_hash(str) - if str and str~="" then - return lpegmatch(pattern,str) - else - return {} - end + if str and str~="" then + return lpegmatch(pattern,str) + else + return {} + end end local defaultspecification={ separator=",",quote='"' } function parsers.csvsplitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=specification.quote - local separator=S(separator~="" and separator or ",") - local whatever=C((1-separator-newline)^0) - if quotechar and quotechar~="" then - local quotedata=nil - for chr in gmatch(quotechar,".") do - local quotechar=P(chr) - local quoteword=quotechar*C((1-quotechar)^0)*quotechar - if quotedata then - quotedata=quotedata+quoteword - else - quotedata=quoteword - end - end - whatever=quotedata+whatever - end - local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) - return function(data) - return lpegmatch(parser,data) + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=specification.quote + local separator=S(separator~="" and separator or ",") + local whatever=C((1-separator-newline)^0) + if quotechar and quotechar~="" then + local quotedata=nil + for chr in gmatch(quotechar,".") do + local quotechar=P(chr) + local quoteword=quotechar*C((1-quotechar)^0)*quotechar + if quotedata then + quotedata=quotedata+quoteword + else + quotedata=quoteword + end end + whatever=quotedata+whatever + end + local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) + return function(data) + return lpegmatch(parser,data) + end end function parsers.rfc4180splitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=P(specification.quote) - local dquotechar=quotechar*quotechar + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=P(specification.quote) + local dquotechar=quotechar*quotechar /specification.quote - 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+Cc("") - local record=Ct(field*(separator*field)^1) - local headerline=record*Cp() - local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 - local headeryes=Ct(morerecords) - local headernop=Ct(record*morerecords) - return function(data,getheader) - if getheader then - local header,position=lpegmatch(headerline,data) - local data=lpegmatch(headeryes,data,position) - return data,header - else - return lpegmatch(headernop,data) - end - end + 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+Cc("") + local record=Ct(field*(separator*field)^1) + local headerline=record*Cp() + local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 + local headeryes=Ct(morerecords) + local headernop=Ct(record*morerecords) + return function(data,getheader) + if getheader then + local header,position=lpegmatch(headerline,data) + local data=lpegmatch(headeryes,data,position) + return data,header + else + return lpegmatch(headernop,data) + end + end end local function ranger(first,last,n,action) - if not first then - elseif last==true then - for i=first,n or first do - action(i) - end - elseif last then - for i=first,last do - action(i) - end - else - action(first) + if not first then + elseif last==true then + for i=first,n or first do + action(i) end + elseif last then + for i=first,last do + action(i) + end + else + action(first) + end end local cardinal=lpegpatterns.cardinal/tonumber local spacers=lpegpatterns.spacer^0 @@ -8760,89 +9325,89 @@ local endofstring=lpegpatterns.endofstring local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1 local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring function parsers.stepper(str,n,action) - if type(n)=="function" then - lpegmatch(stepper,str,1,false,n or print) - else - lpegmatch(stepper,str,1,n,action or print) - end + if type(n)=="function" then + lpegmatch(stepper,str,1,false,n or print) + else + lpegmatch(stepper,str,1,n,action or print) + end end local pattern_math=Cs((P("%")/"\\percent "+P("^")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) local pattern_text=Cs((P("%")/"\\percent "+(P("^")/"\\high")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) patterns.unittotex=pattern function parsers.unittotex(str,textmode) - return lpegmatch(textmode and pattern_text or pattern_math,str) + return lpegmatch(textmode and pattern_text or pattern_math,str) end local pattern=Cs((P("^")/"<sup>"*lpegpatterns.integer*Cc("</sup>")+anything)^0) function parsers.unittoxml(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache={} local spaces=lpegpatterns.space^0 local dummy=function() end setmetatableindex(cache,function(t,k) - local separator=P(k) - local value=(1-separator)^0 - local pattern=spaces*C(value)*separator^0*Cp() - t[k]=pattern - return pattern + local separator=P(k) + local value=(1-separator)^0 + local pattern=spaces*C(value)*separator^0*Cp() + t[k]=pattern + return pattern end) local commalistiterator=cache[","] function utilities.parsers.iterator(str,separator) - local n=#str - if n==0 then - return dummy - else - local pattern=separator and cache[separator] or commalistiterator - local p=1 - return function() - if p<=n then - local s,e=lpegmatch(pattern,str,p) - if e then - p=e - return s - end - end + local n=#str + if n==0 then + return dummy + else + local pattern=separator and cache[separator] or commalistiterator + local p=1 + return function() + if p<=n then + local s,e=lpegmatch(pattern,str,p) + if e then + p=e + return s end + end end + end end local function initialize(t,name) - local source=t[name] - if source then - local result={} - for k,v in next,t[name] do - result[k]=v - end - return result - else - return {} + local source=t[name] + if source then + local result={} + for k,v in next,t[name] do + result[k]=v end + return result + else + return {} + end end local function fetch(t,name) - return t[name] or {} + return t[name] or {} end local function process(result,more) - for k,v in next,more do - result[k]=v - end - return result + for k,v in next,more do + result[k]=v + end + return result end local name=C((1-S(", "))^1) local parser=(Carg(1)*name/initialize)*(S(", ")^1*(Carg(1)*name/fetch))^0 local merge=Cf(parser,process) function utilities.parsers.mergehashes(hash,list) - return lpegmatch(merge,list,1,hash) + 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 + 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 local spacing=whitespace^0 local apply=P("->") @@ -8850,11 +9415,11 @@ local method=C((1-apply)^1) local token=lbrace*C((1-rbrace)^1)*rbrace+C(anything^1) local pattern=spacing*(method*spacing*apply+Carg(1))*spacing*token function utilities.parsers.splitmethod(str,default) - if str then - return lpegmatch(pattern,str,1,default or false) - else - return default or false,"" - end + if str then + return lpegmatch(pattern,str,1,default or false) + else + return default or false,"" + end end @@ -8864,14 +9429,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fmt"] = package.loaded["util-fmt"] or true --- original size: 2274, stripped down to: 1781 +-- original size: 2541, stripped down to: 1624 if not modules then modules={} end modules ['util-fmt']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.formatters=utilities.formatters or {} @@ -8882,61 +9447,2887 @@ local strip=string.strip local lpegmatch=lpeg.match local stripper=lpeg.patterns.stripzeros function formatters.stripzeros(str) - return lpegmatch(stripper,str) + return lpegmatch(stripper,str) end function formatters.formatcolumns(result,between) - if result and #result>0 then - between=between or " " - local widths,numbers={},{} - local first=result[1] - local n=#first - for i=1,n do - widths[i]=0 + if result and #result>0 then + between=between or " " + local widths,numbers={},{} + local first=result[1] + local n=#first + for i=1,n do + widths[i]=0 + end + for i=1,#result do + local r=result[i] + for j=1,n do + local rj=r[j] + local tj=type(rj) + if tj=="number" then + numbers[j]=true + rj=tostring(rj) + elseif tj~="string" then + rj=tostring(rj) + r[j]=rj + end + local w=#rj + if w>widths[j] then + widths[j]=w end - for i=1,#result do - local r=result[i] - for j=1,n do - local rj=r[j] - local tj=type(rj) - if tj=="number" then - numbers[j]=true - end - if tj~="string" then - rj=tostring(rj) - r[j]=rj - end - local w=#rj - if w>widths[j] then - widths[j]=w - end + end + end + for i=1,n do + local w=widths[i] + if numbers[i] then + if w>80 then + widths[i]="%s"..between + else + widths[i]="%0"..w.."i"..between + end + else + if w>80 then + widths[i]="%s"..between + elseif w>0 then + widths[i]="%-"..w.."s"..between + else + widths[i]="%s" + end + end + end + local template=strip(concat(widths)) + for i=1,#result do + local str=format(template,unpack(result[i])) + result[i]=strip(str) + end + end + return result +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-reset"] = package.loaded["util-soc-imp-reset"] or true + +-- original size: 374, stripped down to: 282 + +local loaded=package.loaded +loaded["socket"]=nil +loaded["copas"]=nil +loaded["ltn12"]=nil +loaded["mbox"]=nil +loaded["mime"]=nil +loaded["socket.url"]=nil +loaded["socket.headers"]=nil +loaded["socket.tp"]=nil +loaded["socket.http"]=nil +loaded["socket.ftp"]=nil +loaded["socket.smtp"]=nil + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-socket"] = package.loaded["util-soc-imp-socket"] or true + +-- original size: 4870, stripped down to: 3527 + + +local type,tostring,setmetatable=type,tostring,setmetatable +local min=math.min +local format=string.format +local socket=require("socket.core") +local connect=socket.connect +local tcp4=socket.tcp4 +local tcp6=socket.tcp6 +local getaddrinfo=socket.dns.getaddrinfo +local defaulthost="0.0.0.0" +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("socket") + report(fmt,first,...) + elseif fmt then + fmt="socket: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +socket.report=report +function socket.connect4(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet") +end +function socket.connect6(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet6") +end +function socket.bind(host,port,backlog) + if host=="*" or host=="" then + host=defaulthost + end + local addrinfo,err=getaddrinfo(host) + if not addrinfo then + return nil,err + end + for i=1,#addrinfo do + local alt=addrinfo[i] + local sock,err=(alt.family=="inet" and tcp4 or tcp6)() + if not sock then + return nil,err or "unknown error" + end + sock:setoption("reuseaddr",true) + local res,err=sock:bind(alt.addr,port) + if res then + res,err=sock:listen(backlog) + if res then + return sock + else + sock:close() + end + else + sock:close() + end + end + return nil,"invalid address" +end +socket.try=socket.newtry() +function socket.choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local f=list[name or "nil"] + if f then + return f(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end +end +local sourcet={} +local sinkt={} +socket.sourcet=sourcet +socket.sinkt=sinkt +socket.BLOCKSIZE=2048 +sinkt["close-when-done"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + sock:close() + return 1 + end + end + } + ) +end +sinkt["keep-open"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + return 1 + end + end + } + ) +end +sinkt["default"]=sinkt["keep-open"] +socket.sink=socket.choose(sinkt) +sourcet["by-length"]=function(sock,length) + local blocksize=socket.BLOCKSIZE + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function() + if length<=0 then + return nil + end + local chunk,err=sock:receive(min(blocksize,length)) + if err then + return nil,err + end + length=length-#chunk + return chunk + end + } + ) +end +sourcet["until-closed"]=function(sock) + local blocksize=socket.BLOCKSIZE + local done=false + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + if done then + return nil + end + local chunk,status,partial=sock:receive(blocksize) + if not status then + return chunk + elseif status=="closed" then + sock:close() + done=true + return partial + else + return nil,status + end + end + } + ) +end +sourcet["default"]=sourcet["until-closed"] +socket.source=socket.choose(sourcet) +_G.socket=socket +package.loaded["socket"]=socket + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-copas"] = package.loaded["util-soc-imp-copas"] or true + +-- original size: 25844, stripped down to: 14821 + + +local socket=socket or require("socket") +local ssl=ssl or nil +local WATCH_DOG_TIMEOUT=120 +local UDP_DATAGRAM_MAX=8192 +local type,next,pcall,getmetatable,tostring=type,next,pcall,getmetatable,tostring +local min,max,random=math.min,math.max,math.random +local find=string.find +local insert,remove=table.insert,table.remove +local gettime=socket.gettime +local selectsocket=socket.select +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.yield +local runningcoroutine=coroutine.running +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("copas") + report(fmt,first,...) + elseif fmt then + fmt="copas: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local copas={ + _COPYRIGHT="Copyright (C) 2005-2016 Kepler Project", + _DESCRIPTION="Coroutine Oriented Portable Asynchronous Services", + _VERSION="Copas 2.0.1", + autoclose=true, + running=false, + report=report, +} +local function statushandler(status,...) + if status then + return... + end + local err=(...) + if type(err)=="table" then + err=err[1] + end + report("error: %s",tostring(err)) + return nil,err +end +function socket.protect(func) + return function(...) + return statushandler(pcall(func,...)) + end +end +function socket.newtry(finalizer) + return function (...) + local status=(...) + if not status then + local detail=select(2,...) + pcall(finalizer,detail) + report("error: %s",tostring(detail)) + return + end + return... + end +end +local function newset() + local reverse={} + local set={} + local queue={} + setmetatable(set,{ + __index={ + insert=function(set,value) + if not reverse[value] then + local n=#set+1 + set[n]=value + reverse[value]=n + end + end, + remove=function(set,value) + local index=reverse[value] + if index then + reverse[value]=nil + local n=#set + local top=set[n] + set[n]=nil + if top~=value then + reverse[top]=index + set[index]=top end + end + end, + push=function (set,key,itm) + local entry=queue[key] + if entry==nil then + queue[key]={ itm } + else + entry[#entry+1]=itm + end + end, + pop=function (set,key) + local top=queue[key] + if top~=nil then + local ret=remove(top,1) + if top[1]==nil then + queue[key]=nil + end + return ret + end end - for i=1,n do - local w=widths[i] - if numbers[i] then - if w>80 then - widths[i]="%s"..between - else - widths[i]="%0"..w.."i"..between - end - else - if w>80 then - widths[i]="%s"..between - elseif w>0 then - widths[i]="%-"..w.."s"..between - else - widths[i]="%s" - end + } + } ) + return set +end +local _sleeping={ + times={}, + cos={}, + lethargy={}, + insert=function() + end, + remove=function() + end, + push=function(self,sleeptime,co) + if not co then + return + end + if sleeptime<0 then + self.lethargy[co]=true + return + else + sleeptime=gettime()+sleeptime + end + local t=self.times + local c=self.cos + local i=1 + local n=#t + while i<=n and t[i]<=sleeptime do + i=i+1 + end + insert(t,i,sleeptime) + insert(c,i,co) + end, + getnext= + function(self) + local t=self.times + local delay=t[1] and t[1]-gettime() or nil + return delay and max(delay,0) or nil + end, + pop= + function(self,time) + local t=self.times + local c=self.cos + if #t==0 or time<t[1] then + return + end + local co=c[1] + remove(t,1) + remove(c,1) + return co + end, + wakeup=function(self,co) + local let=self.lethargy + if let[co] then + self:push(0,co) + let[co]=nil + else + local c=self.cos + local t=self.times + for i=1,#c do + if c[i]==co then + remove(c,i) + remove(t,i) + self:push(0,co) + return end + end end - local template=strip(concat(widths)) - for i=1,#result do - local str=format(template,unpack(result[i])) - result[i]=strip(str) + end +} +local _servers=newset() +local _reading=newset() +local _writing=newset() +local _reading_log={} +local _writing_log={} +local _is_timeout={ + timeout=true, + wantread=true, + wantwrite=true, +} +local function isTCP(socket) + return not find(tostring(socket),"^udp") +end +local function copasreceive(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local current_log=_reading_log + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (not _is_timeout[err]) then + current_log[client]=nil + return s,err,part + end + if err=="wantwrite" then + current_log=_writing_log + current_log[client]=gettime() + yieldcoroutine(client,_writing) + else + current_log=_reading_log + current_log[client]=gettime() + yieldcoroutine(client,_reading) + end + until false +end +local function copasreceivefrom(client,size) + local s,err,port + if not size or size==0 then + size=UDP_DATAGRAM_MAX + end + repeat + s,err,port=client:receivefrom(size) + if s or err~="timeout" then + _reading_log[client]=nil + return s,err,port + end + _reading_log[client]=gettime() + yieldcoroutine(client,_reading) + until false +end +local function copasreceivepartial(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local logger=_reading_log + local queue=_reading + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (type(pattern)=="number" and part~="" and part) or not _is_timeout[err] then + logger[client]=nil + return s,err,part + end + if err=="wantwrite" then + logger=_writing_log + queue=_writing + else + logger=_reading_log + queue=_reading + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassend(client,data,from,to) + if not from then + from=1 + end + local lastIndex=from-1 + local logger=_writing_log + local queue=_writing + local s,err + repeat + s,err,lastIndex=client:send(data,lastIndex+1,to) + if random(100)>90 then + logger[client]=gettime() + yieldcoroutine(client,queue) + end + if s or not _is_timeout[err] then + logger[client]=nil + return s,err,lastIndex + end + if err=="wantread" then + logger=_reading_log + queue=_reading + else + logger=_writing_log + queue=_writing + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassendto(client,data,ip,port) + repeat + local s,err=client:sendto(data,ip,port) + if random(100)>90 then + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + end + if s or err~="timeout" then + _writing_log[client]=nil + return s,err + end + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + until false +end +local function copasconnect(skt,host,port) + skt:settimeout(0) + local ret,err,tried_more_than_once + repeat + ret,err=skt:connect (host,port) + if ret or (err~="timeout" and err~="Operation already in progress") then + if not ret and err=="already connected" and tried_more_than_once then + ret=1 + err=nil + end + _writing_log[skt]=nil + return ret,err + end + tried_more_than_once=tried_more_than_once or true + _writing_log[skt]=gettime() + yieldcoroutine(skt,_writing) + until false +end +local function copasdohandshake(skt,sslt) + if not ssl then + ssl=require("ssl") + end + if not ssl then + report("error: no ssl library") + return + end + local nskt,err=ssl.wrap(skt,sslt) + if not nskt then + report("error: %s",tostring(err)) + return + end + nskt:settimeout(0) + local queue + repeat + local success,err=nskt:dohandshake() + if success then + return nskt + elseif err=="wantwrite" then + queue=_writing + elseif err=="wantread" then + queue=_reading + else + report("error: %s",tostring(err)) + return + end + yieldcoroutine(nskt,queue) + until false +end +local function copasflush(client) +end +copas.connect=copassconnect +copas.send=copassend +copas.sendto=copassendto +copas.receive=copasreceive +copas.receivefrom=copasreceivefrom +copas.copasreceivepartial=copasreceivepartial +copas.copasreceivePartial=copasreceivepartial +copas.dohandshake=copasdohandshake +copas.flush=copasflush +local function _skt_mt_tostring(self) + return tostring(self.socket).." (copas wrapped)" +end +local _skt_mt_tcp_index={ + send=function(self,data,from,to) + return copassend (self.socket,data,from,to) + end, + receive=function (self,pattern,prefix) + if self.timeout==0 then + return copasreceivePartial(self.socket,pattern,prefix) + else + return copasreceive(self.socket,pattern,prefix) + end + end, + flush=function (self) + return copasflush(self.socket) + end, + settimeout=function (self,time) + self.timeout=time + return true + end, + connect=function(self,...) + local res,err=copasconnect(self.socket,...) + if res and self.ssl_params then + res,err=self:dohandshake() + end + return res,err + end, + close=function(self,...) + return self.socket:close(...) + end, + bind=function(self,...) + return self.socket:bind(...) + end, + getsockname=function(self,...) + return self.socket:getsockname(...) + end, + getstats=function(self,...) + return self.socket:getstats(...) + end, + setstats=function(self,...) + return self.socket:setstats(...) + end, + listen=function(self,...) + return self.socket:listen(...) + end, + accept=function(self,...) + return self.socket:accept(...) + end, + setoption=function(self,...) + return self.socket:setoption(...) + end, + getpeername=function(self,...) + return self.socket:getpeername(...) + end, + shutdown=function(self,...) + return self.socket:shutdown(...) + end, + dohandshake=function(self,sslt) + self.ssl_params=sslt or self.ssl_params + local nskt,err=copasdohandshake(self.socket,self.ssl_params) + if not nskt then + return nskt,err + end + self.socket=nskt + return self + end, +} +local _skt_mt_tcp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_tcp_index, +} +local _skt_mt_udp_index={ + sendto=function (self,...) + return copassendto(self.socket,...) + end, + receive=function (self,size) + return copasreceive(self.socket,size or UDP_DATAGRAM_MAX) + end, + receivefrom=function (self,size) + return copasreceivefrom(self.socket,size or UDP_DATAGRAM_MAX) + end, + setpeername=function(self,...) + return self.socket:getpeername(...) + end, + setsockname=function(self,...) + return self.socket:setsockname(...) + end, + close=function(self,...) + return true + end +} +local _skt_mt_udp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_udp_index, +} +for k,v in next,_skt_mt_tcp_index do + if not _skt_mt_udp_index[k] then + _skt_mt_udp_index[k]=v + end +end +local function wrap(skt,sslt) + if getmetatable(skt)==_skt_mt_tcp or getmetatable(skt)==_skt_mt_udp then + return skt + end + skt:settimeout(0) + if isTCP(skt) then + return setmetatable ({ socket=skt,ssl_params=sslt },_skt_mt_tcp) + else + return setmetatable ({ socket=skt },_skt_mt_udp) + end +end +copas.wrap=wrap +function copas.handler(handler,sslparams) + return function (skt,...) + skt=wrap(skt) + if sslparams then + skt:dohandshake(sslparams) + end + return handler(skt,...) + end +end +local _errhandlers={} +function copas.setErrorHandler(err) + local co=runningcoroutine() + if co then + _errhandlers[co]=err + end +end +local function _deferror (msg,co,skt) + report("%s (%s) (%s)",msg,tostring(co),tostring(skt)) +end +local function _doTick (co,skt,...) + if not co then + return + end + local ok,res,new_q=resumecoroutine(co,skt,...) + if ok and res and new_q then + new_q:insert(res) + new_q:push(res,co) + else + if not ok then + pcall(_errhandlers[co] or _deferror,res,co,skt) + end + if skt and copas.autoclose and isTCP(skt) then + skt:close() + end + _errhandlers[co]=nil + end +end +local function _accept(input,handler) + local client=input:accept() + if client then + client:settimeout(0) + local co=createcoroutine(handler) + _doTick (co,client) + end + return client +end +local function _tickRead(skt) + _doTick(_reading:pop(skt),skt) +end +local function _tickWrite(skt) + _doTick(_writing:pop(skt),skt) +end +local function addTCPserver(server,handler,timeout) + server:settimeout(timeout or 0) + _servers[server]=handler + _reading:insert(server) +end +local function addUDPserver(server,handler,timeout) + server:settimeout(timeout or 0) + local co=createcoroutine(handler) + _reading:insert(server) + _doTick(co,server) +end +function copas.addserver(server,handler,timeout) + if isTCP(server) then + addTCPserver(server,handler,timeout) + else + addUDPserver(server,handler,timeout) + end +end +function copas.removeserver(server,keep_open) + local s=server + local mt=getmetatable(server) + if mt==_skt_mt_tcp or mt==_skt_mt_udp then + s=server.socket + end + _servers[s]=nil + _reading:remove(s) + if keep_open then + return true + end + return server:close() +end +function copas.addthread(handler,...) + local thread=createcoroutine(function(_,...) return handler(...) end) + _doTick(thread,nil,...) + return thread +end +local _tasks={} +local function addtaskRead(task) + task.def_tick=_tickRead + _tasks[task]=true +end +local function addtaskWrite(task) + task.def_tick=_tickWrite + _tasks[task]=true +end +local function tasks() + return next,_tasks +end +local _readable_t={ + events=function(self) + local i=0 + return function () + i=i+1 + return self._evs[i] + end + end, + tick=function(self,input) + local handler=_servers[input] + if handler then + input=_accept(input,handler) + else + _reading:remove(input) + self.def_tick(input) + end + end +} +addtaskRead(_readable_t) +local _writable_t={ + events=function(self) + local i=0 + return function() + i=i+1 + return self._evs[i] + end + end, + tick=function(self,output) + _writing:remove(output) + self.def_tick(output) + end +} +addtaskWrite(_writable_t) +local _sleeping_t={ + tick=function(self,time,...) + _doTick(_sleeping:pop(time),...) + end +} +function copas.sleep(sleeptime) + yieldcoroutine((sleeptime or 0),_sleeping) +end +function copas.wakeup(co) + _sleeping:wakeup(co) +end +local last_cleansing=0 +local function _select(timeout) + local now=gettime() + local r_evs,w_evs,err=selectsocket(_reading,_writing,timeout) + _readable_t._evs=r_evs + _writable_t._evs=w_evs + if (last_cleansing-now)>WATCH_DOG_TIMEOUT then + last_cleansing=now + for skt,time in next,_reading_log do + if not r_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#r_evs+1 + _reading_log[skt]=nil + r_evs[n]=skt + r_evs[skt]=n + end + end + for skt,time in next,_writing_log do + if not w_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#w_evs+1 + _writing_log[skt]=nil + w_evs[n]=skt + w_evs[skt]=n + end + end + end + if err=="timeout" and #r_evs+#w_evs>0 then + return nil + else + return err + end +end +local function copasfinished() + return not (next(_reading) or next(_writing) or _sleeping:getnext()) +end +local function copasstep(timeout) + _sleeping_t:tick(gettime()) + local nextwait=_sleeping:getnext() + if nextwait then + timeout=timeout and min(nextwait,timeout) or nextwait + elseif copasfinished() then + return false + end + local err=_select(timeout) + if err then + if err=="timeout" then + return false + end + return nil,err + end + for task in tasks() do + for event in task:events() do + task:tick(event) + end + end + return true +end +copas.finished=copasfinished +copas.step=copasstep +function copas.loop(timeout) + copas.running=true + while not copasfinished() do + copasstep(timeout) + end + copas.running=false +end +package.loaded["copas"]=copas + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ltn12"] = package.loaded["util-soc-imp-ltn12"] or true + +-- original size: 8709, stripped down to: 5411 + + +local select,unpack=select,unpack +local insert,remove=table.insert,table.remove +local sub=string.sub +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("ltn12") + report(fmt,first,...) + elseif fmt then + fmt="ltn12: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local filter={} +local source={} +local sink={} +local pump={} +local ltn12={ + _VERSION="LTN12 1.0.3", + BLOCKSIZE=2048, + filter=filter, + source=source, + sink=sink, + pump=pump, + report=report, +} +function filter.cycle(low,ctx,extra) + if low then + return function(chunk) + return (low(ctx,chunk,extra)) + end + end +end +function filter.chain(...) + local arg={... } + local n=select('#',...) + local top=1 + local index=1 + local retry="" + return function(chunk) + retry=chunk and retry + while true do + local action=arg[index] + if index==top then + chunk=action(chunk) + if chunk=="" or top==n then + return chunk + elseif chunk then + index=index+1 + else + top=top+1 + index=top + end + else + chunk=action(chunk or "") + if chunk=="" then + index=index-1 + chunk=retry + elseif chunk then + if index==n then + return chunk + else + index=index+1 + end + else + report("error: filter returned inappropriate 'nil'") + return end + end end - return result + end +end +local function empty() + return nil +end +function source.empty() + return empty +end +local function sourceerror(err) + return function() + return nil,err + end +end +source.error=sourceerror +function source.file(handle,io_err) + if handle then + local blocksize=ltn12.BLOCKSIZE + return function() + local chunk=handle:read(blocksize) + if not chunk then + handle:close() + end + return chunk + end + else + return sourceerror(io_err or "unable to open file") + end +end +function source.simplify(src) + return function() + local chunk,err_or_new=src() + if err_or_new then + src=err_or_new + end + if chunk then + return chunk + else + return nil,err_or_new + end + end +end +function source.string(s) + if s then + local blocksize=ltn12.BLOCKSIZE + local i=1 + return function() + local nexti=i+blocksize + local chunk=sub(s,i,nexti-1) + i=nexti + if chunk~="" then + return chunk + else + return nil + end + end + else return source.empty() end +end +function source.rewind(src) + local t={} + return function(chunk) + if chunk then + insert(t,chunk) + else + chunk=remove(t) + if chunk then + return chunk + else + return src() + end + end + end +end +function source.chain(src,f,...) + if... then + f=filter.chain(f,...) + end + local last_in="" + local last_out="" + local state="feeding" + local err + return function() + if not last_out then + report("error: source is empty") + return + end + while true do + if state=="feeding" then + last_in,err=src() + if err then + return nil,err + end + last_out=f(last_in) + if not last_out then + if last_in then + report("error: filter returned inappropriate 'nil'") + end + return nil + elseif last_out~="" then + state="eating" + if last_in then + last_in="" + end + return last_out + end + else + last_out=f(last_in) + if last_out=="" then + if last_in=="" then + state="feeding" + else + report("error: filter returned nothing") + return + end + elseif not last_out then + if last_in then + report("filter returned inappropriate 'nil'") + end + return nil + else + return last_out + end + end + end + end +end +function source.cat(...) + local arg={... } + local src=remove(arg,1) + return function() + while src do + local chunk,err=src() + if chunk then + return chunk + end + if err then + return nil,err + end + src=remove(arg,1) + end + end +end +function sink.table(t) + if not t then + t={} + end + local f=function(chunk,err) + if chunk then + insert(t,chunk) + end + return 1 + end + return f,t +end +function sink.simplify(snk) + return function(chunk,err) + local ret,err_or_new=snk(chunk,err) + if not ret then + return nil,err_or_new + end + if err_or_new then + snk=err_or_new + end + return 1 + end +end +local function null() + return 1 +end +function sink.null() + return null +end +local function sinkerror(err) + return function() + return nil,err + end +end +sink.error=sinkerror +function sink.file(handle,io_err) + if handle then + return function(chunk,err) + if not chunk then + handle:close() + return 1 + else + return handle:write(chunk) + end + end + else + return sinkerror(io_err or "unable to open file") + end +end +function sink.chain(f,snk,...) + if... then + local args={ f,snk,... } + snk=remove(args,#args) + f=filter.chain(unpack(args)) + end + return function(chunk,err) + if chunk~="" then + local filtered=f(chunk) + local done=chunk and "" + while true do + local ret,snkerr=snk(filtered,err) + if not ret then + return nil,snkerr + end + if filtered==done then + return 1 + end + filtered=f(done) + end + else + return 1 + end + end +end +function pump.step(src,snk) + local chunk,src_err=src() + local ret,snk_err=snk(chunk,src_err) + if chunk and ret then + return 1 + else + return nil,src_err or snk_err + end +end +function pump.all(src,snk,step) + if not step then + step=pump.step + end + while true do + local ret,err=step(src,snk) + if not ret then + if err then + return nil,err + else + return 1 + end + end + end +end +package.loaded["ltn12"]=ltn12 + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-mime"] = package.loaded["util-soc-imp-mime"] or true + +-- original size: 2328, stripped down to: 1874 + + +local type,tostring=type,tostring +local mime=require("mime.core") +local ltn12=ltn12 or require("ltn12") +local filtercycle=ltn12.filter.cycle +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("mime") + report(fmt,first,...) + elseif fmt then + fmt="mime: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +mime.report=report +local encodet={} +local decodet={} +local wrapt={} +mime.encodet=encodet +mime.decodet=decodet +mime.wrapt=wrapt +local mime_b64=mime.b64 +local mime_qp=mime.qp +local mime_unb64=mime.unb64 +local mime_unqp=mime.unqp +local mime_wrp=mime.wrp +local mime_qpwrp=mime.qpwrp +local mime_eol=mime_eol +local mime_dot=mime_dot +encodet['base64']=function() + return filtercycle(mime_b64,"") +end +encodet['quoted-printable']=function(mode) + return filtercycle(mime_qp,"",mode=="binary" and "=0D=0A" or "\r\n") +end +decodet['base64']=function() + return filtercycle(mime_unb64,"") +end +decodet['quoted-printable']=function() + return filtercycle(mime_unqp,"") +end +local wraptext=function(length) + if not length then + length=76 + end + return filtercycle(mime_wrp,length,length) +end +local wrapquoted=function() + return filtercycle(mime_qpwrp,76,76) +end +wrapt['text']=wraptext +wrapt['base64']=wraptext +wrapt['default']=wraptext +wrapt['quoted-printable']=wrapquoted +function mime.normalize(marker) + return filtercycle(mime_eol,0,marker) +end +function mime.stuff() + return filtercycle(mime_dot,2) +end +local function choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local filter=list[name or "nil"] + if filter then + return filter(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end end +mime.encode=choose(encodet) +mime.decode=choose(decodet) +mime.wrap=choose(wrapt) +package.loaded["mime"]=mime + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-url"] = package.loaded["util-soc-imp-url"] or true + +-- original size: 6863, stripped down to: 5269 + + +local tonumber,tostring,type=tonumber,tostring,type +local gsub,sub,match,find,format,byte,char=string.gsub,string.sub,string.match,string.find,string.format,string.byte,string.char +local insert=table.insert +local socket=socket or require("socket") +local url={ + _VERSION="URL 1.0.3", +} +socket.url=url +function url.escape(s) + return (gsub(s,"([^A-Za-z0-9_])",function(c) + return format("%%%02x",byte(c)) + end)) +end +local function make_set(t) + local s={} + for i=1,#t do + s[t[i]]=true + end + return s +end +local segment_set=make_set { + "-","_",".","!","~","*","'","(", + ")",":","@","&","=","+","$",",", +} +local function protect_segment(s) + return gsub(s,"([^A-Za-z0-9_])",function(c) + if segment_set[c] then + return c + else + return format("%%%02X",byte(c)) + end + end) +end +function url.unescape(s) + return (gsub(s,"%%(%x%x)",function(hex) + return char(tonumber(hex,16)) + end)) +end +local function absolute_path(base_path,relative_path) + if find(relative_path,"^/") then + return relative_path + end + local path=gsub(base_path,"[^/]*$","") + path=path..relative_path + path=gsub(path,"([^/]*%./)",function (s) + if s~="./" then + return s + else + return "" + end + end) + path=gsub(path,"/%.$","/") + local reduced + while reduced~=path do + reduced=path + path=gsub(reduced,"([^/]*/%.%./)",function (s) + if s~="../../" then + return "" + else + return s + end + end) + end + path=gsub(reduced,"([^/]*/%.%.)$",function (s) + if s~="../.." then + return "" + else + return s + end + end) + return path +end +function url.parse(url,default) + local parsed={} + for k,v in next,default or parsed do + parsed[k]=v + end + if not url or url=="" then + return nil,"invalid url" + end + url=gsub(url,"#(.*)$",function(f) + parsed.fragment=f + return "" + end) + url=gsub(url,"^([%w][%w%+%-%.]*)%:",function(s) + parsed.scheme=s + return "" + end) + url=gsub(url,"^//([^/]*)",function(n) + parsed.authority=n + return "" + end) + url=gsub(url,"%?(.*)",function(q) + parsed.query=q + return "" + end) + url=gsub(url,"%;(.*)",function(p) + parsed.params=p + return "" + end) + if url~="" then + parsed.path=url + end + local authority=parsed.authority + if not authority then + return parsed + end + authority=gsub(authority,"^([^@]*)@",function(u) + parsed.userinfo=u + return "" + end) + authority=gsub(authority,":([^:%]]*)$",function(p) + parsed.port=p + return "" + end) + if authority~="" then + parsed.host=match(authority,"^%[(.+)%]$") or authority + end + local userinfo=parsed.userinfo + if not userinfo then + return parsed + end + userinfo=gsub(userinfo,":([^:]*)$",function(p) + parsed.password=p + return "" + end) + parsed.user=userinfo + return parsed +end +function url.build(parsed) + local url=parsed.path or "" + if parsed.params then + url=url..";"..parsed.params + end + if parsed.query then + url=url.."?"..parsed.query + end + local authority=parsed.authority + if parsed.host then + authority=parsed.host + if find(authority,":") then + authority="["..authority.."]" + end + if parsed.port then + authority=authority..":"..tostring(parsed.port) + end + local userinfo=parsed.userinfo + if parsed.user then + userinfo=parsed.user + if parsed.password then + userinfo=userinfo..":"..parsed.password + end + end + if userinfo then authority=userinfo.."@"..authority end + end + if authority then + url="//"..authority..url + end + if parsed.scheme then + url=parsed.scheme..":"..url + end + if parsed.fragment then + url=url.."#"..parsed.fragment + end + return url +end +function url.absolute(base_url,relative_url) + local base_parsed + if type(base_url)=="table" then + base_parsed=base_url + base_url=url.build(base_parsed) + else + base_parsed=url.parse(base_url) + end + local relative_parsed=url.parse(relative_url) + if not base_parsed then + return relative_url + elseif not relative_parsed then + return base_url + elseif relative_parsed.scheme then + return relative_url + else + relative_parsed.scheme=base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority=base_parsed.authority + if not relative_parsed.path then + relative_parsed.path=base_parsed.path + if not relative_parsed.params then + relative_parsed.params=base_parsed.params + if not relative_parsed.query then + relative_parsed.query=base_parsed.query + end + end + else + relative_parsed.path=absolute_path(base_parsed.path or "",relative_parsed.path) + end + end + return url.build(relative_parsed) + end +end +function url.parse_path(path) + local parsed={} + path=path or "" + gsub(path,"([^/]+)",function (s) + insert(parsed,s) + end) + for i=1,#parsed do + parsed[i]=url.unescape(parsed[i]) + end + if sub(path,1,1)=="/" then + parsed.is_absolute=1 + end + if sub(path,-1,-1)=="/" then + parsed.is_directory=1 + end + return parsed +end +function url.build_path(parsed,unsafe) + local path="" + local n=#parsed + if unsafe then + for i=1,n-1 do + path=path..parsed[i].."/" + end + if n>0 then + path=path..parsed[n] + if parsed.is_directory then + path=path.."/" + end + end + else + for i=1,n-1 do + path=path..protect_segment(parsed[i]).."/" + end + if n>0 then + path=path..protect_segment(parsed[n]) + if parsed.is_directory then + path=path.."/" + end + end + end + if parsed.is_absolute then + path="/"..path + end + return path +end +package.loaded["socket.url"]=url + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-headers"] = package.loaded["util-soc-imp-headers"] or true + +-- original size: 5721, stripped down to: 3754 + + +local next=next +local lower=string.lower +local concat=table.concat +local socket=socket or require("socket") +local headers={} +socket.headers=headers +local canonic={ + ["accept"]="Accept", + ["accept-charset"]="Accept-Charset", + ["accept-encoding"]="Accept-Encoding", + ["accept-language"]="Accept-Language", + ["accept-ranges"]="Accept-Ranges", + ["action"]="Action", + ["alternate-recipient"]="Alternate-Recipient", + ["age"]="Age", + ["allow"]="Allow", + ["arrival-date"]="Arrival-Date", + ["authorization"]="Authorization", + ["bcc"]="Bcc", + ["cache-control"]="Cache-Control", + ["cc"]="Cc", + ["comments"]="Comments", + ["connection"]="Connection", + ["content-description"]="Content-Description", + ["content-disposition"]="Content-Disposition", + ["content-encoding"]="Content-Encoding", + ["content-id"]="Content-ID", + ["content-language"]="Content-Language", + ["content-length"]="Content-Length", + ["content-location"]="Content-Location", + ["content-md5"]="Content-MD5", + ["content-range"]="Content-Range", + ["content-transfer-encoding"]="Content-Transfer-Encoding", + ["content-type"]="Content-Type", + ["cookie"]="Cookie", + ["date"]="Date", + ["diagnostic-code"]="Diagnostic-Code", + ["dsn-gateway"]="DSN-Gateway", + ["etag"]="ETag", + ["expect"]="Expect", + ["expires"]="Expires", + ["final-log-id"]="Final-Log-ID", + ["final-recipient"]="Final-Recipient", + ["from"]="From", + ["host"]="Host", + ["if-match"]="If-Match", + ["if-modified-since"]="If-Modified-Since", + ["if-none-match"]="If-None-Match", + ["if-range"]="If-Range", + ["if-unmodified-since"]="If-Unmodified-Since", + ["in-reply-to"]="In-Reply-To", + ["keywords"]="Keywords", + ["last-attempt-date"]="Last-Attempt-Date", + ["last-modified"]="Last-Modified", + ["location"]="Location", + ["max-forwards"]="Max-Forwards", + ["message-id"]="Message-ID", + ["mime-version"]="MIME-Version", + ["original-envelope-id"]="Original-Envelope-ID", + ["original-recipient"]="Original-Recipient", + ["pragma"]="Pragma", + ["proxy-authenticate"]="Proxy-Authenticate", + ["proxy-authorization"]="Proxy-Authorization", + ["range"]="Range", + ["received"]="Received", + ["received-from-mta"]="Received-From-MTA", + ["references"]="References", + ["referer"]="Referer", + ["remote-mta"]="Remote-MTA", + ["reply-to"]="Reply-To", + ["reporting-mta"]="Reporting-MTA", + ["resent-bcc"]="Resent-Bcc", + ["resent-cc"]="Resent-Cc", + ["resent-date"]="Resent-Date", + ["resent-from"]="Resent-From", + ["resent-message-id"]="Resent-Message-ID", + ["resent-reply-to"]="Resent-Reply-To", + ["resent-sender"]="Resent-Sender", + ["resent-to"]="Resent-To", + ["retry-after"]="Retry-After", + ["return-path"]="Return-Path", + ["sender"]="Sender", + ["server"]="Server", + ["smtp-remote-recipient"]="SMTP-Remote-Recipient", + ["status"]="Status", + ["subject"]="Subject", + ["te"]="TE", + ["to"]="To", + ["trailer"]="Trailer", + ["transfer-encoding"]="Transfer-Encoding", + ["upgrade"]="Upgrade", + ["user-agent"]="User-Agent", + ["vary"]="Vary", + ["via"]="Via", + ["warning"]="Warning", + ["will-retry-until"]="Will-Retry-Until", + ["www-authenticate"]="WWW-Authenticate", + ["x-mailer"]="X-Mailer", +} +headers.canonic=setmetatable(canonic,{ + __index=function(t,k) + socket.report("invalid header: %s",k) + t[k]=k + return k + end +}) +function headers.normalize(headers) + if not headers then + return {} + end + local normalized={} + for k,v in next,headers do + normalized[#normalized+1]=canonic[k]..": "..v + end + normalized[#normalized+1]="" + normalized[#normalized+1]="" + return concat(normalized,"\r\n") +end +function headers.lower(lowered,headers) + if not lowered then + return {} + end + if not headers then + lowered,headers={},lowered + end + for k,v in next,headers do + lowered[lower(k)]=v + end + return lowered +end +socket.headers=headers +package.loaded["socket.headers"]=headers + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-tp"] = package.loaded["util-soc-imp-tp"] or true + +-- original size: 3116, stripped down to: 2533 + + +local setmetatable,next,type,tonumber=setmetatable,next,type,tonumber +local find,upper=string.find,string.upper +local socket=socket or require("socket") +local ltn12=ltn12 or require("ltn12") +local skipsocket=socket.skip +local sinksocket=socket.sink +local tcpsocket=socket.tcp +local ltn12pump=ltn12.pump +local pumpall=ltn12pump.all +local pumpstep=ltn12pump.step +local tp={ + TIMEOUT=60, +} +socket.tp=tp +local function get_reply(c) + local line,err=c:receive() + local reply=line + if err then return + nil,err + end + local code,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + if not code then + return nil,"invalid server reply" + end + if sep=="-" then + local current + repeat + line,err=c:receive() + if err then + return nil,err + end + current,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + reply=reply.."\n"..line + until code==current and sep==" " + end + return code,reply +end +local methods={} +local mt={ __index=methods } +function methods.getpeername(self) + return self.c:getpeername() +end +function methods.getsockname(self) + return self.c:getpeername() +end +function methods.check(self,ok) + local code,reply=get_reply(self.c) + if not code then + return nil,reply + end + local c=tonumber(code) + local t=type(ok) + if t=="function" then + return ok(c,reply) + elseif t=="table" then + for i=1,#ok do + if find(code,ok[i]) then + return c,reply + end + end + return nil,reply + elseif find(code,ok) then + return c,reply + else + return nil,reply + end +end +function methods.command(self,cmd,arg) + cmd=upper(cmd) + if arg then + cmd=cmd.." "..arg.."\r\n" + else + cmd=cmd.."\r\n" + end + return self.c:send(cmd) +end +function methods.sink(self,snk,pat) + local chunk,err=self.c:receive(pat) + return snk(chunk,err) +end +function methods.send(self,data) + return self.c:send(data) +end +function methods.receive(self,pat) + return self.c:receive(pat) +end +function methods.getfd(self) + return self.c:getfd() +end +function methods.dirty(self) + return self.c:dirty() +end +function methods.getcontrol(self) + return self.c +end +function methods.source(self,source,step) + local sink=sinksocket("keep-open",self.c) + local ret,err=pumpall(source,sink,step or pumpstep) + return ret,err +end +function methods.close(self) + self.c:close() + return 1 +end +function tp.connect(host,port,timeout,create) + local c,e=(create or tcpsocket)() + if not c then + return nil,e + end + c:settimeout(timeout or tp.TIMEOUT) + local r,e=c:connect(host,port) + if not r then + c:close() + return nil,e + end + return setmetatable({ c=c },mt) +end +package.loaded["socket.tp"]=tp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-http"] = package.loaded["util-soc-imp-http"] or true + +-- original size: 12577, stripped down to: 9577 + + +local tostring,tonumber,setmetatable,next,type=tostring,tonumber,setmetatable,next,type +local find,lower,format,gsub,match=string.find,string.lower,string.format,string.gsub,string.match +local concat=table.concat +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local ltn12=ltn12 or require("ltn12") +local mime=mime or require("mime") +local headers=socket.headers or require("socket.headers") +local normalizeheaders=headers.normalize +local parseurl=url.parse +local buildurl=url.build +local absoluteurl=url.absolute +local unescapeurl=url.unescape +local skipsocket=socket.skip +local sinksocket=socket.sink +local sourcesocket=socket.source +local trysocket=socket.try +local tcpsocket=socket.tcp +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local emptysource=ltn12.source.empty +local stringsource=ltn12.source.string +local rewindsource=ltn12.source.rewind +local pumpstep=ltn12.pump.step +local pumpall=ltn12.pump.all +local sinknull=ltn12.sink.null +local sinktable=ltn12.sink.table +local lowerheaders=headers.lower +local mimeb64=mime.b64 +local http={ + TIMEOUT=60, + USERAGENT=socket._VERSION, +} +socket.http=http +local PORT=80 +local SCHEMES={ + http=true, +} +local function receiveheaders(sock,headers) + if not headers then + headers={} + end + local line,err=sock:receive() + if err then + return nil,err + end + while line~="" do + local name,value=skipsocket(2,find(line,"^(.-):%s*(.*)")) + if not (name and value) then + return nil,"malformed reponse headers" + end + name=lower(name) + line,err=sock:receive() + if err then + return nil,err + end + while find(line,"^%s") do + value=value..line + line=sock:receive() + if err then + return nil,err + end + end + local found=headers[name] + if found then + value=found..", "..value + end + headers[name]=value + end + return headers +end +socket.sourcet["http-chunked"]=function(sock,headers) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + local line,err=sock:receive() + if err then + return nil,err + end + local size=tonumber(gsub(line,";.*",""),16) + if not size then + return nil,"invalid chunk size" + end + if size>0 then + local chunk,err,part=sock:receive(size) + if chunk then + sock:receive() + end + return chunk,err + else + headers,err=receiveheaders(sock,headers) + if not headers then + return nil,err + end + end + end + } + ) +end +socket.sinkt["http-chunked"]=function(sock) + return setmetatable( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if not chunk then + chunk="" + end + return sock:send(format("%X\r\n%s\r\n",#chunk,chunk)) + end + }) +end +local methods={} +local mt={ __index=methods } +local function openhttp(host,port,create) + local c=trysocket((create or tcpsocket)()) + local h=setmetatable({ c=c },mt) + local try=newtrysocket(function() h:close() end) + h.try=try + try(c:settimeout(http.TIMEOUT)) + try(c:connect(host,port or PORT)) + return h +end +http.open=openhttp +function methods.sendrequestline(self,method,uri) + local requestline=format("%s %s HTTP/1.1\r\n",method or "GET",uri) + return self.try(self.c:send(requestline)) +end +function methods.sendheaders(self,headers) + self.try(self.c:send(normalizeheaders(headers))) + return 1 +end +function methods.sendbody(self,headers,source,step) + if not source then + source=emptysource() + end + if not step then + step=pumpstep + end + local mode="http-chunked" + if headers["content-length"] then + mode="keep-open" + end + return self.try(pumpall(source,sinksocket(mode,self.c),step)) +end +function methods.receivestatusline(self) + local try=self.try + local status=try(self.c:receive(5)) + if status~="HTTP/" then + return nil,status + end + status=try(self.c:receive("*l",status)) + local code=skipsocket(2,find(status,"HTTP/%d*%.%d* (%d%d%d)")) + return try(tonumber(code),status) +end +function methods.receiveheaders(self) + return self.try(receiveheaders(self.c)) +end +function methods.receivebody(self,headers,sink,step) + if not sink then + sink=sinknull() + end + if not step then + step=pumpstep + end + local length=tonumber(headers["content-length"]) + local encoding=headers["transfer-encoding"] + local mode="default" + if encoding and encoding~="identity" then + mode="http-chunked" + elseif length then + mode="by-length" + end + return self.try(pumpall(sourcesocket(mode,self.c,length),sink,step)) +end +function methods.receive09body(self,status,sink,step) + local source=rewindsource(sourcesocket("until-closed",self.c)) + source(status) + return self.try(pumpall(source,sink,step)) +end +function methods.close(self) + return self.c:close() +end +local function adjusturi(request) + if not request.proxy and not http.PROXY then + request={ + path=trysocket(request.path,"invalid path 'nil'"), + params=request.params, + query=request.query, + fragment=request.fragment, + } + end + return buildurl(request) +end +local function adjustheaders(request) + local headers={ + ["user-agent"]=http.USERAGENT, + ["host"]=gsub(request.authority,"^.-@",""), + ["connection"]="close, TE", + ["te"]="trailers" + } + local username=request.user + local password=request.password + if username and password then + headers["authorization"]="Basic "..(mimeb64(username..":"..unescapeurl(password))) + end + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + local username=proxy.user + local password=proxy.password + if username and password then + headers["proxy-authorization"]="Basic "..(mimeb64(username..":"..password)) + end + end + local requestheaders=request.headers + if requestheaders then + headers=lowerheaders(headers,requestheaders) + end + return headers +end +local default={ + host="", + port=PORT, + path="/", + scheme="http" +} +local function adjustrequest(originalrequest) + local url=originalrequest.url + local request=url and parseurl(url,default) or {} + for k,v in next,originalrequest do + request[k]=v + end + local host=request.host + local port=request.port + local uri=request.uri + if not host or host=="" then + trysocket(nil,"invalid host '"..tostring(host).."'") + end + if port=="" then + request.port=PORT + end + if not uri or uri=="" then + request.uri=adjusturi(request) + end + request.headers=adjustheaders(request) + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + request.host=proxy.host + request.port=proxy.port or 3128 + end + return request +end +local maxredericts=4 +local validredirects={ [301]=true,[302]=true,[303]=true,[307]=true } +local validmethods={ [false]=true,GET=true,HEAD=true } +local function shouldredirect(request,code,headers) + local location=headers.location + if not location then + return false + end + location=gsub(location,"%s","") + if location=="" then + return false + end + local scheme=match(location,"^([%w][%w%+%-%.]*)%:") + if scheme and not SCHEMES[scheme] then + return false + end + local method=request.method + local redirect=request.redirect + local redirects=request.nredirects or 0 + return redirect and validredirects[code] and validmethods[method] and redirects<=maxredericts +end +local function shouldreceivebody(request,code) + if request.method=="HEAD" then + return nil + end + if code==204 or code==304 then + return nil + end + if code>=100 and code<200 then + return nil + end + return 1 +end +local tredirect,trequest,srequest +tredirect=function(request,location) + local result,code,headers,status=trequest { + url=absoluteurl(request.url,location), + source=request.source, + sink=request.sink, + headers=request.headers, + proxy=request.proxy, + nredirects=(request.nredirects or 0)+1, + create=request.create, + } + if not headers then + headers={} + end + if not headers.location then + headers.location=location + end + return result,code,headers,status +end +trequest=function(originalrequest) + local request=adjustrequest(originalrequest) + local connection=openhttp(request.host,request.port,request.create) + local headers=request.headers + connection:sendrequestline(request.method,request.uri) + connection:sendheaders(headers) + if request.source then + connection:sendbody(headers,request.source,request.step) + end + local code,status=connection:receivestatusline() + if not code then + connection:receive09body(status,request.sink,request.step) + return 1,200 + end + while code==100 do + headers=connection:receiveheaders() + code,status=connection:receivestatusline() + end + headers=connection:receiveheaders() + if shouldredirect(request,code,headers) and not request.source then + connection:close() + return tredirect(originalrequest,headers.location) + end + if shouldreceivebody(request,code) then + connection:receivebody(headers,request.sink,request.step) + end + connection:close() + return 1,code,headers,status +end +local function genericform(url,body) + local buffer={} + local request={ + url=url, + sink=sinktable(buffer), + target=buffer, + } + if body then + request.source=stringsource(body) + request.method="POST" + request.headers={ + ["content-length"]=#body, + ["content-type"]="application/x-www-form-urlencoded" + } + end + return request +end +http.genericform=genericform +srequest=function(url,body) + local request=genericform(url,body) + local _,code,headers,status=trequest(request) + return concat(request.target),code,headers,status +end +http.request=protectsocket(function(request,body) + if type(request)=="string" then + return srequest(request,body) + else + return trequest(request) + end +end) +package.loaded["socket.http"]=http + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ftp"] = package.loaded["util-soc-imp-ftp"] or true + +-- original size: 10357, stripped down to: 8548 + + +local setmetatable,type,next=setmetatable,type,next +local find,format,gsub,match=string.find,string.format,string.gsub,string.match +local concat=table.concat +local mod=math.mod +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local tp=socket.tp or require("socket.tp") +local ltn12=ltn12 or require("ltn12") +local tcpsocket=socket.tcp +local trysocket=socket.try +local skipsocket=socket.skip +local sinksocket=socket.sink +local selectsocket=socket.select +local bindsocket=socket.bind +local newtrysocket=socket.newtry +local sourcesocket=socket.source +local protectsocket=socket.protect +local parseurl=url.parse +local unescapeurl=url.unescape +local pumpall=ltn12.pump.all +local pumpstep=ltn12.pump.step +local sourcestring=ltn12.source.string +local sinktable=ltn12.sink.table +local ftp={ + TIMEOUT=60, + USER="ftp", + PASSWORD="anonymous@anonymous.org", +} +socket.ftp=ftp +local PORT=21 +local methods={} +local mt={ __index=methods } +function ftp.open(server,port,create) + local tp=trysocket(tp.connect(server,port or PORT,ftp.TIMEOUT,create)) + local f=setmetatable({ tp=tp },metat) + f.try=newtrysocket(function() f:close() end) + return f +end +function methods.portconnect(self) + local try=self.try + local server=self.server + try(server:settimeout(ftp.TIMEOUT)) + self.data=try(server:accept()) + try(self.data:settimeout(ftp.TIMEOUT)) +end +function methods.pasvconnect(self) + local try=self.try + self.data=try(tcpsocket()) + self(self.data:settimeout(ftp.TIMEOUT)) + self(self.data:connect(self.pasvt.address,self.pasvt.port)) +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("user",user or ftp.USER)) + local code,reply=try(tp:check{"2..",331}) + if code==331 then + try(tp:command("pass",password or ftp.PASSWORD)) + try(tp:check("2..")) + end + return 1 +end +function methods.pasv(self) + local try=self.try + local tp=self.tp + try(tp:command("pasv")) + local code,reply=try(self.tp:check("2..")) + local pattern="(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a,b,c,d,p1,p2=skipsocket(2,find(reply,pattern)) + try(a and b and c and d and p1 and p2,reply) + local address=format("%d.%d.%d.%d",a,b,c,d) + local port=p1*256+p2 + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if server then + server:close() + self.server=nil + end + return address,port +end +function methods.epsv(self) + local try=self.try + local tp=self.tp + try(tp:command("epsv")) + local code,reply=try(tp:check("229")) + local pattern="%((.)(.-)%1(.-)%1(.-)%1%)" + local d,prt,address,port=match(reply,pattern) + try(port,"invalid epsv response") + local address=tp:getpeername() + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if self.server then + server:close() + self.server=nil + end + return address,port +end +function methods.port(self,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local pl=mod(port,256) + local ph=(port-pl)/256 + local arg=gsub(format("%s,%d,%d",address,ph,pl),"%.",",") + try(tp:command("port",arg)) + try(tp:check("2..")) + return 1 +end +function methods.eprt(self,family,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local arg=format("|%s|%s|%d|",family,address,port) + try(tp:command("eprt",arg)) + try(tp:check("2..")) + return 1 +end +function methods.send(self,sendt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then + self:pasvconnect() + end + local argument=sendt.argument or unescapeurl(gsub(sendt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=sendt.command or "stor" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"2..","1.."}) + if not self.pasvt then + self:portconnect() + end + local step=sendt.step or pumpstep + local readt={ tp } + local checkstep=function(src,snk) + local readyt=selectsocket(readt,nil,0) + if readyt[tp] then + code=try(tp:check("2..")) + end + return step(src,snk) + end + local sink=sinksocket("close-when-done",self.data) + try(pumpall(sendt.source,sink,checkstep)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + local sent=skipsocket(1,self.data:getstats()) + self.data=nil + return sent +end +function methods.receive(self,recvt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument=recvt.argument or unescapeurl(gsub(recvt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=recvt.command or "retr" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"1..","2.."}) + if code>=200 and code<=299 then + recvt.sink(reply) + return 1 + end + if not self.pasvt then + self:portconnect() + end + local source=sourcesocket("until-closed",self.data) + local step=recvt.step or pumpstep + try(pumpall(source,recvt.sink,step)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + self.data=nil + return 1 +end +function methods.cwd(self,dir) + local try=self.try + local tp=self.tp + try(tp:command("cwd",dir)) + try(tp:check(250)) + return 1 +end +function methods.type(self,typ) + local try=self.try + local tp=self.tp + try(tp:command("type",typ)) + try(tp:check(200)) + return 1 +end +function methods.greet(self) + local try=self.try + local tp=self.tp + local code=try(tp:check{"1..","2.."}) + if find(code,"1..") then + try(tp:check("2..")) + end + return 1 +end +function methods.quit(self) + local try=self.try + try(self.tp:command("quit")) + try(self.tp:check("2..")) + return 1 +end +function methods.close(self) + local data=self.data + if data then + data:close() + end + local server=self.server + if server then + server:close() + end + local tp=self.tp + if tp then + tp:close() + end +end +local function override(t) + if t.url then + local u=parseurl(t.url) + for k,v in next,t do + u[k]=v + end + return u + else + return t + end +end +local function tput(putt) + putt=override(putt) + local host=putt.host + trysocket(host,"missing hostname") + local f=ftp.open(host,putt.port,putt.create) + f:greet() + f:login(putt.user,putt.password) + local typ=putt.type + if typ then + f:type(typ) + end + f:epsv() + local sent=f:send(putt) + f:quit() + f:close() + return sent +end +local default={ + path="/", + scheme="ftp", +} +local function genericform(u) + local t=trysocket(parseurl(u,default)) + trysocket(t.scheme=="ftp","wrong scheme '"..t.scheme.."'") + trysocket(t.host,"missing hostname") + local pat="^type=(.)$" + if t.params then + local typ=skipsocket(2,find(t.params,pat)) + t.type=typ + trysocket(typ=="a" or typ=="i","invalid type '"..typ.."'") + end + return t +end +ftp.genericform=genericform +local function sput(u,body) + local putt=genericform(u) + putt.source=sourcestring(body) + return tput(putt) +end +ftp.put=protectsocket(function(putt,body) + if type(putt)=="string" then + return sput(putt,body) + else + return tput(putt) + end +end) +local function tget(gett) + gett=override(gett) + local host=gett.host + trysocket(host,"missing hostname") + local f=ftp.open(host,gett.port,gett.create) + f:greet() + f:login(gett.user,gett.password) + if gett.type then + f:type(gett.type) + end + f:epsv() + f:receive(gett) + f:quit() + return f:close() +end +local function sget(u) + local gett=genericform(u) + local t={} + gett.sink=sinktable(t) + tget(gett) + return concat(t) +end +ftp.command=protectsocket(function(cmdt) + cmdt=override(cmdt) + local command=cmdt.command + local argument=cmdt.argument + local check=cmdt.check + local host=cmdt.host + trysocket(host,"missing hostname") + trysocket(command,"missing command") + local f=ftp.open(host,cmdt.port,cmdt.create) + local try=f.try + local tp=f.tp + f:greet() + f:login(cmdt.user,cmdt.password) + if type(command)=="table" then + local argument=argument or {} + for i=1,#command do + local cmd=command[i] + try(tp:command(cmd,argument[i])) + if check and check[i] then + try(tp:check(check[i])) + end + end + else + try(tp:command(command,argument)) + if check then + try(tp:check(check)) + end + end + f:quit() + return f:close() +end) +ftp.get=protectsocket(function(gett) + if type(gett)=="string" then + return sget(gett) + else + return tget(gett) + end +end) +package.loaded["socket.ftp"]=ftp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-smtp"] = package.loaded["util-soc-imp-smtp"] or true + +-- original size: 7018, stripped down to: 5883 + + +local type,setmetatable,next=type,setmetatable,next +local find,lower,format=string.find,string.lower,string.format +local osdate,osgetenv=os.date,os.getenv +local random=math.random +local socket=socket or require("socket") +local headers=socket.headers or require("socket.headers") +local ltn12=ltn12 or require("ltn12") +local tp=socket.tp or require("socket.tp") +local mime=mime or require("mime") +local mimeb64=mime.b64 +local mimestuff=mime.stuff +local skipsocket=socket.skip +local trysocket=socket.try +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local normalizeheaders=headers.normalize +local lowerheaders=headers.lower +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.resume +local smtp={ + TIMEOUT=60, + SERVER="localhost", + PORT=25, + DOMAIN=osgetenv("SERVER_NAME") or "localhost", + ZONE="-0000", +} +socket.smtp=smtp +local methods={} +local mt={ __index=methods } +function methods.greet(self,domain) + local try=self.try + local tp=self.tp + try(tp:check("2..")) + try(tp:command("EHLO",domain or _M.DOMAIN)) + return skipsocket(1,try(tp:check("2.."))) +end +function methods.mail(self,from) + local try=self.try + local tp=self.tp + try(tp:command("MAIL","FROM:"..from)) + return try(tp:check("2..")) +end +function methods.rcpt(self,to) + local try=self.try + local tp=self.tp + try(tp:command("RCPT","TO:"..to)) + return try(tp:check("2..")) +end +function methods.data(self,src,step) + local try=self.try + local tp=self.tp + try(tp:command("DATA")) + try(tp:check("3..")) + try(tp:source(src,step)) + try(tp:send("\r\n.\r\n")) + return try(tp:check("2..")) +end +function methods.quit(self) + local try=self.try + local tp=self.tp + try(tp:command("QUIT")) + return try(tp:check("2..")) +end +function methods.close(self) + return self.tp:close() +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("AUTH","LOGIN")) + try(tp:check("3..")) + try(tp:send(mimeb64(user).."\r\n")) + try(tp:check("3..")) + try(tp:send(mimeb64(password).."\r\n")) + return try(tp:check("2..")) +end +function methods.plain(self,user,password) + local try=self.try + local tp=self.tp + local auth="PLAIN "..mimeb64("\0"..user.."\0"..password) + try(tp:command("AUTH",auth)) + return try(tp:check("2..")) +end +function methods.auth(self,user,password,ext) + if not user or not password then + return 1 + end + local try=self.try + if find(ext,"AUTH[^\n]+LOGIN") then + return self:login(user,password) + elseif find(ext,"AUTH[^\n]+PLAIN") then + return self:plain(user,password) + else + try(nil,"authentication not supported") + end +end +function methods.send(self,mail) + self:mail(mail.from) + local receipt=mail.rcpt + if type(receipt)=="table" then + for i=1,#receipt do + self:rcpt(receipt[i]) + end + elseif receipt then + self:rcpt(receipt) + end + self:data(ltn12.source.chain(mail.source,mimestuff()),mail.step) +end +local function opensmtp(self,server,port,create) + if not server or server=="" then + server=smtp.SERVER + end + if not port or port=="" then + port=smtp.PORT + end + local s={ + tp=trysocket(tp.connect(server,port,smtp.TIMEOUT,create)), + try=newtrysocket(function() + s:close() + end), + } + setmetatable(s,mt) + return s +end +smtp.open=opensmtp +local nofboundaries=0 +local function newboundary() + nofboundaries=nofboundaries+1 + return format('%s%05d==%05u',osdate('%d%m%Y%H%M%S'),random(0,99999),nofboundaries) +end +local send_message +local function send_headers(headers) + yieldcoroutine(normalizeheaders(headers)) +end +local function send_multipart(message) + local boundary=newboundary() + local headers=lowerheaders(message.headers) + local body=message.body + local preamble=body.preamble + local epilogue=body.epilogue + local content=headers['content-type'] or 'multipart/mixed' + headers['content-type']=content..'; boundary="'..boundary..'"' + send_headers(headers) + if preamble then + yieldcoroutine(preamble) + yieldcoroutine("\r\n") + end + for i=1,#body do + yieldcoroutine("\r\n--"..boundary.."\r\n") + send_message(body[i]) + end + yieldcoroutine("\r\n--"..boundary.."--\r\n\r\n") + if epilogue then + yieldcoroutine(epilogue) + yieldcoroutine("\r\n") + end +end +local default_content_type='text/plain; charset="UTF-8"' +local function send_source(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + local getchunk=message.body + while true do + local chunk,err=getchunk() + if err then + yieldcoroutine(nil,err) + elseif chunk then + yieldcoroutine(chunk) + else + break + end + end +end +local function send_string(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + yieldcoroutine(message.body) +end +function send_message(message) + local body=message.body + if type(body)=="table" then + send_multipart(message) + elseif type(body)=="function" then + send_source(message) + else + send_string(message) + end +end +local function adjust_headers(message) + local headers=lowerheaders(message.headers) + if not headers["date"] then + headers["date"]=osdate("!%a, %d %b %Y %H:%M:%S ")..(message.zone or smtp.ZONE) + end + if not headers["x-mailer"] then + headers["x-mailer"]=socket._VERSION + end + headers["mime-version"]="1.0" + return headers +end +function smtp.message(message) + message.headers=adjust_headers(message) + local action=createcoroutine(function() + send_message(message) + end) + return function() + local ret,a,b=resumecoroutine(action) + if ret then + return a,b + else + return nil,a + end + end +end +smtp.send=protectsocket(function(mail) + local snd=opensmtp(smtp,mail.server,mail.port,mail.create) + local ext=snd:greet(mail.domain) + snd:auth(mail.user,mail.password,ext) + snd:send(mail) + snd:quit() + return snd:close() +end) +package.loaded["socket.smtp"]=smtp end -- of closure @@ -8945,14 +12336,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-set"] = package.loaded["trac-set"] or true --- original size: 13044, stripped down to: 9231 +-- original size: 13340, stripped down to: 8826 if not modules then modules={} end modules ['trac-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber=type,next,tostring,tonumber local concat,sortedhash=table.concat,table.sortedhash @@ -8967,305 +12358,318 @@ utilities.setters=setters local data={} local trace_initialize=false function setters.initialize(filename,name,values) - local setter=data[name] - if setter then - frozen=true - local data=setter.data - if data then - for key,newvalue in sortedhash(values) do - local newvalue=is_boolean(newvalue,newvalue,true) - local functions=data[key] - if functions then - local oldvalue=functions.value - if functions.frozen then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) - end - elseif #functions>0 and not oldvalue then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) - end - for i=1,#functions do - functions[i](newvalue) - end - functions.value=newvalue - functions.frozen=functions.frozen or frozen - else - if trace_initialize then - setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) - end - end - else - functions={ default=newvalue,frozen=frozen } - data[key]=functions - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) - end - end + local setter=data[name] + if setter then + frozen=true + local data=setter.data + if data then + for key,newvalue in sortedhash(values) do + local newvalue=is_boolean(newvalue,newvalue,true) + local functions=data[key] + if functions then + local oldvalue=functions.value + if functions.frozen then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) + end + elseif #functions>0 and not oldvalue then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) + end + for i=1,#functions do + functions[i](newvalue) + end + functions.value=newvalue + functions.frozen=functions.frozen or frozen + else + if trace_initialize then + setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) end - return true + end + else + functions={ default=newvalue,frozen=frozen } + data[key]=functions + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) + end end + end + return true end + end end local function set(t,what,newvalue) - local data=t.data - if not data.frozen then - local done=t.done - if type(what)=="string" then - what=settings_to_hash(what) - end - if type(what)~="table" then - return - end - if not done then - done={} - t.done=done - end - for w,value in sortedhash(what) do - if value=="" then - value=newvalue - elseif not value then - value=false - else - value=is_boolean(value,value,true) - end - w=topattern(w,true,true) - for name,functions in sortedhash(data) do - if done[name] then - elseif find(name,w) then - done[name]=true - for i=1,#functions do - functions[i](value) - end - functions.value=value - end - end + local data=t.data + if not data.frozen then + local done=t.done + if type(what)=="string" then + what=settings_to_hash(what) + end + if type(what)~="table" then + return + end + if not done then + done={} + t.done=done + end + for w,value in sortedhash(what) do + if value=="" then + value=newvalue + elseif not value then + value=false + else + value=is_boolean(value,value,true) + end + w=topattern(w,true,true) + for name,functions in sortedhash(data) do + if done[name] then + elseif find(name,w) then + done[name]=true + for i=1,#functions do + functions[i](value) + end + functions.value=value end + end end + end end local function reset(t) - local data=t.data - if not data.frozen then - for name,functions in sortedthash(data) do - for i=1,#functions do - functions[i](false) - end - functions.value=false - end + local data=t.data + if not data.frozen then + for name,functions in sortedthash(data) do + for i=1,#functions do + functions[i](false) + end + functions.value=false end + end end local function enable(t,what) - set(t,what,true) + set(t,what,true) end local function disable(t,what) - local data=t.data - if not what or what=="" then - t.done={} - reset(t) - else - set(t,what,false) - end + local data=t.data + if not what or what=="" then + t.done={} + reset(t) + else + set(t,what,false) + end end function setters.register(t,what,...) - local data=t.data - what=lower(what) - local functions=data[what] - if not functions then - functions={} - data[what]=functions - if trace_initialize then - t.report("defining %a",what) - end - end - local default=functions.default - for i=1,select("#",...) do - local fnc=select(i,...) - local typ=type(fnc) - if typ=="string" then - if trace_initialize then - t.report("coupling %a to %a",what,fnc) - end - local s=fnc - fnc=function(value) set(t,s,value) end - elseif typ~="function" then - fnc=nil - end - if fnc then - functions[#functions+1]=fnc - local value=functions.value or default - if value~=nil then - fnc(value) - functions.value=value - end - end + local data=t.data + what=lower(what) + local functions=data[what] + if not functions then + functions={} + data[what]=functions + if trace_initialize then + t.report("defining %a",what) + end + end + local default=functions.default + for i=1,select("#",...) do + local fnc=select(i,...) + local typ=type(fnc) + if typ=="string" then + if trace_initialize then + t.report("coupling %a to %a",what,fnc) + end + local s=fnc + fnc=function(value) set(t,s,value) end + elseif typ~="function" then + fnc=nil + end + if fnc then + functions[#functions+1]=fnc + local value=functions.value or default + if value~=nil then + fnc(value) + functions.value=value + end end - return false + end + return false end function setters.enable(t,what) - local e=t.enable - t.enable,t.done=enable,{} - enable(t,what) - t.enable,t.done=e,{} + local e=t.enable + t.enable,t.done=enable,{} + enable(t,what) + t.enable,t.done=e,{} end function setters.disable(t,what) - local e=t.disable - t.disable,t.done=disable,{} - disable(t,what) - t.disable,t.done=e,{} + local e=t.disable + t.disable,t.done=disable,{} + disable(t,what) + t.disable,t.done=e,{} end function setters.reset(t) - t.done={} - reset(t) + t.done={} + reset(t) end function setters.list(t) - local list=table.sortedkeys(t.data) - local user,system={},{} - for l=1,#list do - local what=list[l] - if find(what,"^%*") then - system[#system+1]=what - else - user[#user+1]=what - end + local list=table.sortedkeys(t.data) + local user,system={},{} + for l=1,#list do + local what=list[l] + if find(what,"^%*") then + system[#system+1]=what + else + user[#user+1]=what end - return user,system + end + return user,system end function setters.show(t) - local list=setters.list(t) - t.report() - for k=1,#list do - local name=list[k] - local functions=t.data[name] - if functions then - local value=functions.value - local default=functions.default - local modules=#functions - if default==nil then - default="unset" - elseif type(default)=="table" then - default=concat(default,"|") - else - default=tostring(default) - end - if value==nil then - value="unset" - elseif type(value)=="table" then - value=concat(value,"|") - else - value=tostring(value) - end - t.report(name) - t.report(" modules : %i",modules) - t.report(" default : %s",default) - t.report(" value : %s",value) - t.report() - end + local list=setters.list(t) + t.report() + for k=1,#list do + local name=list[k] + local functions=t.data[name] + if functions then + local value=functions.value + local default=functions.default + local modules=#functions + if default==nil then + default="unset" + elseif type(default)=="table" then + default=concat(default,"|") + else + default=tostring(default) + end + if value==nil then + value="unset" + elseif type(value)=="table" then + value=concat(value,"|") + else + value=tostring(value) + end + t.report(name) + t.report(" modules : %i",modules) + t.report(" default : %s",default) + t.report(" value : %s",value) + t.report() end + end end local enable,disable,register,list,show=setters.enable,setters.disable,setters.register,setters.list,setters.show function setters.report(setter,...) - print(format("%-15s : %s\n",setter.name,format(...))) + print(format("%-15s : %s\n",setter.name,format(...))) end local function default(setter,name) - local d=setter.data[name] - return d and d.default + local d=setter.data[name] + return d and d.default end local function value(setter,name) - local d=setter.data[name] - return d and (d.value or d.default) + local d=setter.data[name] + return d and (d.value or d.default) end function setters.new(name) - local setter - setter={ - data=allocate(), - name=name, - report=function(...) setters.report (setter,...) end, - enable=function(...) enable (setter,...) end, - disable=function(...) disable (setter,...) end, - reset=function(...) reset (setter,...) end, - register=function(...) register(setter,...) end, - list=function(...) list (setter,...) end, - show=function(...) show (setter,...) end, - default=function(...) return default (setter,...) end, - value=function(...) return value (setter,...) end, - } - data[name]=setter - return setter + local setter + setter={ + data=allocate(), + name=name, + report=function(...) setters.report (setter,...) end, + enable=function(...) enable (setter,...) end, + disable=function(...) disable (setter,...) end, + reset=function(...) reset (setter,...) end, + register=function(...) register(setter,...) end, + list=function(...) list (setter,...) end, + show=function(...) show (setter,...) end, + default=function(...) return default (setter,...) end, + value=function(...) return value (setter,...) end, + } + data[name]=setter + return setter end trackers=setters.new("trackers") directives=setters.new("directives") experiments=setters.new("experiments") -local t_enable,t_disable=trackers .enable,trackers .disable +local t_enable,t_disable=trackers .enable,trackers .disable local d_enable,d_disable=directives .enable,directives .disable local e_enable,e_disable=experiments.enable,experiments.disable -local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) -local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) +local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) +local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) function directives.enable(...) - if trace_directives then - directives.report("enabling: % t",{...}) - end - d_enable(...) + if trace_directives then + directives.report("enabling: % t",{...}) + end + d_enable(...) end function directives.disable(...) - if trace_directives then - directives.report("disabling: % t",{...}) - end - d_disable(...) + if trace_directives then + directives.report("disabling: % t",{...}) + end + d_disable(...) end function experiments.enable(...) - if trace_experiments then - experiments.report("enabling: % t",{...}) - end - e_enable(...) + if trace_experiments then + experiments.report("enabling: % t",{...}) + end + e_enable(...) end function experiments.disable(...) - if trace_experiments then - experiments.report("disabling: % t",{...}) - end - e_disable(...) + if trace_experiments then + experiments.report("disabling: % t",{...}) + end + e_disable(...) end directives.register("system.nostatistics",function(v) - if statistics then - statistics.enable=not v - else - end + if statistics then + statistics.enable=not v + else + end end) directives.register("system.nolibraries",function(v) - if libraries then - libraries=nil - else - end + if libraries then + libraries=nil + else + end end) if environment then - local engineflags=environment.engineflags - if engineflags then - local list=engineflags["c:trackers"] or engineflags["trackers"] - if type(list)=="string" then - setters.initialize("commandline flags","trackers",settings_to_hash(list)) - end - local list=engineflags["c:directives"] or engineflags["directives"] - if type(list)=="string" then - setters.initialize("commandline flags","directives",settings_to_hash(list)) - end + local engineflags=environment.engineflags + if engineflags then + local list=engineflags["c:trackers"] or engineflags["trackers"] + if type(list)=="string" then + setters.initialize("commandline flags","trackers",settings_to_hash(list)) end -end -if texconfig then - local function set(k,v) - v=tonumber(v) - if v then - texconfig[k]=v - end + local list=engineflags["c:directives"] or engineflags["directives"] + if type(list)=="string" then + setters.initialize("commandline flags","directives",settings_to_hash(list)) end - directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) - directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) - directives.register("luatex.nestsize",function(v) set("nest_size",v) end) - directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) - directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) - directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) - directives.register("luatex.paramsize",function(v) set("param_size",v) end) - directives.register("luatex.savesize",function(v) set("save_size",v) end) - directives.register("luatex.stacksize",function(v) set("stack_size",v) end) + end end +if texconfig then + local function set(k,v) + v=tonumber(v) + if v then + texconfig[k]=v + end + end + directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) + directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) + directives.register("luatex.nestsize",function(v) set("nest_size",v) end) + directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) + directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) + directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) + directives.register("luatex.paramsize",function(v) set("param_size",v) end) + directives.register("luatex.savesize",function(v) set("save_size",v) end) + directives.register("luatex.stacksize",function(v) set("stack_size",v) end) +end +local data=table.setmetatableindex("table") +updaters={ + register=function(what,f) + local d=data[what] + d[#d+1]=f + end, + apply=function(what,...) + local d=data[what] + for i=1,#d do + d[i](...) + end + end, +} end -- of closure @@ -9274,14 +12678,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-log"] = package.loaded["trac-log"] or true --- original size: 32922, stripped down to: 23011 +-- original size: 32608, stripped down to: 20925 if not modules then modules={} end modules ['trac-log']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,select,print=next,type,select,print local format,gmatch,find=string.format,string.gmatch,string.find @@ -9292,7 +12696,7 @@ local datetime=os.date local openfile=io.open local runningtex=tex and (tex.jobname or tex.formatname) local write_nl=runningtex and texio and texio.write_nl or print -local write=runningtex and texio and texio.write or io.write +local write=runningtex and texio and texio.write or io.write local setmetatableindex=table.setmetatableindex local formatters=string.formatters local settings_to_hash=utilities.parsers.settings_to_hash @@ -9308,404 +12712,404 @@ webpage : http://www.pragma-ade.nl / http://tex.aanhet.net wiki : http://contextgarden.net ]] formatters.add ( - formatters,"unichr", - [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] + formatters,"unichr", + [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] ) formatters.add ( - formatters,"chruni", - [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] + formatters,"chruni", + [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] ) 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,setlogfile,settimedlog,setprocessor,setformatters,newline if runningtex then - if texio.setescape then - texio.setescape(0) - end - if arg then - for k,v in next,arg do - if v=="--ansi" or v=="--c:ansi" then - variant="ansi" - break - end - end - end - local function useluawrites() - local texio_write_nl=texio.write_nl - local texio_write=texio.write - local io_write=io.write - write_nl=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write_nl("log",...) - texio_write_nl("term","") - io_write(...) - elseif target=="log" then - texio_write_nl("log",...) - elseif target=="term" then - texio_write_nl("term","") - io_write(...) - elseif type(target)=="number" then - texio_write_nl(target,...) - elseif target~="none" then - texio_write_nl("log",target,...) - texio_write_nl("term","") - io_write(target,...) - end - end - write=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write("log",...) - io_write(...) - elseif target=="log" then - texio_write("log",...) - elseif target=="term" then - io_write(...) - elseif type(target)=="number" then - texio_write(target,...) - elseif target~="none" then - texio_write("log",target,...) - io_write(target,...) - end - end - texio.write=write - texio.write_nl=write_nl - useluawrites=ignore - end - local whereto="both" - local target=nil - local targets=nil - local formats=table.setmetatableindex("self") - local translations=table.setmetatableindex("self") - local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes - local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s > %s\n"], - report_nop=formatters["%-15s >\n"], - direct_yes=formatters["%-15s > %s"], - direct_nop=formatters["%-15s >"], - subreport_yes=formatters["%-15s > %s > %s\n"], - subreport_nop=formatters["%-15s > %s >\n"], - subdirect_yes=formatters["%-15s > %s > %s"], - subdirect_nop=formatters["%-15s > %s >"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - targets={ - logfile="log", - log="log", - file="log", - console="term", - terminal="term", - both="term and log", - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], - report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], - direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], - direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], - subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], - subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], - subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], - subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], - status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], - }, - targets={ - logfile="none", - log="none", - file="none", - console="term", - terminal="term", - both="term", - }, - } - } - logs.flush=io.flush - writer=function(...) - write_nl(target,...) - end - newline=function() - write_nl(target,"\n") - end - report=function(a,b,c,...) - if c~=nil then - write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,report_yes(translations[a],formats[b])) - elseif a then - write_nl(target,report_nop(translations[a])) - else - write_nl(target,"\n") - end - end - direct=function(a,b,c,...) - if c~=nil then - return direct_yes(translations[a],formatters[formats[b]](c,...)) - elseif b then - return direct_yes(translations[a],formats[b]) - elseif a then - return direct_nop(translations[a]) - else - return "" - end - end - subreport=function(a,s,b,c,...) - if c~=nil then - write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) - elseif a then - write_nl(target,subreport_nop(translations[a],translations[s])) - else - write_nl(target,"\n") - end - end - subdirect=function(a,s,b,c,...) - if c~=nil then - return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) - elseif b then - return subdirect_yes(translations[a],translations[s],formats[b]) - elseif a then - return subdirect_nop(translations[a],translations[s]) - else - return "" - end + if texio.setescape then + texio.setescape(0) + end + if arg then + for k,v in next,arg do + if v=="--ansi" or v=="--c:ansi" then + variant="ansi" + break + end end - status=function(a,b,c,...) - if c~=nil then - write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,status_yes(translations[a],formats[b])) - elseif a then - write_nl(target,status_nop(translations[a])) - else - write_nl(target,"\n") - end + end + local function useluawrites() + local texio_write_nl=texio.write_nl + local texio_write=texio.write + local io_write=io.write + write_nl=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write_nl("log",...) + texio_write_nl("term","") + io_write(...) + elseif target=="log" then + texio_write_nl("log",...) + elseif target=="term" then + texio_write_nl("term","") + io_write(...) + elseif type(target)=="number" then + texio_write_nl(target,...) + elseif target~="none" then + texio_write_nl("log",target,...) + texio_write_nl("term","") + io_write(target,...) + end end - settarget=function(askedwhereto) - whereto=askedwhereto or whereto or "both" - target=targets[whereto] - if not target then - whereto="both" - target=targets[whereto] - end - if target=="term" or target=="term and log" then - logs.flush=io.flush - else - logs.flush=ignore - end + write=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write("log",...) + io_write(...) + elseif target=="log" then + texio_write("log",...) + elseif target=="term" then + io_write(...) + elseif type(target)=="number" then + texio_write(target,...) + elseif target~="none" then + texio_write("log",target,...) + io_write(target,...) + end end - local stack={} - pushtarget=function(newtarget) - insert(stack,target) - settarget(newtarget) + texio.write=write + texio.write_nl=write_nl + useluawrites=ignore + end + local whereto="both" + local target=nil + local targets=nil + local formats=table.setmetatableindex("self") + local translations=table.setmetatableindex("self") + local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes + local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s > %s\n"], + report_nop=formatters["%-15s >\n"], + direct_yes=formatters["%-15s > %s"], + direct_nop=formatters["%-15s >"], + subreport_yes=formatters["%-15s > %s > %s\n"], + subreport_nop=formatters["%-15s > %s >\n"], + subdirect_yes=formatters["%-15s > %s > %s"], + subdirect_nop=formatters["%-15s > %s >"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + targets={ + logfile="log", + log="log", + file="log", + console="term", + terminal="term", + both="term and log", + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], + report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], + direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], + direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], + subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], + subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], + subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], + subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], + status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], + }, + targets={ + logfile="none", + log="none", + file="none", + console="term", + terminal="term", + both="term", + }, + } + } + logs.flush=io.flush + writer=function(...) + write_nl(target,...) + end + newline=function() + write_nl(target,"\n") + end + report=function(a,b,c,...) + if c~=nil then + write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,report_yes(translations[a],formats[b])) + elseif a then + write_nl(target,report_nop(translations[a])) + else + write_nl(target,"\n") end - poptarget=function() - if #stack>0 then - settarget(remove(stack)) - end + end + direct=function(a,b,c,...) + if c~=nil then + return direct_yes(translations[a],formatters[formats[b]](c,...)) + elseif b then + return direct_yes(translations[a],formats[b]) + elseif a then + return direct_nop(translations[a]) + else + return "" end - setformats=function(f) - formats=f + end + subreport=function(a,s,b,c,...) + if c~=nil then + write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) + elseif a then + write_nl(target,subreport_nop(translations[a],translations[s])) + else + write_nl(target,"\n") end - settranslations=function(t) - translations=t + end + subdirect=function(a,s,b,c,...) + if c~=nil then + return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) + elseif b then + return subdirect_yes(translations[a],translations[s],formats[b]) + elseif a then + return subdirect_nop(translations[a],translations[s]) + else + return "" end - setprocessor=function(f) - local writeline=write_nl - write_nl=function(target,...) - writeline(target,f(...)) - end + end + status=function(a,b,c,...) + if c~=nil then + write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,status_yes(translations[a],formats[b])) + elseif a then + write_nl(target,status_nop(translations[a])) + else + write_nl(target,"\n") + end + end + settarget=function(askedwhereto) + whereto=askedwhereto or whereto or "both" + target=targets[whereto] + if not target then + whereto="both" + target=targets[whereto] + end + if target=="term" or target=="term and log" then + logs.flush=io.flush + else + logs.flush=ignore + end + end + local stack={} + pushtarget=function(newtarget) + insert(stack,target) + settarget(newtarget) + end + poptarget=function() + if #stack>0 then + settarget(remove(stack)) + end + end + setformats=function(f) + formats=f + end + settranslations=function(t) + translations=t + end + setprocessor=function(f) + local writeline=write_nl + write_nl=function(target,...) + writeline(target,f(...)) + end + end + setformatters=function(specification) + local t=nil + local f=nil + local d=variants.default + if not specification then + elseif type(specification)=="table" then + t=specification.targets + f=specification.formats or specification + else + local v=variants[specification] + if v then + t=v.targets + f=v.formats + variant=specification + end end - setformatters=function(specification) - local t=nil - local f=nil - local d=variants.default - if not specification then - elseif type(specification)=="table" then - t=specification.targets - f=specification.formats or specification - else - local v=variants[specification] - if v then - t=v.targets - f=v.formats - variant=specification - end - end - targets=t or d.targets - target=targets[whereto] or target - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - direct_yes=f.direct_yes - direct_nop=f.direct_nop - subdirect_yes=f.subdirect_yes - subdirect_nop=f.subdirect_nop - status_yes=f.status_yes - status_nop=f.status_nop - if variant=="ansi" then - useluawrites() - end - settarget(whereto) - end - setformatters(variant) - setlogfile=ignore - settimedlog=ignore + targets=t or d.targets + target=targets[whereto] or target + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + direct_yes=f.direct_yes + direct_nop=f.direct_nop + subdirect_yes=f.subdirect_yes + subdirect_nop=f.subdirect_nop + status_yes=f.status_yes + status_nop=f.status_nop + if variant=="ansi" then + useluawrites() + end + settarget(whereto) + end + setformatters(variant) + setlogfile=ignore + settimedlog=ignore else - local report_yes,subreport_yes,status_yes - local report_nop,subreport_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s | %s"], - report_nop=formatters["%-15s |"], - subreport_yes=formatters["%-15s | %s | %s"], - subreport_nop=formatters["%-15s | %s |"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], - report_nop=formatters["[0;32m%-15s [0;1m|[0m"], - subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], - subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], - status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], - }, - }, - } - logs.flush=ignore - writer=function(s) - write_nl(s) - end - newline=function() - write_nl("\n") + local report_yes,subreport_yes,status_yes + local report_nop,subreport_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s | %s"], + report_nop=formatters["%-15s |"], + subreport_yes=formatters["%-15s | %s | %s"], + subreport_nop=formatters["%-15s | %s |"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], + report_nop=formatters["[0;32m%-15s [0;1m|[0m"], + subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], + subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], + status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], + }, + }, + } + logs.flush=ignore + writer=function(s) + write_nl(s) + end + newline=function() + write_nl("\n") + end + report=function(a,b,c,...) + if c then + write_nl(report_yes(a,formatters[b](c,...))) + elseif b then + write_nl(report_yes(a,b)) + elseif a then + write_nl(report_nop(a)) + else + write_nl("") end - report=function(a,b,c,...) - if c then - write_nl(report_yes(a,formatters[b](c,...))) - elseif b then - write_nl(report_yes(a,b)) - elseif a then - write_nl(report_nop(a)) - else - write_nl("") - end + end + subreport=function(a,sub,b,c,...) + if c then + write_nl(subreport_yes(a,sub,formatters[b](c,...))) + elseif b then + write_nl(subreport_yes(a,sub,b)) + elseif a then + write_nl(subreport_nop(a,sub)) + else + write_nl("") end - subreport=function(a,sub,b,c,...) - if c then - write_nl(subreport_yes(a,sub,formatters[b](c,...))) - elseif b then - write_nl(subreport_yes(a,sub,b)) - elseif a then - write_nl(subreport_nop(a,sub)) - else - write_nl("") + end + status=function(a,b,c,...) + if c then + write_nl(status_yes(a,formatters[b](c,...))) + elseif b then + write_nl(status_yes(a,b)) + elseif a then + write_nl(status_nop(a)) + else + write_nl("\n") + end + end + direct=ignore + subdirect=ignore + settarget=ignore + pushtarget=ignore + poptarget=ignore + setformats=ignore + settranslations=ignore + setprocessor=function(f) + local writeline=write_nl + write_nl=function(s) + writeline(f(s)) + end + end + setformatters=function(specification) + local f=nil + local d=variants.default + if specification then + if type(specification)=="table" then + f=specification.formats or specification + else + local v=variants[specification] + if v then + f=v.formats end + end end - status=function(a,b,c,...) - if c then - write_nl(status_yes(a,formatters[b](c,...))) - elseif b then - write_nl(status_yes(a,b)) - elseif a then - write_nl(status_nop(a)) - else - write_nl("\n") - end - end - direct=ignore - subdirect=ignore - settarget=ignore - pushtarget=ignore - poptarget=ignore - setformats=ignore - settranslations=ignore - setprocessor=function(f) - local writeline=write_nl + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + status_yes=f.status_yes + status_nop=f.status_nop + end + setformatters(variant) + 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(f(s)) - end - end - setformatters=function(specification) - local f=nil - local d=variants.default - if specification then - if type(specification)=="table" then - f=specification.formats or specification - else - local v=variants[specification] - if v then - f=v.formats - end - end - end - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - status_yes=f.status_yes - status_nop=f.status_nop - end - setformatters(variant) - 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 + writeline(s) + f:write(localtime()," | ",s,"\n") end - setlogfile=ignore - end - settimedlog=function() - local localtime=os.localtime - local writeline=write_nl + else write_nl=function(s) - writeline(localtime().." | "..s) + writeline(s) + local f=io.open(name,"ab") + f:write(localtime()," | ",s,"\n") + f:close() end - settimedlog=ignore + 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 @@ -9727,198 +13131,186 @@ local data={} local states=nil local force=false function logs.reporter(category,subcategory) - local logger=data[category] - if not logger then - local state=states==true - if not state and type(states)=="table" then - for c,_ in next,states do - if find(category,c) then - state=true - break - end - end + local logger=data[category] + if not logger then + local state=states==true + if not state and type(states)=="table" then + for c,_ in next,states do + if find(category,c) then + state=true + break end - logger={ - reporters={}, - state=state, - } - data[category]=logger - end - local reporter=logger.reporters[subcategory or "default"] - if not reporter then - if subcategory then - reporter=function(...) - if force or not logger.state then - subreport(category,subcategory,...) - end - end - logger.reporters[subcategory]=reporter - else - local tag=category - reporter=function(...) - if force or not logger.state then - report(category,...) - end - end - logger.reporters.default=reporter + end + end + logger={ + reporters={}, + state=state, + } + data[category]=logger + end + local reporter=logger.reporters[subcategory or "default"] + if not reporter then + if subcategory then + reporter=function(...) + if force or not logger.state then + subreport(category,subcategory,...) end + end + logger.reporters[subcategory]=reporter + else + local tag=category + reporter=function(...) + if force or not logger.state then + report(category,...) + end + end + logger.reporters.default=reporter end - return reporter + end + return reporter end logs.new=logs.reporter local ctxreport=logs.writer function logs.setmessenger(m) - ctxreport=m + ctxreport=m end function logs.messenger(category,subcategory) - if subcategory then - return function(...) - ctxreport(subdirect(category,subcategory,...)) - end - else - return function(...) - ctxreport(direct(category,...)) - end + if subcategory then + return function(...) + ctxreport(subdirect(category,subcategory,...)) end + else + return function(...) + ctxreport(direct(category,...)) + end + end end local function setblocked(category,value) - if category==true or category=="all" then - category,value="*",true - elseif category==false then - category,value="*",false - elseif value==nil then - value=true - end - if category=="*" then - states=value + if category==true or category=="all" then + category,value="*",true + elseif category==false then + category,value="*",false + elseif value==nil then + value=true + end + if category=="*" then + states=value + for k,v in next,data do + v.state=value + end + else + alllocked=false + states=settings_to_hash(category,type(states)=="table" and states or nil) + for c in next,states do + local v=data[c] + if v then + v.state=value + else + c=topattern(c,true,true) for k,v in next,data do + if find(k,c) then v.state=value + end end - else - alllocked=false - states=settings_to_hash(category,type(states)=="table" and states or nil) - for c in next,states do - local v=data[c] - if v then - v.state=value - else - c=topattern(c,true,true) - for k,v in next,data do - if find(k,c) then - v.state=value - end - end - end - end + end end + end end function logs.disable(category,value) - setblocked(category,value==nil and true or value) + setblocked(category,value==nil and true or value) end function logs.enable(category) - setblocked(category,false) + setblocked(category,false) end function logs.categories() - return sortedkeys(data) + return sortedkeys(data) end function logs.show() - local n,c,s,max=0,0,0,0 - for category,v in table.sortedpairs(data) do - n=n+1 - local state=v.state - local reporters=v.reporters - local nc=#category - if nc>c then - c=nc - end - for subcategory,_ in next,reporters do - local ns=#subcategory - if ns>c then - s=ns - end - local m=nc+ns - if m>max then - max=m - end - end - local subcategories=concat(sortedkeys(reporters),", ") - if state==true then - state="disabled" - elseif state==false then - state="enabled" - else - state="unknown" - end - report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + local n,c,s,max=0,0,0,0 + for category,v in table.sortedpairs(data) do + n=n+1 + local state=v.state + local reporters=v.reporters + local nc=#category + if nc>c then + c=nc + end + for subcategory,_ in next,reporters do + local ns=#subcategory + if ns>c then + s=ns + end + local m=nc+ns + if m>max then + max=m + end + end + local subcategories=concat(sortedkeys(reporters),", ") + if state==true then + state="disabled" + elseif state==false then + state="enabled" + else + state="unknown" end - report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) + report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + end + report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) end local delayed_reporters={} setmetatableindex(delayed_reporters,function(t,k) - local v=logs.reporter(k.name) - t[k]=v - return v + local v=logs.reporter(k.name) + t[k]=v + return v end) function utilities.setters.report(setter,...) - delayed_reporters[setter](...) + delayed_reporters[setter](...) end directives.register("logs.blocked",function(v) - setblocked(v,true) + setblocked(v,true) end) directives.register("logs.target",function(v) - settarget(v) + settarget(v) end) if tex then - local report=logs.reporter("pages") - local texgetcount=tex and tex.getcount - local real,user,sub - function logs.start_page_number() - real=texgetcount("realpageno") - user=texgetcount("userpageno") - sub=texgetcount("subpageno") - end - local timing=false - local starttime=nil - local lasttime=nil - trackers.register("pages.timing",function(v) - starttime=os.clock() - timing=true - end) - function logs.stop_page_number() - if timing then - local elapsed,average - local stoptime=os.clock() - if not lasttime or real<2 then - elapsed=stoptime - average=stoptime - starttime=stoptime - else - elapsed=stoptime-lasttime - average=(stoptime-starttime)/(real-1) - end - lasttime=stoptime - if real<=0 then - report("flushing page, time %0.04f / %0.04f",elapsed,average) - elseif user<=0 then - report("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average) - elseif sub<=0 then - report("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average) - else - report("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average) - end - else - if real<=0 then - report("flushing page") - elseif user<=0 then - report("flushing realpage %s",real) - elseif sub<=0 then - report("flushing realpage %s, userpage %s",real,user) - else - report("flushing realpage %s, userpage %s, subpage %s",real,user,sub) - end - end - logs.flush() + local report=logs.reporter("pages") + local texgetcount=tex and tex.getcount + local real,user,sub=0,0,0 + function logs.start_page_number() + real=texgetcount("realpageno") + user=texgetcount("userpageno") + sub=texgetcount("subpageno") + end + local timing=false + local lasttime=nil + trackers.register("pages.timing",function(v) + timing="" + end) + function logs.stop_page_number() + if timing then + local elapsed=statistics.currenttime(statistics) + local average,page + if not lasttime or real<2 then + average=elapsed + page=elapsed + else + average=elapsed/(real-1) + page=elapsed-lasttime + end + lasttime=elapsed + timing=formatters[", total %0.03f, page %0.03f, average %0.03f"](elapsed,page,average) end + if real<=0 then + report("flushing page%s",timing) + elseif user<=0 then + report("flushing realpage %s%s",real,timing) + elseif sub<=0 then + report("flushing realpage %s, userpage %s%s",real,user,timing) + else + report("flushing realpage %s, userpage %s, subpage %s%s",real,user,sub,timing) + end + logs.flush() + end end local nesting=0 local verbose=false @@ -9942,222 +13334,222 @@ logs.help=ignore local Carg,C,lpegmatch=lpeg.Carg,lpeg.C,lpeg.match local p_newline=lpeg.patterns.newline local linewise=( - Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline + Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline )^1 local function reportlines(t,str) - if str then - lpegmatch(linewise,str,1,t) - end + if str then + lpegmatch(linewise,str,1,t) + end end local function reportbanner(t) - local banner=t.banner - if banner then - t.report(banner) - t.report() - end + local banner=t.banner + if banner then + t.report(banner) + t.report() + end end local function reportversion(t) - local banner=t.banner - if banner then - t.report(banner) - end + local banner=t.banner + if banner then + t.report(banner) + end end local function reporthelp(t,...) - local helpinfo=t.helpinfo - if type(helpinfo)=="string" then - reportlines(t,helpinfo) - elseif type(helpinfo)=="table" then - for i=1,select("#",...) do - reportlines(t,t.helpinfo[select(i,...)]) - if i<n then - t.report() - end - end + local helpinfo=t.helpinfo + if type(helpinfo)=="string" then + reportlines(t,helpinfo) + elseif type(helpinfo)=="table" then + for i=1,select("#",...) do + reportlines(t,t.helpinfo[select(i,...)]) + if i<n then + t.report() + end end + end end local function reportinfo(t) - t.report() - reportlines(t,t.moreinfo) + t.report() + reportlines(t,t.moreinfo) end local function reportexport(t,method) - report(t.helpinfo) + report(t.helpinfo) end local reporters={ - lines=reportlines, - banner=reportbanner, - version=reportversion, - help=reporthelp, - info=reportinfo, - export=reportexport, + lines=reportlines, + banner=reportbanner, + version=reportversion, + help=reporthelp, + info=reportinfo, + export=reportexport, } local exporters={ } logs.reporters=reporters logs.exporters=exporters function logs.application(t) - t.name=t.name or "unknown" - t.banner=t.banner - t.moreinfo=moreinfo - t.report=logs.reporter(t.name) - t.help=function(...) - reporters.banner(t) - reporters.help(t,...) - reporters.info(t) - end - t.export=function(...) - reporters.export(t,...) - end - t.identify=function() - reporters.banner(t) - end - t.version=function() - reporters.version(t) - end - return t + t.name=t.name or "unknown" + t.banner=t.banner + t.moreinfo=moreinfo + t.report=logs.reporter(t.name) + t.help=function(...) + reporters.banner(t) + reporters.help(t,...) + reporters.info(t) + end + t.export=function(...) + reporters.export(t,...) + end + t.identify=function() + reporters.banner(t) + end + t.version=function() + reporters.version(t) + end + return t end local f_syslog=formatters["%s %s => %s => %s => %s\r"] function logs.system(whereto,process,jobname,category,fmt,arg,...) - local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) - for i=1,10 do - local f=openfile(whereto,"a") - if f then - f:write(message) - f:close() - break - else - sleep(0.1) - end + local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) + for i=1,10 do + local f=openfile(whereto,"a") + if f then + f:write(message) + f:close() + break + else + sleep(0.1) end + end end local report_system=logs.reporter("system","logs") function logs.obsolete(old,new) - local o=loadstring("return "..new)() - if type(o)=="function" then - return function(...) - report_system("function %a is obsolete, use %a",old,new) - loadstring(old.."="..new.." return "..old)()(...) - end - elseif type(o)=="table" then - local t,m={},{} - m.__index=function(t,k) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - return o[k] - end - m.__newindex=function(t,k,v) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - o[k]=v - end - if libraries then - libraries.obsolete[old]=t - end - setmetatable(t,m) - return t + local o=loadstring("return "..new)() + if type(o)=="function" then + return function(...) + report_system("function %a is obsolete, use %a",old,new) + loadstring(old.."="..new.." return "..old)()(...) + end + elseif type(o)=="table" then + local t,m={},{} + m.__index=function(t,k) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + return o[k] + end + m.__newindex=function(t,k,v) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + o[k]=v + end + if libraries then + libraries.obsolete[old]=t end + setmetatable(t,m) + return t + end end if utilities then - utilities.report=report_system + utilities.report=report_system end if tex and tex.error then - function logs.texerrormessage(...) - tex.error(format(...),{}) - end + function logs.texerrormessage(...) + tex.error(format(...)) + end else - function logs.texerrormessage(...) - print(format(...)) - end + function logs.texerrormessage(...) + print(format(...)) + end end io.stdout:setvbuf('no') io.stderr:setvbuf('no') if package.helpers.report then - package.helpers.report=logs.reporter("package loader") + package.helpers.report=logs.reporter("package loader") end if tex then - local finalactions={} - local fatalerrors={} - local possiblefatal={} - local loggingerrors=false - function logs.loggingerrors() - return loggingerrors - end - directives.register("logs.errors",function(v) - loggingerrors=v - if type(v)=="string" then - fatalerrors=settings_to_hash(v) - else - fatalerrors={} - end - end) - function logs.registerfinalactions(...) - insert(finalactions,...) - end - local what=nil - local report=nil - local state=nil - local target=nil - local function startlogging(t,r,w,s) - target=t - state=force - force=true - report=type(r)=="function" and r or logs.reporter(r) - what=w - pushtarget(target) + local finalactions={} + local fatalerrors={} + local possiblefatal={} + local loggingerrors=false + function logs.loggingerrors() + return loggingerrors + end + directives.register("logs.errors",function(v) + loggingerrors=v + if type(v)=="string" then + fatalerrors=settings_to_hash(v) + else + fatalerrors={} + end + end) + function logs.registerfinalactions(...) + insert(finalactions,...) + end + local what=nil + local report=nil + local state=nil + local target=nil + local function startlogging(t,r,w,s) + target=t + state=force + force=true + report=type(r)=="function" and r or logs.reporter(r) + what=w + pushtarget(target) + newline() + if s then + report("start %s: %s",what,s) + else + report("start %s",what) + end + if target=="logfile" then + newline() + end + return report + end + local function stoplogging() + if target=="logfile" then + newline() + end + report("stop %s",what) + if target=="logfile" then + newline() + end + poptarget() + state=oldstate + end + function logs.startfilelogging(...) + return startlogging("logfile",...) + end + logs.stopfilelogging=stoplogging + local done=false + function logs.starterrorlogging(r,w,...) + if not done then + pushtarget("terminal") + newline() + logs.report("error logging","start possible issues") + poptarget() + done=true + end + if fatalerrors[w] then + possiblefatal[w]=true + end + return startlogging("terminal",r,w,...) + end + logs.stoperrorlogging=stoplogging + function logs.finalactions() + if #finalactions>0 then + for i=1,#finalactions do + finalactions[i]() + end + if done then + pushtarget("terminal") newline() - if s then - report("start %s: %s",what,s) - else - report("start %s",what) - end - if target=="logfile" then - newline() - end - return report - end - local function stoplogging() - if target=="logfile" then - newline() - end - report("stop %s",what) - if target=="logfile" then - newline() - end + logs.report("error logging","stop possible issues") poptarget() - state=oldstate - end - function logs.startfilelogging(...) - return startlogging("logfile",...) - end - logs.stopfilelogging=stoplogging - local done=false - function logs.starterrorlogging(r,w,...) - if not done then - pushtarget("terminal") - newline() - logs.report("error logging","start possible issues") - poptarget() - done=true - end - if fatalerrors[w] then - possiblefatal[w]=true - end - return startlogging("terminal",r,w,...) - end - logs.stoperrorlogging=stoplogging - function logs.finalactions() - if #finalactions>0 then - for i=1,#finalactions do - finalactions[i]() - end - if done then - pushtarget("terminal") - newline() - logs.report("error logging","stop possible issues") - poptarget() - end - return next(possiblefatal) and sortedkeys(possiblefatal) or false - end + end + return next(possiblefatal) and sortedkeys(possiblefatal) or false end + end end @@ -10167,14 +13559,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8097, stripped down to: 5534 +-- original size: 9072, stripped down to: 6055 if not modules then modules={} end modules ['trac-inf']={ - version=1.001, - comment="companion to trac-inf.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-inf.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber,select=type,tonumber,select local format,lower,find=string.format,string.lower,string.find @@ -10189,161 +13581,191 @@ statistics.enable=true statistics.threshold=0.01 local statusinfo,n,registered,timers={},0,{},{} setmetatableindex(timers,function(t,k) - local v={ timing=0,loadtime=0 } - t[k]=v - return v + local v={ timing=0,loadtime=0 } + t[k]=v + return v end) local function hastiming(instance) - return instance and timers[instance] + return instance and timers[instance] end local function resettiming(instance) - timers[instance or "notimer"]={ timing=0,loadtime=0 } + timers[instance or "notimer"]={ timing=0,loadtime=0 } end local ticks=clock local seconds=function(n) return n or 0 end -local function starttiming(instance) - local timer=timers[instance or "notimer"] - local it=timer.timing - if it==0 then - timer.starttime=ticks() - if not timer.loadtime then - timer.loadtime=0 - end - end - timer.timing=it+1 +local function starttiming(instance,reset) + local timer=timers[instance or "notimer"] + local it=timer.timing + if reset then + it=0 + timer.loadtime=0 + end + if it==0 then + timer.starttime=ticks() + if not timer.loadtime then + timer.loadtime=0 + end + end + timer.timing=it+1 end local function stoptiming(instance) + local timer=timers[instance or "notimer"] + local it=timer.timing + if it>1 then + timer.timing=it-1 + else + local starttime=timer.starttime + if starttime and starttime>0 then + local stoptime=ticks() + local loadtime=stoptime-starttime + timer.stoptime=stoptime + timer.loadtime=timer.loadtime+loadtime + timer.timing=0 + timer.starttime=0 + return loadtime + end + end + return 0 +end +local function elapsed(instance) + if type(instance)=="number" then + return instance + else + local timer=timers[instance or "notimer"] + return timer and seconds(timer.loadtime) or 0 + end +end +local function currenttime(instance) + if type(instance)=="number" then + return instance + else local timer=timers[instance or "notimer"] local it=timer.timing if it>1 then - timer.timing=it-1 else - local starttime=timer.starttime - if starttime and starttime>0 then - local stoptime=ticks() - local loadtime=stoptime-starttime - timer.stoptime=stoptime - timer.loadtime=timer.loadtime+loadtime - timer.timing=0 - timer.starttime=0 - return loadtime - end + local starttime=timer.starttime + if starttime and starttime>0 then + return seconds(timer.loadtime+ticks()-starttime) + end end return 0 -end -local function elapsed(instance) - if type(instance)=="number" then - return instance - else - local timer=timers[instance or "notimer"] - return timer and seconds(timer.loadtime) or 0 - end + end end local function elapsedtime(instance) - return format("%0.3f",elapsed(instance)) + return format("%0.3f",elapsed(instance)) end local function elapsedindeed(instance) - return elapsed(instance)>statistics.threshold + return elapsed(instance)>statistics.threshold end local function elapsedseconds(instance,rest) - if elapsedindeed(instance) then - return format("%0.3f seconds %s",elapsed(instance),rest or "") - end + if elapsedindeed(instance) then + return format("%0.3f seconds %s",elapsed(instance),rest or "") + end end statistics.hastiming=hastiming statistics.resettiming=resettiming statistics.starttiming=starttiming statistics.stoptiming=stoptiming +statistics.currenttime=currenttime statistics.elapsed=elapsed statistics.elapsedtime=elapsedtime statistics.elapsedindeed=elapsedindeed statistics.elapsedseconds=elapsedseconds function statistics.register(tag,fnc) - if statistics.enable and type(fnc)=="function" then - local rt=registered[tag] or (#statusinfo+1) - statusinfo[rt]={ tag,fnc } - registered[tag]=rt - if #tag>n then n=#tag end - end + if statistics.enable and type(fnc)=="function" then + local rt=registered[tag] or (#statusinfo+1) + statusinfo[rt]={ tag,fnc } + registered[tag]=rt + if #tag>n then n=#tag end + end end 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("used engine",function() - return format("%s version %s with functionality level %s, banner: %s", - LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) - end) - register("control sequences",function() - return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) - end) - register("callbacks",statistics.callbacks) - if TEXENGINE=="luajittex" and JITSUPPORTED then - local jitstatus=jit.status - if jitstatus then - local jitstatus={ jitstatus() } - if jitstatus[1] then - register("luajit options",concat(jitstatus," ",2)) - end - end - end - register("lua properties",function() - local hashchar=tonumber(status.luatex_hashchars) - local hashtype=status.luatex_hashtype - local mask=lua.mask or "ascii" - return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", - jit and "luajit" or "lua", - LUAVERSION, - statistics.memused(), - 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 - local s=statusinfo[i] - local r=s[2]() - if r then - report("%s: %s",s[1],r) - end + 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("used engine",function() + return format("%s version %s with functionality level %s, banner: %s", + LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) + end) + register("control sequences",function() + return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) + end) + register("callbacks",statistics.callbacks) + if TEXENGINE=="luajittex" and JITSUPPORTED then + local jitstatus=jit.status + if jitstatus then + local jitstatus={ jitstatus() } + if jitstatus[1] then + register("luajit options",concat(jitstatus," ",2)) end - statistics.enable=false + end end + register("lua properties",function() + local hashchar=tonumber(status.luatex_hashchars) + local hashtype=status.luatex_hashtype + local mask=lua.mask or "ascii" + return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", + jit and "luajit" or "lua", + LUAVERSION, + statistics.memused(), + 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 + local s=statusinfo[i] + local r=s[2]() + if r then + report("%s: %s",s[1],r) + end + end + statistics.enable=false + end end function statistics.memused() - local round=math.round or math.floor - return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) + local round=math.round or math.floor + return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) end starttiming(statistics) function statistics.formatruntime(runtime) - return format("%s seconds",runtime) + return format("%s seconds",runtime) end function statistics.runtime() - stoptiming(statistics) - return statistics.formatruntime(elapsedtime(statistics)) + stoptiming(statistics) + local runtime=lua.getruntime and lua.getruntime() or elapsedtime(statistics) + return statistics.formatruntime(runtime) end local report=logs.reporter("system") -function statistics.timed(action) - starttiming("run") - action() - stoptiming("run") - report("total runtime: %s seconds",elapsedtime("run")) +function statistics.timed(action,all) + starttiming("run") + action() + stoptiming("run") + local runtime=tonumber(elapsedtime("run")) + if all then + local alltime=tonumber(lua.getruntime and lua.getruntime() or elapsedtime(statistics)) + if alltime and alltime>0 then + report("total runtime: %0.3f seconds of %0.3f seconds",runtime,alltime) + return + end + end + report("total runtime: %0.3f seconds",runtime) 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 + 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 @@ -10353,144 +13775,144 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-pro"] = package.loaded["trac-pro"] or true --- original size: 5841, stripped down to: 3511 +-- original size: 5841, stripped down to: 3352 if not modules then modules={} end modules ['trac-pro']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local getmetatable,setmetatable,rawset,type,next=getmetatable,setmetatable,rawset,type,next -local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) +local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) local report_system=logs.reporter("system","protection") namespaces=namespaces or {} 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) - debugger.showtraceback(report_system) - else - report_system("reference to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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) - debugger.showtraceback(report_system) - else - report_system("assignment to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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 end local function register(name) - local data=name=="global" and _G or _G[name] - if not data then - return - end - registered[name]=data - local m=getmetatable(data) - if not m then - m={} - setmetatable(data,m) - end - local index,newindex={},{} - m.__saved__index=m.__index - m.__no__index=function(t,k) - if not index[k] then - index[k]=true - report_index(k,name) - end - return nil + local data=name=="global" and _G or _G[name] + if not data then + return + end + registered[name]=data + local m=getmetatable(data) + if not m then + m={} + setmetatable(data,m) + end + local index,newindex={},{} + m.__saved__index=m.__index + m.__no__index=function(t,k) + if not index[k] then + index[k]=true + report_index(k,name) end - m.__saved__newindex=m.__newindex - m.__no__newindex=function(t,k,v) - if not newindex[k] then - newindex[k]=true - report_newindex(k,name) - end - rawset(t,k,v) + return nil + end + m.__saved__newindex=m.__newindex + m.__no__newindex=function(t,k,v) + if not newindex[k] then + newindex[k]=true + report_newindex(k,name) end - m.__protection__depth=0 + rawset(t,k,v) + end + m.__protection__depth=0 end local function private(name) - local data=registered[name] + local data=registered[name] + if not data then + data=_G[name] if not data then - data=_G[name] - if not data then - data={} - _G[name]=data - end - register(name) + data={} + _G[name]=data end - return data + register(name) + end + return data end local function protect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>0 then - m.__protection__depth=pd+1 - else - m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex - m.__index,m.__newindex=m.__no__index,m.__no__newindex - m.__protection__depth=1 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>0 then + m.__protection__depth=pd+1 + else + m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex + m.__index,m.__newindex=m.__no__index,m.__no__newindex + m.__protection__depth=1 + end end local function unprotect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>1 then - m.__protection__depth=pd-1 - else - m.__index,m.__newindex=m.__saved__index,m.__saved__newindex - m.__protection__depth=0 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>1 then + m.__protection__depth=pd-1 + else + m.__index,m.__newindex=m.__saved__index,m.__saved__newindex + m.__protection__depth=0 + end end local function protectall() - for name,_ in next,registered do - if name~="global" then - protect(name) - end + for name,_ in next,registered do + if name~="global" then + protect(name) end + end end local function unprotectall() - for name,_ in next,registered do - if name~="global" then - unprotect(name) - end + for name,_ in next,registered do + if name~="global" then + unprotect(name) end + end end -namespaces.register=register -namespaces.private=private +namespaces.register=register +namespaces.private=private namespaces.protect=protect namespaces.unprotect=unprotect namespaces.protectall=protectall namespaces.unprotectall=unprotectall namespaces.private("namespaces") registered={} register("global") directives.register("system.protect",function(v) - if v then - protectall() - else - unprotectall() - end + if v then + protectall() + else + unprotectall() + end end) directives.register("system.checkglobals",function(v) - if v then - report_system("enabling global namespace guard") - protect("global") - else - report_system("disabling global namespace guard") - unprotect("global") - end + if v then + report_system("enabling global namespace guard") + protect("global") + else + report_system("disabling global namespace guard") + unprotect("global") + end end) @@ -10500,15 +13922,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lua"] = package.loaded["util-lua"] or true --- original size: 6621, stripped down to: 4764 +-- original size: 6664, stripped down to: 4589 if not modules then modules={} end modules ['util-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - comment="the strip code is written by Peter Cawley", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + comment="the strip code is written by Peter Cawley", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local rep,sub,byte,dump,format=string.rep,string.sub,string.byte,string.dump,string.format local load,loadfile,type,collectgarbage=load,loadfile,type,collectgarbage @@ -10519,150 +13941,151 @@ local report_lua=logs.reporter("system","lua") local report_mem=logs.reporter("system","lua memory") local tracestripping=false local tracememory=false -luautilities.stripcode=true +luautilities.stripcode=true luautilities.alwaysstripcode=false luautilities.nofstrippedchunks=0 luautilities.nofstrippedbytes=0 local strippedchunks={} luautilities.strippedchunks=strippedchunks luautilities.suffixes={ - tma="tma", - tmc=jit and "tmb" or "tmc", - lua="lua", - luc=jit and "lub" or "luc", - lui="lui", - luv="luv", - luj="luj", - tua="tua", - tuc="tuc", + tma="tma", + tmc=jit and "tmb" or "tmc", + lua="lua", + luc=jit and "lub" or "luc", + lui="lui", + luv="luv", + luj="luj", + tua="tua", + tuc="tuc", } 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 + 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 -end -function luautilities.loadedluacode(fullname,forcestrip,name,macros) - name=name or fullname - if macros then - macros=lua.macros - end - local code,message - if macros then - code,message=macros.loaded(fullname,true,false) - else - code,message=loadfile(fullname) - end + local code=io.loaddata(luafile) + if code and code~="" then + code=load(code) if code then - code() - else - report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") - end - if forcestrip and luautilities.stripcode then - if type(forcestrip)=="function" then - forcestrip=forcestrip(fullname) - end - if forcestrip or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end - elseif 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 + io.savedata(lucfile,code) + return true,0 + end else - return code,0 + 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 +end +function luautilities.loadedluacode(fullname,forcestrip,name,macros) + name=name or fullname + if macros then + macros=lua.macros + end + local code,message + if macros then + code,message=macros.loaded(fullname,true,false) + else + code,message=loadfile(fullname) + end + if code then + code() + else + report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") + code,message=loadfile(fullname) + end + if forcestrip and luautilities.stripcode then + if type(forcestrip)=="function" then + forcestrip=forcestrip(fullname) + end + 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 end function luautilities.strippedloadstring(code,name,forcestrip) - 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 - if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end + 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 + if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 + else + return code,0 + end end function luautilities.loadstring(code,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 - return code,0 + 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 + return 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 - end - return done + 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 + end + return done end function luautilities.loadstripped(...) - local l=load(...) - if l then - return load(dump(l,true)) - end + local l=load(...) + if l then + return load(dump(l,true)) + end end local finalizers={} setmetatable(finalizers,{ - __gc=function(t) - for i=1,#t do - pcall(t[i]) - end + __gc=function(t) + for i=1,#t do + pcall(t[i]) end + end } ) function luautilities.registerfinalizer(f) - finalizers[#finalizers+1]=f + finalizers[#finalizers+1]=f end function luautilities.checkmemory(previous,threshold,trace) - local current=collectgarbage("count") - if previous then - local checked=(threshold or 64)*1024 - local delta=current-previous - if current-previous>checked then - collectgarbage("collect") - local afterwards=collectgarbage("count") - if trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB, afterwards %i MB", - previous/1024,current/1024,delta/1024,threshold,afterwards) - end - return afterwards - elseif trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB", - previous/1024,current/1024,delta/1024,threshold) - end + local current=collectgarbage("count") + if previous then + local checked=(threshold or 64)*1024 + local delta=current-previous + if current-previous>checked then + collectgarbage("collect") + local afterwards=collectgarbage("count") + if trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB", + previous/1024,current/1024,delta/1024,threshold,afterwards) + end + return afterwards + elseif trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB", + previous/1024,current/1024,delta/1024,threshold) end - return current + end + return current end @@ -10672,17 +14095,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-deb"] = package.loaded["util-deb"] or true --- original size: 8984, stripped down to: 6573 +-- original size: 9955, stripped down to: 6693 if not modules then modules={} end modules ['util-deb']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local debug=require "debug" -local getinfo,sethook=debug.getinfo,debug.sethook local type,next,tostring,tonumber=type,next,tostring,tonumber local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub local insert,remove,sort=table.insert,table.remove,table.sort @@ -10700,228 +14121,266 @@ local names={} local initialize=false if not (FFISUPPORTED and ffi) then elseif os.type=="windows" then - initialize=function() - local kernel=ffilib("kernel32","system") - if kernel then - local tonumber=ffi.number or tonumber - ffi.cdef[[ + initialize=function() + local kernel=ffilib("kernel32","system") + if kernel then + local tonumber=ffi.number or tonumber + ffi.cdef[[ int QueryPerformanceFrequency(int64_t *lpFrequency); int QueryPerformanceCounter(int64_t *lpPerformanceCount); ]] - local target=ffi.new("__int64[1]") - ticks=function() - if kernel.QueryPerformanceCounter(target)==1 then - return tonumber(target[0]) - else - return 0 - end - end - local target=ffi.new("__int64[1]") - seconds=function(ticks) - if kernel.QueryPerformanceFrequency(target)==1 then - return ticks/tonumber(target[0]) - else - return 0 - end - end + local target=ffi.new("__int64[1]") + ticks=function() + if kernel.QueryPerformanceCounter(target)==1 then + return tonumber(target[0]) + else + return 0 end - initialize=false + end + local target=ffi.new("__int64[1]") + seconds=function(ticks) + if kernel.QueryPerformanceFrequency(target)==1 then + return ticks/tonumber(target[0]) + else + return 0 + end + end end + initialize=false + end elseif os.type=="unix" then - initialize=function() - local C=ffi.C - local tonumber=ffi.number or tonumber - ffi.cdef [[ + initialize=function() + local C=ffi.C + local tonumber=ffi.number or tonumber + ffi.cdef [[ /* what a mess */ typedef int clk_id_t; typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID } clk_id; typedef struct timespec { long sec; long nsec; } ctx_timespec; int clock_gettime(clk_id_t timerid, struct timespec *t); ]] - local target=ffi.new("ctx_timespec[?]",1) - local clock=C.CLOCK_PROCESS_CPUTIME_ID - ticks=function () - C.clock_gettime(clock,target) - return tonumber(target[0].sec*1000000000+target[0].nsec) - end - seconds=function(ticks) - return ticks/1000000000 - end - initialize=false + local target=ffi.new("ctx_timespec[?]",1) + local clock=C.CLOCK_PROCESS_CPUTIME_ID + ticks=function () + C.clock_gettime(clock,target) + return tonumber(target[0].sec*1000000000+target[0].nsec) + end + seconds=function(ticks) + return ticks/1000000000 end + initialize=false + end end setmetatableindex(names,function(t,name) - local v=setmetatableindex(function(t,source) - local v=setmetatableindex(function(t,line) - local v={ total=0,count=0 } - t[line]=v - return v - end) - t[source]=v - return v + local v=setmetatableindex(function(t,source) + local v=setmetatableindex(function(t,line) + local v={ total=0,count=0,nesting=0 } + t[line]=v + return v end) - t[name]=v + t[source]=v return v + end) + t[name]=v + return v end) +local getinfo=nil +local sethook=nil local function hook(where) - local f=getinfo(2,"nSl") - if f then - local source=f.short_src - if not source then - return - end - local line=f.linedefined or 0 - local name=f.name - if not name then - local what=f.what - if what=="C" then - name="<anonymous>" - else - name=f.namewhat or what or "<unknown>" - end - end - local data=names[name][source][line] - if where=="call" then - data.count=data.count+1 - insert(data,ticks()) - elseif where=="return" then - local t=remove(data) - if t then - data.total=data.total+ticks()-t - end + local f=getinfo(2,"nSl") + if f then + local source=f.short_src + if not source then + return + end + local line=f.linedefined or 0 + local name=f.name + if not name then + local what=f.what + if what=="C" then + name="<anonymous>" + else + name=f.namewhat or what or "<unknown>" + end + end + local data=names[name][source][line] + if where=="call" then + local nesting=data.nesting + if nesting==0 then + data.count=data.count+1 + insert(data,ticks()) + data.nesting=1 + else + data.nesting=nesting+1 + end + elseif where=="return" then + local nesting=data.nesting + if nesting==1 then + local t=remove(data) + if t then + data.total=data.total+ticks()-t end + data.nesting=0 + else + data.nesting=nesting-1 + end end + end end function debugger.showstats(printer,threshold) - local printer=printer or report - local calls=0 - local functions=0 - local dataset={} - local length=0 - local realtime=0 - local totaltime=0 - local threshold=threshold or 0 - for name,sources in next,names do - for source,lines in next,sources do - for line,data in next,lines do - local count=data.count - if count>threshold then - if #name>length then - length=#name - end - local total=data.total - local real=total - if real>0 then - real=total-(count*overhead/dummycalls) - if real<0 then - real=0 - end - realtime=realtime+real - end - totaltime=totaltime+total - if line<0 then - line=0 - end - dataset[#dataset+1]={ real,total,count,name,source,line } - end - end + local printer=printer or report + local calls=0 + local functions=0 + local dataset={} + local length=0 + local realtime=0 + local totaltime=0 + local threshold=threshold or 0 + for name,sources in next,names do + for source,lines in next,sources do + for line,data in next,lines do + local count=data.count + if count>threshold then + if #name>length then + length=#name + end + local total=data.total + local real=total + if real>0 then + real=total-(count*overhead/dummycalls) + if real<0 then + real=0 + end + realtime=realtime+real + end + totaltime=totaltime+total + if line<0 then + line=0 + end + dataset[#dataset+1]={ real,total,count,name,source,line } end + end end - sort(dataset,function(a,b) - if a[1]==b[1] then - if a[2]==b[2] then - if a[3]==b[3] then - if a[4]==b[4] then - if a[5]==b[5] then - return a[6]<b[6] - else - return a[5]<b[5] - end - else - return a[4]<b[4] - end - else - return b[3]<a[3] - end + end + sort(dataset,function(a,b) + if a[1]==b[1] then + if a[2]==b[2] then + if a[3]==b[3] then + if a[4]==b[4] then + if a[5]==b[5] then + return a[6]<b[6] else - return b[2]<a[2] + return a[5]<b[5] end + else + return a[4]<b[4] + end else - return b[1]<a[1] + return b[3]<a[3] end - end) - if length>50 then - length=50 - end - local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] - for i=1,#dataset do - local data=dataset[i] - local real=data[1] - local total=data[2] - local count=data[3] - local name=data[4] - local source=data[5] - local line=data[6] - calls=calls+count - functions=functions+1 - name=gsub(name,"%s+"," ") - if #name>length then - name=sub(name,1,length) - end - printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) - end - printer("") - printer(format("functions : %i",functions)) - printer(format("calls : %i",calls)) - printer(format("overhead : %f",seconds(overhead/1000))) + else + return b[2]<a[2] + end + else + return b[1]<a[1] + end + end) + if length>50 then + length=50 + end + local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] + for i=1,#dataset do + local data=dataset[i] + local real=data[1] + local total=data[2] + local count=data[3] + local name=data[4] + local source=data[5] + local line=data[6] + calls=calls+count + functions=functions+1 + name=gsub(name,"%s+"," ") + if #name>length then + name=sub(name,1,length) + end + printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) + end + printer("") + printer(format("functions : %i",functions)) + printer(format("calls : %i",calls)) + printer(format("overhead : %f",seconds(overhead/1000))) +end +local function getdebug() + if sethook and getinfo then + return + end + if not debug then + local okay + okay,debug=pcall(require,"debug") + end + if type(debug)~="table" then + return + end + getinfo=debug.getinfo + sethook=debug.sethook + if type(getinfo)~="function" then + getinfo=nil + end + if type(sethook)~="function" then + sethook=nil + end end function debugger.savestats(filename,threshold) - local f=io.open(filename,'w') - if f then - debugger.showstats(function(str) f:write(str,"\n") end,threshold) - f:close() - end + local f=io.open(filename,'w') + if f then + debugger.showstats(function(str) f:write(str,"\n") end,threshold) + f:close() + end end function debugger.enable() - if nesting==0 then - running=true - if initialize then - initialize() - end - sethook(hook,"cr") - local function dummy() end - local t=ticks() - for i=1,dummycalls do - dummy() - end - overhead=ticks()-t - end - if nesting>0 then - nesting=nesting+1 - end + getdebug() + if sethook and getinfo and nesting==0 then + running=true + if initialize then + initialize() + end + sethook(hook,"cr") + local function dummy() end + local t=ticks() + for i=1,dummycalls do + dummy() + end + overhead=ticks()-t + end + if nesting>0 then + nesting=nesting+1 + end end function debugger.disable() - if nesting>0 then - nesting=nesting-1 - end - if nesting==0 then - sethook() - end + if nesting>0 then + nesting=nesting-1 + end + if sethook and getinfo and nesting==0 then + sethook() + end end local function showtraceback(rep) + getdebug() + if getinfo then local level=2 local reporter=rep or report while true do - local info=getinfo(level,"Sl") - if not info then - break - elseif info.what=="C" then - reporter("%2i : %s",level-1,"C function") - else - reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) - end - level=level+1 + local info=getinfo(level,"Sl") + if not info then + break + elseif info.what=="C" then + reporter("%2i : %s",level-1,"C function") + else + reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) + end + level=level+1 end + end end debugger.showtraceback=showtraceback @@ -10932,91 +14391,91 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tpl"] = package.loaded["util-tpl"] or true --- original size: 7112, stripped down to: 3988 +-- original size: 7112, stripped down to: 3887 if not modules then modules={} end modules ['util-tpl']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities.templates=utilities.templates or {} local templates=utilities.templates -local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) +local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) local report_template=logs.reporter("template") local tostring,next=tostring,next 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] - if not v then - if trace_template then - report_template("unknown key %a",k) - end - return "" + local v=t[k] + if not v then + if trace_template then + report_template("unknown key %a",k) + end + return "" + else + v=tostring(v) + if trace_template then + report_template("setting key %a to value %a",k,v) + end + if recursive then + return lpegmatch(replacer,v,1,t,how,recursive) else - v=tostring(v) - if trace_template then - report_template("setting key %a to value %a",k,v) - end - if recursive then - return lpegmatch(replacer,v,1,t,how,recursive) - else - return v - end + return v end + end end local sqlescape=lpeg.replacer { - { "'","''" }, - { "\\","\\\\" }, - { "\r\n","\\n" }, - { "\r","\\n" }, + { "'","''" }, + { "\\","\\\\" }, + { "\r\n","\\n" }, + { "\r","\\n" }, } local sqlquoted=Cs(Cc("'")*sqlescape*Cc("'")) lpegpatterns.sqlescape=sqlescape lpegpatterns.sqlquoted=sqlquoted local luaescape=lpegpatterns.luaescape local escapers={ - lua=function(s) - return lpegmatch(luaescape,s) - end, - sql=function(s) - return lpegmatch(sqlescape,s) - end, + lua=function(s) + return lpegmatch(luaescape,s) + end, + sql=function(s) + return lpegmatch(sqlescape,s) + end, } local quotedescapers={ - lua=function(s) - return format("%q",s) - end, - sql=function(s) - return lpegmatch(sqlquoted,s) - end, + lua=function(s) + return format("%q",s) + end, + sql=function(s) + return lpegmatch(sqlquoted,s) + end, } local luaescaper=escapers.lua local quotedluaescaper=quotedescapers.lua local function replacekeyunquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and escapers[how] or luaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and escapers[how] or luaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replacekeyquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and quotedescapers[how] or quotedluaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and quotedescapers[how] or quotedluaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replaceoptional(l,m,r,t,how,recurse) - local v=t[l] - return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" + local v=t[l] + return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" end -local single=P("%") +local single=P("%") local double=P("%%") local lquoted=P("%[") local rquoted=P("]%") @@ -11033,41 +14492,41 @@ local noloptional=P("%?")/'' local noroptional=P("?%")/'' local nomoptional=P(":")/'' local args=Carg(1)*Carg(2)*Carg(3) -local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle -local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq -local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted +local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle +local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq +local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted local optional=noloptional*((C((1-nomoptional)^1)*nomoptional*C((1-noroptional)^1)*args)/replaceoptional)*noroptional local any=P(1) replacer=Cs((unquoted+quoted+escape+optional+key+any)^0) local function replace(str,mapping,how,recurse) - if mapping and str then - return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str - else - return str - end + if mapping and str then + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + else + return str + 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 + 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 - return replace(data,mapping,how,recurse) - else - return data - end + local data=io.loaddata(filename) or "" + if mapping and next(mapping) then + return replace(data,mapping,how,recurse) + else + return data + end end function templates.resolve(t,mapping,how,recurse) - if not mapping then - mapping=t - end - for k,v in next,t do - t[k]=replace(v,mapping,how,recurse) - end - return t + if not mapping then + mapping=t + end + for k,v in next,t do + t[k]=replace(v,mapping,how,recurse) + end + return t end @@ -11077,14 +14536,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sbx"] = package.loaded["util-sbx"] or true --- original size: 20393, stripped down to: 13924 +-- original size: 20393, stripped down to: 13121 if not modules then modules={} end modules ['util-sbx']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not sandbox then require("l-sandbox") end local next,type=next,type @@ -11117,144 +14576,144 @@ local report=logs.reporter("sandbox") trackers.register("sandbox",function(v) trace=v end) sandbox.setreporter(report) sandbox.finalizer { - category="files", - action=function() - finalized=true - end + category="files", + action=function() + finalized=true + end } local function registerroot(root,what) - if finalized then - report("roots are already finalized") - else - if type(root)=="table" then - root,what=root[1],root[2] - end - if type(root)=="string" and root~="" then - root=collapsepath(expandname(root)) - if what=="r" or what=="ro" or what=="readable" then - what="read" - elseif what=="w" or what=="wo" or what=="writable" then - what="write" - end - validroots[root]=what=="write" or false - end + if finalized then + report("roots are already finalized") + else + if type(root)=="table" then + root,what=root[1],root[2] + end + if type(root)=="string" and root~="" then + root=collapsepath(expandname(root)) + if what=="r" or what=="ro" or what=="readable" then + what="read" + elseif what=="w" or what=="wo" or what=="writable" then + what="write" + end + validroots[root]=what=="write" or false end + end end sandbox.finalizer { - category="files", - action=function() + category="files", + action=function() + if p_validroot then + report("roots are already initialized") + else + sandbox.registerroot(".","write") + for name in sortedhash(validroots) do if p_validroot then - report("roots are already initialized") + p_validroot=P(name)+p_validroot else - sandbox.registerroot(".","write") - for name in sortedhash(validroots) do - if p_validroot then - p_validroot=P(name)+p_validroot - else - p_validroot=P(name) - end - end - p_validroot=p_validroot/validroots + p_validroot=P(name) end + end + p_validroot=p_validroot/validroots end + end } local function registerbinary(name) - if finalized then - report("binaries are already finalized") - elseif type(name)=="string" and name~="" then - if not validbinaries then - return - end - if validbinaries==true then - validbinaries={ [name]=true } - else - validbinaries[name]=true - end - elseif name==true then - validbinaries={} + if finalized then + report("binaries are already finalized") + elseif type(name)=="string" and name~="" then + if not validbinaries then + return + end + if validbinaries==true then + validbinaries={ [name]=true } + else + validbinaries[name]=true end + elseif name==true then + validbinaries={} + end end local function registerlibrary(name) - if finalized then - report("libraries are already finalized") - elseif type(name)=="string" and name~="" then - if not validlibraries then - return - end - if validlibraries==true then - validlibraries={ [nameonly(name)]=true } - else - validlibraries[nameonly(name)]=true - end - elseif name==true then - validlibraries={} + if finalized then + report("libraries are already finalized") + elseif type(name)=="string" and name~="" then + if not validlibraries then + return + end + if validlibraries==true then + validlibraries={ [nameonly(name)]=true } + else + validlibraries[nameonly(name)]=true end + elseif name==true then + validlibraries={} + end end local p_write=S("wa") p_write=(1-p_write)^0*p_write -local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path +local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path local function normalized(name) - if platform=="windows" then - name=gsub(name,"/","\\") - end - return name + if platform=="windows" then + name=gsub(name,"/","\\") + end + return name end function sandbox.possiblepath(name) - return lpegmatch(p_path,name) and true or false + return lpegmatch(p_path,name) and true or false end local filenamelogger=false function sandbox.setfilenamelogger(l) - filenamelogger=type(l)=="function" and l or false + filenamelogger=type(l)=="function" and l or false end local function validfilename(name,what) - if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then - local asked=collapsepath(expandname(name)) - local okay=lpegmatch(p_validroot,asked) - if okay==true then - if filenamelogger then - filenamelogger(name,"w",asked,true) - end - return name - elseif okay==false then - if not what then - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - elseif lpegmatch(p_write,what) then - if filenamelogger then - filenamelogger(name,"w",asked,false) - end - return - else - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - end - elseif filenamelogger then - filenamelogger(name,"*",name,false) + if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then + local asked=collapsepath(expandname(name)) + local okay=lpegmatch(p_validroot,asked) + if okay==true then + if filenamelogger then + filenamelogger(name,"w",asked,true) + end + return name + elseif okay==false then + if not what then + if filenamelogger then + filenamelogger(name,"r",asked,true) end - else return name + elseif lpegmatch(p_write,what) then + if filenamelogger then + filenamelogger(name,"w",asked,false) + end + return + else + if filenamelogger then + filenamelogger(name,"r",asked,true) + end + return name + end + elseif filenamelogger then + filenamelogger(name,"*",name,false) end + else + return name + end end local function readable(name,finalized) - return validfilename(name,"r") + return validfilename(name,"r") end local function normalizedreadable(name,finalized) - local valid=validfilename(name,"r") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"r") + if valid then + return normalized(valid) + end end local function writeable(name,finalized) - return validfilename(name,"w") + return validfilename(name,"w") end local function normalizedwriteable(name,finalized) - local valid=validfilename(name,"w") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"w") + if valid then + return normalized(valid) + end end validators.readable=readable validators.writeable=normalizedwriteable @@ -11262,316 +14721,316 @@ validators.normalizedreadable=normalizedreadable validators.normalizedwriteable=writeable validators.filename=readable table.setmetatableindex(validators,function(t,k) - if k then - t[k]=readable - end - return readable + if k then + t[k]=readable + end + return readable end) function validators.string(s,finalized) - if finalized and suspicious(s) then - return "" - else - return s - end + if finalized and suspicious(s) then + return "" + else + return s + end end function validators.cache(s) - if finalized then - return basename(s) - else - return s - end + if finalized then + return basename(s) + else + return s + end end function validators.url(s) - if finalized and find("^file:") then - return "" - else - return s - end + if finalized and find("^file:") then + return "" + else + return s + end end local function filehandlerone(action,one,...) - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - else - end + local checkedone=validfilename(one) + if checkedone then + return action(one,...) + else + end end local function filehandlertwo(action,one,two,...) - local checkedone=validfilename(one) - if checkedone then - local checkedtwo=validfilename(two) - if checkedtwo then - return action(one,two,...) - else - end + local checkedone=validfilename(one) + if checkedone then + local checkedtwo=validfilename(two) + if checkedtwo then + return action(one,two,...) else end + else + end end local function iohandler(action,one,...) - if type(one)=="string" then - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - end - elseif one then - return action(one,...) - else - return action() + if type(one)=="string" then + local checkedone=validfilename(one) + if checkedone then + return action(one,...) end + elseif one then + return action(one,...) + else + return action() + end end local osexecute=sandbox.original(os.execute) local iopopen=sandbox.original(io.popen) local reported={} local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict) - if validbinaries~=false and (validbinaries==true or validbinaries[program]) then - if variables then - for variable,value in next,variables do - local checker=validators[checkers[variable]] - if checker then - value=checker(unquoted(value),strict) - if value then - variables[variable]=optionalquoted(value) - else - report("variable %a with value %a fails the check",variable,value) - return - end - else - report("variable %a has no checker",variable) - return - end - end - for variable,default in next,defaults do - local value=variables[variable] - if not value or value=="" then - local checker=validators[checkers[variable]] - if checker then - default=checker(unquoted(default),strict) - if default then - variables[variable]=optionalquoted(default) - else - report("variable %a with default %a fails the check",variable,default) - return - end - end - end - end - end - local command=program.." "..replace(template,variables) - if reporter then - reporter("executing runner %a: %s",name,command) - elseif trace then - report("executing runner %a: %s",name,command) - end - return command - elseif not reported[name] then - report("executing program %a of runner %a is not permitted",program,name) - reported[name]=true - end -end -local runners={ - resultof=function(...) - local command=validcommand(...) - if command then - if trace then - report("resultof: %s",command) - end - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - end - end - end, - execute=function(...) - local command=validcommand(...) - if command then - if trace then - report("execute: %s",command) - end - return osexecute(command) + if validbinaries~=false and (validbinaries==true or validbinaries[program]) then + if variables then + for variable,value in next,variables do + local checker=validators[checkers[variable]] + if checker then + value=checker(unquoted(value),strict) + if value then + variables[variable]=optionalquoted(value) + else + report("variable %a with value %a fails the check",variable,value) + return + end + else + report("variable %a has no checker",variable) + return end - end, - pipeto=function(...) - local command=validcommand(...) - if command then - if trace then - report("pipeto: %s",command) + end + for variable,default in next,defaults do + local value=variables[variable] + if not value or value=="" then + local checker=validators[checkers[variable]] + if checker then + default=checker(unquoted(default),strict) + if default then + variables[variable]=optionalquoted(default) + else + report("variable %a with default %a fails the check",variable,default) + return end - return iopopen(command,"w") - end - end, -} -function sandbox.registerrunner(specification) - if type(specification)=="string" then - local wrapped=validrunners[specification] - inspect(table.sortedkeys(validrunners)) - if wrapped then - return wrapped - else - report("unknown predefined runner %a",specification) - return + end end + end end - if type(specification)~="table" then - report("specification should be a table (or string)") - return - end - local name=specification.name - if type(name)~="string" then - report("invalid name, string expected",name) - return - end - if validrunners[name] then - report("invalid name, runner %a already defined") - return - end - local program=specification.program - if type(program)=="string" then - elseif type(program)=="table" then - program=program[platform] or program.default or program.unix - end - if type(program)~="string" or program=="" then - report("invalid runner %a specified for platform %a",name,platform) - return + local command=program.." "..replace(template,variables) + if reporter then + reporter("executing runner %a: %s",name,command) + elseif trace then + report("executing runner %a: %s",name,command) end - local template=specification.template - if not template then - report("missing template for runner %a",name) - return + return command + elseif not reported[name] then + report("executing program %a of runner %a is not permitted",program,name) + reported[name]=true + end +end +local runners={ + resultof=function(...) + local command=validcommand(...) + if command then + if trace then + report("resultof: %s",command) + end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + end end - local method=specification.method or "execute" - local checkers=specification.checkers or {} - local defaults=specification.defaults or {} - local runner=runners[method] - if runner then - local finalized=finalized - local wrapped=function(variables) - return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) - end - validrunners[name]=wrapped - return wrapped - else - validrunners[name]=nil - report("invalid method for runner %a",name) + end, + execute=function(...) + local command=validcommand(...) + if command then + if trace then + report("execute: %s",command) + end + return osexecute(command) + end + end, + pipeto=function(...) + local command=validcommand(...) + if command then + if trace then + report("pipeto: %s",command) + end + return iopopen(command,"w") end + end, +} +function sandbox.registerrunner(specification) + if type(specification)=="string" then + local wrapped=validrunners[specification] + inspect(table.sortedkeys(validrunners)) + if wrapped then + return wrapped + else + report("unknown predefined runner %a",specification) + return + end + end + if type(specification)~="table" then + report("specification should be a table (or string)") + return + end + local name=specification.name + if type(name)~="string" then + report("invalid name, string expected",name) + return + end + if validrunners[name] then + report("invalid name, runner %a already defined") + return + end + local program=specification.program + if type(program)=="string" then + elseif type(program)=="table" then + program=program[platform] or program.default or program.unix + end + if type(program)~="string" or program=="" then + report("invalid runner %a specified for platform %a",name,platform) + return + end + local template=specification.template + if not template then + report("missing template for runner %a",name) + return + end + local method=specification.method or "execute" + local checkers=specification.checkers or {} + local defaults=specification.defaults or {} + local runner=runners[method] + if runner then + local finalized=finalized + local wrapped=function(variables) + return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) + end + validrunners[name]=wrapped + return wrapped + else + validrunners[name]=nil + report("invalid method for runner %a",name) + end end function sandbox.getrunner(name) - return name and validrunners[name] + return name and validrunners[name] end local function suspicious(str) - return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false + return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false end local function binaryrunner(action,command,...) - if validbinaries==false then - report("no binaries permitted, ignoring command: %s",command) - return - end - if type(command)~="string" then - report("command should be a string") - return - end - local program=lpegmatch(p_split,command) - if not program or program=="" then - report("unable to filter binary from command: %s",command) - return - end - if validbinaries==true then - elseif not validbinaries[program] then - report("binary not permitted, ignoring command: %s",command) - return - elseif suspicious(command) then - report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) - return - end - return action(command,...) + if validbinaries==false then + report("no binaries permitted, ignoring command: %s",command) + return + end + if type(command)~="string" then + report("command should be a string") + return + end + local program=lpegmatch(p_split,command) + if not program or program=="" then + report("unable to filter binary from command: %s",command) + return + end + if validbinaries==true then + elseif not validbinaries[program] then + report("binary not permitted, ignoring command: %s",command) + return + elseif suspicious(command) then + report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) + return + end + return action(command,...) end local function dummyrunner(action,command,...) - if type(command)=="table" then - command=concat(command," ",command[0] and 0 or 1) - end - report("ignoring command: %s",command) + if type(command)=="table" then + command=concat(command," ",command[0] and 0 or 1) + end + report("ignoring command: %s",command) end sandbox.filehandlerone=filehandlerone sandbox.filehandlertwo=filehandlertwo sandbox.iohandler=iohandler function sandbox.disablerunners() - validbinaries=false + validbinaries=false end function sandbox.disablelibraries() - validlibraries=false + validlibraries=false end if FFISUPPORTED and ffi then - function sandbox.disablelibraries() - validlibraries=false - for k,v in next,ffi do - if k~="gc" then - ffi[k]=nil - end - end + function sandbox.disablelibraries() + validlibraries=false + for k,v in next,ffi do + if k~="gc" then + ffi[k]=nil + end end - local fiiload=ffi.load - if fiiload then - local reported={} - function ffi.load(name,...) - if validlibraries==false then - elseif validlibraries==true then - return fiiload(name,...) - elseif validlibraries[nameonly(name)] then - return fiiload(name,...) - else - end - if not reported[name] then - report("using library %a is not permitted",name) - reported[name]=true - end - return nil - end + end + local fiiload=ffi.load + if fiiload then + local reported={} + function ffi.load(name,...) + if validlibraries==false then + elseif validlibraries==true then + return fiiload(name,...) + elseif validlibraries[nameonly(name)] then + return fiiload(name,...) + else + end + if not reported[name] then + report("using library %a is not permitted",name) + reported[name]=true + end + return nil end + end end local overload=sandbox.overload local register=sandbox.register - overload(loadfile,filehandlerone,"loadfile") + overload(loadfile,filehandlerone,"loadfile") if io then - overload(io.open,filehandlerone,"io.open") - overload(io.popen,binaryrunner,"io.popen") - overload(io.input,iohandler,"io.input") - overload(io.output,iohandler,"io.output") - overload(io.lines,filehandlerone,"io.lines") + overload(io.open,filehandlerone,"io.open") + overload(io.popen,binaryrunner,"io.popen") + overload(io.input,iohandler,"io.input") + overload(io.output,iohandler,"io.output") + overload(io.lines,filehandlerone,"io.lines") end if os then - overload(os.execute,binaryrunner,"os.execute") - overload(os.spawn,dummyrunner,"os.spawn") - overload(os.exec,dummyrunner,"os.exec") - overload(os.resultof,binaryrunner,"os.resultof") - overload(os.pipeto,binaryrunner,"os.pipeto") - overload(os.rename,filehandlertwo,"os.rename") - overload(os.remove,filehandlerone,"os.remove") + overload(os.execute,binaryrunner,"os.execute") + overload(os.spawn,dummyrunner,"os.spawn") + overload(os.exec,dummyrunner,"os.exec") + overload(os.resultof,binaryrunner,"os.resultof") + overload(os.pipeto,binaryrunner,"os.pipeto") + overload(os.rename,filehandlertwo,"os.rename") + overload(os.remove,filehandlerone,"os.remove") end if lfs then - overload(lfs.chdir,filehandlerone,"lfs.chdir") - overload(lfs.mkdir,filehandlerone,"lfs.mkdir") - overload(lfs.rmdir,filehandlerone,"lfs.rmdir") - overload(lfs.isfile,filehandlerone,"lfs.isfile") - overload(lfs.isdir,filehandlerone,"lfs.isdir") - overload(lfs.attributes,filehandlerone,"lfs.attributes") - overload(lfs.dir,filehandlerone,"lfs.dir") - overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") - overload(lfs.touch,filehandlerone,"lfs.touch") - overload(lfs.link,filehandlertwo,"lfs.link") - overload(lfs.setmode,filehandlerone,"lfs.setmode") - overload(lfs.readlink,filehandlerone,"lfs.readlink") - overload(lfs.shortname,filehandlerone,"lfs.shortname") - overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") + overload(lfs.chdir,filehandlerone,"lfs.chdir") + overload(lfs.mkdir,filehandlerone,"lfs.mkdir") + overload(lfs.rmdir,filehandlerone,"lfs.rmdir") + overload(lfs.isfile,filehandlerone,"lfs.isfile") + overload(lfs.isdir,filehandlerone,"lfs.isdir") + overload(lfs.attributes,filehandlerone,"lfs.attributes") + overload(lfs.dir,filehandlerone,"lfs.dir") + overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") + overload(lfs.touch,filehandlerone,"lfs.touch") + overload(lfs.link,filehandlertwo,"lfs.link") + overload(lfs.setmode,filehandlerone,"lfs.setmode") + overload(lfs.readlink,filehandlerone,"lfs.readlink") + overload(lfs.shortname,filehandlerone,"lfs.shortname") + overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") end if zip then - zip.open=register(zip.open,filehandlerone,"zip.open") + zip.open=register(zip.open,filehandlerone,"zip.open") end if fontloader then - fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") - fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") + fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") + fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") end if epdf then - epdf.open=register(epdf.open,filehandlerone,"epdf.open") + epdf.open=register(epdf.open,filehandlerone,"epdf.open") end sandbox.registerroot=registerroot sandbox.registerbinary=registerbinary @@ -11585,14 +15044,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-mrg"] = package.loaded["util-mrg"] or true --- original size: 7757, stripped down to: 6015 +-- original size: 7819, stripped down to: 5881 if not modules then modules={} end modules ['util-mrg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gsub,format=string.gsub,string.format local concat=table.concat @@ -11620,19 +15079,19 @@ local m_report=[[ ]] local m_preloaded=[[package.loaded[%q] = package.loaded[%q] or true]] local function self_fake() - return m_faked + return m_faked end local function self_nothing() - return "" + return "" end local function self_load(name) - local data=io.loaddata(name) or "" - if data=="" then - report("unknown file %a",name) - else - report("inserting file %a",name) - end - return data or "" + local data=io.loaddata(name) or "" + if data=="" then + report("unknown file %a",name) + else + report("inserting file %a",name) + end + return data or "" end local space=patterns.space local eol=patterns.newline @@ -11661,98 +15120,99 @@ local mandatespacing=(eol+space)^1/"" local pack=digit*space^1*operator4*optionalspacing+optionalspacing*operator1*optionalspacing+optionalspacing*operator2*optionalspaces+mandatespacing*operator3*mandatespaces+optionalspaces*separator*optionalspaces local lines=emptyline^2/"\n" local spaces=(space*space)/" " +local spaces=(space*space*space*space)/" " local compact=Cs (( - ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 + ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 )^1 ) local strip=Cs((emptyline^2/"\n"+1)^0) local stripreturn=Cs((1-P("return")*space^1*P(1-space-eol)^1*(space+eol)^0*P(-1))^1) function merger.compact(data) - return lpegmatch(strip,lpegmatch(compact,data)) + return lpegmatch(strip,lpegmatch(compact,data)) end local function self_compact(data) - local delta=0 - if merger.strip_comment then - local before=#data - data=lpegmatch(compact,data) - data=lpegmatch(strip,data) - local after=#data - delta=before-after - report("original size %s, compacted to %s, stripped %s",before,after,delta) - data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) - end - return lpegmatch(stripreturn,data) or data,delta + local delta=0 + if merger.strip_comment then + local before=#data + data=lpegmatch(compact,data) + data=lpegmatch(strip,data) + local after=#data + delta=before-after + report("original size %s, compacted to %s, stripped %s",before,after,delta) + data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) + end + return lpegmatch(stripreturn,data) or data,delta end local function self_save(name,data) - if data~="" then - io.savedata(name,data) - report("saving %s with size %s",name,#data) - end + if data~="" then + io.savedata(name,data) + report("saving %s with size %s",name,#data) + end end local function self_swap(data,code) - return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" + return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" end local function self_libs(libs,list) - local result,f,frozen,foundpath={},nil,false,nil - result[#result+1]="\n" - if type(libs)=='string' then libs={ libs } end - if type(list)=='string' then list={ list } end + local result,f,frozen,foundpath={},nil,false,nil + result[#result+1]="\n" + if type(libs)=='string' then libs={ libs } end + if type(list)=='string' then list={ list } end + for i=1,#libs do + local lib=libs[i] + for j=1,#list do + local pth=gsub(list[j],"\\","/") + report("checking library path %a",pth) + local name=pth.."/"..lib + if lfs.isfile(name) then + foundpath=pth + end + end + if foundpath then break end + end + if foundpath then + report("using library path %a",foundpath) + local right,wrong,original,stripped={},{},0,0 for i=1,#libs do - local lib=libs[i] - for j=1,#list do - local pth=gsub(list[j],"\\","/") - report("checking library path %a",pth) - local name=pth.."/"..lib - if lfs.isfile(name) then - foundpath=pth - end - end - if foundpath then break end - end - if foundpath then - report("using library path %a",foundpath) - local right,wrong,original,stripped={},{},0,0 - for i=1,#libs do - local lib=libs[i] - local fullname=foundpath.."/"..lib - if lfs.isfile(fullname) then - report("using library %a",fullname) - local preloaded=file.nameonly(lib) - local data=io.loaddata(fullname,true) - original=original+#data - local data,delta=self_compact(data) - right[#right+1]=lib - result[#result+1]=m_begin_closure - result[#result+1]=format(m_preloaded,preloaded,preloaded) - result[#result+1]=data - result[#result+1]=m_end_closure - stripped=stripped+delta - else - report("skipping library %a",fullname) - wrong[#wrong+1]=lib - end - end - right=#right>0 and concat(right," ") or "-" - wrong=#wrong>0 and concat(wrong," ") or "-" - report("used libraries: %a",right) - report("skipped libraries: %a",wrong) - report("original bytes: %a",original) - report("stripped bytes: %a",stripped) - result[#result+1]=format(m_report,right,wrong,original,stripped) - else - report("no valid library path found") + local lib=libs[i] + local fullname=foundpath.."/"..lib + if lfs.isfile(fullname) then + report("using library %a",fullname) + local preloaded=file.nameonly(lib) + local data=io.loaddata(fullname,true) + original=original+#data + local data,delta=self_compact(data) + right[#right+1]=lib + result[#result+1]=m_begin_closure + result[#result+1]=format(m_preloaded,preloaded,preloaded) + result[#result+1]=data + result[#result+1]=m_end_closure + stripped=stripped+delta + else + report("skipping library %a",fullname) + wrong[#wrong+1]=lib + end end - return concat(result,"\n\n") + right=#right>0 and concat(right," ") or "-" + wrong=#wrong>0 and concat(wrong," ") or "-" + report("used libraries: %a",right) + report("skipped libraries: %a",wrong) + report("original bytes: %a",original) + report("stripped bytes: %a",stripped) + result[#result+1]=format(m_report,right,wrong,original,stripped) + else + report("no valid library path found") + end + return concat(result,"\n\n") end function merger.selfcreate(libs,list,target) - if target then - self_save(target,self_swap(self_fake(),self_libs(libs,list))) - end + if target then + self_save(target,self_swap(self_fake(),self_libs(libs,list))) + end end function merger.selfmerge(name,libs,list,target) - self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) + self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) end function merger.selfclean(name) - self_save(name,self_swap(self_load(name),self_nothing())) + self_save(name,self_swap(self_load(name),self_nothing())) end @@ -11762,14 +15222,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 9400, stripped down to: 5499 +-- original size: 9738, stripped down to: 5531 if not modules then modules={} end modules ['util-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find @@ -11781,178 +15241,193 @@ local setlocale=os.setlocale setlocale(nil,nil) local report=logs.reporter("system") function os.setlocale(a,b) - if a or b then - if report then - report() - report("You're messing with os.locale in a supposedly locale neutral enviroment. From") - report("now on are on your own and without support. Crashes or unexpected side effects") - report("can happen but don't bother the luatex and context developer team with it.") - report() - report=nil - end - setlocale(a,b) - end + if a or b then + if report then + report() + report("You're messing with os.locale in a supposedly locale neutral enviroment. From") + report("now on are on your own and without support. Crashes or unexpected side effects") + report("can happen but don't bother the luatex and context developer team with it.") + report() + report=nil + end + setlocale(a,b) + end end local validengines=allocate { - ["luatex"]=true, - ["luajittex"]=true, + ["luatex"]=true, + ["luajittex"]=true, } local basicengines=allocate { - ["luatex"]="luatex", - ["texlua"]="luatex", - ["texluac"]="luatex", - ["luajittex"]="luajittex", - ["texluajit"]="luajittex", + ["luatex"]="luatex", + ["texlua"]="luatex", + ["texluac"]="luatex", + ["luajittex"]="luajittex", + ["texluajit"]="luajittex", } local luaengines=allocate { - ["lua"]=true, - ["luajit"]=true, + ["lua"]=true, + ["luajit"]=true, } environment.validengines=validengines environment.basicengines=basicengines if not arg then - environment.used_as_library=true + environment.used_as_library=true elseif luaengines[file.removesuffix(arg[-1])] then elseif validengines[file.removesuffix(arg[0])] then - if arg[1]=="--luaonly" then - arg[-1]=arg[0] - arg[ 0]=arg[2] - for k=3,#arg do - arg[k-2]=arg[k] - end - remove(arg) - remove(arg) - else - end - local originalzero=file.basename(arg[0]) - local specialmapping={ luatools=="base" } - if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then + if arg[1]=="--luaonly" then + arg[-1]=arg[0] + arg[ 0]=arg[2] + for k=3,#arg do + arg[k-2]=arg[k] + end + remove(arg) + remove(arg) + else + end + local originalzero=file.basename(arg[0]) + local specialmapping={ luatools=="base" } + if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then arg[0]=specialmapping[originalzero] or originalzero insert(arg,0,"--script") insert(arg,0,"mtxrun") - end + end end environment.arguments=allocate() environment.files=allocate() environment.sortedflags=nil function environment.initializearguments(arg) - local arguments,files={},{} - environment.arguments,environment.files,environment.sortedflags=arguments,files,nil - for index=1,#arg do - local argument=arg[index] - if index>0 then - local flag,value=match(argument,"^%-+(.-)=(.-)$") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=unquoted(value or "") - else - flag=match(argument,"^%-+(.+)") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=true - else - files[#files+1]=argument - end - end + local arguments={} + local files={} + environment.arguments=arguments + environment.files=files + environment.sortedflags=nil + for index=1,#arg do + local argument=arg[index] + if index>0 then + local flag,value=match(argument,"^%-+(.-)=(.-)$") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=unquoted(value or "") + else + flag=match(argument,"^%-+(.+)") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=true + else + files[#files+1]=argument end + end + end + end + if not environment.ownname then + if os.selfpath and os.selfname then + environment.ownname=file.addsuffix(file.join(os.selfpath,os.selfname),"lua") end - environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') + end + environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') end function environment.setargument(name,value) - environment.arguments[name]=value + environment.arguments[name]=value end function environment.getargument(name,partial) - local arguments,sortedflags=environment.arguments,environment.sortedflags - if arguments[name] then - return arguments[name] - elseif partial then - if not sortedflags then - sortedflags=allocate(table.sortedkeys(arguments)) - for k=1,#sortedflags do - sortedflags[k]="^"..sortedflags[k] - end - environment.sortedflags=sortedflags - end - for k=1,#sortedflags do - local v=sortedflags[k] - if find(name,v) then - return arguments[sub(v,2,#v)] - end - end + local arguments,sortedflags=environment.arguments,environment.sortedflags + if arguments[name] then + return arguments[name] + elseif partial then + if not sortedflags then + sortedflags=allocate(table.sortedkeys(arguments)) + for k=1,#sortedflags do + sortedflags[k]="^"..sortedflags[k] + end + environment.sortedflags=sortedflags end - return nil + for k=1,#sortedflags do + local v=sortedflags[k] + if find(name,v) then + return arguments[sub(v,2,#v)] + end + end + end + return nil end environment.argument=environment.getargument function environment.splitarguments(separator) - local done,before,after=false,{},{} - local originalarguments=environment.originalarguments - for k=1,#originalarguments do - local v=originalarguments[k] - if not done and v==separator then - done=true - elseif done then - after[#after+1]=v - else - before[#before+1]=v - end + local done,before,after=false,{},{} + local originalarguments=environment.originalarguments + for k=1,#originalarguments do + local v=originalarguments[k] + if not done and v==separator then + done=true + elseif done then + after[#after+1]=v + else + before[#before+1]=v end - return before,after + end + return before,after end function environment.reconstructcommandline(arg,noquote) - local resolveprefix=resolvers.resolve - arg=arg or environment.originalarguments - if noquote and #arg==1 then - return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) - elseif #arg>0 then - local result={} - for i=1,#arg do - result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) - end - return concat(result," ") - else - return "" + local resolveprefix=resolvers.resolve + arg=arg or environment.originalarguments + if noquote and #arg==1 then + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) + elseif #arg>0 then + local result={} + for i=1,#arg do + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end + return concat(result," ") + else + return "" + end end function environment.relativepath(path,root) - if not path then - path="" + if not path then + path="" + end + if not file.is_rootbased_path(path) then + if not root then + root=file.pathpart(environment.ownscript or environment.ownname or ".") end - if not file.is_rootbased_path(path) then - if not root then - root=file.pathpart(environment.ownscript or environment.ownname or ".") - end - if root=="" then - root="." - end - path=root.."/"..path + if root=="" then + root="." end - return file.collapsepath(path,true) + path=root.."/"..path + end + return file.collapsepath(path,true) end if arg then - local newarg,instring={},false - for index=1,#arg do - local argument=arg[index] - if find(argument,"^\"") then - newarg[#newarg+1]=gsub(argument,"^\"","") - if not find(argument,"\"$") then - instring=true - end - elseif find(argument,"\"$") then - newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") - instring=false - elseif instring then - newarg[#newarg]=newarg[#newarg].." "..argument - else - newarg[#newarg+1]=argument - end - end - for i=1,-5,-1 do - newarg[i]=arg[i] + local newarg,instring={},false + for index=1,#arg do + local argument=arg[index] + if find(argument,"^\"") then + if find(argument,"\"$") then + newarg[#newarg+1]=gsub(argument,"^\"(.-)\"$","%1") + instring=false + else + newarg[#newarg+1]=gsub(argument,"^\"","") + instring=true + end + elseif find(argument,"\"$") then + if instring then + newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") + instring=false + else + newarg[#newarg+1]=argument + end + elseif instring then + newarg[#newarg]=newarg[#newarg].." "..argument + else + newarg[#newarg+1]=argument end - environment.initializearguments(newarg) - environment.originalarguments=mark(newarg) - environment.rawarguments=mark(arg) - arg={} + end + for i=1,-5,-1 do + newarg[i]=arg[i] + end + environment.initializearguments(newarg) + environment.originalarguments=mark(newarg) + environment.rawarguments=mark(arg) + arg={} end @@ -11962,17 +15437,18 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-env"] = package.loaded["luat-env"] or true --- original size: 5820, stripped down to: 4155 +-- original size: 6134, stripped down to: 4118 if not modules then modules={} end modules ['luat-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local rawset,rawget,loadfile,assert=rawset,rawget,loadfile,assert -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local rawset,rawget,loadfile=rawset,rawget,loadfile +local gsub=string.gsub +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_lua=logs.reporter("resolvers","lua") local luautilities=utilities.lua local luasuffixes=luautilities.suffixes @@ -11980,133 +15456,146 @@ local texgettoks=tex and tex.gettoks environment=environment or {} local environment=environment local mt={ - __index=function(_,k) - if k=="version" then - local version=texgettoks and texgettoks("contextversiontoks") - if version and version~="" then - rawset(environment,"version",version) - return version - else - return "unknown" - end - elseif k=="kind" then - local kind=texgettoks and texgettoks("contextkindtoks") - if kind and kind~="" then - rawset(environment,"kind",kind) - return kind - else - return "unknown" - end - elseif k=="jobname" or k=="formatname" then - local name=tex and tex[k] - if name or name=="" then - rawset(environment,k,name) - return name - else - return "unknown" - end - elseif k=="outputfilename" then - local name=environment.jobname - rawset(environment,k,name) - return name - end + __index=function(_,k) + if k=="version" then + local version=texgettoks and texgettoks("contextversiontoks") + if version and version~="" then + rawset(environment,"version",version) + return version + else + return "unknown" + end + elseif k=="kind" then + local kind=texgettoks and texgettoks("contextkindtoks") + if kind and kind~="" then + rawset(environment,"kind",kind) + return kind + else + return "unknown" + end + elseif k=="jobname" or k=="formatname" then + local name=tex and tex[k] + if name or name=="" then + rawset(environment,k,name) + return name + else + return "unknown" + end + elseif k=="outputfilename" then + local name=environment.jobname + rawset(environment,k,name) + return name end + end } setmetatable(environment,mt) function environment.texfile(filename) - return resolvers.findfile(filename,'tex') + return resolvers.findfile(filename,'tex') end function environment.luafile(filename) - local resolved=resolvers.findfile(filename,'tex') or "" - if resolved~="" then - return resolved - end - resolved=resolvers.findfile(filename,'texmfscripts') or "" - if resolved~="" then - return resolved - end - return resolvers.findfile(filename,'luatexlibs') or "" -end -local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) + local resolved=resolvers.findfile(filename,'tex') or "" + if resolved~="" then + return resolved + end + resolved=resolvers.findfile(filename,'texmfscripts') or "" + if resolved~="" then + return resolved + end + return resolvers.findfile(filename,'luatexlibs') or "" +end +local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) local function strippable(filename) - if stripindeed then - local modu=modules[file.nameonly(filename)] - return modu and modu.dataonly - else - return false - end + if stripindeed then + local modu=modules[file.nameonly(filename)] + return modu and modu.dataonly + else + return false + end end function environment.luafilechunk(filename,silent,macros) - filename=file.replacesuffix(filename,"lua") - local fullname=environment.luafile(filename) - if fullname and fullname~="" then - local data=luautilities.loadedluacode(fullname,strippable,filename,macros) - if not silent then - report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") - end - return data - else - if not silent then - report_lua("unknown file %a",filename) - end - return nil + filename=file.replacesuffix(filename,"lua") + local fullname=environment.luafile(filename) + if fullname and fullname~="" then + local data=luautilities.loadedluacode(fullname,strippable,filename,macros) + if not silent then + report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") + end + return data + else + if not silent then + report_lua("unknown file %a",filename) end + return nil + end end function environment.loadluafile(filename,version) - local lucname,luaname,chunk - local basename=file.removesuffix(filename) - if basename==filename then - luaname=file.addsuffix(basename,luasuffixes.lua) - lucname=file.addsuffix(basename,luasuffixes.luc) - else - luaname=basename - lucname=nil - end - local fullname=(lucname and environment.luafile(lucname)) or "" - if fullname~="" then + local lucname,luaname,chunk + local basename=file.removesuffix(filename) + if basename==filename then + luaname=file.addsuffix(basename,luasuffixes.lua) + lucname=file.addsuffix(basename,luasuffixes.luc) + else + luaname=filename + lucname=nil + end + local fullname=(lucname and environment.luafile(lucname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) + end + chunk=loadfile(fullname) + end + if chunk then + chunk() + if version then + local v=version + if modules and modules[filename] then + v=modules[filename].version + elseif versions and versions[filename] then + v=versions[filename] + end + if v==version then + return true + else if trace_locating then - report_lua("loading %a",fullname) + report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) end - chunk=loadfile(fullname) + environment.loadluafile(filename) + end + else + return true end - if chunk then - assert(chunk)() - if version then - local v=version - if modules and modules[filename] then - v=modules[filename].version - elseif versions and versions[filename] then - v=versions[filename] - end - if v==version then - return true - else - if trace_locating then - report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) - end - environment.loadluafile(filename) - end - else - return true - end + end + fullname=(luaname and environment.luafile(luaname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) end - fullname=(luaname and environment.luafile(luaname)) or "" - if fullname~="" then - if trace_locating then - report_lua("loading %a",fullname) - end - chunk=loadfile(fullname) - if not chunk then - if trace_locating then - report_lua("unknown file %a",filename) - end - else - assert(chunk)() - return true - end + chunk=loadfile(fullname) + if not chunk then + if trace_locating then + report_lua("unknown file %a",filename) + end + else + chunk() + return true end - return false + end + return false end +environment.filenames=setmetatable({},{ + __index=function(t,k) + local v=environment.files[k] + if v then + return (gsub(v,"%.+$","")) + end + end, + __newindex=function(t,k) + end, + __len=function(t) + return #environment.files + end, +} ) end -- of closure @@ -12115,16 +15604,16 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true --- original size: 60383, stripped down to: 38562 +-- original size: 60383, stripped down to: 35698 if not modules then modules={} end modules ['lxml-tab']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_entities=false trackers.register("xml.entities",function(v) trace_entities=v end) +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 {} @@ -12142,17 +15631,17 @@ xml.xmlns=xml.xmlns or {} local check=P(false) local parse=check function xml.registerns(namespace,pattern) - check=check+C(P(lower(pattern)))/namespace - parse=P { P(check)+1*V(1) } + check=check+C(P(lower(pattern)))/namespace + parse=P { P(check)+1*V(1) } end function xml.checkns(namespace,url) - local ns=lpegmatch(parse,lower(url)) - if ns and namespace~=ns then - xml.xmlns[namespace]=ns - end + local ns=lpegmatch(parse,lower(url)) + if ns and namespace~=ns then + xml.xmlns[namespace]=ns + end end function xml.resolvens(url) - return lpegmatch(parse,lower(url)) or "" + return lpegmatch(parse,lower(url)) or "" end end local nsremap,resolvens=xml.xmlns,xml.resolvens @@ -12170,661 +15659,661 @@ local handle_dec_entity local handle_any_entity_dtd local handle_any_entity_text local function preparexmlstate(settings) - if settings then - linenumbers=settings.linenumbers - stack={} - level=0 - top={} - at={} - mt={} - dt={} - nt=0 - xmlns={} - errorstr=nil - strip=settings.strip_cm_and_dt - utfize=settings.utfize_entities - resolve=settings.resolve_entities - resolve_predefined=settings.resolve_predefined_entities - unify_predefined=settings.unify_predefined_entities - cleanup=settings.text_cleanup - entities=settings.entities or {} - currentfilename=settings.currentresource - currentline=1 - parameters={} - reported_at_errors={} - dcache={} - hcache={} - acache={} - if utfize==nil then - settings.utfize_entities=true - utfize=true - end - if resolve_predefined==nil then - settings.resolve_predefined_entities=true - resolve_predefined=true - end - else - linenumbers=false - stack=nil - level=nil - top=nil - at=nil - mt=nil - dt=nil - nt=nil - xmlns=nil - errorstr=nil - strip=nil - utfize=nil - resolve=nil - resolve_predefined=nil - unify_predefined=nil - cleanup=nil - entities=nil - parameters=nil - reported_at_errors=nil - dcache=nil - hcache=nil - acache=nil - currentfilename=nil - currentline=1 - end + if settings then + linenumbers=settings.linenumbers + stack={} + level=0 + top={} + at={} + mt={} + dt={} + nt=0 + xmlns={} + errorstr=nil + strip=settings.strip_cm_and_dt + utfize=settings.utfize_entities + resolve=settings.resolve_entities + resolve_predefined=settings.resolve_predefined_entities + unify_predefined=settings.unify_predefined_entities + cleanup=settings.text_cleanup + entities=settings.entities or {} + currentfilename=settings.currentresource + currentline=1 + parameters={} + reported_at_errors={} + dcache={} + hcache={} + acache={} + if utfize==nil then + settings.utfize_entities=true + utfize=true + end + if resolve_predefined==nil then + settings.resolve_predefined_entities=true + resolve_predefined=true + end + else + linenumbers=false + stack=nil + level=nil + top=nil + at=nil + mt=nil + dt=nil + nt=nil + xmlns=nil + errorstr=nil + strip=nil + utfize=nil + resolve=nil + resolve_predefined=nil + unify_predefined=nil + cleanup=nil + entities=nil + parameters=nil + reported_at_errors=nil + dcache=nil + hcache=nil + acache=nil + currentfilename=nil + currentline=1 + end end local function initialize_mt(root) - mt={ __index=root } + mt={ __index=root } end function xml.setproperty(root,k,v) - getmetatable(root).__index[k]=v + getmetatable(root).__index[k]=v end function xml.checkerror(top,toclose) - return "" + return "" end local checkns=xml.checkns local function add_attribute(namespace,tag,value) - if cleanup and value~="" then - value=cleanup(value) - end - if tag=="xmlns" then - xmlns[#xmlns+1]=resolvens(value) - at[tag]=value - elseif namespace=="" then - at[tag]=value - elseif namespace=="xmlns" then - checkns(tag,value) - at["xmlns:"..tag]=value - else - at[namespace..":"..tag]=value - end + if cleanup and value~="" then + value=cleanup(value) + end + if tag=="xmlns" then + xmlns[#xmlns+1]=resolvens(value) + at[tag]=value + elseif namespace=="" then + at[tag]=value + elseif namespace=="xmlns" then + checkns(tag,value) + at["xmlns:"..tag]=value + else + at[namespace..":"..tag]=value + end end local function add_empty(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - top=stack[level] - dt=top.dt - nt=#dt+1 - local t=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - cf=currentfilename, - cl=currentline, - __p__=top, - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - __p__=top, - } - dt[nt]=t - setmetatable(t,mt) - if at.xmlns then - remove(xmlns) - end - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + top=stack[level] + dt=top.dt + nt=#dt+1 + local t=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + cf=currentfilename, + cl=currentline, + __p__=top, + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + __p__=top, + } + dt[nt]=t + setmetatable(t,mt) + if at.xmlns then + remove(xmlns) + end + at={} end local function add_begin(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - dt={} - top=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - cf=currentfilename, - cl=currentline, - __p__=stack[level], - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - __p__=stack[level], - } - setmetatable(top,mt) - nt=0 - level=level+1 - stack[level]=top - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + dt={} + top=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + cf=currentfilename, + cl=currentline, + __p__=stack[level], + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + __p__=stack[level], + } + setmetatable(top,mt) + nt=0 + level=level+1 + stack[level]=top + at={} end local function add_end(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local toclose=stack[level] - level=level-1 - top=stack[level] - if level<1 then - errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - elseif toclose.tg~=tag then - errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - end - dt=top.dt - nt=#dt+1 - dt[nt]=toclose - toclose.ni=nt - if toclose.at.xmlns then - remove(xmlns) - end + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local toclose=stack[level] + level=level-1 + top=stack[level] + if level<1 then + errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + elseif toclose.tg~=tag then + errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + end + dt=top.dt + nt=#dt+1 + dt[nt]=toclose + toclose.ni=nt + if toclose.at.xmlns then + remove(xmlns) + end end local function add_text(text) - if text=="" then - return - end - if cleanup then - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..cleanup(text) - else - nt=nt+1 - dt[nt]=cleanup(text) - end - else - nt=1 - dt[1]=cleanup(text) - end + if text=="" then + return + end + if cleanup then + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..cleanup(text) + else + nt=nt+1 + dt[nt]=cleanup(text) + end else - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..text - else - nt=nt+1 - dt[nt]=text - end - else - nt=1 - dt[1]=text - end + nt=1 + dt[1]=cleanup(text) end -end -local function add_special(what,spacing,text) - if spacing~="" then + else + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..text + else nt=nt+1 - dt[nt]=spacing - end - if strip and (what=="@cm@" or what=="@dt@") then + dt[nt]=text + end else - nt=nt+1 - dt[nt]=linenumbers and { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - cf=currentfilename, - cl=currentline, - } or { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - } + nt=1 + dt[1]=text end + end +end +local function add_special(what,spacing,text) + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + if strip and (what=="@cm@" or what=="@dt@") then + else + nt=nt+1 + dt[nt]=linenumbers and { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + cf=currentfilename, + cl=currentline, + } or { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + } + end end local function set_message(txt) - errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") + errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") end local function attribute_value_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute value %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute value %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end local function attribute_specification_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute specification %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute specification %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end do - local badentity="&" - xml.placeholders={ - unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, - unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, - unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, - } - local function fromhex(s) - local n=tonumber(s,16) - if n then - return utfchar(n) - else - return formatters["h:%s"](s),true + local badentity="&" + xml.placeholders={ + unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, + unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, + unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, + } + local function fromhex(s) + local n=tonumber(s,16) + if n then + return utfchar(n) + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return utfchar(n) + else + return formatters["d:%s"](s),true + end + end + local p_rest=(1-P(";"))^0 + local p_many=P(1)^0 + local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) + xml.parsedentitylpeg=parsedentity + local predefined_unified={ + [38]="&", + [42]=""", + [47]="'", + [74]="<", + [76]=">", + } + local predefined_simplified={ + [38]="&",amp="&", + [42]='"',quot='"', + [47]="'",apos="'", + [74]="<",lt="<", + [76]=">",gt=">", + } + local nofprivates=0xF0000 + local privates_u={ + [ [[&]] ]="&", + [ [["]] ]=""", + [ [[']] ]="'", + [ [[<]] ]="<", + [ [[>]] ]=">", + } + local privates_p={ + } + local privates_s={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[&]] ]="&U+26;", + [ [[']] ]="&U+27;", + [ [[<]] ]="&U+3C;", + [ [[>]] ]="&U+3E;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_x={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[']] ]="&U+27;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_n={ + } + local escaped=utf.remapper(privates_u,"dynamic") + local unprivatized=utf.remapper(privates_p,"dynamic") + local unspecialized=utf.remapper(privates_s,"dynamic") + local despecialized=utf.remapper(privates_x,"dynamic") + xml.unprivatized=unprivatized + xml.unspecialized=unspecialized + xml.despecialized=despecialized + xml.escaped=escaped + local function unescaped(s) + local p=privates_n[s] + if not p then + nofprivates=nofprivates+1 + p=utfchar(nofprivates) + privates_n[s]=p + s="&"..s..";" + privates_u[p]=s + privates_p[p]=s + privates_s[p]=s + end + return p + end + xml.privatetoken=unescaped + xml.privatecodes=privates_n + xml.specialcodes=privates_s + function xml.addspecialcode(key,value) + privates_s[key]=value or "&"..s..";" + end + handle_hex_entity=function(str) + local h=hcache[str] + if not h then + local n=tonumber(str,16) + h=unify_predefined and predefined_unified[n] + if h then + if trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + elseif utfize then + h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" + if not n then + report_xml("utfize, ignoring hex entity &#x%s;",str) + elseif trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + else + if trace_entities then + report_xml("found entity &#x%s;",str) end + h="&#x"..str..";" + end + hcache[str]=h end - local function fromdec(s) - local n=tonumber(s) - if n then - return utfchar(n) - else - return formatters["d:%s"](s),true - end - end - local p_rest=(1-P(";"))^0 - local p_many=P(1)^0 - local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) - xml.parsedentitylpeg=parsedentity - local predefined_unified={ - [38]="&", - [42]=""", - [47]="'", - [74]="<", - [76]=">", - } - local predefined_simplified={ - [38]="&",amp="&", - [42]='"',quot='"', - [47]="'",apos="'", - [74]="<",lt="<", - [76]=">",gt=">", - } - local nofprivates=0xF0000 - local privates_u={ - [ [[&]] ]="&", - [ [["]] ]=""", - [ [[']] ]="'", - [ [[<]] ]="<", - [ [[>]] ]=">", - } - local privates_p={ - } - local privates_s={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[&]] ]="&U+26;", - [ [[']] ]="&U+27;", - [ [[<]] ]="&U+3C;", - [ [[>]] ]="&U+3E;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_x={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[']] ]="&U+27;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_n={ - } - local escaped=utf.remapper(privates_u,"dynamic") - local unprivatized=utf.remapper(privates_p,"dynamic") - local unspecialized=utf.remapper(privates_s,"dynamic") - local despecialized=utf.remapper(privates_x,"dynamic") - xml.unprivatized=unprivatized - xml.unspecialized=unspecialized - xml.despecialized=despecialized - xml.escaped=escaped - local function unescaped(s) - local p=privates_n[s] - if not p then - nofprivates=nofprivates+1 - p=utfchar(nofprivates) - privates_n[s]=p - s="&"..s..";" - privates_u[p]=s - privates_p[p]=s - privates_s[p]=s - end - return p - end - xml.privatetoken=unescaped - xml.privatecodes=privates_n - xml.specialcodes=privates_s - function xml.addspecialcode(key,value) - privates_s[key]=value or "&"..s..";" - end - handle_hex_entity=function(str) - local h=hcache[str] - if not h then - local n=tonumber(str,16) - h=unify_predefined and predefined_unified[n] - if h then - if trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - elseif utfize then - h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" - if not n then - report_xml("utfize, ignoring hex entity &#x%s;",str) - elseif trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - else - if trace_entities then - report_xml("found entity &#x%s;",str) - end - h="&#x"..str..";" - end - hcache[str]=h - end - return h - end - handle_dec_entity=function(str) - local d=dcache[str] - if not d then - local n=tonumber(str) - d=unify_predefined and predefined_unified[n] - if d then - if trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - elseif utfize then - d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" - if not n then - report_xml("utfize, ignoring dec entity &#%s;",str) - elseif trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - else - if trace_entities then - report_xml("found entity &#%s;",str) - end - d="&#"..str..";" - end - dcache[str]=d + return h + end + handle_dec_entity=function(str) + local d=dcache[str] + if not d then + local n=tonumber(str) + d=unify_predefined and predefined_unified[n] + if d then + if trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + elseif utfize then + d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" + if not n then + report_xml("utfize, ignoring dec entity &#%s;",str) + elseif trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + else + if trace_entities then + report_xml("found entity &#%s;",str) end - return d + d="&#"..str..";" + end + dcache[str]=d end - handle_any_entity_dtd=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end - end - return a + return d + end + handle_any_entity_dtd=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end - end - return a + a=entities[str] end - end - handle_any_entity_text=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(grammar_parsed_text_two,a) or a - if type(a)=="number" then - return "" - else - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - end - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) end - return a + a=a(str) or "" + end + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) end - return a - end - end - local p_rest=(1-P(";"))^1 - local spec={ - [0x23]="\\Ux{23}", - [0x24]="\\Ux{24}", - [0x25]="\\Ux{25}", - [0x5C]="\\Ux{5C}", - [0x7B]="\\Ux{7B}", - [0x7C]="\\Ux{7C}", - [0x7D]="\\Ux{7D}", - [0x7E]="\\Ux{7E}", - } - local hash=table.setmetatableindex(spec,function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] - else - return formatters["u:%s"](s),true + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end - end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] + end + return a + end + end + handle_any_entity_text=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - return formatters["d:%s"](s),true + a=entities[str] end - end - local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - local hash=table.setmetatableindex(function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) + end + a=a(str) or "" + end + a=lpegmatch(grammar_parsed_text_two,a) or a + if type(a)=="number" then + return "" + else + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end + end + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - return formatters["u:%s"](s),true + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) + end + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end + end + return a + end + end + local p_rest=(1-P(";"))^1 + local spec={ + [0x23]="\\Ux{23}", + [0x24]="\\Ux{24}", + [0x25]="\\Ux{25}", + [0x5C]="\\Ux{5C}", + [0x7B]="\\Ux{7B}", + [0x7C]="\\Ux{7C}", + [0x7D]="\\Ux{7D}", + [0x7E]="\\Ux{7E}", + } + local hash=table.setmetatableindex(spec,function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] - else - return formatters["d:%s"](s),true - end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true end - local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - xml.reparsedentitylpeg=reparsedentity - xml.unescapedentitylpeg=unescapedentity + end + local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + local hash=table.setmetatableindex(function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true + end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true + end + end + local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + xml.reparsedentitylpeg=reparsedentity + xml.unescapedentitylpeg=unescapedentity end local escaped=xml.escaped local unescaped=xml.unescaped local placeholders=xml.placeholders local function handle_end_entity(str) - report_xml("error in entity, %a found without ending %a",str,";") - return str + report_xml("error in entity, %a found without ending %a",str,";") + return str end local function handle_crap_error(chr) - report_xml("error in parsing, unexpected %a found ",chr) - add_text(chr) - return chr + report_xml("error in parsing, unexpected %a found ",chr) + add_text(chr) + return chr end local function handlenewline() - currentline=currentline+1 + currentline=currentline+1 end local spacetab=S(' \t') local space=S(' \r\n\t') @@ -12849,141 +16338,141 @@ local space_nl=spacetab+newline local spacing_nl=Cs((space_nl)^0) local anything_nl=newline+P(1) local function weirdentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","weird",k,v) - end - parameters[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","weird",k,v) + end + parameters[k]=v end local function normalentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","normal",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","normal",k,v) + end + entities[k]=v end local function systementity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","system",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","system",k,v) + end + entities[k]=v end local function publicentity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","public",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","public",k,v) + end + entities[k]=v end local function entityfile(pattern,k,v,n) - if n then - local okay,data - if resolvers then - okay,data=resolvers.loadbinfile(n) - else - data=io.loaddata(n) - okay=data and data~="" - end - if okay then - if trace_entities then - report_xml("loading public entities %a as %a from %a",k,v,n) - end - lpegmatch(pattern,data) - return - end + if n then + local okay,data + if resolvers then + okay,data=resolvers.loadbinfile(n) + else + data=io.loaddata(n) + okay=data and data~="" end - report_xml("ignoring public entities %a as %a from %a",k,v,n) + if okay then + if trace_entities then + report_xml("loading public entities %a as %a from %a",k,v,n) + end + lpegmatch(pattern,data) + return + end + end + report_xml("ignoring public entities %a as %a from %a",k,v,n) end local function install(spacenewline,spacing,anything) - local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 - local hexentitycontent=R("AF","af","09")^1 - local decentitycontent=R("09")^1 - local parsedentity=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_dtd) - local parsedentity_text=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_text) - local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local text_unparsed=Cs((anything-open)^1) - local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 - local somespace=(spacenewline)^1 - local optionalspace=(spacenewline)^0 - local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) - local endofattributes=slash*close+close - local whatever=space*name*optionalspace*equal - local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error - local attributevalue=value+wrongvalue - local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute - local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 - local parsedtext=text_parsed - local unparsedtext=text_unparsed/add_text - local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } - local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty - local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin - local endelement=(spacing*open*slash*name*optionalspace*close)/add_end - local begincomment=open*P("!--") - local endcomment=P("--")*close - local begininstruction=open*P("?") - local endinstruction=P("?")*close - local begincdata=open*P("![CDATA[") - local endcdata=P("]]")*close - local someinstruction=C((anything-endinstruction)^0) - local somecomment=C((anything-endcomment )^0) - local somecdata=C((anything-endcdata )^0) - local begindoctype=open*P("!DOCTYPE") - local enddoctype=close - local beginset=P("[") - local endset=P("]") - local wrdtypename=C((anything-somespace-P(";"))^1) - local doctypename=C((anything-somespace-close)^0) - local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close - local basiccomment=begincomment*((anything-endcomment)^0)*endcomment - local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity - local normalentitytype=(doctypename*somespace*value)/normalentity - local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity - local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity - local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close - local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) - entityfile(entitydoctype,...) - end - local function weirdresolve(s) - lpegmatch(entitydoctype,parameters[s]) - end - local function normalresolve(s) - lpegmatch(entitydoctype,entities[s]) - end - local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") - entitydoctype=entitydoctype+entityresolve - local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset - local definitiondoctype=doctypename*somespace*doctypeset - local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset - local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset - local simpledoctype=(anything-close)^1 - local somedoctype=C((somespace*( + local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 + local hexentitycontent=R("AF","af","09")^1 + local decentitycontent=R("09")^1 + local parsedentity=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_dtd) + local parsedentity_text=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_text) + local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local text_unparsed=Cs((anything-open)^1) + local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 + local somespace=(spacenewline)^1 + local optionalspace=(spacenewline)^0 + local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) + local endofattributes=slash*close+close + local whatever=space*name*optionalspace*equal + local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error + local attributevalue=value+wrongvalue + local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute + local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 + local parsedtext=text_parsed + local unparsedtext=text_unparsed/add_text + local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } + local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty + local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin + local endelement=(spacing*open*slash*name*optionalspace*close)/add_end + local begincomment=open*P("!--") + local endcomment=P("--")*close + local begininstruction=open*P("?") + local endinstruction=P("?")*close + local begincdata=open*P("![CDATA[") + local endcdata=P("]]")*close + local someinstruction=C((anything-endinstruction)^0) + local somecomment=C((anything-endcomment )^0) + local somecdata=C((anything-endcdata )^0) + local begindoctype=open*P("!DOCTYPE") + local enddoctype=close + local beginset=P("[") + local endset=P("]") + local wrdtypename=C((anything-somespace-P(";"))^1) + local doctypename=C((anything-somespace-close)^0) + local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close + local basiccomment=begincomment*((anything-endcomment)^0)*endcomment + local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity + local normalentitytype=(doctypename*somespace*value)/normalentity + local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity + local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity + local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close + local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) + entityfile(entitydoctype,...) + end + local function weirdresolve(s) + lpegmatch(entitydoctype,parameters[s]) + end + local function normalresolve(s) + lpegmatch(entitydoctype,entities[s]) + end + local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") + entitydoctype=entitydoctype+entityresolve + local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset + local definitiondoctype=doctypename*somespace*doctypeset + local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset + local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset + local simpledoctype=(anything-close)^1 + local somedoctype=C((somespace*( publicentityfile+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 - local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end - local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand - local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error - local trailer=space^0*(text_unparsed/set_message)^0 - local grammar_parsed_text_one=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, - } - local grammar_parsed_text_two=P { "followup", - followup=V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, - } - local grammar_unparsed_text=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, - } - return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text + 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 + local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end + local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand + local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error + local trailer=space^0*(text_unparsed/set_message)^0 + local grammar_parsed_text_one=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, + } + local grammar_parsed_text_two=P { "followup", + followup=V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, + } + local grammar_unparsed_text=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, + } + return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text end grammar_parsed_text_one_nop, grammar_parsed_text_two_nop, @@ -12992,576 +16481,576 @@ grammar_parsed_text_one_yes, grammar_parsed_text_two_yes, grammar_unparsed_text_yes=install(space_nl,spacing_nl,anything_nl) local function _xmlconvert_(data,settings,detail) - settings=settings or {} - preparexmlstate(settings) - if settings.linenumbers then - grammar_parsed_text_one=grammar_parsed_text_one_yes - grammar_parsed_text_two=grammar_parsed_text_two_yes - grammar_unparsed_text=grammar_unparsed_text_yes - else - grammar_parsed_text_one=grammar_parsed_text_one_nop - grammar_parsed_text_two=grammar_parsed_text_two_nop - grammar_unparsed_text=grammar_unparsed_text_nop - end - local preprocessor=settings.preprocessor - if data and data~="" and type(preprocessor)=="function" then - data=preprocessor(data,settings) or data + settings=settings or {} + preparexmlstate(settings) + if settings.linenumbers then + grammar_parsed_text_one=grammar_parsed_text_one_yes + grammar_parsed_text_two=grammar_parsed_text_two_yes + grammar_unparsed_text=grammar_unparsed_text_yes + else + grammar_parsed_text_one=grammar_parsed_text_one_nop + grammar_parsed_text_two=grammar_parsed_text_two_nop + grammar_unparsed_text=grammar_unparsed_text_nop + end + local preprocessor=settings.preprocessor + if data and data~="" and type(preprocessor)=="function" then + data=preprocessor(data,settings) or data + end + if settings.parent_root then + mt=getmetatable(settings.parent_root) + else + initialize_mt(top) + end + level=level+1 + stack[level]=top + top.dt={} + dt=top.dt + nt=0 + if not data or data=="" then + errorstr="empty xml file" + elseif data==true then + errorstr=detail or "problematic xml file" + elseif utfize or resolve then + local m=lpegmatch(grammar_parsed_text_one,data) + if m then + m=lpegmatch(grammar_parsed_text_two,data,m) end - if settings.parent_root then - mt=getmetatable(settings.parent_root) - else - initialize_mt(top) - end - level=level+1 - stack[level]=top - top.dt={} - dt=top.dt - nt=0 - if not data or data=="" then - errorstr="empty xml file" - elseif data==true then - errorstr=detail or "problematic xml file" - elseif utfize or resolve then - local m=lpegmatch(grammar_parsed_text_one,data) - if m then - m=lpegmatch(grammar_parsed_text_two,data,m) - end - if m then - else - errorstr="invalid xml file - parsed text" - end - elseif type(data)=="string" then - if lpegmatch(grammar_unparsed_text,data) then - errorstr="" - else - errorstr="invalid xml file - unparsed text" - end + if m then else - errorstr="invalid xml file - no text at all" - end - local result - if errorstr and errorstr~="" then - result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } - setmetatable(result,mt) - setmetatable(result.dt[1],mt) - setmetatable(stack,mt) - local errorhandler=settings.error_handler - if errorhandler==false then + errorstr="invalid xml file - parsed text" + end + elseif type(data)=="string" then + if lpegmatch(grammar_unparsed_text,data) then + errorstr="" + else + errorstr="invalid xml file - unparsed text" + end + else + errorstr="invalid xml file - no text at all" + end + local result + if errorstr and errorstr~="" then + result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } + setmetatable(result,mt) + setmetatable(result.dt[1],mt) + setmetatable(stack,mt) + local errorhandler=settings.error_handler + if errorhandler==false then + else + errorhandler=errorhandler or xml.errorhandler + if errorhandler then + local currentresource=settings.currentresource + if currentresource and currentresource~="" then + xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) else - errorhandler=errorhandler or xml.errorhandler - if errorhandler then - local currentresource=settings.currentresource - if currentresource and currentresource~="" then - xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) - else - xml.errorhandler(formatters["load error: %s"](errorstr)) - end - end - end - else - result=stack[1] - end - if not settings.no_root then - result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } - setmetatable(result,mt) - local rdt=result.dt - for k=1,#rdt do - local v=rdt[k] - if type(v)=="table" and not v.special then - result.ri=k - v.__p__=result - break - end + xml.errorhandler(formatters["load error: %s"](errorstr)) end + end end - if errorstr and errorstr~="" then - result.error=true - else - errorstr=nil - end - result.statistics={ - errormessage=errorstr, - entities={ - decimals=dcache, - hexadecimals=hcache, - names=acache, - intermediates=parameters, - } + else + result=stack[1] + end + if not settings.no_root then + result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } + setmetatable(result,mt) + local rdt=result.dt + for k=1,#rdt do + local v=rdt[k] + if type(v)=="table" and not v.special then + result.ri=k + v.__p__=result + break + end + end + end + if errorstr and errorstr~="" then + result.error=true + else + errorstr=nil + end + result.statistics={ + errormessage=errorstr, + entities={ + decimals=dcache, + hexadecimals=hcache, + names=acache, + intermediates=parameters, } - preparexmlstate() - return result + } + preparexmlstate() + return result end local function xmlconvert(data,settings) - local ok,result=pcall(function() return _xmlconvert_(data,settings) end) - if ok then - return result - elseif type(result)=="string" then - return _xmlconvert_(true,settings,result) - else - return _xmlconvert_(true,settings) - end + local ok,result=pcall(function() return _xmlconvert_(data,settings) end) + if ok then + return result + elseif type(result)=="string" then + return _xmlconvert_(true,settings,result) + else + return _xmlconvert_(true,settings) + end end xml.convert=xmlconvert function xml.inheritedconvert(data,xmldata) - local settings=xmldata.settings - if settings then - settings.parent_root=xmldata - end - local xc=xmlconvert(data,settings) - return xc + local settings=xmldata.settings + if settings then + settings.parent_root=xmldata + end + local xc=xmlconvert(data,settings) + return xc end function xml.is_valid(root) - return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er + return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er end function xml.package(tag,attributes,data) - local ns,tg=match(tag,"^(.-):?([^:]+)$") - local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } - setmetatable(t,mt) - return t + local ns,tg=match(tag,"^(.-):?([^:]+)$") + local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } + setmetatable(t,mt) + return t end function xml.is_valid(root) - return root and not root.error + return root and not root.error end xml.errorhandler=report_xml function xml.load(filename,settings) - local data="" - if type(filename)=="string" then - local f=io.open(filename,'r') - if f then - data=f:read("*all") - f:close() - end - elseif filename then - data=filename:read("*all") - end - if settings then - settings.currentresource=filename - local result=xmlconvert(data,settings) - settings.currentresource=nil - return result - else - return xmlconvert(data,{ currentresource=filename }) - end + local data="" + if type(filename)=="string" then + local f=io.open(filename,'r') + if f then + data=f:read("*all") + f:close() + end + elseif filename then + data=filename:read("*all") + end + if settings then + settings.currentresource=filename + local result=xmlconvert(data,settings) + settings.currentresource=nil + return result + else + return xmlconvert(data,{ currentresource=filename }) + end end local no_root={ no_root=true } function xml.toxml(data) - if type(data)=="string" then - local root={ xmlconvert(data,no_root) } - return (#root>1 and root) or root[1] - else - return data - end + if type(data)=="string" then + local root={ xmlconvert(data,no_root) } + return (#root>1 and root) or root[1] + else + return data + end end local function copy(old,p) - if old then - local new={} - for k,v in next,old do - local t=type(v)=="table" - if k=="at" then - local t={} - for k,v in next,v do - t[k]=v - end - new[k]=t - elseif k=="dt" then - v.__p__=nil - v=copy(v,new) - new[k]=v - v.__p__=p - else - new[k]=v - end - end - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + local t=type(v)=="table" + if k=="at" then + local t={} + for k,v in next,v do + t[k]=v + end + new[k]=t + elseif k=="dt" then + v.__p__=nil + v=copy(v,new) + new[k]=v + v.__p__=p + else + new[k]=v + end end + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end + return new + else + return {} + end end xml.copy=copy function xml.checkbom(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then - return - end - end - insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) - insert(dt,2,"\n" ) + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then + return + end end + insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) + insert(dt,2,"\n" ) + end end local f_attribute=formatters['%s=%q'] local function verbose_element(e,handlers,escape) - local handle=handlers.handle - local serialize=handlers.serialize - local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn - local ats=eat and next(eat) and {} - if ats then - local n=0 - for k in next,eat do - n=n+1 - ats[n]=k - end - if n==1 then - local k=ats[1] - ats=f_attribute(k,escaped(eat[k])) - else - sort(ats) - for i=1,n do - local k=ats[i] - ats[i]=f_attribute(k,escaped(eat[k])) - end - ats=concat(ats," ") - end - end - if ern and trace_entities and ern~=ens then - ens=ern + local handle=handlers.handle + local serialize=handlers.serialize + local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn + local ats=eat and next(eat) and {} + if ats then + local n=0 + for k in next,eat do + n=n+1 + ats[n]=k end - local n=edt and #edt - if ens~="" then - if n and n>0 then - if ats then - handle("<",ens,":",etg," ",ats,">") - else - handle("<",ens,":",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",ens,":",etg,">") + if n==1 then + local k=ats[1] + ats=f_attribute(k,escaped(eat[k])) + else + sort(ats) + for i=1,n do + local k=ats[i] + ats[i]=f_attribute(k,escaped(eat[k])) + end + ats=concat(ats," ") + end + end + if ern and trace_entities and ern~=ens then + ens=ern + end + local n=edt and #edt + if ens~="" then + if n and n>0 then + if ats then + handle("<",ens,":",etg," ",ats,">") + else + handle("<",ens,":",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",ens,":",etg," ",ats,"/>") - else - handle("<",ens,":",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",ens,":",etg,">") else - if n and n>0 then - if ats then - handle("<",etg," ",ats,">") - else - handle("<",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",etg,">") + if ats then + handle("<",ens,":",etg," ",ats,"/>") + else + handle("<",ens,":",etg,"/>") + end + end + else + if n and n>0 then + if ats then + handle("<",etg," ",ats,">") + else + handle("<",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",etg," ",ats,"/>") - else - handle("<",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",etg,">") + else + if ats then + handle("<",etg," ",ats,"/>") + else + handle("<",etg,"/>") + end end + end end local function verbose_pi(e,handlers) - handlers.handle("<?",e.dt[1],"?>") + handlers.handle("<?",e.dt[1],"?>") end local function verbose_comment(e,handlers) - handlers.handle("<!--",e.dt[1],"-->") + handlers.handle("<!--",e.dt[1],"-->") end local function verbose_cdata(e,handlers) - handlers.handle("<![CDATA[",e.dt[1],"]]>") + handlers.handle("<![CDATA[",e.dt[1],"]]>") end local function verbose_doctype(e,handlers) - handlers.handle("<!DOCTYPE",e.dt[1],">") + handlers.handle("<!DOCTYPE",e.dt[1],">") end local function verbose_root(e,handlers) - handlers.serialize(e.dt,handlers) + handlers.serialize(e.dt,handlers) end local function verbose_text(e,handlers) - handlers.handle(escaped(e)) + handlers.handle(escaped(e)) end local function verbose_document(e,handlers) - local serialize=handlers.serialize - local functions=handlers.functions - for i=1,#e do - local ei=e[i] - if type(ei)=="string" then - functions["@tx@"](ei,handlers) - else - serialize(ei,handlers) - end + local serialize=handlers.serialize + local functions=handlers.functions + for i=1,#e do + local ei=e[i] + if type(ei)=="string" then + functions["@tx@"](ei,handlers) + else + serialize(ei,handlers) end + end end local function serialize(e,handlers,...) - 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 + 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 end local function xserialize(e,handlers) - if e then - local functions=handlers.functions - local etg=e.tg - if etg then - (functions[etg] or functions["@el@"])(e,handlers) - else - functions["@dc@"](e,handlers) - end + if e then + local functions=handlers.functions + local etg=e.tg + if etg then + (functions[etg] or functions["@el@"])(e,handlers) + else + functions["@dc@"](e,handlers) end + end end local handlers={} local function newhandlers(settings) - local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) - if settings then - for k,v in next,settings do - if type(v)=="table" then - local tk=t[k] if not tk then tk={} t[k]=tk end - for kk,vv in next,v do - tk[kk]=vv - end - else - t[k]=v - end - end - if settings.name then - handlers[settings.name]=t - end + local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) + if settings then + for k,v in next,settings do + if type(v)=="table" then + local tk=t[k] if not tk then tk={} t[k]=tk end + for kk,vv in next,v do + tk[kk]=vv + end + else + t[k]=v + end end - utilities.storage.mark(t) - return t + if settings.name then + handlers[settings.name]=t + end + end + utilities.storage.mark(t) + return t end local nofunction=function() end function xml.sethandlersfunction(handler,name,fnc) - handler.functions[name]=fnc or nofunction + handler.functions[name]=fnc or nofunction end function xml.gethandlersfunction(handler,name) - return handler.functions[name] + return handler.functions[name] end function xml.gethandlers(name) - return handlers[name] + return handlers[name] end newhandlers { - name="verbose", - initialize=false, - finalize=false, - serialize=xserialize, - handle=print, - functions={ - ["@dc@"]=verbose_document, - ["@dt@"]=verbose_doctype, - ["@rt@"]=verbose_root, - ["@el@"]=verbose_element, - ["@pi@"]=verbose_pi, - ["@cm@"]=verbose_comment, - ["@cd@"]=verbose_cdata, - ["@tx@"]=verbose_text, - } + name="verbose", + initialize=false, + finalize=false, + serialize=xserialize, + handle=print, + functions={ + ["@dc@"]=verbose_document, + ["@dt@"]=verbose_doctype, + ["@rt@"]=verbose_root, + ["@el@"]=verbose_element, + ["@pi@"]=verbose_pi, + ["@cm@"]=verbose_comment, + ["@cd@"]=verbose_cdata, + ["@tx@"]=verbose_text, + } } local result local xmlfilehandler=newhandlers { - name="file", - initialize=function(name) - result=io.open(name,"wb") - return result - end, - finalize=function() - result:close() - return true - end, - handle=function(...) - result:write(...) - end, + name="file", + initialize=function(name) + result=io.open(name,"wb") + return result + end, + finalize=function() + result:close() + return true + end, + handle=function(...) + result:write(...) + end, } function xml.save(root,name) - serialize(root,xmlfilehandler,name) + serialize(root,xmlfilehandler,name) end local result,r,threshold={},0,512 local xmlstringhandler=newhandlers { - name="string", - initialize=function() - r=0 - return result - end, - finalize=function() - local done=concat(result,"",1,r) - r=0 - if r>threshold then - result={} - end - return done - end, - handle=function(...) - for i=1,select("#",...) do - r=r+1 - result[r]=select(i,...) - end - end, + name="string", + initialize=function() + r=0 + return result + end, + finalize=function() + local done=concat(result,"",1,r) + r=0 + if r>threshold then + result={} + end + return done + end, + handle=function(...) + for i=1,select("#",...) do + r=r+1 + result[r]=select(i,...) + end + end, } local function xmltostring(root) - if not root then - return "" - elseif type(root)=="string" then - return root - else - return serialize(root,xmlstringhandler) or "" - end + if not root then + return "" + elseif type(root)=="string" then + return root + else + return serialize(root,xmlstringhandler) or "" + end end local function __tostring(root) - return (root and xmltostring(root)) or "" + return (root and xmltostring(root)) or "" end initialize_mt=function(root) - mt={ __tostring=__tostring,__index=root } + mt={ __tostring=__tostring,__index=root } end xml.defaulthandlers=handlers xml.newhandlers=newhandlers xml.serialize=serialize xml.tostring=xmltostring local function xmlstring(e,handle) - if not handle or (e.special and e.tg~="@rt@") then - elseif e.tg then - local edt=e.dt - if edt then - for i=1,#edt do - xmlstring(edt[i],handle) - end - end - else - handle(e) + if not handle or (e.special and e.tg~="@rt@") then + elseif e.tg then + local edt=e.dt + if edt then + for i=1,#edt do + xmlstring(edt[i],handle) + end end + else + handle(e) + end end xml.string=xmlstring function xml.settings(e) - while e do - local s=e.settings - if s then - return s - else - e=e.__p__ - end + while e do + local s=e.settings + if s then + return s + else + e=e.__p__ end - return nil + end + return nil end function xml.root(e) - local r=e - while e do - e=e.__p__ - if e then - r=e - end + local r=e + while e do + e=e.__p__ + if e then + r=e end - return r + end + return r end function xml.parent(root) - return root.__p__ + return root.__p__ end function xml.body(root) - return root.ri and root.dt[root.ri] or root + return root.ri and root.dt[root.ri] or root end function xml.name(root) - if not root then - return "" - end - local ns=root.ns - local tg=root.tg - if ns=="" then - return tg - else - return ns..":"..tg - end + if not root then + return "" + end + local ns=root.ns + local tg=root.tg + if ns=="" then + return tg + else + return ns..":"..tg + end end function xml.erase(dt,k) - if dt then - if k then - dt[k]="" - else for k=1,#dt do - dt[1]={ "" } - end end - end + if dt then + if k then + dt[k]="" + else for k=1,#dt do + dt[1]={ "" } + end end + end end function xml.assign(dt,k,root) - if dt and k then - dt[k]=type(root)=="table" and xml.body(root) or root - return dt[k] - else - return xml.body(root) - end + if dt and k then + dt[k]=type(root)=="table" and xml.body(root) or root + return dt[k] + else + return xml.body(root) + end end function xml.tocdata(e,wrapper) - local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" - if wrapper then - whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) - end - local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } - setmetatable(t,getmetatable(e)) - e.dt={ t } + local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" + if wrapper then + whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) + end + local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } + setmetatable(t,getmetatable(e)) + e.dt={ t } end function xml.makestandalone(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" then - local txt=v.dt[1] - if find(txt,"xml.*version=") then - v.dt[1]=txt.." standalone='yes'" - break - end - end + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" then + local txt=v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1]=txt.." standalone='yes'" + break end + end end - return root + end + return root end function xml.kind(e) - local dt=e and e.dt - if dt then - local n=#dt - if n==1 then - local d=dt[1] - if d.special then - local tg=d.tg - if tg=="@cd@" then - return "cdata" - elseif tg=="@cm" then - return "comment" - elseif tg=="@pi@" then - return "instruction" - elseif tg=="@dt@" then - return "declaration" - end - elseif type(d)=="string" then - return "text" - end - return "element" - elseif n>0 then - return "mixed" - end + local dt=e and e.dt + if dt then + local n=#dt + if n==1 then + local d=dt[1] + if d.special then + local tg=d.tg + if tg=="@cd@" then + return "cdata" + elseif tg=="@cm" then + return "comment" + elseif tg=="@pi@" then + return "instruction" + elseif tg=="@dt@" then + return "declaration" + end + elseif type(d)=="string" then + return "text" + end + return "element" + elseif n>0 then + return "mixed" end - return "empty" + end + return "empty" end @@ -13571,14 +17060,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true --- original size: 53301, stripped down to: 32477 +-- original size: 55145, stripped down to: 30992 if not modules then modules={} end modules ['lxml-lpt']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local concat,remove,insert=table.concat,table.remove,table.insert local type,next,tonumber,tostring,setmetatable,load,select=type,next,tonumber,tostring,setmetatable,load,select @@ -13591,21 +17080,21 @@ local trace_lparse=false local trace_lprofile=false local report_lpath=logs.reporter("xml","lpath") if trackers then - trackers.register("xml.path",function(v) - trace_lpath=v - end) - trackers.register("xml.parse",function(v) - trace_lparse=v - end) - trackers.register("xml.profile",function(v) - trace_lpath=v - trace_lparse=v - trace_lprofile=v - end) + trackers.register("xml.path",function(v) + trace_lpath=v + end) + trackers.register("xml.parse",function(v) + trace_lparse=v + end) + trackers.register("xml.profile",function(v) + trace_lpath=v + trace_lparse=v + trace_lprofile=v + end) end local xml=xml -local lpathcalls=0 function xml.lpathcalls () return lpathcalls end -local lpathcached=0 function xml.lpathcached() return lpathcached end +local lpathcalls=0 function xml.lpathcalls () return lpathcalls end +local lpathcached=0 function xml.lpathcached() return lpathcached end xml.functions=xml.functions or {} local functions=xml.functions xml.expressions=xml.expressions or {} @@ -13619,216 +17108,271 @@ local xmlpatterns=lpegpatterns.xml finalizers.xml=finalizers.xml or {} finalizers.tex=finalizers.tex or {} local function fallback (t,name) - local fn=finalizers[name] - if fn then - t[name]=fn - else - report_lpath("unknown sub finalizer %a",name) - fn=function() end - end - return fn + local fn=finalizers[name] + if fn then + t[name]=fn + else + report_lpath("unknown sub finalizer %a",name) + fn=function() end + end + return fn end setmetatableindex(finalizers.xml,fallback) setmetatableindex(finalizers.tex,fallback) xml.defaultprotocol="xml" local apply_axis={} apply_axis['root']=function(list) - local collected={} - for l=1,#list do - local ll=list[l] - local rt=ll - while ll do - ll=ll.__p__ - if ll then - rt=ll - end - end - collected[l]=rt + local collected={} + for l=1,#list do + local ll=list[l] + local rt=ll + while ll do + ll=ll.__p__ + if ll then + rt=ll + end end - return collected + collected[l]=rt + end + return collected end apply_axis['self']=function(list) - return list + return list end apply_axis['child']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local dt=ll.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - end - end - ll.en=en + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local dt=ll.dt + if dt then + local n=#dt + if n==0 then + ll.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + ll.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + end end + ll.en=en + end end - return collected + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + else + list.en=0 + end + else + local en=0 + for k=1,n do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant']=function(list) - local collected,c={},0 - for l=1,#list do - c=collect(list[l],collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + c=collect(list[l],collected,c) + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - if ll.special~=true then - c=c+1 - collected[c]=ll - end - c=collect(ll,collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + if ll.special~=true then + c=c+1 + collected[c]=ll + end + c=collect(ll,collected,c) + end + return collected end apply_axis['ancestor']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + while ll do + ll=ll.__p__ + if ll then + c=c+1 + collected[c]=ll + end end - return collected + end + return collected end apply_axis['ancestor-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + c=c+1 + collected[c]=ll + while ll do + ll=ll.__p__ + if ll then c=c+1 collected[c]=ll - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + end end - return collected + end + return collected end apply_axis['parent']=function(list) - local collected,c={},0 - for l=1,#list do - local pl=list[l].__p__ - if pl then - c=c+1 - collected[c]=pl - end + local collected={} + local c=0 + for l=1,#list do + local pl=list[l].__p__ + if pl then + c=c+1 + collected[c]=pl end - return collected + end + return collected end apply_axis['attribute']=function(list) - return {} + return {} end apply_axis['namespace']=function(list) - return {} + return {} end apply_axis['following']=function(list) - return {} + return {} end apply_axis['preceding']=function(list) - return {} + return {} end apply_axis['following-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni+1,#d do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni+1,#d do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['preceding-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=1,ll.ni-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=1,ll.ni-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['reverse-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni-1,1,-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni-1,1,-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['auto-descendant-or-self']=apply_axis['descendant-or-self'] apply_axis['auto-descendant']=apply_axis['descendant'] @@ -13836,130 +17380,147 @@ apply_axis['auto-child']=apply_axis['child'] apply_axis['auto-self']=apply_axis['self'] apply_axis['initial-child']=apply_axis['child'] local function apply_nodes(list,directive,nodes) - local maxn=#nodes - if maxn==3 then - local nns,ntg=nodes[2],nodes[3] - if not nns and not ntg then + local maxn=#nodes + if maxn==3 then + local nns=nodes[2] + local ntg=nodes[3] + if not nns and not ntg then + if directive then + return list + else + return {} + end + else + local collected={} + local c=0 + local m=0 + local p=nil + if not nns then + for l=1,#list do + local ll=list[l] + local ltg=ll.tg + if ltg then if directive then - return list - else - return {} + if ntg==ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif ntg~=ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - else - local collected,c,m,p={},0,0,nil - if not nns then - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - if directive then - if ntg==ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif ntg~=ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - elseif not ntg then - for l=1,#list do - local ll=list[l] - local lns=ll.rn or ll.ns - if lns then - if directive then - if lns==nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif lns~=nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - else - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=ltg==ntg and lns==nns - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end + end + end + elseif not ntg then + for l=1,#list do + local ll=list[l] + local lns=ll.rn or ll.ns + if lns then + if directive then + if lns==nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif lns~=nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - return collected + end end - else - local collected,c,m,p={},0,0,nil + else for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=false - for n=1,maxn,3 do - local nns,ntg=nodes[n+1],nodes[n+2] - ok=(not ntg or ltg==ntg) and (not nns or lns==nns) - if ok then - break - end - end - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=ltg==ntg and lns==nns + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end + end end - return collected + end + return collected end -end -local quit_expression=false -local function apply_expression(list,expression,order) - local collected,c={},0 - quit_expression=false + else + local collected={} + local c=0 + local m=0 + local p=nil for l=1,#list do - local ll=list[l] - if expression(list,ll,l,order) then + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=false + for n=1,maxn,3 do + local nns=nodes[n+1] + local ntg=nodes[n+2] + ok=(not ntg or ltg==ntg) and (not nns or lns==nns) + if ok then + break + end + end + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end c=c+1 collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - if quit_expression then - break - end + end end return collected + end end -local function apply_selector(list,specification) - if xml.applyselector then - apply_selector=xml.applyselector - return apply_selector(list,specification) - else - return list +local quit_expression=false +local function apply_expression(list,expression,order) + local collected={} + local c=0 + quit_expression=false + for l=1,#list do + local ll=list[l] + if expression(list,ll,l,order) then + c=c+1 + collected[c]=ll + end + if quit_expression then + break end + end + return collected +end +local function apply_selector(list,specification) + if xml.applyselector then + apply_selector=xml.applyselector + return apply_selector(list,specification) + else + return list + end end local P,V,C,Cs,Cc,Ct,R,S,Cg,Cb=lpeg.P,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.R,lpeg.S,lpeg.Cg,lpeg.Cb local spaces=S(" \n\r\t\f")^0 @@ -13970,24 +17531,24 @@ local lp_doequal=P("=")/"==" local lp_or=P("|")/" or " local lp_and=P("&")/" and " local builtin={ - text="(ll.dt[1] or '')", - content="ll.dt", - name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", - tag="ll.tg", - position="l", - firstindex="1", - firstelement="1", - first="1", - lastindex="(#ll.__p__.dt or 1)", - lastelement="(ll.__p__.en or 1)", - last="#list", - rootposition="order", - order="order", - element="(ll.ei or 1)", - index="(ll.ni or 1)", - match="(ll.mi or 1)", - namespace="ll.ns", - ns="ll.ns", + text="(ll.dt[1] or '')", + content="ll.dt", + name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", + tag="ll.tg", + position="l", + firstindex="1", + firstelement="1", + first="1", + lastindex="(#ll.__p__.dt or 1)", + lastelement="(ll.__p__.en or 1)", + last="#list", + rootposition="order", + order="order", + element="(ll.ei or 1)", + index="(ll.ni or 1)", + match="(ll.mi or 1)", + namespace="ll.ns", + ns="ll.ns", } local lp_builtin=lpeg.utfchartabletopattern(builtin)/builtin*((spaces*P("(")*spaces*P(")"))/"") local lp_attribute=(P("@")+P("attribute::"))/""*Cc("(ll.at and ll.at['")*((R("az","AZ")+S("-_:"))^1)*Cc("'])") @@ -13997,11 +17558,11 @@ local lp_fastpos=lp_fastpos_n+lp_fastpos_p local lp_reserved=C("and")+C("or")+C("not")+C("div")+C("mod")+C("true")+C("false") local lp_lua_function=Cs((R("az","AZ","__")^1*(P(".")*R("az","AZ","__")^1)^1)*("("))/"%0" local lp_function=C(R("az","AZ","__")^1)*P("(")/function(t) - if expressions[t] then - return "expr."..t.."(" - else - return "expr.error(" - end + if expressions[t] then + return "expr."..t.."(" + else + return "expr.error(" + end end local lparent=P("(") local rparent=P(")") @@ -14014,24 +17575,24 @@ local lp_string=Cc("'")*R("az","AZ","--","__")^1*Cc("'") local lp_content=(P("'")*(1-P("'"))^0*P("'")+P('"')*(1-P('"'))^0*P('"')) local cleaner local lp_special=(C(P("name")+P("text")+P("tag")+P("count")+P("child")))*value/function(t,s) - if expressions[t] then - s=s and s~="" and lpegmatch(cleaner,s) - if s and s~="" then - return "expr."..t.."(ll,"..s..")" - else - return "expr."..t.."(ll)" - end + if expressions[t] then + s=s and s~="" and lpegmatch(cleaner,s) + if s and s~="" then + return "expr."..t.."(ll,"..s..")" else - return "expr.error("..t..")" + return "expr."..t.."(ll)" end + else + return "expr.error("..t..")" + end end local content=lp_builtin+lp_attribute+lp_special+lp_noequal+lp_doequal+lp_or+lp_and+lp_reserved+lp_lua_function+lp_function+lp_content+ - lp_child+lp_any + lp_child+lp_any local converter=Cs ( - lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 + lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 ) cleaner=Cs (( - lp_reserved+lp_number+lp_string+1 )^1 ) + lp_reserved+lp_number+lp_string+1 )^1 ) local template_e=[[ local expr = xml.expressions return function(list,ll,l,order) @@ -14047,75 +17608,75 @@ local template_f_y=[[ local template_f_n=[[ return xml.finalizers['%s']['%s'] ]] -local register_last_match={ kind="axis",axis="last-match" } -local register_self={ kind="axis",axis="self" } -local register_parent={ kind="axis",axis="parent" } -local register_descendant={ kind="axis",axis="descendant" } -local register_child={ kind="axis",axis="child" } +local register_last_match={ kind="axis",axis="last-match" } +local register_self={ kind="axis",axis="self" } +local register_parent={ kind="axis",axis="parent" } +local register_descendant={ kind="axis",axis="descendant" } +local register_child={ kind="axis",axis="child" } local register_descendant_or_self={ kind="axis",axis="descendant-or-self" } -local register_root={ kind="axis",axis="root" } -local register_ancestor={ kind="axis",axis="ancestor" } -local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } -local register_attribute={ kind="axis",axis="attribute" } -local register_namespace={ kind="axis",axis="namespace" } -local register_following={ kind="axis",axis="following" } +local register_root={ kind="axis",axis="root" } +local register_ancestor={ kind="axis",axis="ancestor" } +local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } +local register_attribute={ kind="axis",axis="attribute" } +local register_namespace={ kind="axis",axis="namespace" } +local register_following={ kind="axis",axis="following" } local register_following_sibling={ kind="axis",axis="following-sibling" } -local register_preceding={ kind="axis",axis="preceding" } +local register_preceding={ kind="axis",axis="preceding" } local register_preceding_sibling={ kind="axis",axis="preceding-sibling" } -local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } +local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } local register_auto_descendant_or_self={ kind="axis",axis="auto-descendant-or-self" } -local register_auto_descendant={ kind="axis",axis="auto-descendant" } -local register_auto_self={ kind="axis",axis="auto-self" } -local register_auto_child={ kind="axis",axis="auto-child" } -local register_initial_child={ kind="axis",axis="initial-child" } +local register_auto_descendant={ kind="axis",axis="auto-descendant" } +local register_auto_self={ kind="axis",axis="auto-self" } +local register_auto_child={ kind="axis",axis="auto-child" } +local register_initial_child={ kind="axis",axis="initial-child" } local register_all_nodes={ kind="nodes",nodetest=true,nodes={ true,false,false } } local skip={} local function errorrunner_e(str,cnv) - if not skip[str] then - report_lpath("error in expression: %s => %s",str,cnv) - skip[str]=cnv or str - end - return false + if not skip[str] then + report_lpath("error in expression: %s => %s",str,cnv) + skip[str]=cnv or str + end + return false end local function errorrunner_f(str,arg) - report_lpath("error in finalizer: %s(%s)",str,arg or "") - return false + report_lpath("error in finalizer: %s(%s)",str,arg or "") + return false end local function register_nodes(nodetest,nodes) - return { kind="nodes",nodetest=nodetest,nodes=nodes } + return { kind="nodes",nodetest=nodetest,nodes=nodes } end local function register_selector(specification) - return { kind="selector",specification=specification } + return { kind="selector",specification=specification } end local function register_expression(expression) - local converted=lpegmatch(converter,expression) - local runner=load(format(template_e,converted)) - runner=(runner and runner()) or function() errorrunner_e(expression,converted) end - return { kind="expression",expression=expression,converted=converted,evaluator=runner } + local converted=lpegmatch(converter,expression) + local runner=load(format(template_e,converted)) + runner=(runner and runner()) or function() errorrunner_e(expression,converted) end + return { kind="expression",expression=expression,converted=converted,evaluator=runner } end local function register_finalizer(protocol,name,arguments) - local runner - if arguments and arguments~="" then - runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) - else - runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) - end - runner=(runner and runner()) or function() errorrunner_f(name,arguments) end - return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } + local runner + if arguments and arguments~="" then + runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) + else + runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) + end + runner=(runner and runner()) or function() errorrunner_f(name,arguments) end + return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } end local expression=P { "ex", - ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", - sq="'"*(1-S("'"))^0*"'", - dq='"'*(1-S('"'))^0*'"', + ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", + sq="'"*(1-S("'"))^0*"'", + dq='"'*(1-S('"'))^0*'"', } local arguments=P { "ar", - ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", - nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, - sq=P("'")*(1-P("'"))^0*P("'"), - dq=P('"')*(1-P('"'))^0*P('"'), + ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", + nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, + sq=P("'")*(1-P("'"))^0*P("'"), + dq=P('"')*(1-P('"'))^0*P('"'), } local function register_error(str) - return { kind="error",error=format("unparsed: %s",str) } + return { kind="error",error=format("unparsed: %s",str) } end local special_1=P("*")*Cc(register_auto_descendant)*Cc(register_all_nodes) local special_2=P("/")*Cc(register_auto_self) @@ -14123,367 +17684,368 @@ local special_3=P("")*Cc(register_auto_self) local no_nextcolon=P(-1)+#(1-P(":")) local no_nextlparent=P(-1)+#(1-P("(")) local pathparser=Ct { "patterns", - patterns=spaces*V("protocol")*spaces*( - (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) - ), - protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), - step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, - axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), - special=special_1+special_2+special_3, - initial=(P("/")*spaces*Cc(register_initial_child))^-1, - error=(P(1)^1)/register_error, - shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), - shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, - s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), - s_descendant=P("**")*Cc(register_descendant), - s_child=P("*")*no_nextcolon*Cc(register_child), - s_parent=P("..")*Cc(register_parent), - s_self=P("." )*Cc(register_self), - s_root=P("^^")*Cc(register_root), - s_ancestor=P("^")*Cc(register_ancestor), - s_lastmatch=P("=")*Cc(register_last_match), - descendant=P("descendant::")*Cc(register_descendant), - child=P("child::")*Cc(register_child), - parent=P("parent::")*Cc(register_parent), - self=P("self::")*Cc(register_self), - root=P('root::')*Cc(register_root), - ancestor=P('ancestor::')*Cc(register_ancestor), - descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), - ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), - following=P('following::')*Cc(register_following), - following_sibling=P('following-sibling::')*Cc(register_following_sibling), - preceding=P('preceding::')*Cc(register_preceding), - preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), - reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), - last_match=P('last-match::')*Cc(register_last_match), - selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, - nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, - expressions=expression/register_expression, - letters=R("az")^1, - name=(1-S("/[]()|:*!"))^1, - negate=P("!")*Cc(false), - nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), - nodetest=V("negate")+Cc(true), - nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), - wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, - nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, - finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, + patterns=spaces*V("protocol")*spaces*( + (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) + ), + protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), + step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, + axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), + special=special_1+special_2+special_3, + initial=(P("/")*spaces*Cc(register_initial_child))^-1, + error=(P(1)^1)/register_error, + shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), + shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, + s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), + s_descendant=P("**")*Cc(register_descendant), + s_child=P("*")*no_nextcolon*Cc(register_child), + s_parent=P("..")*Cc(register_parent), + s_self=P("." )*Cc(register_self), + s_root=P("^^")*Cc(register_root), + s_ancestor=P("^")*Cc(register_ancestor), + s_lastmatch=P("=")*Cc(register_last_match), + descendant=P("descendant::")*Cc(register_descendant), + child=P("child::")*Cc(register_child), + parent=P("parent::")*Cc(register_parent), + self=P("self::")*Cc(register_self), + root=P('root::')*Cc(register_root), + ancestor=P('ancestor::')*Cc(register_ancestor), + descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), + ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), + following=P('following::')*Cc(register_following), + following_sibling=P('following-sibling::')*Cc(register_following_sibling), + preceding=P('preceding::')*Cc(register_preceding), + preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), + reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), + last_match=P('last-match::')*Cc(register_last_match), + selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, + nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, + expressions=expression/register_expression, + letters=R("az")^1, + name=(1-S("/[]()|:*!"))^1, + negate=P("!")*Cc(false), + nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), + nodetest=V("negate")+Cc(true), + nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), + wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, + nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, + finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, } xmlpatterns.pathparser=pathparser local cache={} local function nodesettostring(set,nodetest) - local t={} - for i=1,#set,3 do - local directive,ns,tg=set[i],set[i+1],set[i+2] - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - t[#t+1]=(directive and tg) or format("not(%s)",tg) - end - if nodetest==false then - return format("not(%s)",concat(t,"|")) - else - return concat(t,"|") - end + local t={} + for i=1,#set,3 do + local directive,ns,tg=set[i],set[i+1],set[i+2] + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) + t[#t+1]=(directive and tg) or format("not(%s)",tg) + end + if nodetest==false then + return format("not(%s)",concat(t,"|")) + else + return concat(t,"|") + end end local function tagstostring(list) - if #list==0 then - return "no elements" - else - local t={} - for i=1,#list do - local li=list[i] - local ns,tg=li.ns,li.tg - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - end - return concat(t," ") + if #list==0 then + return "no elements" + else + local t={} + for i=1,#list do + local li=list[i] + local ns=li.ns + local tg=li.tg + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) end + return concat(t," ") + end end xml.nodesettostring=nodesettostring local lpath local function lshow(parsed) - if type(parsed)=="string" then - parsed=lpath(parsed) - end - report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, - table.serialize(parsed,false)) + if type(parsed)=="string" then + parsed=lpath(parsed) + end + report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, + table.serialize(parsed,false)) end xml.lshow=lshow local function add_comment(p,str) - local pc=p.comment - if not pc then - p.comment={ str } - else - pc[#pc+1]=str - end + local pc=p.comment + if not pc then + p.comment={ str } + else + pc[#pc+1]=str + end end lpath=function (pattern) - lpathcalls=lpathcalls+1 - if type(pattern)=="table" then - return pattern - else - local parsed=cache[pattern] - if parsed then - lpathcached=lpathcached+1 + lpathcalls=lpathcalls+1 + if type(pattern)=="table" then + return pattern + else + local parsed=cache[pattern] + if parsed then + lpathcached=lpathcached+1 + else + parsed=lpegmatch(pathparser,pattern) + if parsed then + parsed.pattern=pattern + local np=#parsed + if np==0 then + parsed={ pattern=pattern,register_self,state="parsing error" } + report_lpath("parsing error in pattern: %s",pattern) + lshow(parsed) else - parsed=lpegmatch(pathparser,pattern) - if parsed then - parsed.pattern=pattern - local np=#parsed - if np==0 then - parsed={ pattern=pattern,register_self,state="parsing error" } - report_lpath("parsing error in pattern: %s",pattern) - lshow(parsed) - else - local pi=parsed[1] - if pi.axis=="auto-child" then - if false then - add_comment(parsed,"auto-child replaced by auto-descendant-or-self") - parsed[1]=register_auto_descendant_or_self - else - add_comment(parsed,"auto-child replaced by auto-descendant") - parsed[1]=register_auto_descendant - end - elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then - add_comment(parsed,"initial-child removed") - remove(parsed,1) - end - local np=#parsed - if np>1 then - local pnp=parsed[np] - if pnp.kind=="nodes" and pnp.nodetest==true then - local nodes=pnp.nodes - if nodes[1]==true and nodes[2]==false and nodes[3]==false then - add_comment(parsed,"redundant final wildcard filter removed") - remove(parsed,np) - end - end - end - end + local pi=parsed[1] + if pi.axis=="auto-child" then + if false then + add_comment(parsed,"auto-child replaced by auto-descendant-or-self") + parsed[1]=register_auto_descendant_or_self else - parsed={ pattern=pattern } + add_comment(parsed,"auto-child replaced by auto-descendant") + parsed[1]=register_auto_descendant end - cache[pattern]=parsed - if trace_lparse and not trace_lprofile then - lshow(parsed) + elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then + add_comment(parsed,"initial-child removed") + remove(parsed,1) + end + local np=#parsed + if np>1 then + local pnp=parsed[np] + if pnp.kind=="nodes" and pnp.nodetest==true then + local nodes=pnp.nodes + if nodes[1]==true and nodes[2]==false and nodes[3]==false then + add_comment(parsed,"redundant final wildcard filter removed") + remove(parsed,np) + end end + end end - return parsed + else + parsed={ pattern=pattern } + end + cache[pattern]=parsed + if trace_lparse and not trace_lprofile then + lshow(parsed) + end end + return parsed + end end xml.lpath=lpath do - local profiled={} - xml.profiled=profiled - local lastmatch=nil - local keepmatch=nil - if directives then - directives.register("xml.path.keeplastmatch",function(v) - keepmatch=v - lastmatch=nil - end) - end - apply_axis["last-match"]=function() - return lastmatch or {} - end - local function profiled_apply(list,parsed,nofparsed,order) - local p=profiled[parsed.pattern] - if p then - p.tested=p.tested+1 - else - p={ tested=1,matched=0,finalized=0 } - profiled[parsed.pattern]=p - end - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - p.matched=p.matched+1 - p.finalized=p.finalized+1 - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - p.finalized=p.finalized+1 - return collected - end - return nil - end - end - if collected then - p.matched=p.matched+1 - end - return collected - end - local function traced_apply(list,parsed,nofparsed,order) - if trace_lparse then - lshow(parsed) - end - report_lpath("collecting: %s",parsed.pattern) - report_lpath("root tags : %s",tagstostring(list)) - report_lpath("order : %s",order or "unset") - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") - return collected - end - return nil - end - end + local profiled={} + xml.profiled=profiled + local lastmatch=nil + local keepmatch=nil + if directives then + directives.register("xml.path.keeplastmatch",function(v) + keepmatch=v + lastmatch=nil + end) + end + apply_axis["last-match"]=function() + return lastmatch or {} + end + local function profiled_apply(list,parsed,nofparsed,order) + local p=profiled[parsed.pattern] + if p then + p.tested=p.tested+1 + else + p={ tested=1,matched=0,finalized=0 } + profiled[parsed.pattern]=p + end + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + p.matched=p.matched+1 + p.finalized=p.finalized+1 return collected - end - local function normal_apply(list,parsed,nofparsed,order) - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - local axis=pi.axis - if axis~="self" then - collected=apply_axis[axis](collected) - end - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - return pi.finalizer(collected) - end - if not collected or #collected==0 then - local pf=i<nofparsed and parsed[nofparsed].finalizer - if pf then - return pf(collected) - end - return nil - end + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + p.finalized=p.finalized+1 + return collected end - return collected + return nil + end end - local apply=normal_apply - if trackers then - trackers.register("xml.path,xml.parse,xml.profile",function() - if trace_lprofile then - apply=profiled_apply - elseif trace_lpath then - apply=traced_apply - else - apply=normal_apply - end - end) + if collected then + p.matched=p.matched+1 end - function xml.applylpath(list,pattern) - if not list then - lastmatch=nil - return - end - local parsed=cache[pattern] - if parsed then - lpathcalls=lpathcalls+1 - lpathcached=lpathcached+1 - elseif type(pattern)=="table" then - lpathcalls=lpathcalls+1 - parsed=pattern - else - parsed=lpath(pattern) or pattern - end - if not parsed then - lastmatch=nil - return - end - local nofparsed=#parsed - if nofparsed==0 then - lastmatch=nil - return - end - local collected=apply({ list },parsed,nofparsed,list.mi) - lastmatch=keepmatch and collected or nil + return collected + end + local function traced_apply(list,parsed,nofparsed,order) + if trace_lparse then + lshow(parsed) + end + report_lpath("collecting: %s",parsed.pattern) + report_lpath("root tags : %s",tagstostring(list)) + report_lpath("order : %s",order or "unset") + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") return collected + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") + return collected + end + return nil + end end - function xml.lastmatch() - return lastmatch - end - local stack={} - function xml.pushmatch() - insert(stack,lastmatch) - end - function xml.popmatch() - lastmatch=remove(stack) + return collected + end + local function normal_apply(list,parsed,nofparsed,order) + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + local axis=pi.axis + if axis~="self" then + collected=apply_axis[axis](collected) + end + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + return pi.finalizer(collected) + end + if not collected or #collected==0 then + local pf=i<nofparsed and parsed[nofparsed].finalizer + if pf then + return pf(collected) + end + return nil + end end + return collected + end + local apply=normal_apply + if trackers then + trackers.register("xml.path,xml.parse,xml.profile",function() + if trace_lprofile then + apply=profiled_apply + elseif trace_lpath then + apply=traced_apply + else + apply=normal_apply + end + end) + end + function xml.applylpath(list,pattern) + if not list then + lastmatch=nil + return + end + local parsed=cache[pattern] + if parsed then + lpathcalls=lpathcalls+1 + lpathcached=lpathcached+1 + elseif type(pattern)=="table" then + lpathcalls=lpathcalls+1 + parsed=pattern + else + parsed=lpath(pattern) or pattern + end + if not parsed then + lastmatch=nil + return + end + local nofparsed=#parsed + if nofparsed==0 then + lastmatch=nil + return + end + local collected=apply({ list },parsed,nofparsed,list.mi) + lastmatch=keepmatch and collected or nil + return collected + end + function xml.lastmatch() + return lastmatch + end + local stack={} + function xml.pushmatch() + insert(stack,lastmatch) + end + function xml.popmatch() + lastmatch=remove(stack) + end end local applylpath=xml.applylpath function xml.filter(root,pattern) - return applylpath(root,pattern) + return applylpath(root,pattern) end expressions.child=function(e,pattern) - return applylpath(e,pattern) + return applylpath(e,pattern) end expressions.count=function(e,pattern) - local collected=applylpath(e,pattern) - return pattern and (collected and #collected) or 0 + local collected=applylpath(e,pattern) + return pattern and (collected and #collected) or 0 end expressions.oneof=function(s,...) - for i=1,select("#",...) do - if s==select(i,...) then - return true - end + for i=1,select("#",...) do + if s==select(i,...) then + return true end - return false + end + return false end expressions.error=function(str) - xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) - return false + xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) + return false end expressions.undefined=function(s) - return s==nil + return s==nil end expressions.quit=function(s) - if s or s==nil then - quit_expression=true - end - return true + if s or s==nil then + quit_expression=true + end + return true end expressions.print=function(...) - print(...) - return true + print(...) + return true end expressions.find=find expressions.upper=upper @@ -14491,233 +18053,238 @@ expressions.lower=lower expressions.number=tonumber expressions.boolean=toboolean function expressions.contains(str,pattern) - local t=type(str) - if t=="string" then - if find(str,pattern) then - return true - end - elseif t=="table" then - for i=1,#str do - local d=str[i] - if type(d)=="string" and find(d,pattern) then - return true - end - end + local t=type(str) + if t=="string" then + if find(str,pattern) then + return true end - return false + elseif t=="table" then + for i=1,#str do + local d=str[i] + if type(d)=="string" and find(d,pattern) then + return true + end + end + end + return false end function xml.expressions.idstring(str) - return type(str)=="string" and gsub(str,"^#","") or "" + return type(str)=="string" and gsub(str,"^#","") or "" end local function traverse(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local r=e.__p__ - handle(r,r.dt,e.ni) - end + local collected=applylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local r=e.__p__ + handle(r,r.dt,e.ni) end + end end local function selection(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - if handle then - for c=1,#collected do - handle(collected[c]) - end - else - return collected - end + local collected=applylpath(root,pattern) + if collected then + if handle then + for c=1,#collected do + handle(collected[c]) + end + else + return collected end + end end -xml.traverse=traverse +xml.traverse=traverse xml.selection=selection local function dofunction(collected,fnc,...) - if collected then - local f=functions[fnc] - if f then - for c=1,#collected do - f(collected[c],...) - end - else - report_lpath("unknown function %a",fnc) - end + if collected then + local f=functions[fnc] + if f then + for c=1,#collected do + f(collected[c],...) + end + else + report_lpath("unknown function %a",fnc) end + end end finalizers.xml["function"]=dofunction finalizers.tex["function"]=dofunction expressions.text=function(e,n) - local rdt=e.__p__.dt - return rdt and rdt[n] or "" + local rdt=e.__p__.dt + return rdt and rdt[n] or "" end expressions.name=function(e,n) - local found=false - n=tonumber(n) or 0 - if n==0 then - found=type(e)=="table" and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end + local found=false + n=tonumber(n) or 0 + if n==0 then + found=type(e)=="table" and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 end + end end - if found then - local ns,tg=found.rn or found.ns or "",found.tg - if ns~="" then - return ns..":"..tg + else + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break else - return tg + n=n-1 end + end + end + end + if found then + local ns=found.rn or found.ns or "" + local tg=found.tg + if ns~="" then + return ns..":"..tg else - return "" + return tg end + else + return "" + end end expressions.tag=function(e,n) - if not e then - return "" + if not e then + return "" + else + local found=false + n=tonumber(n) or 0 + if n==0 then + found=(type(e)=="table") and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 + end + end + end else - local found=false - n=tonumber(n) or 0 - if n==0 then - found=(type(e)=="table") and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end - end + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break + else + n=n-1 + end end - return (found and found.tg) or "" + end end + return (found and found.tg) or "" + end end local dummy=function() end function xml.elements(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end 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 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end end + end end function xml.collected(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + return collected[c] + end 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 - return collected[c] - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - return collected[c] - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + return collected[c] + end end + end end function xml.inspect(collection,pattern) - pattern=pattern or "." - for e in xml.collected(collection,pattern or ".") do - report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) - end + pattern=pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) + end end local function split(e) - local dt=e.dt - if dt then - for i=1,#dt do - local dti=dt[i] - if type(dti)=="string" then - dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") - dti=gsub(dti,"[\n\r]+","\n\n") - dt[i]=dti - else - split(dti) - end - end + local dt=e.dt + if dt then + for i=1,#dt do + local dti=dt[i] + if type(dti)=="string" then + dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") + dti=gsub(dti,"[\n\r]+","\n\n") + dt[i]=dti + else + split(dti) + end end - return e + end + return e end function xml.finalizers.paragraphs(c) - for i=1,#c do - split(c[i]) - end - return c + for i=1,#c do + split(c[i]) + end + return c end @@ -14727,14 +18294,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-mis"] = package.loaded["lxml-mis"] or true --- original size: 3574, stripped down to: 1863 +-- original size: 3574, stripped down to: 1808 if not modules then modules={} end modules ['lxml-mis']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local xml,lpeg,string=xml,lpeg,string local type=type @@ -14745,26 +18312,26 @@ local P,S,R,C,V,Cc,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.Cc,lpeg.Cs lpegpatterns.xml=lpegpatterns.xml or {} local xmlpatterns=lpegpatterns.xml local function xmlgsub(t,old,new) - local dt=t.dt - if dt then - for k=1,#dt do - local v=dt[k] - if type(v)=="string" then - dt[k]=gsub(v,old,new) - else - xmlgsub(v,old,new) - end - end + local dt=t.dt + if dt then + for k=1,#dt do + local v=dt[k] + if type(v)=="string" then + dt[k]=gsub(v,old,new) + else + xmlgsub(v,old,new) + end end + end end function xml.stripleadingspaces(dk,d,k) - if d and k then - local dkm=d[k-1] - if dkm and type(dkm)=="string" then - local s=match(dkm,"\n(%s+)") - xmlgsub(dk,"\n"..rep(" ",#s),"\n") - end + if d and k then + local dkm=d[k-1] + if dkm and type(dkm)=="string" then + local s=match(dkm,"\n(%s+)") + xmlgsub(dk,"\n"..rep(" ",#s),"\n") end + end end local normal=(1-S("<&>"))^0 local special=P("<")/"<"+P(">")/">"+P("&")/"&" @@ -14776,17 +18343,17 @@ local cleansed=Cs(((P("<")*(1-P(">"))^0*P(">"))/""+1)^0) xmlpatterns.escaped=escaped xmlpatterns.unescaped=unescaped xmlpatterns.cleansed=cleansed -function xml.escaped (str) return lpegmatch(escaped,str) end +function xml.escaped (str) return lpegmatch(escaped,str) end function xml.unescaped(str) return lpegmatch(unescaped,str) end -function xml.cleansed (str) return lpegmatch(cleansed,str) end +function xml.cleansed (str) return lpegmatch(cleansed,str) end function xml.fillin(root,pattern,str,check) - local e=xml.first(root,pattern) - if e then - local n=#e.dt - if not check or n==0 or (n==1 and e.dt[1]=="") then - e.dt={ str } - end + local e=xml.first(root,pattern) + if e then + local n=#e.dt + if not check or n==0 or (n==1 and e.dt[1]=="") then + e.dt={ str } end + end end @@ -14796,17 +18363,17 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true --- original size: 30650, stripped down to: 21793 +-- original size: 30771, stripped down to: 19680 if not modules then modules={} end modules ['lxml-aux']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) -local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) +local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) +local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) local report_xml=logs.reporter("xml") local xml=xml local xmlcopy,xmlname=xml.copy,xml.name @@ -14819,308 +18386,313 @@ local utfbyte=utf.byte local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local striplinepatterns=utilities.strings.striplinepatterns local function report(what,pattern,c,e) - report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) + report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) end local function withelements(e,handle,depth) - if e and handle then - local edt=e.dt - if edt then - depth=depth or 0 - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - handle(e,depth) - withelements(e,handle,depth+1) - end - end + if e and handle then + local edt=e.dt + if edt then + depth=depth or 0 + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + handle(e,depth) + withelements(e,handle,depth+1) end + end end + end end xml.withelements=withelements function xml.withelement(e,n,handle) - if e and n~=0 and handle then - local edt=e.dt - if edt then - if n>0 then - for i=1,#edt do - local ei=edt[i] - if type(ei)=="table" then - if n==1 then - handle(ei) - return - else - n=n-1 - end - end - end - elseif n<0 then - for i=#edt,1,-1 do - local ei=edt[i] - if type(ei)=="table" then - if n==-1 then - handle(ei) - return - else - n=n+1 - end - end - end + if e and n~=0 and handle then + local edt=e.dt + if edt then + if n>0 then + for i=1,#edt do + local ei=edt[i] + if type(ei)=="table" then + if n==1 then + handle(ei) + return + else + n=n-1 end + end end - end -end -function xml.each(root,pattern,handle,reverse) - local collected=xmlapplylpath(root,pattern) - if collected then - if handle then - if reverse then - for c=#collected,1,-1 do - handle(collected[c]) - end + elseif n<0 then + for i=#edt,1,-1 do + local ei=edt[i] + if type(ei)=="table" then + if n==-1 then + handle(ei) + return else - for c=1,#collected do - handle(collected[c]) - end + n=n+1 end + end end - return collected + end end + end end -function xml.processattributes(root,pattern,handle) - local collected=xmlapplylpath(root,pattern) - if collected and handle then +function xml.each(root,pattern,handle,reverse) + local collected=xmlapplylpath(root,pattern) + if collected then + if handle then + if reverse then + for c=#collected,1,-1 do + handle(collected[c]) + end + else for c=1,#collected do - handle(collected[c].at) + handle(collected[c]) end + end end return collected + end +end +function xml.processattributes(root,pattern,handle) + local collected=xmlapplylpath(root,pattern) + if collected and handle then + for c=1,#collected do + handle(collected[c].at) + end + end + return collected end function xml.collect(root,pattern) - return xmlapplylpath(root,pattern) + return xmlapplylpath(root,pattern) end function xml.collecttexts(root,pattern,flatten) - local collected=xmlapplylpath(root,pattern) - if collected and flatten then - local xmltostring=xml.tostring - for c=1,#collected do - collected[c]=xmltostring(collected[c].dt) - end + local collected=xmlapplylpath(root,pattern) + if collected and flatten then + local xmltostring=xml.tostring + for c=1,#collected do + collected[c]=xmltostring(collected[c].dt) end - return collected or {} + end + return collected or {} end function xml.collect_tags(root,pattern,nonamespace) - local collected=xmlapplylpath(root,pattern) - if collected then - local t,n={},0 - for c=1,#collected do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace then - t[n]=tg - elseif ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end - end - return t + local collected=xmlapplylpath(root,pattern) + if collected then + local t={} + local n=0 + for c=1,#collected do + local e=collected[c] + local ns=e.ns + local tg=e.tg + n=n+1 + if nonamespace then + t[n]=tg + elseif ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg + end end + return t + end end local no_root={ no_root=true } local function redo_ni(d) - for k=1,#d do - local dk=d[k] - if type(dk)=="table" then - dk.ni=k - end + for k=1,#d do + local dk=d[k] + if type(dk)=="table" then + dk.ni=k end + end end xml.reindex=redo_ni local function xmltoelement(whatever,root) - if not whatever then - return nil - end - local element - if type(whatever)=="string" then - element=xmlinheritedconvert(whatever,root) - else - element=whatever - end - if element.error then - return whatever - end - if element then - end - return element + if not whatever then + return nil + end + local element + if type(whatever)=="string" then + element=xmlinheritedconvert(whatever,root) + else + element=whatever + end + if element.error then + return whatever + end + if element then + end + return element end xml.toelement=xmltoelement local function copiedelement(element,newparent) - if type(element)=="string" then - return element - else - element=xmlcopy(element).dt - if newparent and type(element)=="table" then - element.__p__=newparent - end - return element + if type(element)=="string" then + return element + else + element=xmlcopy(element).dt + if newparent and type(element)=="table" then + element.__p__=newparent end + return element + end end function xml.delete(root,pattern) - if not pattern or pattern=="" then - local p=root.__p__ + if not pattern or pattern=="" then + local p=root.__p__ + if p then + if trace_manipulations then + report('deleting',"--",c,root) + end + local d=p.dt + remove(d,root.ni) + redo_ni(d) + end + else + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ if p then - if trace_manipulations then - report('deleting',"--",c,root) - end - local d=p.dt - remove(d,root.ni) - redo_ni(d) - end - else - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('deleting',pattern,c,e) - end - local d=p.dt - local ni=e.ni - if ni<=#d then - if false then - p.dt[ni]="" - else - remove(d,ni) - redo_ni(d) - end - else - end - end + if trace_manipulations then + report('deleting',pattern,c,e) + end + local d=p.dt + local ni=e.ni + if ni<=#d then + if false then + p.dt[ni]="" + else + remove(d,ni) + redo_ni(d) end + else + end end + end end + end end function xml.replace(root,pattern,whatever) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('replacing',pattern,c,e) - end - local d=p.dt - local n=e.ni - local t=copiedelement(element,p) - if type(t)=="table" then - d[n]=t[1] - for i=2,#t do - n=n+1 - insert(d,n,t[i]) - end - else - d[n]=t - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ + if p then + if trace_manipulations then + report('replacing',pattern,c,e) + end + local d=p.dt + local n=e.ni + local t=copiedelement(element,p) + if type(t)=="table" then + d[n]=t[1] + for i=2,#t do + n=n+1 + insert(d,n,t[i]) + end + else + d[n]=t end + redo_ni(d) + end end + end end local function wrap(e,wrapper) - local t={ - rn=e.rn, - tg=e.tg, - ns=e.ns, - at=e.at, - dt=e.dt, - __p__=e, - } - setmetatable(t,getmetatable(e)) - e.rn=wrapper.rn or e.rn or "" - e.tg=wrapper.tg or e.tg or "" - e.ns=wrapper.ns or e.ns or "" - e.at=fastcopy(wrapper.at) - e.dt={ t } + local t={ + rn=e.rn, + tg=e.tg, + ns=e.ns, + at=e.at, + dt=e.dt, + __p__=e, + } + setmetatable(t,getmetatable(e)) + e.rn=wrapper.rn or e.rn or "" + e.tg=wrapper.tg or e.tg or "" + e.ns=wrapper.ns or e.ns or "" + e.at=fastcopy(wrapper.at) + e.dt={ t } end function xml.wrap(root,pattern,whatever) - if whatever then - local wrapper=xmltoelement(whatever,root) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if trace_manipulations then - report('wrapping',pattern,c,e) - end - wrap(e,wrapper) - end + if whatever then + local wrapper=xmltoelement(whatever,root) + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if trace_manipulations then + report('wrapping',pattern,c,e) end - else - wrap(root,xmltoelement(pattern)) + wrap(e,wrapper) + end end + else + wrap(root,xmltoelement(pattern)) + end end local function inject_element(root,pattern,whatever,prepend) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function inject_e(e) - local r=e.__p__ - local d,k,rri=r.dt,e.ni,r.ri - local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) - if edt then - local be,af - local cp=copiedelement(element,e) - if prepend then - be,af=cp,edt - else - be,af=edt,cp - end - local bn=#be - for i=1,#af do - bn=bn+1 - be[bn]=af[i] - end - if rri then - r.dt[rri].dt=be - else - d[k].dt=be - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function inject_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + local rri=r.ri + local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) + if edt then + local be,af + local cp=copiedelement(element,e) + if prepend then + be,af=cp,edt + else + be,af=edt,cp + end + local bn=#be + for i=1,#af do + bn=bn+1 + be[bn]=af[i] + end + if rri then + r.dt[rri].dt=be + else + d[k].dt=be + end + redo_ni(d) end - if not collected then - elseif collected.tg then - inject_e(collected) - else - for c=1,#collected do - inject_e(collected[c]) - end + end + if not collected then + elseif collected.tg then + inject_e(collected) + else + for c=1,#collected do + inject_e(collected[c]) end + end end local function insert_element(root,pattern,whatever,before) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function insert_e(e) - local r=e.__p__ - local d,k=r.dt,e.ni - if not before then - k=k+1 - end - insert(d,k,copiedelement(element,r)) - redo_ni(d) - end - if not collected then - elseif collected.tg then - insert_e(collected) - else - for c=1,#collected do - insert_e(collected[c]) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function insert_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + if not before then + k=k+1 + end + insert(d,k,copiedelement(element,r)) + redo_ni(d) + end + if not collected then + elseif collected.tg then + insert_e(collected) + else + for c=1,#collected do + insert_e(collected[c]) end + end end xml.insert_element=insert_element xml.insertafter=insert_element @@ -15128,124 +18700,124 @@ xml.insertbefore=function(r,p,e) insert_element(r,p,e,true) end xml.injectafter=inject_element xml.injectbefore=function(r,p,e) inject_element(r,p,e,true) end local function include(xmldata,pattern,attribute,recursive,loaddata,level) - pattern=pattern or 'include' - loaddata=loaddata or io.loaddata - local collected=xmlapplylpath(xmldata,pattern) - if collected then - if not level then - level=1 - end - for c=1,#collected do - local ek=collected[c] - local name=nil - local ekdt=ek.dt - if ekdt then - local ekat=ek.at - local ekrt=ek.__p__ - if ekrt then - local epdt=ekrt.dt - if not attribute or attribute=="" then - name=(type(ekdt)=="table" and ekdt[1]) or ekdt - end - if not name then - for a in gmatch(attribute or "href","([^|]+)") do - name=ekat[a] - if name then - break - end - end - end - local data=nil - if name and name~="" then - local d,n=loaddata(name) - data=d or "" - name=n or name - if trace_inclusions then - report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") - end - end - if not data or data=="" then - epdt[ek.ni]="" - elseif ekat["parse"]=="text" then - epdt[ek.ni]=xml.escaped(data) - else + pattern=pattern or 'include' + loaddata=loaddata or io.loaddata + local collected=xmlapplylpath(xmldata,pattern) + if collected then + if not level then + level=1 + end + for c=1,#collected do + local ek=collected[c] + local name=nil + local ekdt=ek.dt + if ekdt then + local ekat=ek.at + local ekrt=ek.__p__ + if ekrt then + local epdt=ekrt.dt + if not attribute or attribute=="" then + name=(type(ekdt)=="table" and ekdt[1]) or ekdt + end + if not name then + for a in gmatch(attribute or "href","([^|]+)") do + name=ekat[a] + if name then + break + end + end + end + local data=nil + if name and name~="" then + local d,n=loaddata(name) + data=d or "" + name=n or name + if trace_inclusions then + report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") + end + end + if not data or data=="" then + epdt[ek.ni]="" + elseif ekat["parse"]=="text" then + epdt[ek.ni]=xml.escaped(data) + else local settings=xmldata.settings local savedresource=settings.currentresource settings.currentresource=name - local xi=xmlinheritedconvert(data,xmldata) - if not xi then - epdt[ek.ni]="" - else - if recursive then - include(xi,pattern,attribute,recursive,loaddata,level+1) - end - local child=xml.body(xi) - child.__p__=ekrt - child.__f__=name + local xi=xmlinheritedconvert(data,xmldata) + if not xi then + epdt[ek.ni]="" + else + if recursive then + include(xi,pattern,attribute,recursive,loaddata,level+1) + end + local child=xml.body(xi) + child.__p__=ekrt + child.__f__=name child.cf=name - epdt[ek.ni]=child - local settings=xmldata.settings - local inclusions=settings and settings.inclusions - if inclusions then - inclusions[#inclusions+1]=name - elseif settings then - settings.inclusions={ name } - else - settings={ inclusions={ name } } - xmldata.settings=settings - end - if child.er then - local badinclusions=settings.badinclusions - if badinclusions then - badinclusions[#badinclusions+1]=name - else - settings.badinclusions={ name } - end - end - end -settings.currentresource=savedresource - end + epdt[ek.ni]=child + local settings=xmldata.settings + local inclusions=settings and settings.inclusions + if inclusions then + inclusions[#inclusions+1]=name + elseif settings then + settings.inclusions={ name } + else + settings={ inclusions={ name } } + xmldata.settings=settings + end + if child.er then + local badinclusions=settings.badinclusions + if badinclusions then + badinclusions[#badinclusions+1]=name + else + settings.badinclusions={ name } end + end end +settings.currentresource=savedresource + end end + end end + end end xml.include=include function xml.inclusion(e,default) - while e do - local f=e.__f__ - if f then - return f - else - e=e.__p__ - end + while e do + local f=e.__f__ + if f then + return f + else + e=e.__p__ end - return default + end + return default end local function getinclusions(key,e,sorted) - while e do - local settings=e.settings - if settings then - local inclusions=settings[key] - if inclusions then - inclusions=table.unique(inclusions) - if sorted then - table.sort(inclusions) - end - return inclusions - else - e=e.__p__ - end - else - e=e.__p__ - end + while e do + local settings=e.settings + if settings then + local inclusions=settings[key] + if inclusions then + inclusions=table.unique(inclusions) + if sorted then + table.sort(inclusions) + end + return inclusions + else + e=e.__p__ + end + else + e=e.__p__ end + end end function xml.inclusions(e,sorted) - return getinclusions("inclusions",e,sorted) + return getinclusions("inclusions",e,sorted) end function xml.badinclusions(e,sorted) - return getinclusions("badinclusions",e,sorted) + return getinclusions("badinclusions",e,sorted) end local b_collapser=lpegpatterns.b_collapser local m_collapser=lpegpatterns.m_collapser @@ -15254,194 +18826,194 @@ local b_stripper=lpegpatterns.b_stripper local m_stripper=lpegpatterns.m_stripper local e_stripper=lpegpatterns.e_stripper local function stripelement(e,nolines,anywhere) - local edt=e.dt - if edt then - local n=#edt - if n==0 then - return e - elseif anywhere then - local t={} - local m=0 - for e=1,n do - local str=edt[e] - if type(str)~="string" then - m=m+1 - t[m]=str - elseif str~="" then - if nolines then - str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) - else - str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) - end - if str~="" then - m=m+1 - t[m]=str - end - end - end - e.dt=t + local edt=e.dt + if edt then + local n=#edt + if n==0 then + return e + elseif anywhere then + local t={} + local m=0 + for e=1,n do + local str=edt[e] + if type(str)~="string" then + m=m+1 + t[m]=str + elseif str~="" then + if nolines then + str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) + else + str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) + end + if str~="" then + m=m+1 + t[m]=str + end + end + end + e.dt=t + else + local str=edt[1] + if type(str)=="string" then + if str~="" then + str=lpegmatch(nolines and b_collapser or b_stripper,str) + end + if str=="" then + remove(edt,1) + n=n-1 else - local str=edt[1] - if type(str)=="string" then - if str~="" then - str=lpegmatch(nolines and b_collapser or b_stripper,str) - end - if str=="" then - remove(edt,1) - n=n-1 - else - edt[1]=str - end - end - if n>0 then - str=edt[n] - if type(str)=="string" then - if str=="" then - remove(edt) - else - str=lpegmatch(nolines and e_collapser or e_stripper,str) - if str=="" then - remove(edt) - else - edt[n]=str - end - end - end + edt[1]=str + end + end + if n>0 then + str=edt[n] + if type(str)=="string" then + if str=="" then + remove(edt) + else + str=lpegmatch(nolines and e_collapser or e_stripper,str) + if str=="" then + remove(edt) + else + edt[n]=str end + end end + end end - return e + end + return e end xml.stripelement=stripelement function xml.strip(root,pattern,nolines,anywhere) - local collected=xmlapplylpath(root,pattern) - if collected then - for i=1,#collected do - stripelement(collected[i],nolines,anywhere) - end + local collected=xmlapplylpath(root,pattern) + if collected then + for i=1,#collected do + stripelement(collected[i],nolines,anywhere) end + end end local function renamespace(root,oldspace,newspace) - local ndt=#root.dt - for i=1,ndt or 0 do - local e=root[i] - if type(e)=="table" then - if e.ns==oldspace then - e.ns=newspace - if e.rn then - e.rn=newspace - end - end - local edt=e.dt - if edt then - renamespace(edt,oldspace,newspace) - end + local ndt=#root.dt + for i=1,ndt or 0 do + local e=root[i] + if type(e)=="table" then + if e.ns==oldspace then + e.ns=newspace + if e.rn then + e.rn=newspace end + end + local edt=e.dt + if edt then + renamespace(edt,oldspace,newspace) + end end + end end xml.renamespace=renamespace function xml.remaptag(root,pattern,newtg) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].tg=newtg - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].tg=newtg end + end end function xml.remapnamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].ns=newns - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].ns=newns end + end end function xml.checknamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if (not e.rn or e.rn=="") and e.ns=="" then - e.rn=newns - end - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if (not e.rn or e.rn=="") and e.ns=="" then + e.rn=newns + end end + end end function xml.remapname(root,pattern,newtg,newns,newrn) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - e.tg,e.ns,e.rn=newtg,newns,newrn - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + e.tg,e.ns,e.rn=newtg,newns,newrn end + end end function xml.cdatatotext(e) - local dt=e.dt - if #dt==1 then - local first=dt[1] - if first.tg=="@cd@" then - e.dt=first.dt - end - else + local dt=e.dt + if #dt==1 then + local first=dt[1] + if first.tg=="@cd@" then + e.dt=first.dt end + else + end end function xml.texttocdata(e) - local dt=e.dt - local s=xml.tostring(dt) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(dt) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end function xml.elementtocdata(e) - local dt=e.dt - local s=xml.tostring(e) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(e) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end xml.builtinentities=table.tohash { "amp","quot","apos","lt","gt" } local entities=characters and characters.entities or nil local builtinentities=xml.builtinentities function xml.addentitiesdoctype(root,option) - if not entities then - require("char-ent") - entities=characters.entities - end - if entities and root and root.tg=="@rt@" and root.statistics then - local list={} - local hexify=option=="hexadecimal" - for k,v in table.sortedhash(root.statistics.entities.names) do - if not builtinentities[k] then - local e=entities[k] - if not e then - e=format("[%s]",k) - elseif hexify then - e=format("&#%05X;",utfbyte(k)) - end - list[#list+1]=format(" <!ENTITY %s %q >",k,e) - end - end - local dt=root.dt - local n=dt[1].tg=="@pi@" and 2 or 1 - if #list>0 then - insert(dt,n,{ "\n" }) - insert(dt,n,{ - tg="@dt@", - dt={ format("Something [\n%s\n] ",concat(list)) }, - ns="", - special=true, - }) - insert(dt,n,{ "\n\n" }) - else - end + if not entities then + require("char-ent") + entities=characters.entities + end + if entities and root and root.tg=="@rt@" and root.statistics then + local list={} + local hexify=option=="hexadecimal" + for k,v in table.sortedhash(root.statistics.entities.names) do + if not builtinentities[k] then + local e=entities[k] + if not e then + e=format("[%s]",k) + elseif hexify then + e=format("&#%05X;",utfbyte(k)) + end + list[#list+1]=format(" <!ENTITY %s %q >",k,e) + end end + local dt=root.dt + local n=dt[1].tg=="@pi@" and 2 or 1 + if #list>0 then + insert(dt,n,{ "\n" }) + insert(dt,n,{ + tg="@dt@", + dt={ format("Something [\n%s\n] ",concat(list)) }, + ns="", + special=true, + }) + insert(dt,n,{ "\n\n" }) + else + end + end end xml.all=xml.each xml.insert=xml.insertafter @@ -15451,239 +19023,241 @@ xml.before=xml.insertbefore xml.process=xml.each xml.obsolete=xml.obsolete or {} local obsolete=xml.obsolete -xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip -xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect -xml.delete_element=xml.delete obsolete.delete_element=xml.delete -xml.replace_element=xml.replace obsolete.replace_element=xml.replace -xml.each_element=xml.each obsolete.each_element=xml.each -xml.process_elements=xml.process obsolete.process_elements=xml.process -xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter -xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore -xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter -xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore -xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes -xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts -xml.inject_element=xml.inject obsolete.inject_element=xml.inject -xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag -xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname -xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace +xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip +xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect +xml.delete_element=xml.delete obsolete.delete_element=xml.delete +xml.replace_element=xml.replace obsolete.replace_element=xml.replace +xml.each_element=xml.each obsolete.each_element=xml.each +xml.process_elements=xml.process obsolete.process_elements=xml.process +xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter +xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore +xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter +xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore +xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes +xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts +xml.inject_element=xml.inject obsolete.inject_element=xml.inject +xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag +xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname +xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace function xml.cdata(e) - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" end - return "" + end + return "" end function xml.finalizers.xml.cdata(collected) - if collected then - local e=collected[1] - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end - end + if collected then + local e=collected[1] + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" + end end - return "" + end + return "" end function xml.insertcomment(e,str,n) - insert(e.dt,n or 1,{ - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.insertcdata(e,str,n) - insert(e.dt,n or 1,{ - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.setcomment(e,str,n) - e.dt={ { - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.setcdata(e,str) - e.dt={ { - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.separate(x,pattern) - local collected=xmlapplylpath(x,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local d=e.dt - if d==x then - report_xml("warning: xml.separate changes root") - x=d - end - local t,n={ "\n" },1 - local i,nd=1,#d - while i<=nd do - while i<=nd do - local di=d[i] - if type(di)=="string" then - if di=="\n" or find(di,"^%s+$") then - i=i+1 - else - d[i]=strip(di) - break - end - else - break - end - end - if i>nd then - break - end - t[n+1]="\n" - t[n+2]=d[i] - t[n+3]="\n" - n=n+3 - i=i+1 + local collected=xmlapplylpath(x,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local d=e.dt + if d==x then + report_xml("warning: xml.separate changes root") + x=d + end + local t={ "\n" } + local n=1 + local i=1 + local nd=#d + while i<=nd do + while i<=nd do + local di=d[i] + if type(di)=="string" then + if di=="\n" or find(di,"^%s+$") then + i=i+1 + else + d[i]=strip(di) + break end - t[n+1]="\n" - setmetatable(t,getmetatable(d)) - e.dt=t + else + break + end + end + if i>nd then + break end + t[n+1]="\n" + t[n+2]=d[i] + t[n+3]="\n" + n=n+3 + i=i+1 + end + t[n+1]="\n" + setmetatable(t,getmetatable(d)) + e.dt=t end - return x + end + return x end local helpers=xml.helpers or {} xml.helpers=helpers local function normal(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)=="string" and str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)=="string" and str~="" then + edt[i]=action(str) + end end + end end local function recurse(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)~="string" then - recurse(str,action) - elseif str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)~="string" then + recurse(str,action) + elseif str~="" then + edt[i]=action(str) + end end + end end function helpers.recursetext(collected,action,recursive) - if recursive then - for i=1,#collected do - recurse(collected[i],action) - end - else - for i=1,#collected do - normal(collected[i],action) - end + if recursive then + for i=1,#collected do + recurse(collected[i],action) end + else + for i=1,#collected do + normal(collected[i],action) + end + end end local specials={ - ["@rt@"]="root", - ["@pi@"]="instruction", - ["@cm@"]="comment", - ["@dt@"]="declaration", - ["@cd@"]="cdata", + ["@rt@"]="root", + ["@pi@"]="instruction", + ["@cm@"]="comment", + ["@dt@"]="declaration", + ["@cd@"]="cdata", } local function convert(x,strip,flat) - local ns=x.ns - local tg=x.tg - local at=x.at - local dt=x.dt - local node=flat and { - [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, - } or { - _namespace=ns~="" and ns or nil, - _tag=not x.special and tg or nil, - _type=specials[tg] or "_element", - } - if at then - for k,v in next,at do - node[k]=v - end - end - local n=0 - for i=1,#dt do - local di=dt[i] - if type(di)=="table" then - if flat and di.special then - else - di=convert(di,strip,flat) - if di then - n=n+1 - node[n]=di - end - end - elseif strip then - di=lpegmatch(strip,di) - if di~="" then - n=n+1 - node[n]=di - end - else - n=n+1 - node[n]=di + local ns=x.ns + local tg=x.tg + local at=x.at + local dt=x.dt + local node=flat and { + [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, + } or { + _namespace=ns~="" and ns or nil, + _tag=not x.special and tg or nil, + _type=specials[tg] or "_element", + } + if at then + for k,v in next,at do + node[k]=v + end + end + local n=0 + for i=1,#dt do + local di=dt[i] + if type(di)=="table" then + if flat and di.special then + else + di=convert(di,strip,flat) + if di then + n=n+1 + node[n]=di end + end + elseif strip then + di=lpegmatch(strip,di) + if di~="" then + n=n+1 + node[n]=di + end + else + n=n+1 + node[n]=di end - if next(node) then - return node - end + end + if next(node) then + return node + end end function xml.totable(x,strip,flat) - if type(x)=="table" then - if strip then - strip=striplinepatterns[strip] - end - return convert(x,strip,flat) + if type(x)=="table" then + if strip then + strip=striplinepatterns[strip] end + return convert(x,strip,flat) + end end function xml.rename(e,namespace,name,attributes) - if type(e)~="table" or not e.tg then - return - end - if type(name)=="table" then - attributes=name - name=namespace - namespace="" - elseif type(name)~="string" then - attributes={} - name=namespace - namespace="" - end - if type(attributes)~="table" then - attributes={} - end - e.ns=namespace - e.rn=namespace - e.tg=name - e.at=attributes + if type(e)~="table" or not e.tg then + return + end + if type(name)=="table" then + attributes=name + name=namespace + namespace="" + elseif type(name)~="string" then + attributes={} + name=namespace + namespace="" + end + if type(attributes)~="table" then + attributes={} + end + e.ns=namespace + e.rn=namespace + e.tg=name + e.at=attributes end @@ -15693,14 +19267,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-xml"] = package.loaded["lxml-xml"] or true --- original size: 11096, stripped down to: 8243 +-- original size: 11096, stripped down to: 7702 if not modules then modules={} end modules ['lxml-xml']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tonumber,next=tonumber,next local concat=table.concat @@ -15712,241 +19286,241 @@ local xmltostring=xml.tostring local xmlserialize=xml.serialize local xmlcollected=xml.collected local xmlnewhandlers=xml.newhandlers -local reparsedentity=xml.reparsedentitylpeg +local reparsedentity=xml.reparsedentitylpeg local unescapedentity=xml.unescapedentitylpeg local parsedentity=reparsedentity local function first(collected) - return collected and collected[1] + return collected and collected[1] end local function last(collected) - return collected and collected[#collected] + return collected and collected[#collected] end local function all(collected) - return collected + return collected end local reverse=table.reversed local function attribute(collected,name) - if collected and #collected>0 then - local at=collected[1].at - return at and at[name] - end + if collected and #collected>0 then + local at=collected[1].at + return at and at[name] + end end local function att(id,name) - local at=id.at - return at and at[name] + local at=id.at + return at and at[name] end local function count(collected) - return collected and #collected or 0 + return collected and #collected or 0 end local function position(collected,n) - if not collected then - return 0 - end - local nc=#collected - if nc==0 then - return 0 - end - n=tonumber(n) or 0 - if n<0 then - return collected[nc+n+1] - elseif n>0 then - return collected[n] - else - return collected[1].mi or 0 - end + if not collected then + return 0 + end + local nc=#collected + if nc==0 then + return 0 + end + n=tonumber(n) or 0 + if n<0 then + return collected[nc+n+1] + elseif n>0 then + return collected[n] + else + return collected[1].mi or 0 + end end local function match(collected) - return collected and #collected>0 and collected[1].mi or 0 + return collected and #collected>0 and collected[1].mi or 0 end local function index(collected) - return collected and #collected>0 and collected[1].ni or 0 + return collected and #collected>0 and collected[1].ni or 0 end local function attributes(collected,arguments) - if collected and #collected>0 then - local at=collected[1].at - if arguments then - return at[arguments] - elseif next(at) then - return at - end + if collected and #collected>0 then + local at=collected[1].at + if arguments then + return at[arguments] + elseif next(at) then + return at end + end end local function chainattribute(collected,arguments) - if collected and #collected>0 then - local e=collected[1] - while e do - local at=e.at - if at then - local a=at[arguments] - if a then - return a - end - else - break - end - e=e.__p__ + if collected and #collected>0 then + local e=collected[1] + while e do + local at=e.at + if at then + local a=at[arguments] + if a then + return a end + else + break + end + e=e.__p__ end - return "" + end + return "" end local function raw(collected) - if collected and #collected>0 then - local e=collected[1] or collected - return e and xmltostring(e) or "" - else - return "" - end + if collected and #collected>0 then + local e=collected[1] or collected + return e and xmltostring(e) or "" + else + return "" + end end local xmltexthandler=xmlnewhandlers { - name="string", - initialize=function() - result={} - return result - end, - finalize=function() - return concat(result) - end, - handle=function(...) - result[#result+1]=concat {... } - end, - escape=false, + name="string", + initialize=function() + result={} + return result + end, + finalize=function() + return concat(result) + end, + handle=function(...) + result[#result+1]=concat {... } + end, + escape=false, } local function xmltotext(root) - local dt=root.dt - if not dt then - return "" - end - local nt=#dt - if nt==0 then - return "" - elseif nt==1 and type(dt[1])=="string" then - return dt[1] - else - return xmlserialize(root,xmltexthandler) or "" - end + local dt=root.dt + if not dt then + return "" + end + local nt=#dt + if nt==0 then + return "" + elseif nt==1 and type(dt[1])=="string" then + return dt[1] + else + return xmlserialize(root,xmltexthandler) or "" + end end function xml.serializetotext(root) - return root and xmlserialize(root,xmltexthandler) or "" + return root and xmlserialize(root,xmltexthandler) or "" end local function text(collected) - if collected then - local e=collected[1] or collected - return e and xmltotext(e) or "" - else - return "" - end + if collected then + local e=collected[1] or collected + return e and xmltotext(e) or "" + else + return "" + end end local function texts(collected) - if not collected then - return {} - end - local nc=#collected - if nc==0 then - return {} - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - if e and e.dt then - n=n+1 - t[n]=e.dt - end - end - return t + if not collected then + return {} + end + local nc=#collected + if nc==0 then + return {} + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + if e and e.dt then + n=n+1 + t[n]=e.dt + end + end + return t end local function tag(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - return c and c.tg + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + return c and c.tg end local function name(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - if not c then - elseif c.ns=="" then - return c.tg - else - return c.ns..":"..c.tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + if not c then + elseif c.ns=="" then + return c.tg + else + return c.ns..":"..c.tg + end end local function tags(collected,nonamespace) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace or ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + local ns,tg=e.ns,e.tg + n=n+1 + if nonamespace or ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg end - return t + end + return t end local function empty(collected,spacesonly) - if not collected then - return true - end - local nc=#collected - if nc==0 then - return true - end - for c=1,nc do - local e=collected[c] - if e then - local edt=e.dt - if edt then - local n=#edt - if n==1 then - local edk=edt[1] - local typ=type(edk) - if typ=="table" then - return false - elseif edk~="" then - return false - elseif spacesonly and not find(edk,"%S") then - return false - end - elseif n>1 then - return false - end - end + if not collected then + return true + end + local nc=#collected + if nc==0 then + return true + end + for c=1,nc do + local e=collected[c] + if e then + local edt=e.dt + if edt then + local n=#edt + if n==1 then + local edk=edt[1] + local typ=type(edk) + if typ=="table" then + return false + elseif edk~="" then + return false + elseif spacesonly and not find(edk,"%S") then + return false + end + elseif n>1 then + return false end + end end - return true + end + return true end finalizers.first=first finalizers.last=last @@ -15969,124 +19543,124 @@ finalizers.name=name finalizers.tags=tags finalizers.empty=empty function xml.first(id,pattern) - return first(xmlfilter(id,pattern)) + return first(xmlfilter(id,pattern)) end function xml.last(id,pattern) - return last(xmlfilter(id,pattern)) + return last(xmlfilter(id,pattern)) end function xml.count(id,pattern) - return count(xmlfilter(id,pattern)) + return count(xmlfilter(id,pattern)) end function xml.attribute(id,pattern,a,default) - return attribute(xmlfilter(id,pattern),a,default) + return attribute(xmlfilter(id,pattern),a,default) end function xml.raw(id,pattern) - if pattern then - return raw(xmlfilter(id,pattern)) - else - return raw(id) - end + if pattern then + return raw(xmlfilter(id,pattern)) + else + return raw(id) + end end function xml.text(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - return collected and #collected>0 and xmltotext(collected[1]) or "" - elseif id then - return xmltotext(id) or "" - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + return collected and #collected>0 and xmltotext(collected[1]) or "" + elseif id then + return xmltotext(id) or "" + else + return "" + end end function xml.pure(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - if collected and #collected>0 then - parsedentity=unescapedentity - local s=collected and #collected>0 and xmltotext(collected[1]) or "" - parsedentity=reparsedentity - return s - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + if collected and #collected>0 then + parsedentity=unescapedentity + local s=collected and #collected>0 and xmltotext(collected[1]) or "" + parsedentity=reparsedentity + return s else - parsedentity=unescapedentity - local s=xmltotext(id) or "" - parsedentity=reparsedentity - return s + return "" end + else + parsedentity=unescapedentity + local s=xmltotext(id) or "" + parsedentity=reparsedentity + return s + end end xml.content=text function xml.position(id,pattern,n) - return position(xmlfilter(id,pattern),n) + return position(xmlfilter(id,pattern),n) end function xml.match(id,pattern) - return match(xmlfilter(id,pattern)) + return match(xmlfilter(id,pattern)) end function xml.empty(id,pattern,spacesonly) - return empty(xmlfilter(id,pattern),spacesonly) + return empty(xmlfilter(id,pattern),spacesonly) end xml.all=xml.filter xml.index=xml.position xml.found=xml.filter local function totable(x) - local t={} - for e in xmlcollected(x[1] or x,"/*") do - t[e.tg]=xmltostring(e.dt) or "" - end - return next(t) and t or nil + local t={} + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg]=xmltostring(e.dt) or "" + end + return next(t) and t or nil end xml.table=totable finalizers.table=totable local function textonly(e,t) - if e then - local edt=e.dt - if edt then - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - textonly(e,t) - else - t[#t+1]=e - end - end + if e then + local edt=e.dt + if edt then + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + textonly(e,t) + else + t[#t+1]=e end + end end - return t + end + return t end function xml.textonly(e) - return concat(textonly(e,{})) + return concat(textonly(e,{})) end function finalizers.lowerall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=lower(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[lower(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=lower(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[lower(k)]=v end + e.at=t + end end + end end function finalizers.upperall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=upper(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[upper(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=upper(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[upper(k)]=v end + e.at=t + end end + end end @@ -16096,14 +19670,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-xml"] = package.loaded["trac-xml"] or true --- original size: 6407, stripped down to: 4965 +-- original size: 6407, stripped down to: 4640 if not modules then modules={} end modules ['trac-xml']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local formatters=string.formatters local reporters=logs.reporters @@ -16112,152 +19686,152 @@ local xmlcollected=xml.collected local xmltext=xml.text local xmlfirst=xml.first local function showhelp(specification,...) - local root=xml.convert(specification.helpinfo or "") - if not root then - return - end - local xs=xml.gethandlers("string") - xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) - xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) - local wantedcategories=select("#",...)==0 and true or table.tohash {... } - local nofcategories=xml.count(root,"/application/flags/category") - local report=specification.report - for category in xmlcollected(root,"/application/flags/category") do - local categoryname=category.at.name or "" - if wantedcategories==true or wantedcategories[categoryname] then - if nofcategories>1 then - report("%s options:",categoryname) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for flag in xmlcollected(subcategory,"/flag") do - local name=flag.at.name - local value=flag.at.value - local short=xmltext(xmlfirst(flag,"/short")) - if value then - report("--%-20s %s",formatters["%s=%s"](name,value),short) - else - report("--%-20s %s",name,short) - end - end - report() - end - end - end - for category in xmlcollected(root,"/application/examples/category") do - local title=xmltext(xmlfirst(category,"/title")) - if title and title~="" then - report() - report(title) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for example in xmlcollected(subcategory,"/example") do - local command=xmltext(xmlfirst(example,"/command")) - local comment=xmltext(xmlfirst(example,"/comment")) - report(command) - end - report() - end - end - for comment in xmlcollected(root,"/application/comments/comment") do - local comment=xmltext(comment) + local root=xml.convert(specification.helpinfo or "") + if not root then + return + end + local xs=xml.gethandlers("string") + xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) + xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) + local wantedcategories=select("#",...)==0 and true or table.tohash {... } + local nofcategories=xml.count(root,"/application/flags/category") + local report=specification.report + for category in xmlcollected(root,"/application/flags/category") do + local categoryname=category.at.name or "" + if wantedcategories==true or wantedcategories[categoryname] then + if nofcategories>1 then + report("%s options:",categoryname) report() - report(comment) + end + for subcategory in xmlcollected(category,"/subcategory") do + for flag in xmlcollected(subcategory,"/flag") do + local name=flag.at.name + local value=flag.at.value + local short=xmltext(xmlfirst(flag,"/short")) + if value then + report("--%-20s %s",formatters["%s=%s"](name,value),short) + else + report("--%-20s %s",name,short) + end + end report() + end + end + end + for category in xmlcollected(root,"/application/examples/category") do + local title=xmltext(xmlfirst(category,"/title")) + if title and title~="" then + report() + report(title) + report() + end + for subcategory in xmlcollected(category,"/subcategory") do + for example in xmlcollected(subcategory,"/example") do + local command=xmltext(xmlfirst(example,"/command")) + local comment=xmltext(xmlfirst(example,"/comment")) + report(command) + end + report() end + end + for comment in xmlcollected(root,"/application/comments/comment") do + local comment=xmltext(comment) + report() + report(comment) + report() + end end local reporthelp=reporters.help local exporthelp=reporters.export local function xmlfound(t) - local helpinfo=t.helpinfo - if type(helpinfo)=="table" then - return false + local helpinfo=t.helpinfo + if type(helpinfo)=="table" then + return false + end + if type(helpinfo)~="string" then + helpinfo="Warning: no helpinfo found." + t.helpinfo=helpinfo + return false + end + if string.find(helpinfo,".xml$") then + local ownscript=environment.ownscript + local helpdata=false + if ownscript then + local helpfile=file.join(file.pathpart(ownscript),helpinfo) + helpdata=io.loaddata(helpfile) + if helpdata=="" then + helpdata=false + end end - if type(helpinfo)~="string" then - helpinfo="Warning: no helpinfo found." - t.helpinfo=helpinfo - return false + if not helpdata then + local helpfile=resolvers.findfile(helpinfo,"tex") + helpdata=helpfile and io.loaddata(helpfile) end - if string.find(helpinfo,".xml$") then - local ownscript=environment.ownscript - local helpdata=false - if ownscript then - local helpfile=file.join(file.pathpart(ownscript),helpinfo) - helpdata=io.loaddata(helpfile) - if helpdata=="" then - helpdata=false - end - end - if not helpdata then - local helpfile=resolvers.findfile(helpinfo,"tex") - helpdata=helpfile and io.loaddata(helpfile) - end - if helpdata and helpdata~="" then - helpinfo=helpdata - else - helpinfo=formatters["Warning: help file %a is not found."](helpinfo) - end + if helpdata and helpdata~="" then + helpinfo=helpdata + else + helpinfo=formatters["Warning: help file %a is not found."](helpinfo) end - t.helpinfo=helpinfo - return string.find(t.helpinfo,"^<%?xml") and true or false + end + t.helpinfo=helpinfo + return string.find(t.helpinfo,"^<%?xml") and true or false end function reporters.help(t,...) - if xmlfound(t) then - showhelp(t,...) - else - reporthelp(t,...) - end + if xmlfound(t) then + showhelp(t,...) + else + reporthelp(t,...) + end end function reporters.export(t,methods,filename) - if not xmlfound(t) then - return exporthelp(t) - end - if not methods or methods=="" then - methods=environment.arguments["exporthelp"] - end - if not filename or filename=="" then - filename=environment.files[1] - end - dofile(resolvers.findfile("trac-exp.lua","tex")) - local exporters=logs.exporters - if not exporters or not methods then - return exporthelp(t) - end - if methods=="all" then - methods=table.keys(exporters) - elseif type(methods)=="string" then - methods=utilities.parsers.settings_to_array(methods) - else - return exporthelp(t) - end - if type(filename)~="string" or filename=="" then - filename=false - elseif file.pathpart(filename)=="" then - t.report("export file %a will not be saved on the current path (safeguard)",filename) - return - end - for i=1,#methods do - local method=methods[i] - local exporter=exporters[method] - if exporter then - local result=exporter(t,method) - if result and result~="" then - if filename then - local fullname=file.replacesuffix(filename,method) - t.report("saving export in %a",fullname) - dir.mkdirs(file.pathpart(fullname)) - io.savedata(fullname,result) - else - reporters.lines(t,result) - end - else - t.report("no output from exporter %a",method) - end + if not xmlfound(t) then + return exporthelp(t) + end + if not methods or methods=="" then + methods=environment.arguments["exporthelp"] + end + if not filename or filename=="" then + filename=environment.files[1] + end + dofile(resolvers.findfile("trac-exp.lua","tex")) + local exporters=logs.exporters + if not exporters or not methods then + return exporthelp(t) + end + if methods=="all" then + methods=table.keys(exporters) + elseif type(methods)=="string" then + methods=utilities.parsers.settings_to_array(methods) + else + return exporthelp(t) + end + if type(filename)~="string" or filename=="" then + filename=false + elseif file.pathpart(filename)=="" then + t.report("export file %a will not be saved on the current path (safeguard)",filename) + return + end + for i=1,#methods do + local method=methods[i] + local exporter=exporters[method] + if exporter then + local result=exporter(t,method) + if result and result~="" then + if filename then + local fullname=file.replacesuffix(filename,method) + t.report("saving export in %a",fullname) + dir.mkdirs(file.pathpart(fullname)) + io.savedata(fullname,result) else - t.report("unknown exporter %a",method) + reporters.lines(t,result) end + else + t.report("no output from exporter %a",method) + end + else + t.report("unknown exporter %a",method) end + end end @@ -16267,149 +19841,149 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 11099, stripped down to: 7516 +-- original size: 11099, stripped down to: 7152 if not modules then modules={} end modules ['data-ini']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false texconfig.shell_escape='t' if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then - local default_texmfcnf=kpse.default_texmfcnf() - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") - default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") - environment.default_texmfcnf=default_texmfcnf + local default_texmfcnf=kpse.default_texmfcnf() + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") + default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") + environment.default_texmfcnf=default_texmfcnf end kpse={ original=kpse } setmetatable(kpse,{ - __index=function(kp,name) - report_initialization("fatal error: kpse library is accessed (key: %s)",name) - os.exit() - end + __index=function(kp,name) + report_initialization("fatal error: kpse library is accessed (key: %s)",name) + os.exit() + end } ) do - local osfontdir=osgetenv("OSFONTDIR") - if osfontdir and osfontdir~="" then - elseif osname=="windows" then - ossetenv("OSFONTDIR","c:/windows/fonts//") - elseif osname=="macosx" then - ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") - end + local osfontdir=osgetenv("OSFONTDIR") + if osfontdir and osfontdir~="" then + elseif osname=="windows" then + ossetenv("OSFONTDIR","c:/windows/fonts//") + elseif osname=="macosx" then + ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") + end end do - local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' - if not homedir or homedir=="" then - homedir=char(127) - end - homedir=file.collapsepath(homedir) - ossetenv("HOME",homedir) - ossetenv("USERPROFILE",homedir) - environment.homedir=homedir + local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' + if not homedir or homedir=="" then + homedir=char(127) + end + homedir=file.collapsepath(homedir) + ossetenv("HOME",homedir) + ossetenv("USERPROFILE",homedir) + environment.homedir=homedir end do - local args=environment.originalarguments or arg - if not environment.ownmain then - environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" - end - local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" - local ownpath=environment.ownpath or os.selfdir - ownbin=file.collapsepath(ownbin) - ownpath=file.collapsepath(ownpath) - if not ownpath or ownpath=="" or ownpath=="unset" then - ownpath=args[-1] or arg[-1] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - if not ownpath or ownpath=="" then - ownpath=args[-0] or arg[-0] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - end - local binary=ownbin - if not ownpath or ownpath=="" then - ownpath=ownpath and filedirname(binary) - end - if not ownpath or ownpath=="" then - if os.binsuffix~="" then - binary=file.replacesuffix(binary,os.binsuffix) - end - local path=osgetenv("PATH") - if path then - for p in gmatch(path,"[^"..io.pathseparator.."]+") do - local b=filejoin(p,binary) - if lfs.isfile(b) then - local olddir=lfs.currentdir() - if lfs.chdir(p) then - local pp=lfs.currentdir() - if trace_locating and p~=pp then - report_initialization("following symlink %a to %a",p,pp) - end - ownpath=pp - lfs.chdir(olddir) - else - if trace_locating then - report_initialization("unable to check path %a",p) - end - ownpath=p - end - break - end - end + local args=environment.originalarguments or arg + if not environment.ownmain then + environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" + end + local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" + local ownpath=environment.ownpath or os.selfdir + ownbin=file.collapsepath(ownbin) + ownpath=file.collapsepath(ownpath) + if not ownpath or ownpath=="" or ownpath=="unset" then + ownpath=args[-1] or arg[-1] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + if not ownpath or ownpath=="" then + ownpath=args[-0] or arg[-0] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + end + local binary=ownbin + if not ownpath or ownpath=="" then + ownpath=ownpath and filedirname(binary) + end + if not ownpath or ownpath=="" then + if os.binsuffix~="" then + binary=file.replacesuffix(binary,os.binsuffix) + end + local path=osgetenv("PATH") + if path then + for p in gmatch(path,"[^"..io.pathseparator.."]+") do + local b=filejoin(p,binary) + if lfs.isfile(b) then + local olddir=lfs.currentdir() + if lfs.chdir(p) then + local pp=lfs.currentdir() + if trace_locating and p~=pp then + report_initialization("following symlink %a to %a",p,pp) + end + ownpath=pp + lfs.chdir(olddir) + else + if trace_locating then + report_initialization("unable to check path %a",p) + end + ownpath=p end + break + end end - if not ownpath or ownpath=="" then - ownpath="." - report_initialization("forcing fallback to ownpath %a",ownpath) - elseif trace_locating then - report_initialization("using ownpath %a",ownpath) - end + end end - environment.ownbin=ownbin - environment.ownpath=ownpath + if not ownpath or ownpath=="" then + ownpath="." + report_initialization("forcing fallback to ownpath %a",ownpath) + elseif trace_locating then + report_initialization("using ownpath %a",ownpath) + end + end + environment.ownbin=ownbin + environment.ownpath=ownpath end resolvers.ownpath=environment.ownpath function resolvers.getownpath() - return environment.ownpath + return environment.ownpath end do - local ownpath=environment.ownpath or dir.current() - if ownpath then - ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) - ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) - ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) - else - report_initialization("error: unable to locate ownpath") - os.exit() - end -end -local texos=environment.texos or osgetenv("TEXOS") + local ownpath=environment.ownpath or dir.current() + if ownpath then + ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) + ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) + ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) + else + report_initialization("error: unable to locate ownpath") + os.exit() + end +end +local texos=environment.texos or osgetenv("TEXOS") local texmfos=environment.texmfos or osgetenv('SELFAUTODIR') if not texos or texos=="" then - texos=file.basename(texmfos) + texos=file.basename(texmfos) end ossetenv('TEXMFOS',texmfos) -ossetenv('TEXOS',texos) -ossetenv('SELFAUTOSYSTEM',os.platform) +ossetenv('TEXOS',texos) +ossetenv('SELFAUTOSYSTEM',os.platform) environment.texos=texos environment.texmfos=texmfos local texroot=environment.texroot or osgetenv("TEXROOT") if not texroot or texroot=="" then - texroot=osgetenv('SELFAUTOPARENT') - ossetenv('TEXROOT',texroot) + texroot=osgetenv('SELFAUTOPARENT') + ossetenv('TEXROOT',texroot) end environment.texroot=file.collapsepath(texroot) local prefixes=utilities.storage.allocate() @@ -16418,30 +19992,30 @@ local resolved={} local abstract={} local dynamic={} function resolvers.resetresolve(str) - resolved,abstract={},{} + resolved,abstract={},{} end function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" end - return all + end + return all end local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end end function resolvers.unresolve(str) - return abstract[str] or str + return abstract[str] or str end function resolvers.setdynamic(str) - dynamic[str]=true + dynamic[str]=true end local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) local prefix=C(R("az")^2)*P(":") @@ -16450,65 +20024,65 @@ local notarget=(#S(";,")+P(-1))*Cc("") local p_resolve=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) local p_simple=prefix*P(-1) local function resolve(str) - if type(str)=="table" then - local res={} - for i=1,#str do - res[i]=resolve(str[i]) - end - return res - end - local res=resolved[str] - if res then - return res + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) end - local simple=lpegmatch(p_simple,str) - local action=prefixes[simple] - if action then - local res=action(res) - if not dynamic[simple] then - resolved[simple]=res - abstract[res]=simple - end - return res + return res + end + local res=resolved[str] + if res then + return res + end + local simple=lpegmatch(p_simple,str) + local action=prefixes[simple] + if action then + local res=action(res) + if not dynamic[simple] then + resolved[simple]=res + abstract[res]=simple end - res=lpegmatch(p_resolve,str) - resolved[str]=res - abstract[res]=str return res + end + res=lpegmatch(p_resolve,str) + resolved[str]=res + abstract[res]=str + return res end resolvers.resolve=resolve if type(osuname)=="function" then - for k,v in next,osuname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end end + end end if ostype=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - table.setmetatablenewindex(prefixes,makepattern) - function resolvers.repath(str) - return lpegmatch(pattern,str) + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end else - function resolvers.repath(str) - return str - end + function resolvers.repath(str) + return str + end end @@ -16518,14 +20092,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 18105, stripped down to: 11207 +-- original size: 18105, stripped down to: 10389 if not modules then modules={} end modules ['data-exp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } 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 @@ -16535,21 +20109,21 @@ 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 isdir=lfs.isdir local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers local resolveprefix=resolvers.resolve local function f_both(a,b) - local t,n={},0 - for sb in gmatch(b,"[^,]+") do - for sa in gmatch(a,"[^,]+") do - n=n+1;t[n]=sa..sb - end + local t,n={},0 + for sb in gmatch(b,"[^,]+") do + for sa in gmatch(a,"[^,]+") do + n=n+1;t[n]=sa..sb end - return concat(t,",") + end + return concat(t,",") end local comma=P(",") local nocomma=(1-comma)^1 @@ -16559,7 +20133,7 @@ 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 function f_both (a,b) return lpegmatch(both,b,1,a) end local left=P("{") local right=P("}") local var=P((1-S("{}" ))^0) @@ -16572,141 +20146,141 @@ local l_rest=Cs((left*var*(left/"")*var*(right/"")*var*right+other )^0 ) local stripper_1=lpeg.stripper ("{}@") local replacer_1=lpeg.replacer { { ",}",",@}" },{ "{,","{@," },} local function splitpathexpr(str,newlist,validate) - if trace_expansions then - report_expansions("expanding variable %a",str) - end - local t,ok,done=newlist or {},false,false - local n=#t - str=lpegmatch(replacer_1,str) + if trace_expansions then + report_expansions("expanding variable %a",str) + end + local t,ok,done=newlist or {},false,false + local n=#t + str=lpegmatch(replacer_1,str) + repeat + local old=str repeat - local old=str - repeat - local old=str - str=lpegmatch(l_first,str) - until old==str - repeat - local old=str - str=lpegmatch(l_second,str) - until old==str - repeat - local old=str - str=lpegmatch(l_both,str) - until old==str - repeat - local old=str - str=lpegmatch(l_rest,str) - until old==str - until old==str - str=lpegmatch(stripper_1,str) - if validate then - for s in gmatch(str,"[^,]+") do - s=validate(s) - if s then - n=n+1 - t[n]=s - end - end - else - for s in gmatch(str,"[^,]+") do - n=n+1 - t[n]=s - end + local old=str + str=lpegmatch(l_first,str) + until old==str + repeat + local old=str + str=lpegmatch(l_second,str) + until old==str + repeat + local old=str + str=lpegmatch(l_both,str) + until old==str + repeat + local old=str + str=lpegmatch(l_rest,str) + until old==str + until old==str + str=lpegmatch(stripper_1,str) + if validate then + for s in gmatch(str,"[^,]+") do + s=validate(s) + if s then + n=n+1 + t[n]=s + end end - if trace_expansions then - for k=1,#t do - report_expansions("% 4i: %s",k,t[k]) - end + else + for s in gmatch(str,"[^,]+") do + n=n+1 + t[n]=s end - return t + end + if trace_expansions then + for k=1,#t do + report_expansions("% 4i: %s",k,t[k]) + end + end + return t end local function validate(s) - s=collapsepath(s) - return s~="" and not find(s,"^!*unset/*$") and s + s=collapsepath(s) + return s~="" and not find(s,"^!*unset/*$") and s end resolvers.validatedpath=validate function resolvers.expandedpathfromlist(pathlist) - local newlist={} - for k=1,#pathlist do - splitpathexpr(pathlist[k],newlist,validate) - end - return newlist + local newlist={} + for k=1,#pathlist do + splitpathexpr(pathlist[k],newlist,validate) + end + return newlist end local usedhomedir=nil -local donegation=(P("!")/"" )^0 +local donegation=(P("!")/"" )^0 local doslashes=(P("\\")/"/"+1)^0 local function expandedhome() - if not usedhomedir then - usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent path using current path") - end - usedhomedir="." - end + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") + end + usedhomedir="." end - return usedhomedir + end + return usedhomedir end local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 local cleanup=Cs(donegation*dohome*doslashes) resolvers.cleanpath=function(str) - return str and lpegmatch(cleanup,str) or "" + return str and lpegmatch(cleanup,str) or "" end local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" -local dostring=(expandhome+1 )^0 +local dostring=(expandhome+1 )^0 local stripper=Cs( - lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer + lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer ) function resolvers.checkedvariable(str) - return type(str)=="string" and lpegmatch(stripper,str) or str + return type(str)=="string" and lpegmatch(stripper,str) or str end local cache={} local splitter=lpeg.tsplitat(";") local backslashswapper=lpeg.replacer("\\","/") local function splitconfigurationpath(str) - if str then - local found=cache[str] - if not found then - if str=="" then - found={} - else - local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) - found={} - local noffound=0 - for i=1,#split do - local s=split[i] - if not find(s,"^{*unset}*") then - noffound=noffound+1 - found[noffound]=s - end - end - if trace_expansions then - report_expansions("splitting path specification %a",str) - for k=1,noffound do - report_expansions("% 4i: %s",k,found[k]) - end - end - cache[str]=found - end + if str then + local found=cache[str] + if not found then + if str=="" then + found={} + else + local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) + found={} + local noffound=0 + for i=1,#split do + local s=split[i] + if not find(s,"^{*unset}*") then + noffound=noffound+1 + found[noffound]=s + end end - return found + if trace_expansions then + report_expansions("splitting path specification %a",str) + for k=1,noffound do + report_expansions("% 4i: %s",k,found[k]) + end + end + cache[str]=found + end end + return found + end end resolvers.splitconfigurationpath=splitconfigurationpath function resolvers.splitpath(str) - if type(str)=='table' then - return str - else - return splitconfigurationpath(str) - end + if type(str)=='table' then + return str + else + return splitconfigurationpath(str) + end end function resolvers.joinpath(str) - if type(str)=='table' then - return joinpath(str) - else - return str - end + if type(str)=='table' then + return joinpath(str) + else + return str + end end local attributes,directory=lfs.attributes,lfs.dir local weird=P(".")^1+lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) @@ -16719,201 +20293,201 @@ local fullcache={} local nofsharedscans=0 local addcasecraptoo=true local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant) - local full=path=="" and spec or (spec..path..'/') - local dirlist={} - local nofdirs=0 - local pattern=tolerant and lessweird or weird - local filelist={} - local noffiles=0 - for name in directory(full) do - if not lpegmatch(pattern,name) then - local mode=attributes(full..name,"mode") - if mode=="file" then - n=n+1 - noffiles=noffiles+1 - filelist[noffiles]=name - elseif mode=="directory" then - m=m+1 - nofdirs=nofdirs+1 - if path~="" then - dirlist[nofdirs]=path.."/"..name - else - dirlist[nofdirs]=name - end - end + local full=path=="" and spec or (spec..path..'/') + local dirlist={} + local nofdirs=0 + local pattern=tolerant and lessweird or weird + local filelist={} + local noffiles=0 + for name in directory(full) do + if not lpegmatch(pattern,name) then + local mode=attributes(full..name,"mode") + if mode=="file" then + n=n+1 + noffiles=noffiles+1 + filelist[noffiles]=name + elseif mode=="directory" then + m=m+1 + nofdirs=nofdirs+1 + if path~="" then + dirlist[nofdirs]=path.."/"..name + else + dirlist[nofdirs]=name end + end end - if noffiles>0 then - sort(filelist) - for i=1,noffiles do - local name=filelist[i] - local lower=lower(name) - local paths=files[lower] - if paths then - if onlyone then - else - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - if addcasecraptoo then - local paths=files[name] - if not paths then - files[name]=path - elseif type(paths)=="string" then - files[name]={ paths,path } - else - paths[#paths+1]=path - end - end - end - if type(paths)=="string" then - files[lower]={ paths,path } - else - paths[#paths+1]=path - end - end - else - files[lower]=path - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - end + end + if noffiles>0 then + sort(filelist) + for i=1,noffiles do + local name=filelist[i] + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then + else + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + if addcasecraptoo then + local paths=files[name] + if not paths then + files[name]=path + elseif type(paths)=="string" then + files[name]={ paths,path } + else + paths[#paths+1]=path + end end + end + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end end - end - if nofdirs>0 then - sort(dirlist) - for i=1,nofdirs do - files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) + else + files[lower]=path + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end + end + end + end + if nofdirs>0 then + sort(dirlist) + for i=1,nofdirs do + files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) end - scancache[sub(full,1,-2)]=files - return files,remap,n,m,r + end + scancache[sub(full,1,-2)]=files + return files,remap,n,m,r end function resolvers.scanfiles(path,branch,usecache,onlyonce,tolerant) - local realpath=resolveprefix(path) - if usecache then - local content=fullcache[realpath] - if content then - if trace_locating then - report_expansions("using cached scan of path %a, branch %a",path,branch or path) - end - nofsharedscans=nofsharedscans+1 - return content - end - end - statistics.starttiming(timer) + local realpath=resolveprefix(path) + if usecache then + local content=fullcache[realpath] + if content then + if trace_locating then + report_expansions("using cached scan of path %a, branch %a",path,branch or path) + end + nofsharedscans=nofsharedscans+1 + return content + end + end + statistics.starttiming(timer) + if trace_locating then + report_expansions("scanning path %a, branch %a",path,branch or path) + end + local content + if isdir(realpath) then + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) + content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) + report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end - local content - if isdir(realpath) then - local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) - content={ - metadata={ - path=path, - files=n, - directories=m, - remappings=r, - }, - files=files, - remap=remap, - } - if trace_locating then - report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) - end - else - content={ - metadata={ - path=path, - files=0, - directories=0, - remappings=0, - }, - files={}, - remap={}, - } - if trace_locating then - report_expansions("invalid path %a",realpath) - end - end - if usecache then - scanned[#scanned+1]=realpath - fullcache[realpath]=content + else + content={ + metadata={ + path=path, + files=0, + directories=0, + remappings=0, + }, + files={}, + remap={}, + } + if trace_locating then + report_expansions("invalid path %a",realpath) end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return content + end + if usecache then + scanned[#scanned+1]=realpath + fullcache[realpath]=content + end + nofscans=nofscans+1 + statistics.stoptiming(timer) + return content end function resolvers.simplescanfiles(path,branch,usecache) - return resolvers.scanfiles(path,branch,usecache,true,true) + return resolvers.scanfiles(path,branch,usecache,true,true) end function resolvers.scandata() - table.sort(scanned) - return { - n=nofscans, - shared=nofsharedscans, - time=statistics.elapsedtime(timer), - paths=scanned, - } + table.sort(scanned) + return { + n=nofscans, + shared=nofsharedscans, + time=statistics.elapsedtime(timer), + paths=scanned, + } end function resolvers.get_from_content(content,path,name) - if not content then - return - end - local files=content.files - if not files then - return - end - local remap=content.remap - if not remap then - return - end - if name then - local used=lower(name) - return path,remap[used] or used - else - local name=path - local used=lower(name) - local path=files[used] - if path then - return path,remap[used] or used - end - end + if not content then + return + end + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end end local nothing=function() end function resolvers.filtered_from_content(content,pattern) - if content and type(pattern)=="string" then - local pattern=lower(pattern) - local files=content.files - local remap=content.remap - if files and remap then - local f=sortedkeys(files) - local n=#f - local i=0 - local function iterator() - while i<n do - i=i+1 - local k=f[i] - if find(k,pattern) then - return files[k],remap and remap[k] or k - end - end - end - return iterator + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local f=sortedkeys(files) + local n=#f + local i=0 + local function iterator() + while i<n do + i=i+1 + local k=f[i] + if find(k,pattern) then + return files[k],remap and remap[k] or k + end end + end + return iterator end - return nothing + end + return nothing end @@ -16923,14 +20497,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-env"] = package.loaded["data-env"] or true --- original size: 9360, stripped down to: 6903 +-- original size: 9360, stripped down to: 6312 if not modules then modules={} end modules ['data-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local lower,gsub=string.lower,string.gsub local next=next @@ -16950,255 +20524,255 @@ resolvers.suffixmap=suffixmap resolvers.usertypes=usertypes local luasuffixes=utilities.lua.suffixes local relations=allocate { - core={ - ofm={ - names={ "ofm","omega font metric","omega font metrics" }, - variable='OFMFONTS', - suffixes={ 'ofm','tfm' }, - }, - ovf={ - names={ "ovf","omega virtual font","omega virtual fonts" }, - variable='OVFFONTS', - suffixes={ 'ovf','vf' }, - }, - tfm={ - names={ "tfm","tex font metric","tex font metrics" }, - variable='TFMFONTS', - suffixes={ 'tfm' }, - }, - vf={ - names={ "vf","virtual font","virtual fonts" }, - variable='VFFONTS', - suffixes={ 'vf' }, - }, - otf={ - names={ "otf","opentype","opentype font","opentype fonts"}, - variable='OPENTYPEFONTS', - suffixes={ 'otf' }, - }, - ttf={ - names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, - variable='TTFONTS', - suffixes={ 'ttf','ttc','dfont' }, - }, - afm={ - names={ "afm","adobe font metric","adobe font metrics" }, - variable="AFMFONTS", - suffixes={ "afm" }, - }, - pfb={ - names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, - variable='T1FONTS', - suffixes={ 'pfb','pfa' }, - }, - fea={ - names={ "fea","font feature","font features","font feature file","font feature files" }, - variable='FONTFEATURES', - suffixes={ 'fea' }, - }, - cid={ - names={ "cid","cid map","cid maps","cid file","cid files" }, - variable='FONTCIDMAPS', - suffixes={ 'cid','cidmap' }, - }, - fmt={ - names={ "fmt","format","tex format" }, - variable='TEXFORMATS', - suffixes={ 'fmt' }, - }, - mem={ - names={ 'mem',"metapost format" }, - variable='MPMEMS', - suffixes={ 'mem' }, - }, - mp={ - names={ "mp" }, - variable='MPINPUTS', - suffixes={ 'mp','mpvi','mpiv','mpii' }, - usertype=true, - }, - tex={ - names={ "tex" }, - variable='TEXINPUTS', - suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, - usertype=true, - }, - icc={ - names={ "icc","icc profile","icc profiles" }, - variable='ICCPROFILES', - suffixes={ 'icc' }, - }, - texmfscripts={ - names={ "texmfscript","texmfscripts","script","scripts" }, - variable='TEXMFSCRIPTS', - suffixes={ 'lua','rb','pl','py' }, - }, - lua={ - names={ "lua" }, - variable='LUAINPUTS', - suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, - usertype=true, - }, - lib={ - names={ "lib" }, - variable='CLUAINPUTS', - suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, - }, - bib={ - names={ 'bib' }, - variable='BIBINPUTS', - suffixes={ 'bib' }, - usertype=true, - }, - bst={ - names={ 'bst' }, - variable='BSTINPUTS', - suffixes={ 'bst' }, - usertype=true, - }, - fontconfig={ - names={ 'fontconfig','fontconfig file','fontconfig files' }, - variable='FONTCONFIG_PATH', - }, - pk={ - names={ "pk" }, - variable='PKFONTS', - suffixes={ 'pk' }, - }, + core={ + ofm={ + names={ "ofm","omega font metric","omega font metrics" }, + variable='OFMFONTS', + suffixes={ 'ofm','tfm' }, + }, + ovf={ + names={ "ovf","omega virtual font","omega virtual fonts" }, + variable='OVFFONTS', + suffixes={ 'ovf','vf' }, + }, + tfm={ + names={ "tfm","tex font metric","tex font metrics" }, + variable='TFMFONTS', + suffixes={ 'tfm' }, + }, + vf={ + names={ "vf","virtual font","virtual fonts" }, + variable='VFFONTS', + suffixes={ 'vf' }, + }, + otf={ + names={ "otf","opentype","opentype font","opentype fonts"}, + variable='OPENTYPEFONTS', + suffixes={ 'otf' }, + }, + ttf={ + names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, + variable='TTFONTS', + suffixes={ 'ttf','ttc','dfont' }, + }, + afm={ + names={ "afm","adobe font metric","adobe font metrics" }, + variable="AFMFONTS", + suffixes={ "afm" }, + }, + pfb={ + names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, + variable='T1FONTS', + suffixes={ 'pfb','pfa' }, + }, + fea={ + names={ "fea","font feature","font features","font feature file","font feature files" }, + variable='FONTFEATURES', + suffixes={ 'fea' }, + }, + cid={ + names={ "cid","cid map","cid maps","cid file","cid files" }, + variable='FONTCIDMAPS', + suffixes={ 'cid','cidmap' }, + }, + fmt={ + names={ "fmt","format","tex format" }, + variable='TEXFORMATS', + suffixes={ 'fmt' }, + }, + mem={ + names={ 'mem',"metapost format" }, + variable='MPMEMS', + suffixes={ 'mem' }, + }, + mp={ + names={ "mp" }, + variable='MPINPUTS', + suffixes={ 'mp','mpvi','mpiv','mpii' }, + usertype=true, + }, + tex={ + names={ "tex" }, + variable='TEXINPUTS', + suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, + usertype=true, + }, + icc={ + names={ "icc","icc profile","icc profiles" }, + variable='ICCPROFILES', + suffixes={ 'icc' }, + }, + texmfscripts={ + names={ "texmfscript","texmfscripts","script","scripts" }, + variable='TEXMFSCRIPTS', + suffixes={ 'lua','rb','pl','py' }, + }, + lua={ + names={ "lua" }, + variable='LUAINPUTS', + suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, + usertype=true, }, - obsolete={ - enc={ - names={ "enc","enc files","enc file","encoding files","encoding file" }, - variable='ENCFONTS', - suffixes={ 'enc' }, - }, - map={ - names={ "map","map files","map file" }, - variable='TEXFONTMAPS', - suffixes={ 'map' }, - }, - lig={ - names={ "lig files","lig file","ligature file","ligature files" }, - variable='LIGFONTS', - suffixes={ 'lig' }, - }, - opl={ - names={ "opl" }, - variable='OPLFONTS', - suffixes={ 'opl' }, - }, - ovp={ - names={ "ovp" }, - variable='OVPFONTS', - suffixes={ 'ovp' }, - }, + lib={ + names={ "lib" }, + variable='CLUAINPUTS', + suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, }, - kpse={ - base={ - names={ 'base',"metafont format" }, - variable='MFBASES', - suffixes={ 'base','bas' }, - }, - cmap={ - names={ 'cmap','cmap files','cmap file' }, - variable='CMAPFONTS', - suffixes={ 'cmap' }, - }, - cnf={ - names={ 'cnf' }, - suffixes={ 'cnf' }, - }, - web={ - names={ 'web' }, - suffixes={ 'web','ch' } - }, - cweb={ - names={ 'cweb' }, - suffixes={ 'w','web','ch' }, - }, - gf={ - names={ 'gf' }, - suffixes={ '<resolution>gf' }, - }, - mf={ - names={ 'mf' }, - variable='MFINPUTS', - suffixes={ 'mf' }, - }, - mft={ - names={ 'mft' }, - suffixes={ 'mft' }, - }, - pk={ - names={ 'pk' }, - suffixes={ '<resolution>pk' }, - }, + bib={ + names={ 'bib' }, + variable='BIBINPUTS', + suffixes={ 'bib' }, + usertype=true, }, + bst={ + names={ 'bst' }, + variable='BSTINPUTS', + suffixes={ 'bst' }, + usertype=true, + }, + fontconfig={ + names={ 'fontconfig','fontconfig file','fontconfig files' }, + variable='FONTCONFIG_PATH', + }, + pk={ + names={ "pk" }, + variable='PKFONTS', + suffixes={ 'pk' }, + }, + }, + obsolete={ + enc={ + names={ "enc","enc files","enc file","encoding files","encoding file" }, + variable='ENCFONTS', + suffixes={ 'enc' }, + }, + map={ + names={ "map","map files","map file" }, + variable='TEXFONTMAPS', + suffixes={ 'map' }, + }, + lig={ + names={ "lig files","lig file","ligature file","ligature files" }, + variable='LIGFONTS', + suffixes={ 'lig' }, + }, + opl={ + names={ "opl" }, + variable='OPLFONTS', + suffixes={ 'opl' }, + }, + ovp={ + names={ "ovp" }, + variable='OVPFONTS', + suffixes={ 'ovp' }, + }, + }, + kpse={ + base={ + names={ 'base',"metafont format" }, + variable='MFBASES', + suffixes={ 'base','bas' }, + }, + cmap={ + names={ 'cmap','cmap files','cmap file' }, + variable='CMAPFONTS', + suffixes={ 'cmap' }, + }, + cnf={ + names={ 'cnf' }, + suffixes={ 'cnf' }, + }, + web={ + names={ 'web' }, + suffixes={ 'web','ch' } + }, + cweb={ + names={ 'cweb' }, + suffixes={ 'w','web','ch' }, + }, + gf={ + names={ 'gf' }, + suffixes={ '<resolution>gf' }, + }, + mf={ + names={ 'mf' }, + variable='MFINPUTS', + suffixes={ 'mf' }, + }, + mft={ + names={ 'mft' }, + suffixes={ 'mft' }, + }, + pk={ + names={ 'pk' }, + suffixes={ '<resolution>pk' }, + }, + }, } resolvers.relations=relations function resolvers.updaterelations() - for category,categories in next,relations do - for name,relation in next,categories do - local rn=relation.names - local rv=relation.variable - if rn and rv then - local rs=relation.suffixes - local ru=relation.usertype - for i=1,#rn do - local rni=lower(gsub(rn[i]," ","")) - formats[rni]=rv - if rs then - suffixes[rni]=rs - for i=1,#rs do - local rsi=rs[i] - suffixmap[rsi]=rni - end - end - end - if ru then - usertypes[name]=true - end + for category,categories in next,relations do + for name,relation in next,categories do + local rn=relation.names + local rv=relation.variable + if rn and rv then + local rs=relation.suffixes + local ru=relation.usertype + for i=1,#rn do + local rni=lower(gsub(rn[i]," ","")) + formats[rni]=rv + if rs then + suffixes[rni]=rs + for i=1,#rs do + local rsi=rs[i] + suffixmap[rsi]=rni end + end + end + if ru then + usertypes[name]=true end + end end + end end resolvers.updaterelations() local function simplified(t,k) - return k and rawget(t,lower(gsub(k," ",""))) or nil + return k and rawget(t,lower(gsub(k," ",""))) or nil end setmetatableindex(formats,simplified) setmetatableindex(suffixes,simplified) setmetatableindex(suffixmap,simplified) function resolvers.suffixofformat(str) - local s=suffixes[str] - return s and s[1] or "" + local s=suffixes[str] + return s and s[1] or "" end function resolvers.suffixofformat(str) - return suffixes[str] or {} + return suffixes[str] or {} end for name,format in next,formats do - dangerous[name]=true + dangerous[name]=true end dangerous.tex=nil function resolvers.formatofvariable(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.formatofsuffix(str) - return suffixmap[suffixonly(str)] or 'tex' + return suffixmap[suffixonly(str)] or 'tex' end function resolvers.variableofformat(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.variableofformatorsuffix(str) - local v=formats[str] - if v then - return v - end - v=suffixmap[suffixonly(str)] - if v then - return formats[v] - end - return '' + local v=formats[str] + if v then + return v + end + v=suffixmap[suffixonly(str)] + if v then + return formats[v] + end + return '' end @@ -17208,14 +20782,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 16116, stripped down to: 11459 +-- original size: 16116, stripped down to: 10782 if not modules then modules={} end modules ['data-tmp']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,concat=string.format,string.lower,string.gsub,table.concat local concat=table.concat @@ -17223,19 +20797,19 @@ local mkdirs,isdir,isfile=dir.mkdirs,lfs.isdir,lfs.isfile local addsuffix,is_writable,is_readable=file.addsuffix,file.is_writable,file.is_readable local formatters=string.formatters local next,type=next,type -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers local cleanpath=resolvers.cleanpath -local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) -local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) +local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) +local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile function utilities.lua.compile(luafile,lucfile,cleanup,strip) - if cleanup==nil then cleanup=directive_cleanup end - if strip==nil then strip=directive_strip end - return compile(luafile,lucfile,cleanup,strip) + if cleanup==nil then cleanup=directive_cleanup end + if strip==nil then strip=directive_strip end + return compile(luafile,lucfile,cleanup,strip) end caches=caches or {} local caches=caches @@ -17250,324 +20824,324 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - cachepath=file.collapsepath(cachepath) - local valid=isdir(cachepath) - if valid then - if is_readable(cachepath) then - readables[#readables+1]=cachepath - if not writable and is_writable(cachepath) then - writable=cachepath - end - end - elseif not writable and caches.force then - local cacheparent=file.dirname(cachepath) - if is_writable(cacheparent) and true then - if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then - mkdirs(cachepath) - if isdir(cachepath) and is_writable(cachepath) then - report_caches("path %a created",cachepath) - writable=cachepath - readables[#readables+1]=cachepath - end - end - end - end + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + cachepath=file.collapsepath(cachepath) + local valid=isdir(cachepath) + if valid then + if is_readable(cachepath) then + readables[#readables+1]=cachepath + if not writable and is_writable(cachepath) then + writable=cachepath end - end - end - local texmfcaches=caches.defaults - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - cachepath=resolvers.expansion(cachepath) - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - local valid=isdir(cachepath) - if valid and is_readable(cachepath) then - if not writable and is_writable(cachepath) then - readables[#readables+1]=cachepath - writable=cachepath - break - end - end + end + elseif not writable and caches.force then + local cacheparent=file.dirname(cachepath) + if is_writable(cacheparent) and true then + if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then + mkdirs(cachepath) + if isdir(cachepath) and is_writable(cachepath) then + report_caches("path %a created",cachepath) + writable=cachepath + readables[#readables+1]=cachepath + end end + end end + end end - if not writable then - report_caches("fatal error: there is no valid writable cache path defined") - os.exit() - elseif #readables==0 then - report_caches("fatal error: there is no valid readable cache path defined") - os.exit() - end - writable=dir.expandname(resolvers.cleanpath(writable)) - local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() - if tree then - caches.tree=tree - writable=mkdirs(writable,base,more,tree) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more,tree) - end - else - writable=mkdirs(writable,base,more) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more) + end + local texmfcaches=caches.defaults + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + cachepath=resolvers.expansion(cachepath) + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + local valid=isdir(cachepath) + if valid and is_readable(cachepath) then + if not writable and is_writable(cachepath) then + readables[#readables+1]=cachepath + writable=cachepath + break + end end + end end - if trace_cache then - for i=1,#readables do - report_caches("using readable path %a (order %s)",readables[i],i) - end - report_caches("using writable path %a",writable) + end + if not writable then + report_caches("fatal error: there is no valid writable cache path defined") + os.exit() + elseif #readables==0 then + report_caches("fatal error: there is no valid readable cache path defined") + os.exit() + end + writable=dir.expandname(resolvers.cleanpath(writable)) + local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() + if tree then + caches.tree=tree + writable=mkdirs(writable,base,more,tree) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more,tree) end - identify=function() - return writable,readables + else + writable=mkdirs(writable,base,more) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more) end + end + if trace_cache then + for i=1,#readables do + report_caches("using readable path %a (order %s)",readables[i],i) + end + report_caches("using writable path %a",writable) + end + identify=function() return writable,readables + end + return writable,readables end function caches.usedpaths(separator) - local writable,readables=identify() - if #readables>1 then - local result={} - local done={} - for i=1,#readables do - local readable=readables[i] - if readable==writable then - done[readable]=true - result[#result+1]=formatters["readable+writable: %a"](readable) - elseif usedreadables[i] then - done[readable]=true - result[#result+1]=formatters["readable: %a"](readable) - end - end - if not done[writable] then - result[#result+1]=formatters["writable: %a"](writable) - end - return concat(result,separator or " | ") - else - return writable or "?" + local writable,readables=identify() + if #readables>1 then + local result={} + local done={} + for i=1,#readables do + local readable=readables[i] + if readable==writable then + done[readable]=true + result[#result+1]=formatters["readable+writable: %a"](readable) + elseif usedreadables[i] then + done[readable]=true + result[#result+1]=formatters["readable: %a"](readable) + end end + if not done[writable] then + result[#result+1]=formatters["writable: %a"](writable) + end + return concat(result,separator or " | ") + else + return writable or "?" + end end function caches.configfiles() - return concat(resolvers.configurationfiles(),";") + return concat(resolvers.configurationfiles(),";") end function caches.hashed(tree) - tree=gsub(tree,"[\\/]+$","") - tree=lower(tree) - local hash=md5.hex(tree) - if trace_cache or trace_locating then - report_caches("hashing tree %a, hash %a",tree,hash) - end - return hash + tree=gsub(tree,"[\\/]+$","") + tree=lower(tree) + local hash=md5.hex(tree) + if trace_cache or trace_locating then + report_caches("hashing tree %a, hash %a",tree,hash) + end + return hash end function caches.treehash() - local tree=caches.configfiles() - if not tree or tree=="" then - return false - else - return caches.hashed(tree) - end + local tree=caches.configfiles() + if not tree or tree=="" then + return false + else + return caches.hashed(tree) + end end local r_cache,w_cache={},{} local function getreadablepaths(...) - local tags={... } - local hash=concat(tags,"/") - local done=r_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done={} - for i=1,#readables do - done[i]=file.join(readables[i],...) - end - else - done=readables - end - r_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=r_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done={} + for i=1,#readables do + done[i]=file.join(readables[i],...) + end + else + done=readables end - return done + r_cache[hash]=done + end + return done end local function getwritablepath(...) - local tags={... } - local hash=concat(tags,"/") - local done=w_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done=mkdirs(writable,...) - else - done=writable - end - w_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=w_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done=mkdirs(writable,...) + else + done=writable end - return done + w_cache[hash]=done + end + return done end caches.getreadablepaths=getreadablepaths caches.getwritablepath=getwritablepath function caches.getfirstreadablefile(filename,...) - local fullname,path=caches.setfirstwritablefile(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 - 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 + usedreadables[i]=true + return fullname,path end - return fullname,path + end + return fullname,path end function caches.setfirstwritablefile(filename,...) - local wr=getwritablepath(...) - local fullname=file.join(wr,filename) - return fullname,wr + local wr=getwritablepath(...) + local fullname=file.join(wr,filename) + return fullname,wr end function caches.define(category,subcategory) - return function() - return getwritablepath(category,subcategory) - end + return function() + return getwritablepath(category,subcategory) + end end function caches.setluanames(path,name) - return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) + return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) end function caches.loaddata(readables,name,writable) - if type(readables)=="string" then - readables={ readables } + if type(readables)=="string" then + readables={ readables } + end + for i=1,#readables do + local path=readables[i] + local loader=false + local tmaname,tmcname=caches.setluanames(path,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader and isfile(tmaname) then + local tmacrap,tmcname=caches.setluanames(writable,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + utilities.lua.compile(tmaname,tmcname) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader then + loader=loadfile(tmaname) + end end - for i=1,#readables do - local path=readables[i] - local loader=false - local tmaname,tmcname=caches.setluanames(path,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader and isfile(tmaname) then - local tmacrap,tmcname=caches.setluanames(writable,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - utilities.lua.compile(tmaname,tmcname) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader then - loader=loadfile(tmaname) - end - end - if loader then - loader=loader() - collectgarbage("step") - return loader - end + if loader then + loader=loader() + collectgarbage("step") + return loader end - return false + end + return false end function caches.is_writable(filepath,filename) - local tmaname,tmcname=caches.setluanames(filepath,filename) - return is_writable(tmaname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + return is_writable(tmaname) end local saveoptions={ compact=true } function caches.savedata(filepath,filename,data,raw) - local tmaname,tmcname=caches.setluanames(filepath,filename) - data.cache_uuid=os.uuid() - if caches.direct then - file.savedata(tmaname,table.serialize(data,true,saveoptions)) - else - table.tofile(tmaname,data,true,saveoptions) - end - utilities.lua.compile(tmaname,tmcname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + data.cache_uuid=os.uuid() + if caches.direct then + file.savedata(tmaname,table.serialize(data,true,saveoptions)) + else + table.tofile(tmaname,data,true,saveoptions) + end + utilities.lua.compile(tmaname,tmcname) end local content_state={} function caches.contentstate() - return content_state or {} + return content_state or {} end function caches.loadcontent(cachename,dataname,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) - if blob then - local data=blob() - if data and data.content then - if data.type==dataname then - if data.version==resolvers.cacheversion then - content_state[#content_state+1]=data.uuid - if trace_locating then - report_resolvers("loading %a for %a from %a",dataname,cachename,filename) - end - return data.content - else - report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) - end - else - report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) - end - elseif trace_locating then - report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) + if blob then + local data=blob() + if data and data.content then + if data.type==dataname then + if data.version==resolvers.cacheversion then + content_state[#content_state+1]=data.uuid + if trace_locating then + report_resolvers("loading %a for %a from %a",dataname,cachename,filename) + end + return data.content + else + report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) end + else + report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) + end elseif trace_locating then - report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) end + elseif trace_locating then + report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + end end function caches.collapsecontent(content) - for k,v in next,content do - if type(v)=="table" and #v==1 then - content[k]=v[1] - end + for k,v in next,content do + if type(v)=="table" and #v==1 then + content[k]=v[1] end + end end function caches.savecontent(cachename,dataname,content,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local luaname=addsuffix(filename,luasuffixes.lua) - local lucname=addsuffix(filename,luasuffixes.luc) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local luaname=addsuffix(filename,luasuffixes.lua) + local lucname=addsuffix(filename,luasuffixes.luc) + if trace_locating then + report_resolvers("preparing %a for %a",dataname,cachename) + end + local data={ + type=dataname, + root=cachename, + version=resolvers.cacheversion, + date=os.date("%Y-%m-%d"), + time=os.date("%H:%M:%S"), + content=content, + uuid=os.uuid(), + } + local ok=io.savedata(luaname,table.serialize(data,true)) + if ok then if trace_locating then - report_resolvers("preparing %a for %a",dataname,cachename) - end - local data={ - type=dataname, - root=cachename, - version=resolvers.cacheversion, - date=os.date("%Y-%m-%d"), - time=os.date("%H:%M:%S"), - content=content, - uuid=os.uuid(), - } - local ok=io.savedata(luaname,table.serialize(data,true)) - if ok then - if trace_locating then - report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) - end - if utilities.lua.compile(luaname,lucname) then - if trace_locating then - report_resolvers("%a compiled to %a",dataname,lucname) - end - return true - else - if trace_locating then - report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) - end - os.remove(lucname) - end - elseif trace_locating then - report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) + end + if utilities.lua.compile(luaname,lucname) then + if trace_locating then + report_resolvers("%a compiled to %a",dataname,lucname) + end + return true + else + if trace_locating then + report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) + end + os.remove(lucname) end + elseif trace_locating then + report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + end end @@ -17577,14 +21151,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5310, stripped down to: 3980 +-- original size: 5310, stripped down to: 3784 if not modules then modules={} end modules ['data-met']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,format=string.find,string.format local sequenced=table.sequenced @@ -17598,86 +21172,86 @@ local allocate=utilities.storage.allocate local resolvers=resolvers local registered={} local function splitmethod(filename) - if not filename then - return { scheme="unknown",original=filename } - end - if type(filename)=="table" then - return filename - end - filename=file.collapsepath(filename,".") - if not find(filename,"://",1,true) then - return { scheme="file",path=filename,original=filename,filename=filename } - end - local specification=url.hashed(filename) - if not specification.scheme or specification.scheme=="" then - return { scheme="file",path=filename,original=filename,filename=filename } - else - return specification - end + if not filename then + return { scheme="unknown",original=filename } + end + if type(filename)=="table" then + return filename + end + filename=file.collapsepath(filename,".") + if not find(filename,"://",1,true) then + return { scheme="file",path=filename,original=filename,filename=filename } + end + local specification=url.hashed(filename) + if not specification.scheme or specification.scheme=="" then + return { scheme="file",path=filename,original=filename,filename=filename } + else + return specification + end end resolvers.splitmethod=splitmethod local function methodhandler(what,first,...) - local method=registered[what] - if method then - local how,namespace=method.how,method.namespace - if how=="uri" or how=="url" then - local specification=splitmethod(first) - local scheme=specification.scheme - local resolver=namespace and namespace[scheme] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) - end - return resolver(specification,...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) - end - return resolver(specification,...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") - end - end - elseif how=="tag" then - local resolver=namespace and namespace[first] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,first) - end - return resolver(...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"default") - end - return resolver(...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") - end - end + local method=registered[what] + if method then + local how,namespace=method.how,method.namespace + if how=="uri" or how=="url" then + local specification=splitmethod(first) + local scheme=specification.scheme + local resolver=namespace and namespace[scheme] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) + end + return resolver(specification,...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) + end + return resolver(specification,...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") end - else - report_methods("resolving, invalid method %a") + end + elseif how=="tag" then + local resolver=namespace and namespace[first] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,first) + end + return resolver(...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"default") + end + return resolver(...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") + end + end end + else + report_methods("resolving, invalid method %a") + end end resolvers.methodhandler=methodhandler function resolvers.registermethod(name,namespace,how) - registered[name]={ how=how or "tag",namespace=namespace } - namespace["byscheme"]=function(scheme,filename,...) - if scheme=="file" then - return methodhandler(name,filename,...) - else - return methodhandler(name,addurlscheme(filename,scheme),...) - end + registered[name]={ how=how or "tag",namespace=namespace } + namespace["byscheme"]=function(scheme,filename,...) + if scheme=="file" then + return methodhandler(name,filename,...) + else + return methodhandler(name,addurlscheme(filename,scheme),...) end + end end -local concatinators=allocate { notfound=file.join } -local locators=allocate { notfound=function() end } -local hashers=allocate { notfound=function() end } -local generators=allocate { notfound=function() end } +local concatinators=allocate { notfound=file.join } +local locators=allocate { notfound=function() end } +local hashers=allocate { notfound=function() end } +local generators=allocate { notfound=function() end } resolvers.concatinators=concatinators resolvers.locators=locators resolvers.hashers=hashers @@ -17695,17 +21269,17 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 68263, stripped down to: 47789 +-- original size: 68195, stripped down to: 43680 if not modules then modules={} end modules ['data-res']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,remove,sortedkeys,sortedhash=table.concat,table.insert,table.remove,table.sortedkeys,table.sortedhash +local concat,insert,remove=table.concat,table.insert,table.remove local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -17727,11 +21301,11 @@ local isfile=lfs.isfile local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) -local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) +local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) +local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) local report_resolving=logs.reporter("resolvers","resolving") local resolvers=resolvers local expandedpathfromlist=resolvers.expandedpathfromlist @@ -17752,15 +21326,15 @@ resolvers.luacnfname="texmfcnf.lua" resolvers.luacnffallback="contextcnf.lua" resolvers.luacnfstate="unknown" if environment.default_texmfcnf then - resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf + resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf else - resolvers.luacnfspec=concat ({ - "home:texmf/web2c", - "selfautoparent:/texmf-local/web2c", - "selfautoparent:/texmf-context/web2c", - "selfautoparent:/texmf-dist/web2c", - "selfautoparent:/texmf/web2c", - },";") + resolvers.luacnfspec=concat ({ + "home:texmf/web2c", + "selfautoparent:/texmf-local/web2c", + "selfautoparent:/texmf-context/web2c", + "selfautoparent:/texmf-dist/web2c", + "selfautoparent:/texmf/web2c", + },";") end local unset_variable="unset" local formats=resolvers.formats @@ -17771,24 +21345,24 @@ local suffixmap=resolvers.suffixmap resolvers.defaultsuffixes={ "tex" } local instance=nil function resolvers.setenv(key,value,raw) - if instance then - instance.environment[key]=value - ossetenv(key,raw and value or resolveprefix(value)) - end + if instance then + instance.environment[key]=value + ossetenv(key,raw and value or resolveprefix(value)) + end end local function getenv(key) - local value=rawget(instance.environment,key) - if value and value~="" then - return value - else - local e=osgetenv(key) - return e~=nil and e~="" and checkedvariable(e) or "" - end + local value=rawget(instance.environment,key) + if value and value~="" then + return value + else + local e=osgetenv(key) + return e~=nil and e~="" and checkedvariable(e) or "" + end end resolvers.getenv=getenv resolvers.env=getenv local function resolvevariable(k) - return instance.expansions[k] + return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") local inhibitstripper=P("!")^0*Cs(P(1)^0) @@ -17802,1506 +21376,1506 @@ local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) - return lpegmatch(variableexpander,var) or var + return lpegmatch(variableexpander,var) or var end function resolvers.reset() - if trace_locating then - report_resolving("creating instance") - end - local environment={} - local variables={} - local expansions={} - local order={} - instance={ - environment=environment, - variables=variables, - expansions=expansions, - order=order, - files={}, - setups={}, - found={}, - foundintrees={}, - hashes={}, - hashed={}, - pathlists=false, - specification={}, - lists={}, - data={}, - fakepaths={}, - remember=true, - diskcache=true, - renewcache=false, - renewtree=false, - loaderror=false, - savelists=true, - pattern=nil, - force_suffixes=true, - pathstack={}, - } - setmetatableindex(variables,function(t,k) - local v - for i=1,#order do - v=order[i][k] - if v~=nil then - t[k]=v - return v - end - end - if v==nil then - v="" - end - t[k]=v - return v - end) - setmetatableindex(environment,function(t,k) - local v=osgetenv(k) - if v==nil then - v=variables[k] - end - if v~=nil then - v=checkedvariable(v) or "" - end - v=resolvers.repath(v) - t[k]=v - return v - end) - setmetatableindex(expansions,function(t,k) - local v=environment[k] - if type(v)=="string" then - v=lpegmatch(variableresolver,v) - v=lpegmatch(variablecleaner,v) - end + if trace_locating then + report_resolving("creating instance") + end + local environment={} + local variables={} + local expansions={} + local order={} + instance={ + environment=environment, + variables=variables, + expansions=expansions, + order=order, + files={}, + setups={}, + found={}, + foundintrees={}, + hashes={}, + hashed={}, + pathlists=false, + specification={}, + lists={}, + data={}, + fakepaths={}, + remember=true, + diskcache=true, + renewcache=false, + renewtree=false, + loaderror=false, + savelists=true, + pattern=nil, + force_suffixes=true, + pathstack={}, + } + setmetatableindex(variables,function(t,k) + local v + for i=1,#order do + v=order[i][k] + if v~=nil then t[k]=v return v - end) + end + end + if v==nil then + v="" + end + t[k]=v + return v + end) + setmetatableindex(environment,function(t,k) + local v=osgetenv(k) + if v==nil then + v=variables[k] + end + if v~=nil then + v=checkedvariable(v) or "" + end + v=resolvers.repath(v) + t[k]=v + return v + end) + setmetatableindex(expansions,function(t,k) + local v=environment[k] + if type(v)=="string" then + v=lpegmatch(variableresolver,v) + v=lpegmatch(variablecleaner,v) + end + t[k]=v + return v + end) end function resolvers.initialized() - return instance~=nil + return instance~=nil end local function reset_hashes() - instance.lists={} - instance.pathlists=false - instance.found={} + instance.lists={} + instance.pathlists=false + instance.found={} end local function reset_caches() - instance.lists={} - instance.pathlists=false + instance.lists={} + instance.pathlists=false end local slash=P("/") local pathexpressionpattern=Cs ( - Cc("^")*( - Cc("%")*S(".-")+slash^2*P(-1)/"/.*" + Cc("^")*( + Cc("%")*S(".-")+slash^2*P(-1)/"/.*" +slash^2/"/"+(1-slash)*P(-1)*Cc("/")+P(1) - )^1*Cc("$") + )^1*Cc("$") ) local cache={} local function makepathexpression(str) - if str=="." then - return "^%./$" - else - local c=cache[str] - if not c then - c=lpegmatch(pathexpressionpattern,str) - cache[str]=c - end - return c + if str=="." then + return "^%./$" + else + local c=cache[str] + if not c then + c=lpegmatch(pathexpressionpattern,str) + cache[str]=c end + return c + end end local function reportcriticalvariables(cnfspec) - if trace_locating then - for i=1,#resolvers.criticalvars do - local k=resolvers.criticalvars[i] - local v=resolvers.getenv(k) or "unknown" - report_resolving("variable %a set to %a",k,v) - end - report_resolving() - if cnfspec then - report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) - end - report_resolving() + if trace_locating then + for i=1,#resolvers.criticalvars do + local k=resolvers.criticalvars[i] + local v=resolvers.getenv(k) or "unknown" + report_resolving("variable %a set to %a",k,v) + end + report_resolving() + if cnfspec then + report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) end - reportcriticalvariables=function() end + report_resolving() + end + reportcriticalvariables=function() end end local function identify_configuration_files() - local specification=instance.specification - if #specification==0 then - local cnfspec=getenv("TEXMFCNF") - if cnfspec=="" then - cnfspec=resolvers.luacnfspec - resolvers.luacnfstate="default" - else - resolvers.luacnfstate="environment" - end - reportcriticalvariables(cnfspec) - local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) - local function locatecnf(luacnfname,kind) - for i=1,#cnfpaths do - local filepath=cnfpaths[i] - local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolveprefix(filename) - if trace_locating then - local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") - local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) - report_resolving("looking for %s %a on %s path %a from specification %a", - kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) - end - if isfile(realname) then - specification[#specification+1]=filename - if trace_locating then - report_resolving("found %s configuration file %a",kind,realname) - end - end - end - end - locatecnf(resolvers.luacnfname,"regular") - if #specification==0 then - locatecnf(resolvers.luacnffallback,"fallback") - end + local specification=instance.specification + if #specification==0 then + local cnfspec=getenv("TEXMFCNF") + if cnfspec=="" then + cnfspec=resolvers.luacnfspec + resolvers.luacnfstate="default" + else + resolvers.luacnfstate="environment" + end + reportcriticalvariables(cnfspec) + local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) + local function locatecnf(luacnfname,kind) + for i=1,#cnfpaths do + local filepath=cnfpaths[i] + local filename=collapsepath(filejoin(filepath,luacnfname)) + local realname=resolveprefix(filename) if trace_locating then - report_resolving() + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") + local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) + report_resolving("looking for %s %a on %s path %a from specification %a", + kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) + end + if isfile(realname) then + specification[#specification+1]=filename + if trace_locating then + report_resolving("found %s configuration file %a",kind,realname) + end end - elseif trace_locating then - report_resolving("configuration files already identified") + end + end + locatecnf(resolvers.luacnfname,"regular") + if #specification==0 then + locatecnf(resolvers.luacnffallback,"fallback") + end + if trace_locating then + report_resolving() end + elseif trace_locating then + report_resolving("configuration files already identified") + end end local function load_configuration_files() - local specification=instance.specification - if #specification>0 then - local luacnfname=resolvers.luacnfname - for i=1,#specification do - local filename=specification[i] - local pathname=filedirname(filename) - local filename=filejoin(pathname,luacnfname) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local setups=instance.setups - local data=blob() - local parent=data and data.parent - if parent then - local filename=filejoin(pathname,parent) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local parentdata=blob() - if parentdata then - report_resolving("loading configuration file %a",filename) - data=table.merged(parentdata,data) - end - end - end - data=data and data.content - if data then - if trace_locating then - report_resolving("loading configuration file %a",filename) - report_resolving() - end - local variables=data.variables or {} - local warning=false - for k,v in next,data do - local variant=type(v) - if variant=="table" then - initializesetter(filename,k,v) - elseif variables[k]==nil then - if trace_locating and not warning then - report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolveprefix(filename)) - warning=true - end - variables[k]=v - end - end - setups[pathname]=variables - if resolvers.luacnfstate=="default" then - local cnfspec=variables["TEXMFCNF"] - if cnfspec then - if trace_locating then - report_resolving("reloading configuration due to TEXMF redefinition") - end - resolvers.setenv("TEXMFCNF",cnfspec) - instance.specification={} - identify_configuration_files() - load_configuration_files() - resolvers.luacnfstate="configuration" - break - end - end - else - if trace_locating then - report_resolving("skipping configuration file %a (no content)",filename) - end - setups[pathname]={} - instance.loaderror=true - end - elseif trace_locating then - report_resolving("skipping configuration file %a (no valid format)",filename) + local specification=instance.specification + if #specification>0 then + local luacnfname=resolvers.luacnfname + for i=1,#specification do + local filename=specification[i] + local pathname=filedirname(filename) + local filename=filejoin(pathname,luacnfname) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local setups=instance.setups + local data=blob() + local parent=data and data.parent + if parent then + local filename=filejoin(pathname,parent) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local parentdata=blob() + if parentdata then + report_resolving("loading configuration file %a",filename) + data=table.merged(parentdata,data) end - instance.order[#instance.order+1]=instance.setups[pathname] - if instance.loaderror then - break + end + end + data=data and data.content + if data then + if trace_locating then + report_resolving("loading configuration file %a",filename) + report_resolving() + end + local variables=data.variables or {} + local warning=false + for k,v in next,data do + local variant=type(v) + if variant=="table" then + initializesetter(filename,k,v) + elseif variables[k]==nil then + if trace_locating and not warning then + report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", + k,resolveprefix(filename)) + warning=true + end + variables[k]=v + end + end + setups[pathname]=variables + if resolvers.luacnfstate=="default" then + local cnfspec=variables["TEXMFCNF"] + if cnfspec then + if trace_locating then + report_resolving("reloading configuration due to TEXMF redefinition") + end + resolvers.setenv("TEXMFCNF",cnfspec) + instance.specification={} + identify_configuration_files() + load_configuration_files() + resolvers.luacnfstate="configuration" + break end + end + else + if trace_locating then + report_resolving("skipping configuration file %a (no content)",filename) + end + setups[pathname]={} + instance.loaderror=true end - elseif trace_locating then - report_resolving("warning: no lua configuration files found") + elseif trace_locating then + report_resolving("skipping configuration file %a (no valid format)",filename) + end + instance.order[#instance.order+1]=instance.setups[pathname] + if instance.loaderror then + break + end end + elseif trace_locating then + report_resolving("warning: no lua configuration files found") + end end function resolvers.configurationfiles() - return instance.specification or {} + return instance.specification or {} end local function load_file_databases() - instance.loaderror=false - instance.files={} - if not instance.renewcache then - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - resolvers.hashers.byscheme(hash.type,hash.name) - if instance.loaderror then break end - end + instance.loaderror=false + instance.files={} + if not instance.renewcache then + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + resolvers.hashers.byscheme(hash.type,hash.name) + if instance.loaderror then break end end + end end local function locate_file_databases() - local texmfpaths=resolvers.expandedpathlist("TEXMF") - if #texmfpaths>0 then - for i=1,#texmfpaths do - local path=collapsepath(texmfpaths[i]) - path=gsub(path,"/+$","") - local stripped=lpegmatch(inhibitstripper,path) - if stripped~="" then - local runtime=stripped==path - path=cleanpath(path) - local spec=resolvers.splitmethod(stripped) - if runtime and (spec.noscheme or spec.scheme=="file") then - stripped="tree:///"..stripped - elseif spec.scheme=="cache" or spec.scheme=="file" then - stripped=spec.path - end - if trace_locating then - if runtime then - report_resolving("locating list of %a (runtime) (%s)",path,stripped) - else - report_resolving("locating list of %a (cached)",path) - end - end - methodhandler('locators',stripped) - end + local texmfpaths=resolvers.expandedpathlist("TEXMF") + if #texmfpaths>0 then + for i=1,#texmfpaths do + local path=collapsepath(texmfpaths[i]) + path=gsub(path,"/+$","") + local stripped=lpegmatch(inhibitstripper,path) + if stripped~="" then + local runtime=stripped==path + path=cleanpath(path) + local spec=resolvers.splitmethod(stripped) + if runtime and (spec.noscheme or spec.scheme=="file") then + stripped="tree:///"..stripped + elseif spec.scheme=="cache" or spec.scheme=="file" then + stripped=spec.path end if trace_locating then - report_resolving() + if runtime then + report_resolving("locating list of %a (runtime) (%s)",path,stripped) + else + report_resolving("locating list of %a (cached)",path) + end end - elseif trace_locating then - report_resolving("no texmf paths are defined (using TEXMF)") - end -end -local function generate_file_databases() - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - methodhandler('generators',hash.name) + methodhandler('locators',stripped) + end end if trace_locating then - report_resolving() + report_resolving() end + elseif trace_locating then + report_resolving("no texmf paths are defined (using TEXMF)") + end +end +local function generate_file_databases() + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + methodhandler('generators',hash.name) + end + if trace_locating then + report_resolving() + end end local function save_file_databases() - for i=1,#instance.hashes do - local hash=instance.hashes[i] - local cachename=hash.name - if hash.cache then - local content=instance.files[cachename] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",cachename) - end - caches.savecontent(cachename,"files",content) - elseif trace_locating then - report_resolving("not saving runtime tree %a",cachename) - end + for i=1,#instance.hashes do + local hash=instance.hashes[i] + local cachename=hash.name + if hash.cache then + local content=instance.files[cachename] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",cachename) + end + caches.savecontent(cachename,"files",content) + elseif trace_locating then + report_resolving("not saving runtime tree %a",cachename) end + end end function resolvers.renew(hashname) - if hashname and hashname~="" then - local expanded=resolvers.expansion(hashname) or "" - if expanded~="" then - if trace_locating then - report_resolving("identifying tree %a from %a",expanded,hashname) - end - hashname=expanded - else - if trace_locating then - report_resolving("identifying tree %a",hashname) - end - end - local realpath=resolveprefix(hashname) - if isdir(realpath) then - if trace_locating then - report_resolving("using path %a",realpath) - end - methodhandler('generators',hashname) - local content=instance.files[hashname] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",hashname) - end - caches.savecontent(hashname,"files",content) - else - report_resolving("invalid path %a",realpath) - end + if hashname and hashname~="" then + local expanded=resolvers.expansion(hashname) or "" + if expanded~="" then + if trace_locating then + report_resolving("identifying tree %a from %a",expanded,hashname) + end + hashname=expanded + else + if trace_locating then + report_resolving("identifying tree %a",hashname) + end end + local realpath=resolveprefix(hashname) + if isdir(realpath) then + if trace_locating then + report_resolving("using path %a",realpath) + end + methodhandler('generators',hashname) + local content=instance.files[hashname] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",hashname) + end + caches.savecontent(hashname,"files",content) + else + report_resolving("invalid path %a",realpath) + end + end end local function load_databases() - locate_file_databases() - if instance.diskcache and not instance.renewcache then - load_file_databases() - if instance.loaderror then - generate_file_databases() - save_file_databases() - end - else - generate_file_databases() - if instance.renewcache then - save_file_databases() - end + locate_file_databases() + if instance.diskcache and not instance.renewcache then + load_file_databases() + if instance.loaderror then + generate_file_databases() + save_file_databases() + end + else + generate_file_databases() + if instance.renewcache then + save_file_databases() end + end end function resolvers.appendhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a appended",name) - end - insert(instance.hashes,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a appended",name) end + insert(instance.hashes,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.prependhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a prepended",name) - end - insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a prepended",name) end + insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.extendtexmfvariable(specification) - local t=resolvers.splitpath(getenv("TEXMF")) - insert(t,1,specification) - local newspec=concat(t,",") - if instance.environment["TEXMF"] then - instance.environment["TEXMF"]=newspec - elseif instance.variables["TEXMF"] then - instance.variables["TEXMF"]=newspec - else - end - reset_hashes() + local t=resolvers.splitpath(getenv("TEXMF")) + insert(t,1,specification) + local newspec=concat(t,",") + if instance.environment["TEXMF"] then + instance.environment["TEXMF"]=newspec + elseif instance.variables["TEXMF"] then + instance.variables["TEXMF"]=newspec + else + end + reset_hashes() end function resolvers.splitexpansions() - local ie=instance.expansions - for k,v in next,ie do - local t,tn,h,p={},0,{},splitconfigurationpath(v) - for kk=1,#p do - local vv=p[kk] - if vv~="" and not h[vv] then - tn=tn+1 - t[tn]=vv - h[vv]=true - end - end - if #t>1 then - ie[k]=t - else - ie[k]=t[1] - end + local ie=instance.expansions + for k,v in next,ie do + local t,tn,h,p={},0,{},splitconfigurationpath(v) + for kk=1,#p do + local vv=p[kk] + if vv~="" and not h[vv] then + tn=tn+1 + t[tn]=vv + h[vv]=true + end end + if #t>1 then + ie[k]=t + else + ie[k]=t[1] + end + end end function resolvers.datastate() - return caches.contentstate() + return caches.contentstate() end function resolvers.variable(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.variables[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.variables[name] + return result~=nil and result or "" end function resolvers.expansion(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.expansions[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.expansions[name] + return result~=nil and result or "" end function resolvers.unexpandedpathlist(str) - local pth=resolvers.variable(str) - local lst=resolvers.splitpath(pth) - return expandedpathfromlist(lst) + local pth=resolvers.variable(str) + local lst=resolvers.splitpath(pth) + return expandedpathfromlist(lst) end function resolvers.unexpandedpath(str) - return joinpath(resolvers.unexpandedpathlist(str)) + return joinpath(resolvers.unexpandedpathlist(str)) end function resolvers.pushpath(name) - local pathstack=instance.pathstack - local lastpath=pathstack[#pathstack] - local pluspath=filedirname(name) - if lastpath then - lastpath=collapsepath(filejoin(lastpath,pluspath)) - else - lastpath=collapsepath(pluspath) - end - insert(pathstack,lastpath) - if trace_paths then - report_resolving("pushing path %a",lastpath) - end + local pathstack=instance.pathstack + local lastpath=pathstack[#pathstack] + local pluspath=filedirname(name) + if lastpath then + lastpath=collapsepath(filejoin(lastpath,pluspath)) + else + lastpath=collapsepath(pluspath) + end + insert(pathstack,lastpath) + if trace_paths then + report_resolving("pushing path %a",lastpath) + end end function resolvers.poppath() - local pathstack=instance.pathstack - if trace_paths and #pathstack>0 then - report_resolving("popping path %a",pathstack[#pathstack]) - end - remove(pathstack) + local pathstack=instance.pathstack + if trace_paths and #pathstack>0 then + report_resolving("popping path %a",pathstack[#pathstack]) + end + remove(pathstack) end function resolvers.stackpath() - local pathstack=instance.pathstack - local currentpath=pathstack[#pathstack] - return currentpath~="" and currentpath or nil + local pathstack=instance.pathstack + local currentpath=pathstack[#pathstack] + return currentpath~="" and currentpath or nil end local done={} function resolvers.resetextrapaths() - local ep=instance.extra_paths - if not ep then - done={} - instance.extra_paths={} - elseif #ep>0 then - done={} - reset_caches() - end + local ep=instance.extra_paths + if not ep then + done={} + instance.extra_paths={} + elseif #ep>0 then + done={} + reset_caches() + end end function resolvers.getextrapaths() - return instance.extra_paths or {} + return instance.extra_paths or {} end function resolvers.registerextrapath(paths,subpaths) - if not subpaths or subpaths=="" then - if not paths or path=="" then - return - elseif done[paths] then - return - end - end - local paths=settings_to_array(paths) - local subpaths=settings_to_array(subpaths) - local ep=instance.extra_paths or {} - local oldn=#ep - local newn=oldn - local nofpaths=#paths - local nofsubpaths=#subpaths - if nofpaths>0 then - if nofsubpaths>0 then - for i=1,nofpaths do - local p=paths[i] - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=p.."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end - end - else - for i=1,nofpaths do - local p=paths[i] - if not done[p] then - newn=newn+1 - ep[newn]=cleanpath(p) - done[p]=true - end - end + if not subpaths or subpaths=="" then + if not paths or path=="" then + return + elseif done[paths] then + return + end + end + local paths=settings_to_array(paths) + local subpaths=settings_to_array(subpaths) + local ep=instance.extra_paths or {} + local oldn=#ep + local newn=oldn + local nofpaths=#paths + local nofsubpaths=#subpaths + if nofpaths>0 then + if nofsubpaths>0 then + for i=1,nofpaths do + local p=paths[i] + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=p.."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end end - elseif nofsubpaths>0 then - for i=1,oldn do - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=ep[i].."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end + end + else + for i=1,nofpaths do + local p=paths[i] + if not done[p] then + newn=newn+1 + ep[newn]=cleanpath(p) + done[p]=true end + end end - if newn>0 then - instance.extra_paths=ep - end - if newn~=oldn then - reset_caches() + elseif nofsubpaths>0 then + for i=1,oldn do + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=ep[i].."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end + end end + end + if newn>0 then + instance.extra_paths=ep + end + if newn~=oldn then + reset_caches() + end end function resolvers.pushextrapath(path) - local paths=settings_to_array(path) - if instance.extra_stack then - insert(instance.extra_stack,1,paths) - else - instance.extra_stack={ paths } - end - reset_caches() + local paths=settings_to_array(path) + if instance.extra_stack then + insert(instance.extra_stack,1,paths) + else + instance.extra_stack={ paths } + end + reset_caches() end function resolvers.popextrapath() - if instance.extra_stack then - reset_caches() - return remove(instance.extra_stack,1) - end + if instance.extra_stack then + reset_caches() + return remove(instance.extra_stack,1) + end end local function made_list(instance,list,extra_too) - local done={} - local new={} - local newn=0 - local function add(p) - for k=1,#p do - local v=p[k] - if not done[v] then - done[v]=true - newn=newn+1 - new[newn]=v - end - end + local done={} + local new={} + local newn=0 + local function add(p) + for k=1,#p do + local v=p[k] + if not done[v] then + done[v]=true + newn=newn+1 + new[newn]=v + end end - for k=1,#list do - local v=list[k] - if done[v] then - elseif find(v,"^[%.%/]$") then - done[v]=true - newn=newn+1 - new[newn]=v - else - break - end + end + for k=1,#list do + local v=list[k] + if done[v] then + elseif find(v,"^[%.%/]$") then + done[v]=true + newn=newn+1 + new[newn]=v + else + break + end + end + if extra_too then + local es=instance.extra_stack + if es and #es>0 then + for k=1,#es do + add(es[k]) + end end - if extra_too then - local es=instance.extra_stack - if es and #es>0 then - for k=1,#es do - add(es[k]) - end - end - local ep=instance.extra_paths - if ep and #ep>0 then - add(ep) - end + local ep=instance.extra_paths + if ep and #ep>0 then + add(ep) end - add(list) - return new + end + add(list) + return new end function resolvers.cleanpathlist(str) - local t=resolvers.expandedpathlist(str) - if t then - for i=1,#t do - t[i]=collapsepath(cleanpath(t[i])) - end + local t=resolvers.expandedpathlist(str) + if t then + for i=1,#t do + t[i]=collapsepath(cleanpath(t[i])) end - return t + end + return t end function resolvers.expandpath(str) - return joinpath(resolvers.expandedpathlist(str)) + return joinpath(resolvers.expandedpathlist(str)) end function resolvers.expandedpathlist(str,extra_too) - if not str then - return {} - elseif instance.savelists then - str=lpegmatch(dollarstripper,str) - local lists=instance.lists - local lst=lists[str] - if not lst then - local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) - lst=expandedpathfromlist(l) - lists[str]=lst - end - return lst - else - local lst=resolvers.splitpath(resolvers.expansion(str)) - return made_list(instance,expandedpathfromlist(lst),extra_too) + if not str then + return {} + elseif instance.savelists then + str=lpegmatch(dollarstripper,str) + local lists=instance.lists + local lst=lists[str] + if not lst then + local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) + lst=expandedpathfromlist(l) + lists[str]=lst end + return lst + else + local lst=resolvers.splitpath(resolvers.expansion(str)) + return made_list(instance,expandedpathfromlist(lst),extra_too) + end end function resolvers.expandedpathlistfromvariable(str) - str=lpegmatch(dollarstripper,str) - local tmp=resolvers.variableofformatorsuffix(str) - return resolvers.expandedpathlist(tmp~="" and tmp or str) + str=lpegmatch(dollarstripper,str) + local tmp=resolvers.variableofformatorsuffix(str) + return resolvers.expandedpathlist(tmp~="" and tmp or str) end function resolvers.expandpathfromvariable(str) - return joinpath(resolvers.expandedpathlistfromvariable(str)) + return joinpath(resolvers.expandedpathlistfromvariable(str)) end function resolvers.cleanedpathlist(v) - local t=resolvers.expandedpathlist(v) - for i=1,#t do - t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) - end - return t + local t=resolvers.expandedpathlist(v) + for i=1,#t do + t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) + end + return t end function resolvers.expandbraces(str) - local pth=expandedpathfromlist(resolvers.splitpath(str)) - return joinpath(pth) + local pth=expandedpathfromlist(resolvers.splitpath(str)) + return joinpath(pth) end function resolvers.registerfilehash(name,content,someerror) - if content then - instance.files[name]=content - else - instance.files[name]={} - if somerror==true then - instance.loaderror=someerror - end + if content then + instance.files[name]=content + else + instance.files[name]={} + if somerror==true then + instance.loaderror=someerror end + end end function resolvers.getfilehashes() - return instance and instance.files or {} + return instance and instance.files or {} end function resolvers.gethashes() - return instance and instance.hashes or {} + return instance and instance.hashes or {} end function resolvers.renewcache() - if instance then - instance.renewcache=true - end + if instance then + instance.renewcache=true + end end local function isreadable(name) - local readable=isfile(name) - if trace_detail then - if readable then - report_resolving("file %a is readable",name) - else - report_resolving("file %a is not readable",name) - end + local readable=isfile(name) + if trace_detail then + if readable then + report_resolving("file %a is readable",name) + else + report_resolving("file %a is not readable",name) end - return readable + end + return readable end local function collect_files(names) - local filelist={} - local noffiles=0 - local function check(hash,root,pathname,path,basename,name) - if not pathname or find(path,pathname) then - local variant=hash.type - local search=filejoin(root,path,name) - local result=methodhandler('concatinators',variant,root,path,name) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,basename,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } end - for k=1,#names do - local filename=names[k] + end + for k=1,#names do + local filename=names[k] + if trace_detail then + report_resolving("checking name %a",filename) + end + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false + else + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" + end + local hashes=instance.hashes + for h=1,#hashes do + local hash=hashes[h] + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("checking name %a",filename) + report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) end - local basename=filebasename(filename) - local pathname=filedirname(filename) - if pathname=="" or find(pathname,"^%.") then - pathname=false - else - pathname=gsub(pathname,"%*",".*") - pathname="/"..pathname.."$" - end - local hashes=instance.hashes - for h=1,#hashes do - local hash=hashes[h] - local hashname=hash.name - local content=hashname and instance.files[hashname] - if content then - if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) - end - local path,name=lookup(content,basename) - if path then - local metadata=content.metadata - local realroot=metadata and metadata.path or hashname - if type(path)=="string" then - check(hash,realroot,pathname,path,basename,name) - else - for i=1,#path do - check(hash,realroot,pathname,path[i],basename,name) - end - end - end - elseif trace_locating then - report_resolving("no match in %a (%s)",hashname,basename) + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,basename,name) + else + for i=1,#path do + check(hash,realroot,pathname,path[i],basename,name) end + end end + elseif trace_locating then + report_resolving("no match in %a (%s)",hashname,basename) + end end - return noffiles>0 and filelist or nil + end + return noffiles>0 and filelist or nil end local fit={} function resolvers.registerintrees(filename,format,filetype,usedmethod,foundname) - local foundintrees=instance.foundintrees - if usedmethod=="direct" and filename==foundname and fit[foundname] then - else - local collapsed=collapsepath(foundname,true) - local t={ - filename=filename, - format=format~="" and format or nil, - filetype=filetype~="" and filetype or nil, - usedmethod=usedmethod, - foundname=foundname, - fullname=collapsed, - } - fit[foundname]=t - foundintrees[#foundintrees+1]=t - end + local foundintrees=instance.foundintrees + if usedmethod=="direct" and filename==foundname and fit[foundname] then + else + local collapsed=collapsepath(foundname,true) + local t={ + filename=filename, + format=format~="" and format or nil, + filetype=filetype~="" and filetype or nil, + usedmethod=usedmethod, + foundname=foundname, + fullname=collapsed, + } + fit[foundname]=t + foundintrees[#foundintrees+1]=t + end end function resolvers.foundintrees() - return instance.foundintrees or {} + return instance.foundintrees or {} end function resolvers.foundintree(fullname) - local f=fit[fullname] - return f and f.usedmethod=="database" + local f=fit[fullname] + return f and f.usedmethod=="database" end local function can_be_dir(name) - local fakepaths=instance.fakepaths - if not fakepaths[name] then - if isdir(name) then - fakepaths[name]=1 - else - fakepaths[name]=2 - end + local fakepaths=instance.fakepaths + if not fakepaths[name] then + if isdir(name) then + fakepaths[name]=1 + else + fakepaths[name]=2 end - return fakepaths[name]==1 + end + return fakepaths[name]==1 end local preparetreepattern=Cs((P(".")/"%%."+P("-")/"%%-"+P(1))^0*Cc("$")) local collect_instance_files local function find_analyze(filename,askedformat,allresults) - local filetype='' - local filesuffix=suffixonly(filename) - local wantedfiles={} - wantedfiles[#wantedfiles+1]=filename - if askedformat=="" then - if filesuffix=="" or not suffixmap[filesuffix] then - local defaultsuffixes=resolvers.defaultsuffixes - local formatofsuffix=resolvers.formatofsuffix - for i=1,#defaultsuffixes do - local forcedname=filename..'.'..defaultsuffixes[i] - wantedfiles[#wantedfiles+1]=forcedname - filetype=formatofsuffix(forcedname) - if trace_locating then - report_resolving("forcing filetype %a",filetype) - end - end - else - filetype=resolvers.formatofsuffix(filename) - if trace_locating then - report_resolving("using suffix based filetype %a",filetype) - end + local filetype='' + local filesuffix=suffixonly(filename) + local wantedfiles={} + wantedfiles[#wantedfiles+1]=filename + if askedformat=="" then + if filesuffix=="" or not suffixmap[filesuffix] then + local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix + for i=1,#defaultsuffixes do + local forcedname=filename..'.'..defaultsuffixes[i] + wantedfiles[#wantedfiles+1]=forcedname + filetype=formatofsuffix(forcedname) + if trace_locating then + report_resolving("forcing filetype %a",filetype) end + end else - if filesuffix=="" or not suffixmap[filesuffix] then - local format_suffixes=suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] - end - end - end - filetype=askedformat - if trace_locating then - report_resolving("using given filetype %a",filetype) + filetype=resolvers.formatofsuffix(filename) + if trace_locating then + report_resolving("using suffix based filetype %a",filetype) + end + end + else + if filesuffix=="" or not suffixmap[filesuffix] then + local format_suffixes=suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] end + end end - return filetype,wantedfiles + filetype=askedformat + if trace_locating then + report_resolving("using given filetype %a",filetype) + end + end + return filetype,wantedfiles end local function find_direct(filename,allresults) - if not dangerous[askedformat] and isreadable(filename) then - if trace_detail then - report_resolving("file %a found directly",filename) - end - return "direct",{ filename } + if not dangerous[askedformat] and isreadable(filename) then + if trace_detail then + report_resolving("file %a found directly",filename) end + return "direct",{ filename } + end end local function find_wildcard(filename,allresults) - if find(filename,'*',1,true) then - if trace_locating then - report_resolving("checking wildcard %a",filename) - end - local result=resolvers.findwildcardfiles(filename) - if result then - return "wildcard",result - end - end -end -local function find_qualified(filename,allresults,askedformat,alsostripped) - if not is_qualified_path(filename) then - return - end + if find(filename,'*',1,true) then if trace_locating then - report_resolving("checking qualified name %a",filename) + report_resolving("checking wildcard %a",filename) end - if isreadable(filename) then - if trace_detail then - report_resolving("qualified file %a found",filename) - end - return "qualified",{ filename } + local result=resolvers.findwildcardfiles(filename) + if result then + return "wildcard",result end + end +end +local function find_qualified(filename,allresults,askedformat,alsostripped) + if not is_qualified_path(filename) then + return + end + if trace_locating then + report_resolving("checking qualified name %a",filename) + end + if isreadable(filename) then if trace_detail then - report_resolving("locating qualified file %a",filename) - end - local forcedname,suffix="",suffixonly(filename) - if suffix=="" then - local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - local s=format_suffixes[i] - forcedname=filename.."."..s - if isreadable(forcedname) then - if trace_locating then - report_resolving("no suffix, forcing format filetype %a",s) - end - return "qualified",{ forcedname } - end - end + report_resolving("qualified file %a found",filename) + end + return "qualified",{ filename } + end + if trace_detail then + report_resolving("locating qualified file %a",filename) + end + local forcedname,suffix="",suffixonly(filename) + if suffix=="" then + local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + local s=format_suffixes[i] + forcedname=filename.."."..s + if isreadable(forcedname) then + if trace_locating then + report_resolving("no suffix, forcing format filetype %a",s) + end + return "qualified",{ forcedname } end + end end - if alsostripped and suffix and suffix~="" then - local basename=filebasename(filename) - local pattern=lpegmatch(preparetreepattern,filename) - local savedformat=askedformat - local format=savedformat or "" - if format=="" then - askedformat=resolvers.formatofsuffix(suffix) + end + if alsostripped and suffix and suffix~="" then + local basename=filebasename(filename) + local pattern=lpegmatch(preparetreepattern,filename) + local savedformat=askedformat + local format=savedformat or "" + if format=="" then + askedformat=resolvers.formatofsuffix(suffix) + end + if not format then + askedformat="othertextfiles" + end + if basename~=filename then + local resolved=collect_instance_files(basename,askedformat,allresults) + if #resolved==0 then + local lowered=lower(basename) + if filename~=lowered then + resolved=collect_instance_files(lowered,askedformat,allresults) end - if not format then - askedformat="othertextfiles" + end + resolvers.format=savedformat + if #resolved>0 then + local result={} + for r=1,#resolved do + local rr=resolved[r] + if find(rr,pattern) then + result[#result+1]=rr + end end - if basename~=filename then - local resolved=collect_instance_files(basename,askedformat,allresults) - if #resolved==0 then - local lowered=lower(basename) - if filename~=lowered then - resolved=collect_instance_files(lowered,askedformat,allresults) - end - end - resolvers.format=savedformat - if #resolved>0 then - local result={} - for r=1,#resolved do - local rr=resolved[r] - if find(rr,pattern) then - result[#result+1]=rr - end - end - if #result>0 then - return "qualified",result - end - end + if #result>0 then + return "qualified",result end + end end + end end local function check_subpath(fname) - if isreadable(fname) then - if trace_detail then - report_resolving("found %a by deep scanning",fname) - end - return fname + if isreadable(fname) then + if trace_detail then + report_resolving("found %a by deep scanning",fname) end + return fname + end end local function makepathlist(list,filetype) - local typespec=resolvers.variableofformat(filetype) - local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) - local entry={} - if pathlist and #pathlist>0 then - for k=1,#pathlist do - local path=pathlist[k] - local prescanned=find(path,'^!!') - local resursive=find(path,'//$') - local pathname=lpegmatch(inhibitstripper,path) - local expression=makepathexpression(pathname) - local barename=gsub(pathname,"/+$","") - barename=resolveprefix(barename) - local scheme=url.hasscheme(barename) - local schemename=gsub(barename,"%.%*$",'') - entry[k]={ - path=path, - pathname=pathname, - prescanned=prescanned, - recursive=recursive, - expression=expression, - barename=barename, - scheme=scheme, - schemename=schemename, - } - end - entry.typespec=typespec - list[filetype]=entry - else - list[filetype]=false - end - return entry + local typespec=resolvers.variableofformat(filetype) + local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) + local entry={} + if pathlist and #pathlist>0 then + for k=1,#pathlist do + local path=pathlist[k] + local prescanned=find(path,'^!!') + local resursive=find(path,'//$') + local pathname=lpegmatch(inhibitstripper,path) + local expression=makepathexpression(pathname) + local barename=gsub(pathname,"/+$","") + barename=resolveprefix(barename) + local scheme=url.hasscheme(barename) + local schemename=gsub(barename,"%.%*$",'') + entry[k]={ + path=path, + pathname=pathname, + prescanned=prescanned, + recursive=recursive, + expression=expression, + barename=barename, + scheme=scheme, + schemename=schemename, + } + end + entry.typespec=typespec + list[filetype]=entry + else + list[filetype]=false + end + return entry end local function find_intree(filename,filetype,wantedfiles,allresults) - local pathlists=instance.pathlists - if not pathlists then - pathlists=setmetatableindex({},makepathlist) - instance.pathlists=pathlists - end - local pathlist=pathlists[filetype] - if pathlist then - local method="intree" - local filelist=collect_files(wantedfiles) - local dirlist={} - local result={} - if filelist then - for i=1,#filelist do - dirlist[i]=filedirname(filelist[i][3]).."/" + local pathlists=instance.pathlists + if not pathlists then + pathlists=setmetatableindex({},makepathlist) + instance.pathlists=pathlists + end + local pathlist=pathlists[filetype] + if pathlist then + local method="intree" + local filelist=collect_files(wantedfiles) + local dirlist={} + local result={} + if filelist then + for i=1,#filelist do + dirlist[i]=filedirname(filelist[i][3]).."/" + end + end + if trace_detail then + report_resolving("checking filename %a in tree",filename) + end + for k=1,#pathlist do + local entry=pathlist[k] + local path=entry.path + local pathname=entry.pathname + local done=false + if filelist then + local expression=entry.expression + if trace_detail then + report_resolving("using pattern %a for path %a",expression,pathname) + end + for k=1,#filelist do + local fl=filelist[k] + local f=fl[2] + local d=dirlist[k] + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) + done=true + if allresults then + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) + end + else + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) + end + break end + elseif trace_detail then + report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + end end - if trace_detail then - report_resolving("checking filename %a in tree",filename) - end - for k=1,#pathlist do - local entry=pathlist[k] - local path=entry.path - local pathname=entry.pathname - local done=false - if filelist then - local expression=entry.expression + end + if done then + method="database" + else + method="filesystem" + local scheme=entry.scheme + if not scheme or scheme=="file" then + local pname=entry.schemename + if not find(pname,"*",1,true) then + if can_be_dir(pname) then + if not done and not entry.prescanned then if trace_detail then - report_resolving("using pattern %a for path %a",expression,pathname) - end - for k=1,#filelist do - local fl=filelist[k] - local f=fl[2] - local d=dirlist[k] - if find(d,expression) or find(resolveprefix(d),expression) then - result[#result+1]=resolveprefix(fl[3]) - done=true - if allresults then - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) - end - else - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) - end - break - end - elseif trace_detail then - report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + report_resolving("quick root scan for %a",pname) + end + for k=1,#wantedfiles do + local w=wantedfiles[k] + local fname=check_subpath(filejoin(pname,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end - end - end - if done then - method="database" - else - method="filesystem" - local scheme=entry.scheme - if not scheme or scheme=="file" then - local pname=entry.schemename - if not find(pname,"*",1,true) then - if can_be_dir(pname) then - if not done and not entry.prescanned then - if trace_detail then - report_resolving("quick root scan for %a",pname) - end - for k=1,#wantedfiles do - local w=wantedfiles[k] - local fname=check_subpath(filejoin(pname,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - if not done and entry.recursive then - if trace_detail then - report_resolving("scanning filesystem for %a",pname) - end - local files=resolvers.simplescanfiles(pname,false,true) - for k=1,#wantedfiles do - local w=wantedfiles[k] - local subpath=files[w] - if not subpath or subpath=="" then - elseif type(subpath)=="string" then - local fname=check_subpath(filejoin(pname,subpath,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - else - for i=1,#subpath do - local sp=subpath[i] - if sp=="" then - else - local fname=check_subpath(filejoin(pname,sp,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - end - if done and not allresults then - break - end - end - end - end - end + end + end + if not done and entry.recursive then + if trace_detail then + report_resolving("scanning filesystem for %a",pname) + end + local files=resolvers.simplescanfiles(pname,false,true) + for k=1,#wantedfiles do + local w=wantedfiles[k] + local subpath=files[w] + if not subpath or subpath=="" then + elseif type(subpath)=="string" then + local fname=check_subpath(filejoin(pname,subpath,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end + end else - end - else - for k=1,#wantedfiles do - local pname=entry.barename - local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) - if fname then + for i=1,#subpath do + local sp=subpath[i] + if sp=="" then + else + local fname=check_subpath(filejoin(pname,sp,w)) + if fname then result[#result+1]=fname done=true if not allresults then - break + break end + end end + end + if done and not allresults then + break + end end + end end + end end - if done and not allresults then + else + end + else + for k=1,#wantedfiles do + local pname=entry.barename + local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) + if fname then + result[#result+1]=fname + done=true + if not allresults then break + end end + end end - if #result>0 then - return method,result - end + end + if done and not allresults then + break + end + end + if #result>0 then + return method,result end + end end local function find_onpath(filename,filetype,wantedfiles,allresults) - if trace_detail then - report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) - end - local result={} - for k=1,#wantedfiles do - local fname=wantedfiles[k] - if fname and isreadable(fname) then - filename=fname - result[#result+1]=filejoin('.',fname) - if not allresults then - break - end - end - end - if #result>0 then - return "onpath",result + if trace_detail then + report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) + end + local result={} + for k=1,#wantedfiles do + local fname=wantedfiles[k] + if fname and isreadable(fname) then + filename=fname + result[#result+1]=filejoin('.',fname) + if not allresults then + break + end end + end + if #result>0 then + return "onpath",result + end end local function find_otherwise(filename,filetype,wantedfiles,allresults) - local filelist=collect_files(wantedfiles) - local fl=filelist and filelist[1] - if fl then - return "otherwise",{ resolveprefix(fl[3]) } - end + local filelist=collect_files(wantedfiles) + local fl=filelist and filelist[1] + if fl then + return "otherwise",{ resolveprefix(fl[3]) } + end end collect_instance_files=function(filename,askedformat,allresults) - if not filename or filename=="" then - return {} - end - askedformat=askedformat or "" - filename=collapsepath(filename,".") - filename=gsub(filename,"^%./",getcurrentdir().."/") - if allresults then - local filetype,wantedfiles=find_analyze(filename,askedformat) - local results={ - { find_direct (filename,true) }, - { find_wildcard (filename,true) }, - { find_qualified(filename,true,askedformat) }, - { find_intree (filename,filetype,wantedfiles,true) }, - { find_onpath (filename,filetype,wantedfiles,true) }, - { find_otherwise(filename,filetype,wantedfiles,true) }, - } - local result,status,done={},{},{} - for k,r in next,results do - local method,list=r[1],r[2] - if method and list then - for i=1,#list do - local c=collapsepath(list[i]) - if not done[c] then - result[#result+1]=c - done[c]=true - end - status[#status+1]=formatters["%-10s: %s"](method,c) - end - end - end - if trace_detail then - report_resolving("lookup status: %s",table.serialize(status,filename)) + if not filename or filename=="" then + return {} + end + askedformat=askedformat or "" + filename=collapsepath(filename,".") + filename=gsub(filename,"^%./",getcurrentdir().."/") + if allresults then + local filetype,wantedfiles=find_analyze(filename,askedformat) + local results={ + { find_direct (filename,true) }, + { find_wildcard (filename,true) }, + { find_qualified(filename,true,askedformat) }, + { find_intree (filename,filetype,wantedfiles,true) }, + { find_onpath (filename,filetype,wantedfiles,true) }, + { find_otherwise(filename,filetype,wantedfiles,true) }, + } + local result,status,done={},{},{} + for k,r in next,results do + local method,list=r[1],r[2] + if method and list then + for i=1,#list do + local c=collapsepath(list[i]) + if not done[c] then + result[#result+1]=c + done[c]=true + end + status[#status+1]=formatters["%-10s: %s"](method,c) end - return result,status - else - local method,result,stamp,filetype,wantedfiles - if instance.remember then - if askedformat=="" then - stamp=formatters["%s::%s"](suffixonly(filename),filename) - else - stamp=formatters["%s::%s"](askedformat,filename) - end - result=stamp and instance.found[stamp] - if result then - if trace_locating then - report_resolving("remembered file %a",filename) - end - return result - end + end + end + if trace_detail then + report_resolving("lookup status: %s",table.serialize(status,filename)) + end + return result,status + else + local method,result,stamp,filetype,wantedfiles + if instance.remember then + if askedformat=="" then + stamp=formatters["%s::%s"](suffixonly(filename),filename) + else + stamp=formatters["%s::%s"](askedformat,filename) + end + result=stamp and instance.found[stamp] + if result then + if trace_locating then + report_resolving("remembered file %a",filename) end - method,result=find_direct(filename) + return result + end + end + method,result=find_direct(filename) + if not result then + method,result=find_wildcard(filename) + if not result then + method,result=find_qualified(filename,false,askedformat) if not result then - method,result=find_wildcard(filename) - if not result then - method,result=find_qualified(filename,false,askedformat) - if not result then - filetype,wantedfiles=find_analyze(filename,askedformat) - method,result=find_intree(filename,filetype,wantedfiles) - if not result then - method,result=find_onpath(filename,filetype,wantedfiles) - if resolve_otherwise and not result then - method,result=find_otherwise(filename,filetype,wantedfiles) - end - end - end - end - end - if result and #result>0 then - local foundname=collapsepath(result[1]) - resolvers.registerintrees(filename,askedformat,filetype,method,foundname) - result={ foundname } - else - result={} - end - if stamp then - if trace_locating then - report_resolving("remembering file %a using hash %a",filename,stamp) + filetype,wantedfiles=find_analyze(filename,askedformat) + method,result=find_intree(filename,filetype,wantedfiles) + if not result then + method,result=find_onpath(filename,filetype,wantedfiles) + if resolve_otherwise and not result then + method,result=find_otherwise(filename,filetype,wantedfiles) end - instance.found[stamp]=result + end end - return result + end + end + if result and #result>0 then + local foundname=collapsepath(result[1]) + resolvers.registerintrees(filename,askedformat,filetype,method,foundname) + result={ foundname } + else + result={} end + if stamp then + if trace_locating then + report_resolving("remembering file %a using hash %a",filename,stamp) + end + instance.found[stamp]=result + end + return result + end end local function findfiles(filename,filetype,allresults) - if not filename or filename=="" then - return {} - end - local result,status=collect_instance_files(filename,filetype or "",allresults) - if not result or #result==0 then - local lowered=lower(filename) - if filename~=lowered then - result,status=collect_instance_files(lowered,filetype or "",allresults) - end + if not filename or filename=="" then + return {} + end + local result,status=collect_instance_files(filename,filetype or "",allresults) + if not result or #result==0 then + local lowered=lower(filename) + if filename~=lowered then + result,status=collect_instance_files(lowered,filetype or "",allresults) end - return result or {},status + end + return result or {},status end function resolvers.findfiles(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,true) - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,true) + end end function resolvers.findfile(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,false)[1] or "" - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,false)[1] or "" + end end function resolvers.findpath(filename,filetype) - return filedirname(findfiles(filename,filetype,false)[1] or "") + return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local base=filebasename(filename) - local result={} - local hashes=instance.hashes - local function okay(hash,path,name) - local found=methodhandler('concatinators',hash.type,hash.name,path,name) - if found and found~="" then - result[#result+1]=resolveprefix(found) - return not allresults - end - end - for k=1,#hashes do - local hash=hashes[k] - local content=instance.files[hash.name] - if content then - local path,name=lookup(content,base) - if not path then - elseif type(path)=="string" then - if okay(hash,path,name) then - return result - end - else - for i=1,#path do - if okay(hash,path[i],name) then - return result - end - end - end + local base=filebasename(filename) + local result={} + local hashes=instance.hashes + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end + for k=1,#hashes do + local hash=hashes[k] + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result + end + else + for i=1,#path do + if okay(hash,path[i],name) then + return result + end end + end end - return result + end + return result end function resolvers.findgivenfiles(filename) - return findgivenfiles(filename,true) + return findgivenfiles(filename,true) end function resolvers.findgivenfile(filename) - return findgivenfiles(filename,false)[1] or "" + return findgivenfiles(filename,false)[1] or "" end local makewildcard=Cs( - (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 + (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) - return lpegmatch(makewildcard,pattern) or pattern + return lpegmatch(makewildcard,pattern) or pattern end local function findwildcardfiles(filename,allresults,result) - local result=result or {} - local base=filebasename(filename) - local dirn=filedirname(filename) - local path=lower(lpegmatch(makewildcard,dirn) or dirn) - local name=lower(lpegmatch(makewildcard,base) or base) - local files=instance.files - if find(name,"*",1,true) then - local hashes=instance.hashes - local function okay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end - end + local result=result or {} + local base=filebasename(filename) + local dirn=filedirname(filename) + local path=lower(lpegmatch(makewildcard,dirn) or dirn) + local name=lower(lpegmatch(makewildcard,base) or base) + local files=instance.files + if find(name,"*",1,true) then + local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults end - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - for found,base in filtered(files[hashname],name) do - if type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end - end + end + end + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break end - end - else - local function okayokay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end end + end end - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - local found,base=lookup(content,base) - if not found then - elseif type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end + end + end + else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break end + end end + end end - return result + end + return result end function resolvers.findwildcardfiles(filename,result) - return findwildcardfiles(filename,true,result) + return findwildcardfiles(filename,true,result) end function resolvers.findwildcardfile(filename) - return findwildcardfiles(filename,false)[1] or "" + return findwildcardfiles(filename,false)[1] or "" end function resolvers.automount() end function resolvers.starttiming() - statistics.starttiming(instance) + statistics.starttiming(instance) end function resolvers.stoptiming() - statistics.stoptiming(instance) + statistics.stoptiming(instance) end function resolvers.load(option) - resolvers.starttiming() - identify_configuration_files() - load_configuration_files() - if option~="nofiles" then - load_databases() - resolvers.automount() - end - resolvers.stoptiming() - local files=instance.files - return files and next(files) and true + resolvers.starttiming() + identify_configuration_files() + load_configuration_files() + if option~="nofiles" then + load_databases() + resolvers.automount() + end + resolvers.stoptiming() + local files=instance.files + return files and next(files) and true end function resolvers.loadtime() - return statistics.elapsedtime(instance) + return statistics.elapsedtime(instance) end local function report(str) - if trace_locating then - report_resolving(str) - else - print(str) - end + if trace_locating then + report_resolving(str) + else + print(str) + end end function resolvers.dowithfilesandreport(command,files,...) - if files and #files>0 then - if trace_locating then - report('') - end - if type(files)=="string" then - files={ files } - end - for f=1,#files do - local file=files[f] - local result=command(file,...) - if type(result)=='string' then - report(result) - else - for i=1,#result do - report(result[i]) - end - end + if files and #files>0 then + if trace_locating then + report('') + end + if type(files)=="string" then + files={ files } + end + for f=1,#files do + local file=files[f] + local result=command(file,...) + if type(result)=='string' then + report(result) + else + for i=1,#result do + report(result[i]) end + end end + end end -function resolvers.showpath(str) - return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) +function resolvers.showpath(str) + return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) end function resolvers.registerfile(files,name,path) - if files[name] then - if type(files[name])=='string' then - files[name]={ files[name],path } - else - files[name]=path - end + if files[name] then + if type(files[name])=='string' then + files[name]={ files[name],path } else - files[name]=path + files[name]=path end + else + files[name]=path + end end function resolvers.dowithpath(name,func) - local pathlist=resolvers.expandedpathlist(name) - for i=1,#pathlist do - func("^"..cleanpath(pathlist[i])) - end + local pathlist=resolvers.expandedpathlist(name) + for i=1,#pathlist do + func("^"..cleanpath(pathlist[i])) + end end function resolvers.dowithvariable(name,func) - func(expandedvariable(name)) + func(expandedvariable(name)) end function resolvers.locateformat(name) - local engine=environment.ownmain or "luatex" - local barename=removesuffix(name) - local fullname=addsuffix(barename,"fmt") - local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" - if fmtname=="" then - fmtname=resolvers.findfile(fullname) - fmtname=cleanpath(fmtname) - end - if fmtname~="" then - local barename=removesuffix(fmtname) - local luaname=addsuffix(barename,luasuffixes.lua) - local lucname=addsuffix(barename,luasuffixes.luc) - local luiname=addsuffix(barename,luasuffixes.lui) - if isfile(luiname) then - return barename,luiname - elseif isfile(lucname) then - return barename,lucname - elseif isfile(luaname) then - return barename,luaname - end - end - return nil,nil + local engine=environment.ownmain or "luatex" + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") + local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" + if fmtname=="" then + fmtname=resolvers.findfile(fullname) + fmtname=cleanpath(fmtname) + end + if fmtname~="" then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then + return barename,luiname + elseif isfile(lucname) then + return barename,lucname + elseif isfile(luaname) then + return barename,luaname + end + end + return nil,nil end function resolvers.booleanvariable(str,default) - local b=resolvers.expansion(str) - if b=="" then - return default - else - b=toboolean(b) - return (b==nil and default) or b - end + local b=resolvers.expansion(str) + if b=="" then + return default + else + b=toboolean(b) + return (b==nil and default) or b + end end function resolvers.dowithfilesintree(pattern,handle,before,after) - local hashes=instance.hashes - for i=1,#hashes do - local hash=hashes[i] - local blobtype=hash.type - local blobpath=hash.name - if blobtype and blobpath then - local total=0 - local checked=0 - local done=0 - if before then - before(blobtype,blobpath,pattern) - end - for path,name in filtered(instance.files[blobpath],pattern) do - if type(path)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,path,name) then - done=done+1 - end - else - checked=checked+#path - for i=1,#path do - if handle(blobtype,blobpath,path[i],name) then - done=done+1 - end - end - end - end - if after then - after(blobtype,blobpath,pattern,total,checked,done) + local hashes=instance.hashes + for i=1,#hashes do + local hash=hashes[i] + local blobtype=hash.type + local blobpath=hash.name + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 + if before then + before(blobtype,blobpath,pattern) + end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end + end end + end + if after then + after(blobtype,blobpath,pattern,checked,done) + end end + end end local obsolete=resolvers.obsolete or {} resolvers.obsolete=obsolete -resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile -resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles +resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile +resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles function resolvers.knownvariables(pattern) - if instance then - local environment=instance.environment - local variables=instance.variables - local expansions=instance.expansions - local order=instance.order - local pattern=upper(pattern or "") - local result={} - for i=1,#order do - for key in next,order[i] do - if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then - result[key]={ - environment=rawget(environment,key), - variable=key, - expansion=expansions[key], - resolved=resolveprefix(expansions[key]), - } - end - end + if instance then + local environment=instance.environment + local variables=instance.variables + local expansions=instance.expansions + local order=instance.order + local pattern=upper(pattern or "") + local result={} + for i=1,#order do + for key in next,order[i] do + if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then + result[key]={ + environment=rawget(environment,key), + variable=key, + expansion=expansions[key], + resolved=resolveprefix(expansions[key]), + } end - return result - else - return {} + end end + return result + else + return {} + end end @@ -19311,14 +22885,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 4090, stripped down to: 3059 +-- original size: 4854, stripped down to: 2889 if not modules then modules={} end modules ['data-pre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local prefixes=resolvers.prefixes @@ -19331,64 +22905,64 @@ local dirname=file.dirname local joinpath=file.join local isfile=lfs.isfile prefixes.environment=function(str) - return cleanpath(expansion(str)) + return cleanpath(expansion(str)) end local function relative(str,n) - if not isfile(str) then - local pstr="./"..str + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str if isfile(pstr) then - str=pstr + str=pstr + break else - local p="../" - for i=1,n or 2 do - local pstr=p..str - if isfile(pstr) then - str=pstr - break - else - p=p.."../" - end - end + p=p.."../" end + end end - return cleanpath(str) + end + return cleanpath(str) end local function locate(str) - local fullname=findgivenfile(str) or "" - return cleanpath(fullname~="" and fullname or str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) end prefixes.relative=relative prefixes.locate=locate prefixes.auto=function(str) - local fullname=relative(str) - if not isfile(fullname) then - fullname=locate(str) - end - return fullname + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) + end + return fullname end prefixes.filename=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(basename((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(basename((fullname~="" and fullname) or str)) end prefixes.pathname=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(dirname((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(dirname((fullname~="" and fullname) or str)) end prefixes.selfautoloc=function(str) - local pth=getenv('SELFAUTOLOC') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOLOC') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautoparent=function(str) - local pth=getenv('SELFAUTOPARENT') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOPARENT') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautodir=function(str) - local pth=getenv('SELFAUTODIR') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTODIR') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.home=function(str) - local pth=getenv('HOME') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('HOME') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.env=prefixes.environment prefixes.rel=prefixes.relative @@ -19398,24 +22972,24 @@ prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname local function toppath() - local inputstack=resolvers.inputstack - if not inputstack then - return "." - end - local pathname=dirname(inputstack[#inputstack] or "") - if pathname=="" then - return "." - else - return pathname - end + local inputstack=resolvers.inputstack + if not inputstack then + return "." + end + local pathname=dirname(inputstack[#inputstack] or "") + if pathname=="" then + return "." + else + return pathname + end end local function jobpath() - local path=resolvers.stackpath() - if not path or path=="" then - return "." - else - return path - end + local path=resolvers.stackpath() + if not path or path=="" then + return "." + else + return path + end end resolvers.toppath=toppath resolvers.jobpath=jobpath @@ -19423,8 +22997,6 @@ prefixes.toppath=function(str) return cleanpath(joinpath(toppath(),str)) end prefixes.jobpath=function(str) return cleanpath(joinpath(jobpath(),str)) end resolvers.setdynamic("toppath") resolvers.setdynamic("jobpath") -prefixes.jobfile=prefixes.jobpath -resolvers.setdynamic("jobfile") end -- of closure @@ -19433,14 +23005,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-inp"] = package.loaded["data-inp"] or true --- original size: 910, stripped down to: 823 +-- original size: 910, stripped down to: 818 if not modules then modules={} end modules ['data-inp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19463,14 +23035,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-out"] = package.loaded["data-out"] or true --- original size: 530, stripped down to: 475 +-- original size: 530, stripped down to: 470 if not modules then modules={} end modules ['data-out']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19486,16 +23058,16 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3863, stripped down to: 3310 +-- original size: 3863, stripped down to: 3170 if not modules then modules={} end modules ['data-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -19503,88 +23075,88 @@ local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolve local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local filename=specification.filename - local realname=resolveprefix(filename) - if realname and realname~='' and lfs.isdir(realname) then - if trace_locating then - report_files("file locator %a found as %a",filename,realname) - end - resolvers.appendhash('file',filename,true) - elseif trace_locating then - report_files("file locator %a not found",filename) + local filename=specification.filename + local realname=resolveprefix(filename) + if realname and realname~='' and lfs.isdir(realname) then + if trace_locating then + report_files("file locator %a found as %a",filename,realname) end + resolvers.appendhash('file',filename,true) + elseif trace_locating then + report_files("file locator %a not found",filename) + end end function hashers.file(specification) - local pathname=specification.filename - local content=caches.loadcontent(pathname,'files') - resolvers.registerfilehash(pathname,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local pathname=specification.filename - local content=resolvers.scanfiles(pathname,false,true) - resolvers.registerfilehash(pathname,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) - local filename=specification.filename - local foundname=resolvers.findfile(filename,filetype) - if foundname and foundname~="" then - if trace_locating then - report_files("file finder: %a found",filename) - end - return foundname - else - if trace_locating then - report_files("file finder: %a not found",filename) - end - return finders.notfound() + local filename=specification.filename + local foundname=resolvers.findfile(filename,filetype) + if foundname and foundname~="" then + if trace_locating then + report_files("file finder: %a found",filename) + end + return foundname + else + if trace_locating then + report_files("file finder: %a not found",filename) end + return finders.notfound() + end end function openers.helpers.textopener(tag,filename,f) - return { - reader=function() return f:read () end, - close=function() logs.show_close(filename) return f:close() end, - } + return { + reader=function() return f:read () end, + close=function() logs.show_close(filename) return f:close() end, + } end function openers.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"r") - if f then - if trace_locating then - report_files("file opener: %a opened",filename) - end - return openers.helpers.textopener("file",filename,f) - end - end - if trace_locating then - report_files("file opener: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"r") + if f then + if trace_locating then + report_files("file opener: %a opened",filename) + end + return openers.helpers.textopener("file",filename,f) end - return openers.notfound() + end + if trace_locating then + report_files("file opener: %a not found",filename) + end + return openers.notfound() end function loaders.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"rb") - if f then - logs.show_load(filename) - if trace_locating then - report_files("file loader: %a loaded",filename) - end - local s=f:read("*a") - if checkgarbage then - checkgarbage(#s) - end - f:close() - if s then - return true,s,#s - end - end - end - if trace_locating then - report_files("file loader: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"rb") + if f then + logs.show_load(filename) + if trace_locating then + report_files("file loader: %a loaded",filename) + end + local s=f:read("*a") + if checkgarbage then + checkgarbage(#s) + end + f:close() + if s then + return true,s,#s + end end - return loaders.notfound() + end + if trace_locating then + report_files("file loader: %a not found",filename) + end + return loaders.notfound() end @@ -19594,116 +23166,116 @@ do -- create closure to overcome 200 locals limit package.loaded["data-con"] = package.loaded["data-con"] or true --- original size: 5029, stripped down to: 3607 +-- original size: 5029, stripped down to: 3432 if not modules then modules={} end modules ['data-con']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) -local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) -local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) +local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) containers=containers or {} local containers=containers containers.usecache=true local report_containers=logs.reporter("resolvers","containers") local allocated={} local mt={ - __index=function(t,k) - if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } - t.writable=writable - return writable - elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } - t.readables=readables - return readables - end - end, - __storage__=true + __index=function(t,k) + if k=="writable" then + local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + t.writable=writable + return writable + elseif k=="readables" then + local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + t.readables=readables + return readables + end + end, + __storage__=true } function containers.define(category,subcategory,version,enabled) - if category and subcategory then - local c=allocated[category] - if not c then - c={} - allocated[category]=c - end - local s=c[subcategory] - if not s then - s={ - category=category, - subcategory=subcategory, - storage={}, - enabled=enabled, - version=version or math.pi, - trace=false, - } - setmetatable(s,mt) - c[subcategory]=s - end - return s + if category and subcategory then + local c=allocated[category] + if not c then + c={} + allocated[category]=c + end + local s=c[subcategory] + if not s then + s={ + category=category, + subcategory=subcategory, + storage={}, + enabled=enabled, + version=version or math.pi, + trace=false, + } + setmetatable(s,mt) + c[subcategory]=s end + return s + end end function containers.is_usable(container,name) - return container.enabled and caches and caches.is_writable(container.writable,name) + return container.enabled and caches and caches.is_writable(container.writable,name) end function containers.is_valid(container,name) - if name and name~="" then - local storage=container.storage[name] - return storage and storage.cache_version==container.version - else - return false - end + if name and name~="" then + local storage=container.storage[name] + return storage and storage.cache_version==container.version + else + return false + end end function containers.read(container,name) - local storage=container.storage - local stored=storage[name] - if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name,container.writable) - if stored and stored.cache_version==container.version then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","load",container.subcategory,name) - end - else - stored=nil - end - storage[name]=stored - elseif stored then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) - end + local storage=container.storage + local stored=storage[name] + if not stored and container.enabled and caches and containers.usecache then + stored=caches.loaddata(container.readables,name,container.writable) + if stored and stored.cache_version==container.version then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","load",container.subcategory,name) + end + else + stored=nil end - return stored + storage[name]=stored + elseif stored then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) + end + end + return stored end function containers.write(container,name,data) - if data then - data.cache_version=container.version - if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","save",container.subcategory,name) - end - data.unique,data.shared=unique,shared - end - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","store",container.subcategory,name) - end - container.storage[name]=data + if data then + data.cache_version=container.version + if container.enabled and caches then + local unique,shared=data.unique,data.shared + data.unique,data.shared=nil,nil + caches.savedata(container.writable,name,data) + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","save",container.subcategory,name) + end + data.unique,data.shared=unique,shared end - return data + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","store",container.subcategory,name) + end + container.storage[name]=data + end + return data end function containers.content(container,name) - return container.storage[name] + return container.storage[name] end function containers.cleanname(name) - return (gsub(lower(name),"[^%w\128-\255]+","-")) + return (gsub(lower(name),"[^%w\128-\255]+","-")) end @@ -19713,97 +23285,101 @@ do -- create closure to overcome 200 locals limit package.loaded["data-use"] = package.loaded["data-use"] or true --- original size: 4272, stripped down to: 3289 +-- original size: 4434, stripped down to: 3180 if not modules then modules={} end modules ['data-use']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,find=string.format,string.lower,string.gsub,string.find -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_mounts=logs.reporter("resolvers","mounts") local resolvers=resolvers resolvers.automounted=resolvers.automounted or {} function resolvers.automount(usecache) - local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) - if (not mountpaths or #mountpaths==0) and usecache then - mountpaths=caches.getreadablepaths("mount") - end - if mountpaths and #mountpaths>0 then - resolvers.starttiming() - for k=1,#mountpaths do - local root=mountpaths[k] - local f=io.open(root.."/url.tmi") - if f then - for line in f:lines() do - if line then - if find(line,"^[%%#%-]") then - elseif find(line,"^zip://") then - if trace_locating then - report_mounts("mounting %a",line) - end - table.insert(resolvers.automounted,line) - resolvers.usezipfile(line) - end - end - end - f:close() + local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) + if (not mountpaths or #mountpaths==0) and usecache then + mountpaths=caches.getreadablepaths("mount") + end + if mountpaths and #mountpaths>0 then + resolvers.starttiming() + for k=1,#mountpaths do + local root=mountpaths[k] + local f=io.open(root.."/url.tmi") + if f then + for line in f:lines() do + if line then + if find(line,"^[%%#%-]") then + elseif find(line,"^zip://") then + if trace_locating then + report_mounts("mounting %a",line) + end + table.insert(resolvers.automounted,line) + resolvers.usezipfile(line) end + end end - resolvers.stoptiming() + f:close() + end end + resolvers.stoptiming() + end 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,kind,banner) - local enginebanner=status.banner - if formatbanner and enginebanner and sourcefile then - local luvname=file.replacesuffix(texname,"luv") - local luvdata={ - enginebanner=enginebanner, - formatbanner=formatbanner, - sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), - sourcefile=sourcefile, - luaversion=LUAVERSION, - } - io.savedata(luvname,table.serialize(luvdata,true)) - lua.registerfinalizer(function() - logs.report("format banner","%s",banner) - logs.newline() - end) - end + local enginebanner=status.banner + if formatbanner and enginebanner and sourcefile then + local luvname=file.replacesuffix(texname,"luv") + local luvdata={ + enginebanner=enginebanner, + formatbanner=formatbanner, + sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), + sourcefile=sourcefile, + luaversion=LUAVERSION, + } + io.savedata(luvname,table.serialize(luvdata,true)) + lua.registerfinalizer(function() + if jit then + logs.report("format banner","%s lua: %s jit",banner,LUAVERSION) + else + logs.report("format banner","%s lua: %s",banner,LUAVERSION) + end + logs.newline() + end) + end end function statistics.checkfmtstatus(texname) - local enginebanner=status.banner - if enginebanner and texname then - local luvname=file.replacesuffix(texname,"luv") - if lfs.isfile(luvname) then - local luv=dofile(luvname) - if luv and luv.sourcefile then - local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") - local luvbanner=luv.enginebanner or "?" - if luvbanner~=enginebanner then - return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) - end - local luvhash=luv.sourcehash or "?" - if luvhash~=sourcehash then - return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) - end - local luvluaversion=luv.luaversion or 0 - if luvluaversion~=LUAVERSION then - return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) - end - else - return "invalid status file" - end - else - return "missing status file" - end + local enginebanner=status.banner + if enginebanner and texname then + local luvname=file.replacesuffix(texname,"luv") + if lfs.isfile(luvname) then + local luv=dofile(luvname) + if luv and luv.sourcefile then + local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") + local luvbanner=luv.enginebanner or "?" + if luvbanner~=enginebanner then + return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) + end + local luvhash=luv.sourcehash or "?" + if luvhash~=sourcehash then + return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) + end + local luvluaversion=luv.luaversion or 0 + if luvluaversion~=LUAVERSION then + return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) + end + else + return "invalid status file" + end + else + return "missing status file" end - return true + end + return true end @@ -19813,233 +23389,233 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8716, stripped down to: 6795 +-- original size: 8700, stripped down to: 6313 if not modules then modules={} end modules ['data-zip']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,find,match=string.format,string.find,string.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_zip=logs.reporter("resolvers","zip") local resolvers=resolvers zip=zip or {} local zip=zip -zip.archives=zip.archives or {} -local archives=zip.archives -zip.registeredfiles=zip.registeredfiles or {} -local registeredfiles=zip.registeredfiles +local archives=zip.archives or {} +zip.archives=archives +local registeredfiles=zip.registeredfiles or {} +zip.registeredfiles=registeredfiles local function validzip(str) - if not find(str,"^zip://") then - return "zip:///"..str - else - return str - end + if not find(str,"^zip://") then + return "zip:///"..str + else + return str + end end function zip.openarchive(name) - if not name or name=="" then - return nil - else - local arch=archives[name] - if not arch then - local full=resolvers.findfile(name) or "" - arch=full~="" and zip.open(full) or false - archives[name]=arch - end - return arch + if not name or name=="" then + return nil + else + local arch=archives[name] + if not arch then + local full=resolvers.findfile(name) or "" + arch=full~="" and zip.open(full) or false + archives[name]=arch end + return arch + end end function zip.closearchive(name) - if not name or (name=="" and archives[name]) then - zip.close(archives[name]) - archives[name]=nil - end + if not name or (name=="" and archives[name]) then + zip.close(archives[name]) + archives[name]=nil + end end function resolvers.locators.zip(specification) - local archive=specification.filename - local zipfile=archive and archive~="" and zip.openarchive(archive) - if trace_locating then - if zipfile then - report_zip("locator: archive %a found",archive) - else - report_zip("locator: archive %a not found",archive) - end + local archive=specification.filename + local zipfile=archive and archive~="" and zip.openarchive(archive) + if trace_locating then + if zipfile then + report_zip("locator: archive %a found",archive) + else + report_zip("locator: archive %a not found",archive) end + end end function resolvers.hashers.zip(specification) - local archive=specification.filename - if trace_locating then - report_zip("loading file %a",archive) - end - resolvers.usezipfile(specification.original) + local archive=specification.filename + if trace_locating then + report_zip("loading file %a",archive) + end + resolvers.usezipfile(specification.original) end function resolvers.concatinators.zip(zipfile,path,name) - if not path or path=="" then - return format('%s?name=%s',zipfile,name) - else - return format('%s?name=%s/%s',zipfile,path,name) - end + if not path or path=="" then + return format('%s?name=%s',zipfile,name) + else + return format('%s?name=%s/%s',zipfile,path,name) + end end function resolvers.finders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("finder: archive %a found",archive) - end - local dfile=zfile:open(queryname) - if dfile then - dfile=zfile:close() - if trace_locating then - report_zip("finder: file %a found",queryname) - end - return specification.original - elseif trace_locating then - report_zip("finder: file %a not found",queryname) - end - elseif trace_locating then - report_zip("finder: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("finder: archive %a found",archive) end + local dfile=zfile:open(queryname) + if dfile then + dfile:close() + if trace_locating then + report_zip("finder: file %a found",queryname) + end + return specification.original + elseif trace_locating then + report_zip("finder: file %a not found",queryname) + end + elseif trace_locating then + report_zip("finder: unknown archive %a",archive) + end end - if trace_locating then - report_zip("finder: %a not found",original) - end - return resolvers.finders.notfound() + end + if trace_locating then + report_zip("finder: %a not found",original) + end + return resolvers.finders.notfound() end function resolvers.openers.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("opener; archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - if trace_locating then - report_zip("opener: file %a found",queryname) - end - return resolvers.openers.helpers.textopener('zip',original,dfile) - elseif trace_locating then - report_zip("opener: file %a not found",queryname) - end - elseif trace_locating then - report_zip("opener: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("opener; archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + if trace_locating then + report_zip("opener: file %a found",queryname) + end + return resolvers.openers.helpers.textopener('zip',original,dfile) + elseif trace_locating then + report_zip("opener: file %a not found",queryname) + end + elseif trace_locating then + report_zip("opener: unknown archive %a",archive) + end end - if trace_locating then - report_zip("opener: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("opener: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.loaders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("loader: archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - logs.show_load(original) - if trace_locating then - report_zip("loader; file %a loaded",original) - end - local s=dfile:read("*all") - dfile:close() - return true,s,#s - elseif trace_locating then - report_zip("loader: file %a not found",queryname) - end - elseif trace_locating then - report_zip("loader; unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("loader: archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + logs.show_load(original) + if trace_locating then + report_zip("loader; file %a loaded",original) + end + local s=dfile:read("*all") + dfile:close() + return true,s,#s + elseif trace_locating then + report_zip("loader: file %a not found",queryname) + end + elseif trace_locating then + report_zip("loader; unknown archive %a",archive) + end end - if trace_locating then - report_zip("loader: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("loader: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.usezipfile(archive) - local specification=resolvers.splitmethod(archive) - local archive=specification.filename - if archive and not registeredfiles[archive] then - local z=zip.openarchive(archive) - if z then - local tree=url.query(specification.query).tree or "" - if trace_locating then - report_zip("registering: archive %a",archive) - end - resolvers.starttiming() - resolvers.prependhash('zip',archive) - resolvers.extendtexmfvariable(archive) - registeredfiles[archive]=z - resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) - resolvers.stoptiming() - elseif trace_locating then - report_zip("registering: unknown archive %a",archive) - end + local specification=resolvers.splitmethod(archive) + local archive=specification.filename + if archive and not registeredfiles[archive] then + local z=zip.openarchive(archive) + if z then + local tree=url.query(specification.query).tree or "" + if trace_locating then + report_zip("registering: archive %a",archive) + end + resolvers.starttiming() + resolvers.prependhash('zip',archive) + resolvers.extendtexmfvariable(archive) + registeredfiles[archive]=z + resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) + resolvers.stoptiming() elseif trace_locating then - report_zip("registering: archive %a not found",archive) + report_zip("registering: unknown archive %a",archive) end + elseif trace_locating then + report_zip("registering: archive %a not found",archive) + end end function resolvers.registerzipfile(z,tree) - local names={} - local files={} - local remap={} - local n=0 - local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) - local register=resolvers.registerfile - if trace_locating then - report_zip("registering: using filter %a",filter) - end - for i in z:files() do - local filename=i.filename - local path,name=match(filename,filter) - if not path then - n=n+1 - register(names,filename,"") - local usedname=lower(filename) - files[usedname]="" - if usedname~=filename then - remap[usedname]=filename - end - elseif name and name~="" then - n=n+1 - register(names,name,path) - local usedname=lower(name) - files[usedname]=path - if usedname~=name then - remap[usedname]=name - end - else - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile + if trace_locating then + report_zip("registering: using filter %a",filter) + end + for i in z:files() do + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename + end + elseif name and name~="" then + n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end - report_zip("registering: %s files registered",n) - return { - files=files, - remap=remap, - } + end + report_zip("registering: %s files registered",n) + return { + files=files, + remap=remap, + } end @@ -20049,20 +23625,20 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 8479, stripped down to: 5580 +-- original size: 8478, stripped down to: 5223 if not modules then modules={} end modules ['data-tre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,gsub,lower=string.find,string.gsub,string.lower -local basename,dirname,joinname=file.basename,file.dirname,file .join +local basename,dirname,joinname=file.basename,file.dirname,file .join local globdir,isdir,isfile=dir.glob,lfs.isdir,lfs.isfile local P,lpegmatch=lpeg.P,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -20071,165 +23647,167 @@ local lookup=resolvers.get_from_content local collectors={} local found={} function resolvers.finders.tree(specification) - local spec=specification.filename - local okay=found[spec] - if okay==nil then - if spec~="" then - local path=dirname(spec) - local name=basename(spec) - if path=="" then - path="." - end - local names=collectors[path] - if not names then - local pattern=find(path,"/%*+$") and path or (path.."/*") - names=globdir(pattern) - collectors[path]=names - end - local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for i=1,#names do - local fullname=names[i] - if find(fullname,pattern) then - found[spec]=fullname - return fullname - end - end - local pattern=lower(pattern) - for i=1,#names do - local fullname=lower(names[i]) - if find(fullname,pattern) then - if isfile(fullname) then - found[spec]=fullname - return fullname - else - break - end - end - end + local spec=specification.filename + local okay=found[spec] + if okay==nil then + if spec~="" then + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names + end + local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname + end + end + local pattern=lower(pattern) + for i=1,#names do + local fullname=lower(names[i]) + if find(fullname,pattern) then + if isfile(fullname) then + found[spec]=fullname + return fullname + else + break + end end - okay=notfound() - found[spec]=okay + end end - return okay + okay=notfound() + found[spec]=okay + end + return okay end function resolvers.locators.tree(specification) - local name=specification.filename - local realname=resolveprefix(name) - if realname and realname~='' and isdir(realname) then - if trace_locating then - report_trees("locator %a found",realname) - end - resolvers.appendhash('tree',name,false) - elseif trace_locating then - report_trees("locator %a not found",name) + local name=specification.filename + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then + if trace_locating then + report_trees("locator %a found",realname) end + resolvers.appendhash('tree',name,false) + elseif trace_locating then + report_trees("locator %a not found",name) + end end function resolvers.hashers.tree(specification) - local name=specification.filename - report_trees("analyzing %a",name) - resolvers.methodhandler("hashers",name) - resolvers.generators.file(specification) + local name=specification.filename + if trace_locating then + report_trees("analyzing %a",name) + end + resolvers.methodhandler("hashers",name) + resolvers.generators.file(specification) end local collectors={} local splitter=lpeg.splitat("/**/") local stripper=lpeg.replacer { [P("/")*P("*")^1*P(-1)]="" } table.setmetatableindex(collectors,function(t,k) - local rootname=lpegmatch(stripper,k) - local dataname=joinname(rootname,"dirlist") - local content=caches.loadcontent(dataname,"files",dataname) - if not content then - content=resolvers.scanfiles(rootname,nil,nil,false,true) - caches.savecontent(dataname,"files",content,dataname) - end - t[k]=content - return content + local rootname=lpegmatch(stripper,k) + local dataname=joinname(rootname,"dirlist") + local content=caches.loadcontent(dataname,"files",dataname) + if not content then + content=resolvers.scanfiles(rootname,nil,nil,false,true) + caches.savecontent(dataname,"files",content,dataname) + end + t[k]=content + return content end) local function checked(root,p,n) - if p then - if type(p)=="table" then - for i=1,#p do - local fullname=joinname(root,p[i],n) - if isfile(fullname) then - return fullname - end - end - else - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end + if p then + if type(p)=="table" then + for i=1,#p do + local fullname=joinname(root,p[i],n) + if isfile(fullname) then + return fullname end + end + else + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - return notfound() + end + return notfound() end local function resolve(specification) - local filename=specification.filename - if filename~="" then - local root,rest=lpegmatch(splitter,filename) - if root and rest then - local path,name=dirname(rest),basename(rest) - if name~=rest then - local content=collectors[root] - local p,n=lookup(content,name) - if not p then - return notfound() - end - local pattern=".*/"..path.."$" - local istable=type(p)=="table" - if istable then - for i=1,#p do - local pi=p[i] - if pi==path or find(pi,pattern) then - local fullname=joinname(root,pi,n) - if isfile(fullname) then - return fullname - end - end - end - elseif p==path or find(p,pattern) then - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end - end - local queries=specification.queries - if queries and queries.option=="fileonly" then - return checked(root,p,n) - else - return notfound() - end + local filename=specification.filename + if filename~="" then + local root,rest=lpegmatch(splitter,filename) + if root and rest then + local path,name=dirname(rest),basename(rest) + if name~=rest then + local content=collectors[root] + local p,n=lookup(content,name) + if not p then + return notfound() + end + local pattern=".*/"..path.."$" + local istable=type(p)=="table" + if istable then + for i=1,#p do + local pi=p[i] + if pi==path or find(pi,pattern) then + local fullname=joinname(root,pi,n) + if isfile(fullname) then + return fullname + end end + end + elseif p==path or find(p,pattern) then + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - local path,name=dirname(filename),basename(filename) - local root=lpegmatch(stripper,path) - local content=collectors[path] - local p,n=lookup(content,name) - if p then - return checked(root,p,n) + local queries=specification.queries + if queries and queries.option=="fileonly" then + return checked(root,p,n) + else + return notfound() end + end end - return notfound() + local path,name=dirname(filename),basename(filename) + local root=lpegmatch(stripper,path) + local content=collectors[path] + local p,n=lookup(content,name) + if p then + return checked(root,p,n) + end + end + return notfound() end -resolvers.finders .dirlist=resolve -resolvers.locators .dirlist=resolvers.locators .tree -resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.finders .dirlist=resolve +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree resolvers.generators.dirlist=resolvers.generators.file -resolvers.openers .dirlist=resolvers.openers .file -resolvers.loaders .dirlist=resolvers.loaders .file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file function resolvers.finders.dirfile(specification) - local queries=specification.queries - if queries then - queries.option="fileonly" - else - specification.queries={ option="fileonly" } - end - return resolve(specification) -end -resolvers.locators .dirfile=resolvers.locators .dirlist -resolvers.hashers .dirfile=resolvers.hashers .dirlist + local queries=specification.queries + if queries then + queries.option="fileonly" + else + specification.queries={ option="fileonly" } + end + return resolve(specification) +end +resolvers.locators .dirfile=resolvers.locators .dirlist +resolvers.hashers .dirfile=resolvers.hashers .dirlist resolvers.generators.dirfile=resolvers.generators.dirlist -resolvers.openers .dirfile=resolvers.openers .dirlist -resolvers.loaders .dirfile=resolvers.loaders .dirlist +resolvers.openers .dirfile=resolvers.openers .dirlist +resolvers.loaders .dirfile=resolvers.loaders .dirlist end -- of closure @@ -20238,19 +23816,19 @@ do -- create closure to overcome 200 locals limit package.loaded["data-sch"] = package.loaded["data-sch"] or true --- original size: 6753, stripped down to: 5511 +-- original size: 6753, stripped down to: 5268 if not modules then modules={} end modules ['data-sch']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local load,tonumber=load,tonumber local gsub,concat,format=string.gsub,table.concat,string.format local finders,openers,loaders=resolvers.finders,resolvers.openers,resolvers.loaders -local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) +local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) local report_schemes=logs.reporter("resolvers","schemes") local http=require("socket.http") local ltn12=require("ltn12") @@ -20263,27 +23841,27 @@ schemes.cleaners=cleaners local threshold=24*60*60 directives.register("schemes.threshold",function(v) threshold=tonumber(v) or threshold end) function cleaners.none(specification) - return specification.original + return specification.original end function cleaners.strip(specification) - local path,name=file.splitbase(specification.original) - if path=="" then - return (gsub(name,"[^%a%d%.]+","-")) - else - return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) - end + local path,name=file.splitbase(specification.original) + if path=="" then + return (gsub(name,"[^%a%d%.]+","-")) + else + return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) + end end function cleaners.md5(specification) - return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) + return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) end local cleaner=cleaners.strip directives.register("schemes.cleanmethod",function(v) cleaner=cleaners[v] or cleaners.strip end) function resolvers.schemes.cleanname(specification) - local hash=cleaner(specification) - if trace_schemes then - report_schemes("hashing %a to %a",specification.original,hash) - end - return hash + local hash=cleaner(specification) + if trace_schemes then + report_schemes("hashing %a to %a",specification.original,hash) + end + return hash end local cached={} local loaded={} @@ -20291,139 +23869,139 @@ local reused={} local thresholds={} local handlers={} local runner=sandbox.registerrunner { - name="curl resolver", - method="execute", - program="curl", - template="--silent --insecure --create-dirs --output %cachename% %original%", - checkers={ - cachename="cache", - original="url", - } + name="curl resolver", + method="execute", + program="curl", + template="--silent --insecure --create-dirs --output %cachename% %original%", + checkers={ + cachename="cache", + original="url", + } } local function fetch(specification) - local original=specification.original - local scheme=specification.scheme - local cleanname=schemes.cleanname(specification) - local cachename=caches.setfirstwritablefile(cleanname,"schemes") - if not cached[original] then - statistics.starttiming(schemes) - if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then - cached[original]=cachename - local handler=handlers[scheme] - if handler then - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") - end - logs.flush() - handler(specification,cachename) - else - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") - end - logs.flush() - runner { - original=original, - cachename=cachename, - } - end - end - if io.exists(cachename) then - cached[original]=cachename - if trace_schemes then - report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) - end - else - cached[original]="" - if trace_schemes then - report_schemes("using missing %a, protocol %a",original,scheme) - end + local original=specification.original + local scheme=specification.scheme + local cleanname=schemes.cleanname(specification) + local cachename=caches.setfirstwritablefile(cleanname,"schemes") + if not cached[original] then + statistics.starttiming(schemes) + if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then + cached[original]=cachename + local handler=handlers[scheme] + if handler then + if trace_schemes then + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") end - loaded[scheme]=loaded[scheme]+1 - statistics.stoptiming(schemes) - else + logs.flush() + handler(specification,cachename) + else if trace_schemes then - report_schemes("reusing %a, protocol %a",original,scheme) + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") end - reused[scheme]=reused[scheme]+1 + logs.flush() + runner { + original=original, + cachename=cachename, + } + end + end + if io.exists(cachename) then + cached[original]=cachename + if trace_schemes then + report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) + end + else + cached[original]="" + if trace_schemes then + report_schemes("using missing %a, protocol %a",original,scheme) + end end - return cached[original] + loaded[scheme]=loaded[scheme]+1 + statistics.stoptiming(schemes) + else + if trace_schemes then + report_schemes("reusing %a, protocol %a",original,scheme) + end + reused[scheme]=reused[scheme]+1 + end + return cached[original] end local function finder(specification,filetype) - return resolvers.methodhandler("finders",fetch(specification),filetype) + return resolvers.methodhandler("finders",fetch(specification),filetype) end local opener=openers.file local loader=loaders.file local function install(scheme,handler,newthreshold) - handlers [scheme]=handler - loaded [scheme]=0 - reused [scheme]=0 - finders [scheme]=finder - openers [scheme]=opener - loaders [scheme]=loader - thresholds[scheme]=newthreshold or threshold + handlers [scheme]=handler + loaded [scheme]=0 + reused [scheme]=0 + finders [scheme]=finder + openers [scheme]=opener + loaders [scheme]=loader + thresholds[scheme]=newthreshold or threshold end schemes.install=install local function http_handler(specification,cachename) - local tempname=cachename..".tmp" - local f=io.open(tempname,"wb") - local status,message=http.request { - url=specification.original, - sink=ltn12.sink.file(f) - } - if not status then - os.remove(tempname) - else - os.remove(cachename) - os.rename(tempname,cachename) - end - return cachename + local tempname=cachename..".tmp" + local f=io.open(tempname,"wb") + local status,message=http.request { + url=specification.original, + sink=ltn12.sink.file(f) + } + if not status then + os.remove(tempname) + else + os.remove(cachename) + os.rename(tempname,cachename) + end + return cachename end install('http',http_handler) install('https') install('ftp') statistics.register("scheme handling time",function() - local l,r,nl,nr={},{},0,0 - for k,v in table.sortedhash(loaded) do - if v>0 then - nl=nl+1 - l[nl]=k..":"..v - end - end - for k,v in table.sortedhash(reused) do - if v>0 then - nr=nr+1 - r[nr]=k..":"..v - end - end - local n=nl+nr - if n>0 then - l=nl>0 and concat(l) or "none" - r=nr>0 and concat(r) or "none" - return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", - statistics.elapsedtime(schemes),n,threshold,l,r) - else - return nil - end + local l,r,nl,nr={},{},0,0 + for k,v in table.sortedhash(loaded) do + if v>0 then + nl=nl+1 + l[nl]=k..":"..v + end + end + for k,v in table.sortedhash(reused) do + if v>0 then + nr=nr+1 + r[nr]=k..":"..v + end + end + local n=nl+nr + if n>0 then + l=nl>0 and concat(l) or "none" + r=nr>0 and concat(r) or "none" + return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", + statistics.elapsedtime(schemes),n,threshold,l,r) + else + return nil + end end) local httprequest=http.request local toquery=url.toquery local function fetchstring(url,data) - local q=data and toquery(data) - if q then - url=url.."?"..q - end - local reply=httprequest(url) - return reply + local q=data and toquery(data) + if q then + url=url.."?"..q + end + local reply=httprequest(url) + return reply end schemes.fetchstring=fetchstring function schemes.fetchtable(url,data) - local reply=fetchstring(url,data) - if reply then - local s=load("return "..reply) - if s then - return s() - end + local reply=fetchstring(url,data) + if reply then + local s=load("return "..reply) + if s then + return s() end + end end @@ -20433,14 +24011,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4207, stripped down to: 3137 +-- original size: 4207, stripped down to: 3041 if not modules then modules={} end modules ['data-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local package,lpeg=package,lpeg local gsub=string.gsub @@ -20459,20 +24037,20 @@ helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) helpers.sequence={ - "already loaded", - "preload table", - "lua variable format", - "lib variable format", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", + "already loaded", + "preload table", + "lua variable format", + "lib variable format", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolveprefix(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local registerpath=helpers.registerpath @@ -20480,56 +24058,56 @@ local lualibfile=helpers.lualibfile local luaformatpaths local libformatpaths local function getluaformatpaths() - if not luaformatpaths then - luaformatpaths={} - for i=1,#luaformats do - registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) - end + if not luaformatpaths then + luaformatpaths={} + for i=1,#luaformats do + registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) end - return luaformatpaths + end + return luaformatpaths end local function getlibformatpaths() - if not libformatpaths then - libformatpaths={} - for i=1,#libformats do - registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) - end + if not libformatpaths then + libformatpaths={} + for i=1,#libformats do + registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) end - return libformatpaths + end + return libformatpaths end local function loadedbyformat(name,rawname,suffixes,islib,what) - local trace=helpers.trace - local report=helpers.report - for i=1,#suffixes do - local format=suffixes[i] - local resolved=resolvers.findfile(name,format) or "" - if trace then - report("%s format, identifying %a using format %a",what,name,format) - end - if resolved~="" then - if trace then - report("%s format, %a found on %a",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + local report=helpers.report + for i=1,#suffixes do + local format=suffixes[i] + local resolved=resolvers.findfile(name,format) or "" + if trace then + report("%s format, identifying %a using format %a",what,name,format) + end + if resolved~="" then + if trace then + report("%s format, %a found on %a",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + end end helpers.loadedbyformat=loadedbyformat methods["lua variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") + if helpers.trace then + helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") end methods["lib variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") + if helpers.trace then + helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") end resolvers.loadlualib=require @@ -20540,64 +24118,64 @@ do -- create closure to overcome 200 locals limit package.loaded["data-aux"] = package.loaded["data-aux"] or true --- original size: 2438, stripped down to: 2003 +-- original size: 2452, stripped down to: 1877 if not modules then modules={} end modules ['data-aux']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find=string.find local type,next=type,next -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +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="context/lua" - newname=file.addsuffix(newname,"lua") - local oldscript=resolvers.cleanpath(oldname) + local scriptpath="context/lua" + newname=file.addsuffix(newname,"lua") + local oldscript=resolvers.cleanpath(oldname) + if trace_locating then + report_scripts("to be replaced old script %a",oldscript) + end + local newscripts=resolvers.findfiles(newname) or {} + if #newscripts==0 then if trace_locating then - report_scripts("to be replaced old script %a",oldscript) + report_scripts("unable to locate new script") end - local newscripts=resolvers.findfiles(newname) or {} - if #newscripts==0 then + else + for i=1,#newscripts do + local newscript=resolvers.cleanpath(newscripts[i]) + if trace_locating then + report_scripts("checking new script %a",newscript) + end + if oldscript==newscript then if trace_locating then - report_scripts("unable to locate new script") + report_scripts("old and new script are the same") end - else - for i=1,#newscripts do - local newscript=resolvers.cleanpath(newscripts[i]) - if trace_locating then - report_scripts("checking new script %a",newscript) - end - if oldscript==newscript then - if trace_locating then - report_scripts("old and new script are the same") - end - elseif not find(newscript,scriptpath,1,true) then - if trace_locating then - report_scripts("new script should come from %a",scriptpath) - end - elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then - if trace_locating then - report_scripts("invalid new script name") - end - else - local newdata=io.loaddata(newscript) - if newdata then - if trace_locating then - report_scripts("old script content replaced by new content") - end - io.savedata(oldscript,newdata) - break - elseif trace_locating then - report_scripts("unable to load new script") - end - end + elseif not find(newscript,scriptpath,1,true) then + if trace_locating then + report_scripts("new script should come from %a",scriptpath) end + elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then + if trace_locating then + report_scripts("invalid new script name") + end + else + local newdata=io.loaddata(newscript) + if newdata then + if trace_locating then + report_scripts("old script content replaced by new content: %s",oldscript) + end + io.savedata(oldscript,newdata) + break + elseif trace_locating then + report_scripts("unable to load new script") + end + end end + end end @@ -20607,53 +24185,53 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2601, stripped down to: 1627 +-- original size: 2601, stripped down to: 1549 if not modules then modules={} end modules ['data-tmf']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local report_tds=logs.reporter("resolvers","tds") function resolvers.load_tree(tree,resolve) - if type(tree)=="string" and tree~="" then - local getenv,setenv=resolvers.getenv,resolvers.setenv - local texos="texmf-"..os.platform - local oldroot=environment.texroot - local newroot=file.collapsepath(tree) - local newtree=file.join(newroot,texos) - local newpath=file.join(newtree,"bin") - if not lfs.isdir(newtree) then - report_tds("no %a under tree %a",texos,tree) - os.exit() - end - if not lfs.isdir(newpath) then - report_tds("no '%s/bin' under tree %a",texos,tree) - os.exit() - end - local texmfos=newtree - environment.texroot=newroot - environment.texos=texos - environment.texmfos=texmfos - if resolve then - resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) - end - setenv('SELFAUTOPARENT',newroot) - setenv('SELFAUTODIR',newtree) - setenv('SELFAUTOLOC',newpath) - setenv('TEXROOT',newroot) - setenv('TEXOS',texos) - setenv('TEXMFOS',texmfos) - setenv('TEXMFCNF',resolvers.luacnfspec,true) - setenv('PATH',newpath..io.pathseparator..getenv('PATH')) - report_tds("changing from root %a to %a",oldroot,newroot) - report_tds("prepending %a to PATH",newpath) - report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) - report_tds() - end + if type(tree)=="string" and tree~="" then + local getenv,setenv=resolvers.getenv,resolvers.setenv + local texos="texmf-"..os.platform + local oldroot=environment.texroot + local newroot=file.collapsepath(tree) + local newtree=file.join(newroot,texos) + local newpath=file.join(newtree,"bin") + if not lfs.isdir(newtree) then + report_tds("no %a under tree %a",texos,tree) + os.exit() + end + if not lfs.isdir(newpath) then + report_tds("no '%s/bin' under tree %a",texos,tree) + os.exit() + end + local texmfos=newtree + environment.texroot=newroot + environment.texos=texos + environment.texmfos=texmfos + if resolve then + resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) + end + setenv('SELFAUTOPARENT',newroot) + setenv('SELFAUTODIR',newtree) + setenv('SELFAUTOLOC',newpath) + setenv('TEXROOT',newroot) + setenv('TEXOS',texos) + setenv('TEXMFOS',texmfos) + setenv('TEXMFCNF',resolvers.luacnfspec,true) + setenv('PATH',newpath..io.pathseparator..getenv('PATH')) + report_tds("changing from root %a to %a",oldroot,newroot) + report_tds("prepending %a to PATH",newpath) + report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) + report_tds() + end end @@ -20663,14 +24241,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 1823, stripped down to: 1591 +-- original size: 1823, stripped down to: 1542 if not modules then modules={} end modules ['data-lst']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local concat,sortedhash=table.concat,table.sortedhash @@ -20681,37 +24259,37 @@ local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local report_resolved=logs.reporter("system","resolved") local function tabstr(str) - if type(str)=='table' then - return concat(str," | ") - else - return str - end + if type(str)=='table' then + return concat(str," | ") + else + return str + end end function listers.variables(pattern) - local result=resolvers.knownvariables(pattern) - for key,value in sortedhash(result) do - report_lists(key) - report_lists(" env: %s",tabstr(value.environment or "unset")) - report_lists(" var: %s",tabstr(value.variable or "unset")) - report_lists(" exp: %s",tabstr(value.expansion or "unset")) - report_lists(" res: %s",tabstr(value.resolved or "unset")) - end + local result=resolvers.knownvariables(pattern) + for key,value in sortedhash(result) do + report_lists(key) + report_lists(" env: %s",tabstr(value.environment or "unset")) + report_lists(" var: %s",tabstr(value.variable or "unset")) + report_lists(" exp: %s",tabstr(value.expansion or "unset")) + report_lists(" res: %s",tabstr(value.resolved or "unset")) + end end function listers.configurations() - local configurations=resolvers.configurationfiles() - for i=1,#configurations do - report_resolved("file : %s",resolveprefix(configurations[i])) - end - report_resolved("") - local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) - for i=1,#list do - local li=resolveprefix(list[i]) - if lfs.isdir(li) then - report_resolved("path - %s",li) - else - report_resolved("path + %s",li) - end + local configurations=resolvers.configurationfiles() + for i=1,#configurations do + report_resolved("file : %s",resolveprefix(configurations[i])) + end + report_resolved("") + local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) + for i=1,#list do + local li=resolveprefix(list[i]) + if lfs.isdir(li) then + report_resolved("path - %s",li) + else + report_resolved("path + %s",li) end + end end @@ -20721,14 +24299,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lib"] = package.loaded["util-lib"] or true --- original size: 14943, stripped down to: 8305 +-- original size: 16094, stripped down to: 8443 if not modules then modules={} end modules ['util-lib']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local type=type local next=next @@ -20748,256 +24326,291 @@ local qualifiedpath=file.is_qualified_path local isfile=lfs.isfile local done=false local function locate(required,version,trace,report,action) - if type(required)~="string" then - report("provide a proper library name") - return - end - if trace then - report("requiring library %a with version %a",required,version or "any") - end - local found_library=nil - local required_full=gsub(required,"%.","/") - local required_path=pathpart(required_full) - local required_base=nameonly(required_full) - if qualifiedpath(required) then - if isfile(addsuffix(required,os.libsuffix)) then - if trace then - report("qualified name %a found",required) - end - found_library=required - else - if trace then - report("qualified name %a not found",required) - end - end + if type(required)~="string" then + report("provide a proper library name") + return + end + if trace then + report("requiring library %a with version %a",required,version or "any") + end + local found_library=nil + local required_full=gsub(required,"%.","/") + local required_path=pathpart(required_full) + local required_base=nameonly(required_full) + if qualifiedpath(required) then + if isfile(addsuffix(required,os.libsuffix)) then + if trace then + report("qualified name %a found",required) + end + found_library=required else - local required_name=required_base.."."..os.libsuffix - local version=type(version)=="string" and version~="" and version or false - local engine="luatex" - if trace and not done then - local list=expandpaths("lib") - for i=1,#list do - report("tds path %i: %s",i,list[i]) - end + if trace then + report("qualified name %a not found",required) + end + end + else + local required_name=required_base.."."..os.libsuffix + local version=type(version)=="string" and version~="" and version or false + local engine="luatex" + if trace and not done then + local list=expandpaths("lib") + for i=1,#list do + report("tds path %i: %s",i,list[i]) + end + end + local function found(locate,asked_library,how,...) + if trace then + report("checking %s: %a",how,asked_library) + end + return locate(asked_library,...) + end + local function check(locate,...) + local found=nil + if version then + local asked_library=joinfile(required_path,version,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function found(locate,asked_library,how,...) - if trace then - report("checking %s: %a",how,asked_library) - end - return locate(asked_library,...) - end - local function check(locate,...) - local found=nil - if version then - local asked_library=joinfile(required_path,version,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - if not found or found=="" then - local asked_library=joinfile(required_path,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - return found and found~="" and found or false + found=locate(asked_library,...) + end + if not found or found=="" then + local asked_library=joinfile(required_path,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function attempt(checkpattern) - if trace then - report("checking tds lib paths strictly") - end - local found=findfile and check(findfile,"lib") - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - if trace then - report("checking tds lib paths with wildcard") - end - local asked_library=joinfile(required_path,".*",required_name) - if trace then - report("checking %s: %a","latest version",asked_library) - end - local list=findfiles(asked_library,"lib",true) - if list and #list>0 then - sort(list) - local found=list[#list] - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - end - if trace then - report("checking lib paths") - end - package.extralibpath(environment.ownpath) - local paths=package.libpaths() - local pattern="/[^/]+%."..os.libsuffix.."$" - for i=1,#paths do - required_path=gsub(paths[i],pattern,"") - local found=check(lfs.isfound) - if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then - return found - end - end - return false + found=locate(asked_library,...) + end + return found and found~="" and found or false + end + local function attempt(checkpattern) + if trace then + report("checking tds lib paths strictly") + end + local found=findfile and check(findfile,"lib") + if found and (not checkpattern or find(found,checkpattern)) then + return found + end + if trace then + report("checking tds lib paths with wildcard") + end + local asked_library=joinfile(required_path,".*",required_name) + if trace then + report("checking %s: %a","latest version",asked_library) + end + local list=findfiles(asked_library,"lib",true) + if list and #list>0 then + sort(list) + local found=list[#list] + if found and (not checkpattern or find(found,checkpattern)) then + return found end - if engine then - if trace then - report("attemp 1, engine %a",engine) - end - found_library=attempt("/"..engine.."/") - if not found_library then - if trace then - report("attemp 2, no engine",asked_library) - end - found_library=attempt() - end - else - found_library=attempt() + end + if trace then + report("checking lib paths") + end + package.extralibpath(environment.ownpath) + local paths=package.libpaths() + local pattern="/[^/]+%."..os.libsuffix.."$" + for i=1,#paths do + required_path=gsub(paths[i],pattern,"") + local found=check(lfs.isfound) + if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then + return found end + end + return false end - if not found_library then + if engine then + if trace then + report("attemp 1, engine %a",engine) + end + found_library=attempt("/"..engine.."/") + if not found_library then if trace then - report("not found: %a",required) + report("attemp 2, no engine",asked_library) end - library=false + found_library=attempt() + end else - if trace then - report("found: %a",found_library) - end - local result,message=action(found_library,required_base) - if result then - library=result - else - library=false - report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") - end + found_library=attempt() end + end + if not found_library then if trace then - if not library then - report("unknown library: %a",required) - else - report("stored library: %a",required) - end + report("not found: %a",required) end - return library + library=false + else + if trace then + report("found: %a",found_library) + end + local result,message=action(found_library,required_base) + if result then + library=result + else + library=false + report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") + end + end + if trace then + if not library then + report("unknown library: %a",required) + else + report("stored library: %a",required) + end + end + return library or nil end do - local report_swiglib=logs.reporter("swiglib") - local trace_swiglib=false - local savedrequire=require - local loadedlibs={} - local loadlib=package.loadlib - local pushdir=dir.push - local popdir=dir.pop - trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) - function requireswiglib(required,version) - local library=loadedlibs[library] - if library==nil then - local trace_swiglib=trace_swiglib or package.helpers.trace - library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) - pushdir(pathpart(name)) - local opener="luaopen_"..base - if trace_swiglib then - report_swiglib("opening: %a with %a",name,opener) - end - local library,message=loadlib(name,opener) - local libtype=type(library) - if libtype=="function" then - library=library() - else - 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 - popdir() - return library - end) - loadedlibs[required]=library or false + local report_swiglib=logs.reporter("swiglib") + local trace_swiglib=false + local savedrequire=require + local loadedlibs={} + local loadlib=package.loadlib + local pushdir=dir.push + local popdir=dir.pop + trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) + function requireswiglib(required,version) + local library=loadedlibs[library] + if library==nil then + local trace_swiglib=trace_swiglib or package.helpers.trace + library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) + pushdir(pathpart(name)) + local opener="luaopen_"..base + if trace_swiglib then + report_swiglib("opening: %a with %a",name,opener) + end + local library,message=loadlib(name,opener) + local libtype=type(library) + if libtype=="function" then + library=library() + else + 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 + popdir() return library + end) + loadedlibs[required]=library or false end - function require(name,version) - if find(name,"^swiglib%.") then - return requireswiglib(name,version) - else - return savedrequire(name) - end + return library + end + function require(name,version) + if find(name,"^swiglib%.") then + return requireswiglib(name,version) + else + return savedrequire(name) + end + end + local swiglibs={} + local initializer="core" + function swiglib(name,version) + local library=swiglibs[name] + if not library then + statistics.starttiming(swiglibs) + if trace_swiglib then + report_swiglib("loading %a",name) + end + 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 - local swiglibs={} - local initializer="core" - function swiglib(name,version) - local library=swiglibs[name] - if not library then - statistics.starttiming(swiglibs) - if trace_swiglib then - report_swiglib("loading %a",name) - end - 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 - return library + return library + end + statistics.register("used swiglibs",function() + if next(swiglibs) then + return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) end - statistics.register("used swiglibs",function() - if next(swiglibs) then - return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) - end - end) + end) end if FFISUPPORTED and ffi and ffi.load then - local report_ffilib=logs.reporter("ffilib") - local trace_ffilib=false - local savedffiload=ffi.load - trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) - local loaded={} - local function locateindeed(name) - name=removesuffix(name) - local l=loaded[name] - if l==nil then - local message,library=pcall(savedffiload,name) - if type(message)=="userdata" then - l=message - elseif type(library)=="userdata" then - l=library - else - l=false - end - loaded[name]=l - elseif trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l + local report_ffilib=logs.reporter("ffilib") + local trace_ffilib=false + local savedffiload=ffi.load + trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) + local loaded={} + local function locateindeed(name) + name=removesuffix(name) + local l=loaded[name] + if l==nil then + local state,library=pcall(savedffiload,name) + if type(library)=="userdata" then + l=library + elseif type(state)=="userdata" then + l=state + else + l=false + end + loaded[name]=l + elseif trace_ffilib then + report_ffilib("reusing already loaded %a",name) end - function ffilib(name,version) - name=removesuffix(name) - local l=loaded[name] - if l~=nil then - if trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l - elseif version=="system" then - return locateindeed(name) - else - return locate(name,version,trace_ffilib,report_ffilib,locateindeed) + return l + end + local function getlist(required) + local list=directives.value("system.librarynames" ) + if type(list)=="table" then + list=list[required] + if type(list)=="table" then + if trace then + report("using lookup list for library %a: % | t",required,list) end + return list + end end - function ffi.load(name) - local library=ffilib(name) + return { required } + end + function ffilib(name,version) + name=removesuffix(name) + local l=loaded[name] + if l~=nil then + if trace_ffilib then + report_ffilib("reusing already loaded %a",name) + end + return l + end + local list=getlist(name) + if version=="system" then + for i=1,#list do + local library=locateindeed(list[i]) if type(library)=="userdata" then - return library + return library end - if trace_ffilib then - report_ffilib("trying to load %a using normal loader",name) + end + else + for i=1,#list do + local library=locate(list[i],version,trace_ffilib,report_ffilib,locateindeed) + if type(library)=="userdata" then + return library end - return savedffiload(name) + end end + end + function ffi.load(name) + local list=getlist(name) + for i=1,#list do + local library=ffilib(list[i]) + if type(library)=="userdata" then + return library + end + end + if trace_ffilib then + report_ffilib("trying to load %a using normal loader",name) + end + for i=1,#list do + local state,library=pcall(savedffiload,list[i]) + if type(library)=="userdata" then + return library + elseif type(state)=="userdata" then + return library + end + end + end end @@ -21007,13 +24620,13 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-sta"] = package.loaded["luat-sta"] or true --- original size: 5703, stripped down to: 2507 +-- original size: 5703, stripped down to: 2321 if not modules then modules={} end modules ['luat-sta']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gmatch,match=string.gmatch,string.match local type=type @@ -21026,81 +24639,81 @@ local hash=states.hash states.tag=states.tag or "" states.filename=states.filename or "" function states.save(filename,tag) - tag=tag or states.tag - filename=file.addsuffix(filename or states.filename,'lus') - io.savedata(filename, - "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) - ) + tag=tag or states.tag + filename=file.addsuffix(filename or states.filename,'lus') + io.savedata(filename, + "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) + ) end function states.load(filename,tag) - states.filename=filename - states.tag=tag or "whatever" - states.filename=file.addsuffix(states.filename,'lus') - data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} + states.filename=filename + states.tag=tag or "whatever" + states.filename=file.addsuffix(states.filename,'lus') + data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} end local function set_by_tag(tag,key,value,default,persistent) - local d,h=data[tag],hash[tag] - if d then - if type(d)=="table" then - local dkey,hkey=key,key - local pre,post=match(key,"(.+)%.([^%.]+)$") - if pre and post then - for k in gmatch(pre,"[^%.]+") do - local dk=d[k] - if not dk then - dk={} - d[k]=dk - elseif type(dk)=="string" then - break - end - d=dk - end - dkey,hkey=post,key - end - if value==nil then - value=default - elseif value==false then - elseif persistent then - value=value or d[dkey] or default - else - value=value or default - end - d[dkey],h[hkey]=value,value - elseif type(d)=="string" then - data[tag],hash[tag]=value,value + local d,h=data[tag],hash[tag] + if d then + if type(d)=="table" then + local dkey,hkey=key,key + local pre,post=match(key,"(.+)%.([^%.]+)$") + if pre and post then + for k in gmatch(pre,"[^%.]+") do + local dk=d[k] + if not dk then + dk={} + d[k]=dk + elseif type(dk)=="string" then + break + end + d=dk end + dkey,hkey=post,key + end + if value==nil then + value=default + elseif value==false then + elseif persistent then + value=value or d[dkey] or default + else + value=value or default + end + d[dkey],h[hkey]=value,value + elseif type(d)=="string" then + data[tag],hash[tag]=value,value end + end end local function get_by_tag(tag,key,default) - local h=hash[tag] - if h and h[key] then - return h[key] - else - local d=data[tag] - if d then - for k in gmatch(key,"[^%.]+") do - local dk=d[k] - if dk~=nil then - d=dk - else - return default - end - end - if d==false then - return false - else - return d or default - end + local h=hash[tag] + if h and h[key] then + return h[key] + else + local d=data[tag] + if d then + for k in gmatch(key,"[^%.]+") do + local dk=d[k] + if dk~=nil then + d=dk + else + return default end + end + if d==false then + return false + else + return d or default + end end + end end states.set_by_tag=set_by_tag states.get_by_tag=get_by_tag function states.set(key,value,default,persistent) - set_by_tag(states.tag,key,value,default,persistent) + set_by_tag(states.tag,key,value,default,persistent) end function states.get(key,default) - return get_by_tag(states.tag,key,default) + return get_by_tag(states.tag,key,default) end @@ -21110,14 +24723,14 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-fmt"] = package.loaded["luat-fmt"] or true --- original size: 9268, stripped down to: 7401 +-- original size: 9418, stripped down to: 7087 if not modules then modules={} end modules ['luat-fmt']={ - version=1.001, - comment="companion to mtxrun", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to mtxrun", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format=string.format local concat=table.concat @@ -21125,229 +24738,232 @@ local quoted=string.quoted local luasuffixes=utilities.lua.suffixes local report_format=logs.reporter("resolvers","formats") local function primaryflags() - local arguments=environment.arguments - local flags={} - if arguments.silent then - flags[#flags+1]="--interaction=batchmode" - end - if arguments.jit then - flags[#flags+1]="--jiton" - end - return concat(flags," ") + local arguments=environment.arguments + local flags={} + if arguments.silent then + flags[#flags+1]="--interaction=batchmode" + end + return concat(flags," ") end local function secondaryflags() - local arguments=environment.arguments - local trackers=arguments.trackers - local directives=arguments.directives - local flags={} - if trackers and trackers~="" then - flags[#flags+1]="--c:trackers="..quoted(trackers) - end - if directives and directives~="" then - flags[#flags+1]="--c:directives="..quoted(directives) - end - if arguments.silent then - flags[#flags+1]="--c:silent" - end - if arguments.errors then - flags[#flags+1]="--c:errors" - end - if arguments.jit then - flags[#flags+1]="--c:jiton" - end - if arguments.ansi then - flags[#flags+1]="--c:ansi" - end - return concat(flags," ") + local arguments=environment.arguments + local trackers=arguments.trackers + local directives=arguments.directives + local flags={} + if trackers and trackers~="" then + flags[#flags+1]="--c:trackers="..quoted(trackers) + end + if directives and directives~="" then + flags[#flags+1]="--c:directives="..quoted(directives) + end + if arguments.silent then + flags[#flags+1]="--c:silent" + end + if arguments.errors then + flags[#flags+1]="--c:errors" + end + if arguments.jit then + flags[#flags+1]="--c:jiton" + end + if arguments.ansi then + flags[#flags+1]="--c:ansi" + end + if arguments.strip then + flags[#flags+1]="--c:strip" + end + if arguments.lmtx then + flags[#flags+1]="--c:lmtx" + end + return concat(flags," ") end local template=[[--ini %primaryflags% --lua=%luafile% %texfile% %secondaryflags% %dump% %redirect%]] local checkers={ - primaryflags="string", - secondaryflags="string", - luafile="readable", - texfile="readable", - redirect="string", - dump="string", + primaryflags="string", + secondaryflags="string", + luafile="readable", + texfile="readable", + redirect="string", + dump="string", } local runners={ - luatex=sandbox.registerrunner { - name="make luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="make luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="make luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="make luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.make_format(name,arguments) - local engine=environment.ownmain or "luatex" - local silent=environment.arguments.silent - local errors=environment.arguments.errors - local olddir=dir.current() - local path=caches.getwritablepath("formats",engine) or "" - if path~="" then - lfs.chdir(path) - end - report_format("using format path %a",dir.current()) - local texsourcename=file.addsuffix(name,"mkiv") - local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - if fulltexsourcename=="" then - texsourcename=file.addsuffix(name,"tex") - fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - end - if fulltexsourcename=="" then - report_format("no tex source file with name %a (mkiv or tex)",name) - lfs.chdir(olddir) - return - else - report_format("using tex source file %a",fulltexsourcename) - end - local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) - local specificationname=file.replacesuffix(fulltexsourcename,"lus") - local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - if fullspecificationname=="" then - specificationname=file.join(texsourcepath,"context.lus") - fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - end - if fullspecificationname=="" then - report_format("unknown stub specification %a",specificationname) - lfs.chdir(olddir) - return - end - local specificationpath=file.dirname(fullspecificationname) - local usedluastub=nil - local usedlualibs=dofile(fullspecificationname) - if type(usedlualibs)=="string" then - usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) - elseif type(usedlualibs)=="table" then - report_format("using stub specification %a",fullspecificationname) - local texbasename=file.basename(name) - local luastubname=file.addsuffix(texbasename,luasuffixes.lua) - local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) - report_format("creating initialization file %a",luastubname) - utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) - if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then - report_format("using compiled initialization file %a",lucstubname) - usedluastub=lucstubname - else - report_format("using uncompiled initialization file %a",luastubname) - usedluastub=luastubname - end - else - report_format("invalid stub specification %a",fullspecificationname) - lfs.chdir(olddir) - return - end - local specification={ - primaryflags=primaryflags(), - secondaryflags=secondaryflags(), - luafile=quoted(usedluastub), - texfile=quoted(fulltexsourcename), - dump=os.platform=="unix" and "\\\\dump" or "\\dump", - } - local runner=runners[engine] - if not runner then - report_format("format %a cannot be generated, no runner available for engine %a",name,engine) - elseif silent then - statistics.starttiming() - specification.redirect="> temp.log" - local result=runner(specification) - local runtime=statistics.stoptiming() - if result~=0 then - print(format("%s silent make > fatal error when making format %q",engine,name)) - else - print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) - end - os.remove("temp.log") - else - runner(specification) - end - local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" - local mp=dir.glob(pattern) - if mp then - for i=1,#mp do - local name=mp[i] - report_format("removing related mplib format %a",file.basename(name)) - os.remove(name) - end - end + local engine=environment.ownmain or "luatex" + local silent=environment.arguments.silent + local errors=environment.arguments.errors + local olddir=dir.current() + local path=caches.getwritablepath("formats",engine) or "" + if path~="" then + lfs.chdir(path) + end + report_format("using format path %a",dir.current()) + local texsourcename=file.addsuffix(name,"mkiv") + local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + if fulltexsourcename=="" then + texsourcename=file.addsuffix(name,"tex") + fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + end + if fulltexsourcename=="" then + report_format("no tex source file with name %a (mkiv or tex)",name) + lfs.chdir(olddir) + return + else + report_format("using tex source file %a",fulltexsourcename) + end + local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) + local specificationname=file.replacesuffix(fulltexsourcename,"lus") + local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + if fullspecificationname=="" then + specificationname=file.join(texsourcepath,"context.lus") + fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + end + if fullspecificationname=="" then + report_format("unknown stub specification %a",specificationname) + lfs.chdir(olddir) + return + end + local specificationpath=file.dirname(fullspecificationname) + local usedluastub=nil + local usedlualibs=dofile(fullspecificationname) + if type(usedlualibs)=="string" then + usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) + elseif type(usedlualibs)=="table" then + report_format("using stub specification %a",fullspecificationname) + local texbasename=file.basename(name) + local luastubname=file.addsuffix(texbasename,luasuffixes.lua) + local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) + report_format("creating initialization file %a",luastubname) + utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) + if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then + report_format("using compiled initialization file %a",lucstubname) + usedluastub=lucstubname + else + report_format("using uncompiled initialization file %a",luastubname) + usedluastub=luastubname + end + else + report_format("invalid stub specification %a",fullspecificationname) lfs.chdir(olddir) + return + end + local specification={ + primaryflags=primaryflags(), + secondaryflags=secondaryflags(), + luafile=quoted(usedluastub), + texfile=quoted(fulltexsourcename), + dump=os.platform=="unix" and "\\\\dump" or "\\dump", + } + local runner=runners[engine] + if not runner then + report_format("format %a cannot be generated, no runner available for engine %a",name,engine) + elseif silent then + statistics.starttiming() + specification.redirect="> temp.log" + local result=runner(specification) + local runtime=statistics.stoptiming() + if result~=0 then + print(format("%s silent make > fatal error when making format %q",engine,name)) + else + print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) + end + os.remove("temp.log") + else + runner(specification) + end + local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" + local mp=dir.glob(pattern) + if mp then + for i=1,#mp do + local name=mp[i] + report_format("removing related mplib format %a",file.basename(name)) + os.remove(name) + end + end + lfs.chdir(olddir) end local template=[[%flags% --fmt=%fmtfile% --lua=%luafile% %texfile% %more%]] local checkers={ - flags="string", - more="string", - fmtfile="readable", - luafile="readable", - texfile="readable", + flags="string", + more="string", + fmtfile="readable", + luafile="readable", + texfile="readable", } local runners={ - luatex=sandbox.registerrunner { - name="run luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="run luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="run luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="run luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.run_format(name,data,more) - if name and name~="" then - local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) - if fmtname=="" then - fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" - end - fmtname=resolvers.cleanpath(fmtname) - if fmtname=="" then - report_format("no format with name %a",name) + if name and name~="" then + local engine=environment.ownmain or "luatex" + local barename=file.removesuffix(name) + local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) + if fmtname=="" then + fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" + end + fmtname=resolvers.cleanpath(fmtname) + if fmtname=="" then + report_format("no format with name %a",name) + else + local barename=file.removesuffix(name) + local luaname=file.addsuffix(barename,"luc") + if not lfs.isfile(luaname) then + luaname=file.addsuffix(barename,"lua") + end + if not lfs.isfile(luaname) then + report_format("using format name %a",fmtname) + report_format("no luc/lua file with name %a",barename) + else + local runner=runners[engine] + if not runner then + report_format("format %a cannot be run, no runner available for engine %a",name,engine) else - local barename=file.removesuffix(name) - local luaname=file.addsuffix(barename,"luc") - if not lfs.isfile(luaname) then - luaname=file.addsuffix(barename,"lua") - end - if not lfs.isfile(luaname) then - report_format("using format name %a",fmtname) - report_format("no luc/lua file with name %a",barename) - else - local runner=runners[engine] - if not runner then - report_format("format %a cannot be run, no runner available for engine %a",name,engine) - else - runner { - flags=primaryflags(), - fmtfile=quoted(barename), - luafile=quoted(luaname), - texfile=quoted(data), - more=more, - } - end - end + runner { + flags=primaryflags(), + fmtfile=quoted(barename), + luafile=quoted(luaname), + texfile=quoted(data), + more=more, + } end + end end + end end end -- of closure --- used libraries : l-lua.lua l-macro.lua l-sandbox.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-fil.lua util-sac.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-tpl.lua util-sbx.lua util-mrg.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 +-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.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-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.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 : 877962 --- stripped bytes : 317771 +-- original bytes : 994864 +-- stripped bytes : 395007 -- end library merge @@ -21370,6 +24986,7 @@ local owntree = environment and environment.ownpath or ownpath local ownlibs = { -- order can be made better + 'l-bit32.lua', 'l-lua.lua', 'l-macro.lua', 'l-sandbox.lua', @@ -21385,6 +25002,7 @@ local ownlibs = { -- order can be made better 'l-file.lua', 'l-gzip.lua', 'l-md5.lua', + 'l-sha.lua', 'l-url.lua', 'l-dir.lua', 'l-boolean.lua', @@ -21399,6 +25017,19 @@ local ownlibs = { -- order can be made better 'util-prs.lua', 'util-fmt.lua', + 'util-soc-imp-reset.lua', + 'util-soc-imp-socket.lua', + 'util-soc-imp-copas.lua', + 'util-soc-imp-ltn12.lua', + -- 'util-soc-imp-mbox.lua', + 'util-soc-imp-mime.lua', + 'util-soc-imp-url.lua', + 'util-soc-imp-headers.lua', + 'util-soc-imp-tp.lua', + 'util-soc-imp-http.lua', + 'util-soc-imp-ftp.lua', + 'util-soc-imp-smtp.lua', + 'trac-set.lua', 'trac-log.lua', 'trac-inf.lua', -- was before trac-set @@ -21601,9 +25232,7 @@ local helpinfo = [[ <flag name="locate"><short>locate given filename in database (default) or system (<ref name="first"/> <ref name="all"/> <ref name="detail"/>)</short></flag> </subcategory> <subcategory> - <flag name="autotree"><short>use texmf tree cf. env texmfstart_tree or texmfstarttree</short></flag> <flag name="tree" value="pathtotree"><short>use given texmf tree (default file: setuptex.tmf)</short></flag> - <flag name="environment" value="name"><short>use given (tmf) environment file</short></flag> <flag name="path" value="runpath"><short>go to given path before execution</short></flag> <flag name="ifchanged" value="filename"><short>only execute when given file has changed (md checksum)</short></flag> <flag name="iftouched" value="old,new"><short>only execute when given file has changed (time stamp)</short></flag> @@ -21623,7 +25252,7 @@ local helpinfo = [[ </subcategory> <subcategory> <flag name="edit"><short>launch editor with found file</short></flag> - <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>)</short></flag> + <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>,<ref name="list"/>)</short></flag> </subcategory> <subcategory> <flag name="timedrun"><short>run a script and time its run</short></flag> @@ -22022,9 +25651,9 @@ function resolvers.launch(str) end function runners.launch_file(filename) - trackers.enable("resolvers.locating") local allresults = environment.arguments["all"] - local pattern = environment.arguments["pattern"] + local pattern = environment.arguments["pattern"] + local listonly = environment.arguments["list"] if not pattern or pattern == "" then pattern = filename end @@ -22039,14 +25668,32 @@ function runners.launch_file(filename) t = resolvers.findfiles("*/" .. pattern .. "*",nil,allresults) end if t and #t > 0 then - if allresults then - for _, v in pairs(t) do - report("launching %s", v) - resolvers.launch(v) + for i=1,#t do + local name = t[i] + if listonly then + report("% 3i: %-30s %s",i,file.basename(name),file.dirname(name)) + else + report("launching: %s",name) + resolvers.launch(name) + if not allresults then + break + end + end + end + if listonly then + io.write("\n") + io.write("\n[select number]\n\n>> ") + local answer = tonumber(io.read()) + if answer then + io.write("\n") + local name = t[answer] + if name then + report("launching: %s",name) + resolvers.launch(name) + else + report("invalid number") + end end - else - report("launching %s", t[1]) - resolvers.launch(t[1]) end else report("no match for %s", pattern) @@ -22166,12 +25813,9 @@ function runners.execute_ctx_script(filename,...) dofile(fullname) local savename = environment.arguments['save'] if savename then - local save_list = runners.save_list - if save_list and next(save_list) then - if type(savename) ~= "string" then savename = file.basename(fullname) end - savename = file.replacesuffix(savename,"cfg") - runners.save_script_session(savename,save_list) - end + if type(savename) ~= "string" then savename = file.basename(fullname) end + savename = file.replacesuffix(savename,"cfg") + runners.save_script_session(savename,save_list) end return true end @@ -22188,22 +25832,22 @@ function runners.execute_ctx_script(filename,...) local scriptbase = match(scriptname,".*mtx%-([^%-]-)%.lua") if scriptbase then local data = io.loaddata(scriptname) -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 + 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 @@ -22243,7 +25887,7 @@ function runners.timedrun(filename) -- just for me end function runners.timed(action) - statistics.timed(action) + statistics.timed(action,true) end function runners.associate(filename) diff --git a/scripts/context/perl/mptopdf.pl b/scripts/context/perl/mptopdf.pl index 42db9001e..165d4d217 100644 --- a/scripts/context/perl/mptopdf.pl +++ b/scripts/context/perl/mptopdf.pl @@ -118,9 +118,14 @@ if (($pattern eq '')||($Help)) { @files = glob "$pattern" ; } +# this patch was send via debian but is not tested by me + foreach my $file (@files) { $_ = $file ; - if (s/\.(\d+|mps)$// && -e $file) { + # if (s/\.(\d+|mps)$// && -e $file) { + if (s/\.(\d+|mps|ps)$// && -e $file) { + my $suffix = $1 ; + my $pdf = basename($_).".pdf" ; if ($miktex) { $command = "pdftex -undump=mptopdf" ; } else { @@ -136,15 +141,22 @@ foreach my $file (@files) { print "\n$program : error while processing tex file\n" ; exit 1 ; } - my $pdfsrc = basename($_).".pdf"; - rename ($pdfsrc, "$_-$1.pdf") ; - if (-e $pdfsrc) { - CopyFile ($pdfsrc, "$_-$1.pdf") ; + # my $pdfsrc = basename($_).".pdf"; + # rename ($pdfsrc, "$_-$1.pdf") ; + # if (-e $pdfsrc) { + # CopyFile ($pdfsrc, "$_-$1.pdf") ; + if ($suffix =~ m/\.\d+$/) { + rename ($pdf, "$_-$suffix.pdf") ; + if (-e $pdf) { + CopyFile ($pdf, "$_-$suffix.pdf") ; + } + $pdf = "$_-$suffix.pdf" ; } if ($done) { $report .= " +" ; } - $report .= " $_-$1.pdf" ; + # $report .= " $_-$1.pdf" ; + $report .= " $pdf" ; ++$done ; } } diff --git a/scripts/context/stubs/install/first-setup.sh b/scripts/context/stubs/install/first-setup.sh index 11af49233..71fe32c16 100644 --- a/scripts/context/stubs/install/first-setup.sh +++ b/scripts/context/stubs/install/first-setup.sh @@ -17,9 +17,23 @@ cpu=`uname -m` case "$system" in # linux Linux) + if command -v ldd >/dev/null && ldd --version 2>&1 | grep -E '^musl' >/dev/null + then + libc=musl + else + libc=glibc + fi case "$cpu" in - i*86) platform="linux" ;; - x86_64|ia64) platform="linux-64" ;; + i*86) + case "$libc" in + glibc) platform="linux" ;; + musl) platform="linuxmusl" ;; + esac ;; + x86_64|ia64) + case "$libc" in + glibc) platform="linux-64" ;; + musl) platform="linuxmusl-64" ;; + esac ;; # a little bit of cheating with ppc64 (won't work on Gentoo) ppc|ppc64) platform="linux-ppc" ;; @@ -138,8 +152,8 @@ fi # download or update the distribution # you may remove the --context=beta switch if you want to use "current" # you can use --engine=luatex if you want just mkiv -env PATH="$PWD/bin:$CONTEXTROOT/texmf-$platform/bin:$PATH" \ -./bin/mtxrun --script ./bin/mtx-update.lua --force --update --make --context=beta --platform=$platform --texroot="$CONTEXTROOT" $@ +env PATH="$PWD/bin:$CONTEXTROOT/texmf-$platform/bin:$PATH" MTX_PLATFORM="$platform" \ +./bin/mtxrun --script ./bin/mtx-update.lua --force --update --make --context=beta --platform="$platform" --texroot="$CONTEXTROOT" $@ echo echo "When you want to use context, you need to initialize the tree by typing:" diff --git a/scripts/context/stubs/mswin/metatex.exe b/scripts/context/stubs/mswin/metatex.exe Binary files differdeleted file mode 100644 index 0e7882cf9..000000000 --- a/scripts/context/stubs/mswin/metatex.exe +++ /dev/null diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 0f4767d91..569a7f2e1 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -1,16 +1,5 @@ #!/usr/bin/env texlua --- for k, v in next, _G.string do --- local tv = type(v) --- if tv == "table" then --- for kk, vv in next, v do --- print(k,kk,vv) --- end --- else --- print(tv,k,v) --- end --- end - if not modules then modules = { } end modules ['mtxrun'] = { version = 1.001, comment = "runner, lua replacement for texmfstart.rb", @@ -20,25 +9,43 @@ if not modules then modules = { } end modules ['mtxrun'] = { } -- one can make a stub: + +-- mtxrun : -- -- #!/bin/sh -- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@" +-- mtxrun.cmd : +-- +-- @luatex --luaonly %~d0%~p0mtxrun.lua %* + -- filename : mtxrun.lua -- comment : companion to context.tex -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files --- This script is based on texmfstart.rb but does not use kpsewhich to --- locate files. Although kpse is a library it never came to opening up --- its interface to other programs (esp scripting languages) and so we --- do it ourselves. The lua variant evolved out of an experimental ruby --- one. Interesting is that using a scripting language instead of c does --- not have a speed penalty. Actually the lua variant is more efficient, --- especially when multiple calls to kpsewhich are involved. The lua +-- This script is based on texmfstart.rb but does not use kpsewhich to locate files. +-- Although kpse is a library it never came to opening up its interface to other +-- programs (esp scripting languages) and so we do it ourselves. The lua variant +-- evolved out of an experimental ruby one. Interesting is that using a scripting +-- language instead of c does not have a speed penalty. Actually the lua variant is +-- more efficient, especially when multiple calls to kpsewhich are involved. The lua -- library also gives way more control. +-- When libraries used here are updates you can run +-- +-- mtxrun --selfmerge +-- +-- to update the embedded code. After that you might need to run +-- +-- mtxrun --selfupdate +-- +-- to copy the new script (from scripts/context/lua) to location where +-- binaries are expected. If you want to remove the embedded code you can run +-- +-- mtxxun --selfclean + -- to be done / considered -- -- support for --exec or make it default @@ -54,16 +61,147 @@ if not modules then modules = { } end modules ['mtxrun'] = { do -- create closure to overcome 200 locals limit +package.loaded["l-bit32"] = package.loaded["l-bit32"] or true + +-- original size: 3607, stripped down to: 3009 + +if not modules then modules={} end modules ['l-bit32']={ + version=1.001, + license="the same as regular Lua", + source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto", + comment="drop-in for bit32, adapted a bit by Hans Hagen", +} +if bit32 then +elseif utf8 then + load ([[ +local select = select -- instead of: arg = { ... } +bit32 = { + bnot = function (a) + return ~a & 0xFFFFFFFF + end, + band = function (x, y, z, ...) + if not z then + return ((x or -1) & (y or -1)) & 0xFFFFFFFF + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bor = function (x, y, z, ...) + if not z then + return ((x or 0) | (y or 0)) & 0xFFFFFFFF + else + local res = x | y | z + for i=1,select("#",...) do + res = res | select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bxor = function (x, y, z, ...) + if not z then + return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF + else + local res = x ~ y ~ z + for i=1,select("#",...) do + res = res ~ select(i,...) + end + return res & 0xFFFFFFFF + end + end, + btest = function (x, y, z, ...) + if not z then + return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0 + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return (res & 0xFFFFFFFF) ~= 0 + end + end, + lshift = function (a, b) + return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF + end, + rshift = function (a, b) + return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF + end, + arshift = function (a, b) + a = a & 0xFFFFFFFF + if b <= 0 or (a & 0x80000000) == 0 then + return (a >> b) & 0xFFFFFFFF + else + return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF + end + end, + lrotate = function (a ,b) + b = b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + rrotate = function (a, b) + b = -b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + extract = function (a, f, w) + return (a >> f) & ~(-1 << (w or 1)) + end, + replace = function (a, v, f, w) + local mask = ~(-1 << (w or 1)) + return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF + end, +} + ]] ) () +elseif bit then + load ([[ +local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift +bit32 = { + arshift = bit.arshift, + band = band, + bnot = bnot, + bor = bit.bor, + bxor = bit.bxor, + btest = function(...) + return band(...) ~= 0 + end, + extract = function(a,f,w) + return band(rshift(a,f),2^(w or 1)-1) + end, + lrotate = bit.rol, + lshift = lshift, + replace = function(a,v,f,w) + local mask = 2^(w or 1)-1 + return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f) + end, + rrotate = bit.ror, + rshift = rshift, +} + ]] ) () +else + xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end) +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + package.loaded["l-lua"] = package.loaded["l-lua"] or true --- original size: 6230, stripped down to: 3662 +-- original size: 6281, stripped down to: 2863 if not modules then modules={} end modules ['l-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,tonumber=next,type,tonumber LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$") @@ -71,122 +209,111 @@ LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5 LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1 LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10 if LUAVERSION<5.2 and jit then - MINORVERSION=2 - LUAVERSION=5.2 + MINORVERSION=2 + LUAVERSION=5.2 end -_LUAVERSION=LUAVERSION if not lpeg then - lpeg=require("lpeg") + lpeg=require("lpeg") end if loadstring then - local loadnormal=load - function load(first,...) - if type(first)=="string" then - return loadstring(first,...) - else - return loadnormal(first,...) - end + local loadnormal=load + function load(first,...) + if type(first)=="string" then + return loadstring(first,...) + else + return loadnormal(first,...) end + end else - loadstring=load + loadstring=load end if not ipairs then - local function iterate(a,i) - i=i+1 - local v=a[i] - if v~=nil then - return i,v - end - end - function ipairs(a) - return iterate,a,0 + local function iterate(a,i) + i=i+1 + local v=a[i] + if v~=nil then + return i,v end + end + function ipairs(a) + return iterate,a,0 + end end if not pairs then - function pairs(t) - return next,t - end + function pairs(t) + return next,t + end end if not table.unpack then - table.unpack=_G.unpack + table.unpack=_G.unpack elseif not unpack then - _G.unpack=table.unpack + _G.unpack=table.unpack end if not package.loaders then - package.loaders=package.searchers + package.loaders=package.searchers end local print,select,tostring=print,select,tostring local inspectors={} function setinspector(kind,inspector) - inspectors[kind]=inspector + inspectors[kind]=inspector end function inspect(...) - for s=1,select("#",...) do - local value=select(s,...) - if value==nil then - print("nil") - else - local done=false - local kind=type(value) - local inspector=inspectors[kind] - if inspector then - done=inspector(value) - if done then - break - end - end - for kind,inspector in next,inspectors do - done=inspector(value) - if done then - break - end - end - if not done then - print(tostring(value)) - end + for s=1,select("#",...) do + local value=select(s,...) + if value==nil then + print("nil") + else + local done=false + local kind=type(value) + local inspector=inspectors[kind] + if inspector then + done=inspector(value) + if done then + break + end + end + for kind,inspector in next,inspectors do + done=inspector(value) + if done then + break end + end + if not done then + print(tostring(value)) + end end + end end local dummy=function() end function optionalrequire(...) - local ok,result=xpcall(require,dummy,...) - if ok then - return result - end + local ok,result=xpcall(require,dummy,...) + if ok then + return result + end end if lua then - lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" + lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" end local flush=io.flush if flush then - local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end - local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end - local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end - local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end + local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end + local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end + local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end + local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end end FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load if not FFISUPPORTED then - local okay;okay,ffi=pcall(require,"ffi") - FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load + local okay;okay,ffi=pcall(require,"ffi") + FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load end if not FFISUPPORTED then - ffi=nil + ffi=nil elseif not ffi.number then - ffi.number=tonumber + ffi.number=tonumber end -if not bit32 then - bit32=require("l-bit32") +if LUAVERSION>5.3 then + collectgarbage("generational") end -local loaded=package.loaded -if not loaded["socket"] then loaded["socket"]=loaded["socket.core"] end -if not loaded["mime"] then loaded["mime"]=loaded["mime.core"] end -if not socket.mime then socket.mime=package.loaded["mime"] end -if not loaded["socket.mime"] then loaded["socket.mime"]=socket.mime end -if not loaded["socket.http"] then loaded["socket.http"]=socket.http end -if not loaded["socket.ftp"] then loaded["socket.ftp"]=socket.ftp end -if not loaded["socket.smtp"] then loaded["socket.smtp"]=socket.smtp end -if not loaded["socket.tp"] then loaded["socket.tp"]=socket.tp end -if not loaded["socket.url"] then loaded["socket.url"]=socket.url end end -- of closure @@ -195,25 +322,27 @@ do -- create closure to overcome 200 locals limit package.loaded["l-macro"] = package.loaded["l-macro"] or true --- original size: 8260, stripped down to: 5213 +-- original size: 10131, stripped down to: 5991 if not modules then modules={} end modules ['l-macros']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg local lpegmatch=lpeg.match local concat=table.concat -local format,sub=string.format,string.sub +local format,sub,match=string.format,string.sub,string.match local next,load,type=next,load,type local newline=S("\n\r")^1 local continue=P("\\")*newline +local whitespace=S(" \t\n\r") local spaces=S(" \t")+continue -local name=R("az","AZ","__","09")^1 -local body=((1+continue/"")-newline)^1 +local nametoken=R("az","AZ","__","09") +local name=nametoken^1 +local body=((continue/""+1)-newline)^1 local lparent=P("(") local rparent=P(")") local noparent=1-(lparent+rparent) @@ -230,172 +359,214 @@ local definitions={} local resolve local subparser local report_lua=function(...) - if logs and logs.reporter then - report_lua=logs.reporter("system","lua") - report_lua(...) - else - print(format(...)) - end -end -resolve=C(C(name)*arguments^-1)/function(raw,s,a) - local d=definitions[s] - if d then - if a then - local n=#a - local p=patterns[s][n] - if p then - local d=d[n] - for i=1,n do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return lpegmatch(p,d,1,a) or d - else - return raw - end - else - return d[0] or raw - end - elseif a then - for i=1,#a do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return s.."("..concat(a,",")..")" - else - return raw - end -end -subparser=Cs((resolve+P(1))^1) -local enddefine=P("#enddefine")/"" -local beginregister=(C(name)*spaces^0*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) - local n=0 + if logs and logs.reporter then + report_lua=logs.reporter("system","lua") + report_lua(...) + else + print(format(...)) + end +end +local safeguard=P("local")*whitespace^1*name*(whitespace+P("=")) +resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a) + local d=definitions[s] + if d then if a then - n=#a - local pattern=P(false) + local n=#a + local p=patterns[s][n] + if p then + local d=d[n] for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p + a[i]=lpegmatch(subparser,a[i]) or a[i] end - p[n]=pattern + return lpegmatch(p,d,1,a) or d + else + return raw + end + else + return d[0] or raw end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d + elseif a then + for i=1,#a do + a[i]=lpegmatch(subparser,a[i]) or a[i] end - d[n]=lpegmatch(subparser,v) or v - return "" + return s.."("..concat(a,",")..")" + else + return raw + end end -local register=(C(name)*spaces^0*(arguments+Cc(false))*spaces^0*C(body))/function(k,a,v) - local n=0 - if a then - n=#a - local pattern=P(false) - for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p - end - p[n]=pattern - end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d - end - d[n]=lpegmatch(subparser,v) or v - return "" +subparser=Cs((resolve+P(1))^1) +local enddefine=P("#enddefine")/"" +local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" +end +local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" end local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a) - local n=0 - if a then - n=#a - local p=patterns[k] - if p then - p[n]=false - end - end - local d=definitions[k] - if d then - d[n]=false + local n=0 + if a then + n=#a + local p=patterns[k] + if p then + p[n]=false end - return "" + end + local d=definitions[k] + if d then + d[n]=false + end + return "" end local begindefine=(P("begindefine")*spaces^0/"")*beginregister -local define=(P("define" )*spaces^0/"")*register -local undefine=(P("undefine" )*spaces^0/"")*unregister +local define=(P("define" )*spaces^0/"")*register +local undefine=(P("undefine" )*spaces^0/"")*unregister local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 ) function macros.reset() - definitions={} - patterns={} + definitions={} + patterns={} +end +function macros.showdefinitions() + for name,list in table.sortedhash(definitions) do + local arguments=list.a + if arguments then + arguments="("..concat(arguments,",")..")" + else + arguments="" + end + print("macro: "..name..arguments) + for i=0,#list do + local l=list[i] + if l then + print(" "..l) + end + end + end end function macros.resolvestring(str) - return lpegmatch(parser,str) or str + return lpegmatch(parser,str) or str end function macros.resolving() - return next(patterns) -end -local function loaded(name,trace,detail) - local f=io.open(name,"rb") - if not f then - return false,format("file '%s' not found",name) - end - local c=f:read("*a") - if not c then - return false,format("file '%s' is invalid",name) - end + return next(patterns) +end +local function reload(path,name,data) + local only=match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only + local f=io.open(name,"wb") + f:write(data) f:close() - local n=lpegmatch(parser,c) - if trace then - if #n~=#c then - report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) - if detail then - report_lua() - report_lua(n) - report_lua() - end - elseif detail then - report_lua("no macros expanded in '%s'",name) - end + local f=loadfile(name) + os.remove(name) + return f + end +end +local function reload(path,name,data) + if path and path~="" then + local only=string.match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only.."-macro.lua" + local f=io.open(name,"wb") + if f then + f:write(data) + f:close() + local l=loadfile(name) + os.remove(name) + return l + end end - if #name>30 then - n="--[["..sub(name,-30).."]] "..n - else - n="--[["..name.."]] "..n + end + return load(data,name) +end +local function loaded(name,trace,detail) + local f=io.open(name,"rb") + if not f then + return false,format("file '%s' not found",name) + end + local c=f:read("*a") + if not c then + return false,format("file '%s' is invalid",name) + end + f:close() + local n=lpegmatch(parser,c) + if trace then + if #n~=#c then + report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) + if detail then + report_lua() + report_lua(n) + report_lua() + end + elseif detail then + report_lua("no macros expanded in '%s'",name) end - return load(n) + end + return reload(lfs and lfs.currentdir(),name,n) end macros.loaded=loaded function required(name,trace) - local filename=file.addsuffix(name,"lua") - local fullname=resolvers and resolvers.find_file(filename) or filename - if not fullname or fullname=="" then - return false - end - local codeblob=package.loaded[fullname] - if codeblob then - return codeblob - end - local code,message=loaded(fullname,macros,trace,trace) - if type(code)=="function" then - code=code() - else - report_lua("error when loading '%s'",fullname) - return false,message - end - if code==nil then - code=false - end - package.loaded[fullname]=code - return code + local filename=file.addsuffix(name,"lua") + local fullname=resolvers and resolvers.find_file(filename) or filename + if not fullname or fullname=="" then + return false + end + local codeblob=package.loaded[fullname] + if codeblob then + return codeblob + end + local code,message=loaded(fullname,macros,trace,trace) + if type(code)=="function" then + code=code() + else + report_lua("error when loading '%s'",fullname) + return false,message + end + if code==nil then + code=false + end + package.loaded[fullname]=code + return code end macros.required=required @@ -406,14 +577,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true --- original size: 9678, stripped down to: 6688 +-- original size: 9747, stripped down to: 6313 if not modules then modules={} end modules ['l-sandbox']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local global=_G local next=next @@ -439,231 +610,234 @@ local trace=false local logger=false local blocked={} local function report(...) - tprint("sandbox ! "..format(...)) + tprint("sandbox ! "..format(...)) end sandbox.report=report function sandbox.setreporter(r) - report=r - sandbox.report=r + report=r + sandbox.report=r end function sandbox.settrace(v) - trace=v + trace=v end function sandbox.setlogger(l) - logger=type(l)=="function" and l or false + logger=type(l)=="function" and l or false end local function register(func,overload,comment) - if type(func)=="function" then - if type(overload)=="string" then - comment=overload - overload=nil - end - local function f(...) - if sandboxed then - local overload=overloads[f] - if overload then - if logger then - local result={ overload(func,...) } - logger { - comment=comments[f] or tostring(f), - arguments={... }, - result=result[1] and true or false, - } - return unpack(result) - else - return overload(func,...) - end - else - end - else - return func(...) - end - end - if comment then - comments[f]=comment - if trace then - report("registering function: %s",comment) - end + if type(func)=="function" then + if type(overload)=="string" then + comment=overload + overload=nil + end + local function f(...) + if sandboxed then + local overload=overloads[f] + if overload then + if logger then + local result={ overload(func,...) } + logger { + comment=comments[f] or tostring(f), + arguments={... }, + result=result[1] and true or false, + } + return unpack(result) + else + return overload(func,...) + end + else end - overloads[f]=overload or false - originals[f]=func - return f + else + return func(...) + end end + if comment then + comments[f]=comment + if trace then + report("registering function: %s",comment) + end + end + overloads[f]=overload or false + originals[f]=func + return f + end end local function redefine(func,comment) - if type(func)=="function" then - skiploads[func]=comment or comments[func] or "unknown" - if overloads[func]==false then - overloads[func]=nil - end + if type(func)=="function" then + skiploads[func]=comment or comments[func] or "unknown" + if overloads[func]==false then + overloads[func]=nil end + end end sandbox.register=register sandbox.redefine=redefine function sandbox.original(func) - return originals and originals[func] or func + return originals and originals[func] or func end function sandbox.overload(func,overload,comment) - comment=comment or comments[func] or "?" - if type(func)~="function" then - if trace then - report("overloading unknown function: %s",comment) - end - elseif type(overload)~="function" then - if trace then - report("overloading function with bad overload: %s",comment) - end - elseif overloads[func]==nil then - if trace then - report("function is not registered: %s",comment) - end - elseif skiploads[func] then - if trace then - report("function is not skipped: %s",comment) - end - else - if trace then - report("overloading function: %s",comment) - end - overloads[func]=overload + comment=comment or comments[func] or "?" + if type(func)~="function" then + if trace then + report("overloading unknown function: %s",comment) + end + elseif type(overload)~="function" then + if trace then + report("overloading function with bad overload: %s",comment) + end + elseif overloads[func]==nil then + if trace then + report("function is not registered: %s",comment) + end + elseif skiploads[func] then + if trace then + report("function is not skipped: %s",comment) end - return func + else + if trace then + report("overloading function: %s",comment) + end + overloads[func]=overload + end + return func end local function whatever(specification,what,target) - if type(specification)~="table" then - report("%s needs a specification",what) - elseif type(specification.category)~="string" or type(specification.action)~="function" then - report("%s needs a category and action",what) - elseif not sandboxed then - target[#target+1]=specification - elseif trace then - report("already enabled, discarding %s",what) - end + if type(specification)~="table" then + report("%s needs a specification",what) + elseif type(specification.category)~="string" or type(specification.action)~="function" then + report("%s needs a category and action",what) + elseif not sandboxed then + target[#target+1]=specification + elseif trace then + report("already enabled, discarding %s",what) + end end function sandbox.initializer(specification) - whatever(specification,"initializer",initializers) + whatever(specification,"initializer",initializers) end function sandbox.finalizer(specification) - whatever(specification,"finalizer",finalizers) + whatever(specification,"finalizer",finalizers) end function require(name) - local n=gsub(name,"^.*[\\/]","") - local n=gsub(n,"[%.].*$","") - local b=blocked[n] - if b==false then - return nil - elseif b then - if trace then - report("using blocked: %s",n) - end - return b - else - if trace then - report("requiring: %s",name) - end - return requiem(name) + local n=gsub(name,"^.*[\\/]","") + local n=gsub(n,"[%.].*$","") + local b=blocked[n] + if b==false then + return nil + elseif b then + if trace then + report("using blocked: %s",n) end -end -function blockrequire(name,lib) + return b + else if trace then - report("preventing reload of: %s",name) + report("requiring: %s",name) end - blocked[name]=lib or _G[name] or false + return requiem(name) + end +end +function blockrequire(name,lib) + if trace then + report("preventing reload of: %s",name) + end + blocked[name]=lib or _G[name] or false end function sandbox.enable() - if not sandboxed then - for i=1,#initializers do - initializers[i].action() - end - for i=1,#finalizers do - finalizers[i].action() - end - local nnot=0 - local nyes=0 - local cnot={} - local cyes={} - local skip={} - for k,v in next,overloads do - local c=comments[k] - if v then - if c then - cyes[#cyes+1]=c - else - nyes=nyes+1 - end - else - if c then - cnot[#cnot+1]=c - else - nnot=nnot+1 - end - end - end - for k,v in next,skiploads do - skip[#skip+1]=v - end - if #cyes>0 then - sort(cyes) - report("overloaded known: %s",concat(cyes," | ")) - end - if nyes>0 then - report("overloaded unknown: %s",nyes) - end - if #cnot>0 then - sort(cnot) - report("not overloaded known: %s",concat(cnot," | ")) - end - if nnot>0 then - report("not overloaded unknown: %s",nnot) + if not sandboxed then + debug={ + traceback=debug.traceback, + } + for i=1,#initializers do + initializers[i].action() + end + for i=1,#finalizers do + finalizers[i].action() + end + local nnot=0 + local nyes=0 + local cnot={} + local cyes={} + local skip={} + for k,v in next,overloads do + local c=comments[k] + if v then + if c then + cyes[#cyes+1]=c + else + nyes=nyes+1 end - if #skip>0 then - sort(skip) - report("not overloaded redefined: %s",concat(skip," | ")) + else + if c then + cnot[#cnot+1]=c + else + nnot=nnot+1 end - initializers=nil - finalizers=nil - originals=nil - sandboxed=true + end + end + for k,v in next,skiploads do + skip[#skip+1]=v + end + if #cyes>0 then + sort(cyes) + report("overloaded known: %s",concat(cyes," | ")) + end + if nyes>0 then + report("overloaded unknown: %s",nyes) end + if #cnot>0 then + sort(cnot) + report("not overloaded known: %s",concat(cnot," | ")) + end + if nnot>0 then + report("not overloaded unknown: %s",nnot) + end + if #skip>0 then + sort(skip) + report("not overloaded redefined: %s",concat(skip," | ")) + end + initializers=nil + finalizers=nil + originals=nil + sandboxed=true + end end blockrequire("lfs",lfs) blockrequire("io",io) blockrequire("os",os) blockrequire("ffi",ffi) local function supported(library) - local l=_G[library] - return l + local l=_G[library] + return l end loadfile=register(loadfile,"loadfile") if supported("io") then - io.open=register(io.open,"io.open") - io.popen=register(io.popen,"io.popen") - io.lines=register(io.lines,"io.lines") - io.output=register(io.output,"io.output") - io.input=register(io.input,"io.input") + io.open=register(io.open,"io.open") + io.popen=register(io.popen,"io.popen") + io.lines=register(io.lines,"io.lines") + io.output=register(io.output,"io.output") + io.input=register(io.input,"io.input") end if supported("os") then - os.execute=register(os.execute,"os.execute") - os.spawn=register(os.spawn,"os.spawn") - os.exec=register(os.exec,"os.exec") - os.rename=register(os.rename,"os.rename") - os.remove=register(os.remove,"os.remove") + os.execute=register(os.execute,"os.execute") + os.spawn=register(os.spawn,"os.spawn") + os.exec=register(os.exec,"os.exec") + os.rename=register(os.rename,"os.rename") + os.remove=register(os.remove,"os.remove") end if supported("lfs") then - lfs.chdir=register(lfs.chdir,"lfs.chdir") - lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") - lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") - lfs.isfile=register(lfs.isfile,"lfs.isfile") - lfs.isdir=register(lfs.isdir,"lfs.isdir") - lfs.attributes=register(lfs.attributes,"lfs.attributes") - lfs.dir=register(lfs.dir,"lfs.dir") - lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") - lfs.touch=register(lfs.touch,"lfs.touch") - lfs.link=register(lfs.link,"lfs.link") - lfs.setmode=register(lfs.setmode,"lfs.setmode") - lfs.readlink=register(lfs.readlink,"lfs.readlink") - lfs.shortname=register(lfs.shortname,"lfs.shortname") - lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") + lfs.chdir=register(lfs.chdir,"lfs.chdir") + lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") + lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") + lfs.isfile=register(lfs.isfile,"lfs.isfile") + lfs.isdir=register(lfs.isdir,"lfs.isdir") + lfs.attributes=register(lfs.attributes,"lfs.attributes") + lfs.dir=register(lfs.dir,"lfs.dir") + lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") + lfs.touch=register(lfs.touch,"lfs.touch") + lfs.link=register(lfs.link,"lfs.link") + lfs.setmode=register(lfs.setmode,"lfs.setmode") + lfs.readlink=register(lfs.readlink,"lfs.readlink") + lfs.shortname=register(lfs.shortname,"lfs.shortname") + lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") end @@ -673,14 +847,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-package"] = package.loaded["l-package"] or true --- original size: 11562, stripped down to: 8625 +-- original size: 11605, stripped down to: 8299 if not modules then modules={} end modules ['l-package']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local gsub,format,find=string.gsub,string.format,string.find @@ -688,40 +862,40 @@ local insert,remove=table.insert,table.remove local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match local package=package local searchers=package.searchers or package.loaders -local filejoin=file and file.join or function(path,name) return path.."/"..name end -local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end -local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end +local filejoin=file and file.join or function(path,name) return path.."/"..name end +local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end +local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end local function cleanpath(path) - return path + return path end local pattern=Cs((((1-S("\\/"))^0*(S("\\/")^1/"/"))^0*(P(".")^1/"/"+P(1))^1)*-1) local function lualibfile(name) - return lpegmatch(pattern,name) or name + return lpegmatch(pattern,name) or name end local offset=luarocks and 1 or 0 local helpers=package.helpers or { - cleanpath=cleanpath, - lualibfile=lualibfile, - trace=false, - report=function(...) print(format(...)) end, - builtin={ - ["preload table"]=searchers[1+offset], - ["path specification"]=searchers[2+offset], - ["cpath specification"]=searchers[3+offset], - ["all in one fallback"]=searchers[4+offset], - }, - methods={}, - sequence={ - "already loaded", - "preload table", - "qualified path", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", - } + cleanpath=cleanpath, + lualibfile=lualibfile, + trace=false, + report=function(...) print(format(...)) end, + builtin={ + ["preload table"]=searchers[1+offset], + ["path specification"]=searchers[2+offset], + ["cpath specification"]=searchers[3+offset], + ["all in one fallback"]=searchers[4+offset], + }, + methods={}, + sequence={ + "already loaded", + "preload table", + "qualified path", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", + } } package.helpers=helpers local methods=helpers.methods @@ -737,253 +911,256 @@ local nofextralib=-1 local nofpathlua=-1 local nofpathlib=-1 local function listpaths(what,paths) - local nofpaths=#paths - if nofpaths>0 then - for i=1,nofpaths do - helpers.report("using %s path %i: %s",what,i,paths[i]) - end - else - helpers.report("no %s paths defined",what) + local nofpaths=#paths + if nofpaths>0 then + for i=1,nofpaths do + helpers.report("using %s path %i: %s",what,i,paths[i]) end - return nofpaths + else + helpers.report("no %s paths defined",what) + end + return nofpaths end local function getextraluapaths() - if helpers.trace and #extraluapaths~=nofextralua then - nofextralua=listpaths("extra lua",extraluapaths) - end - return extraluapaths + if helpers.trace and #extraluapaths~=nofextralua then + nofextralua=listpaths("extra lua",extraluapaths) + end + return extraluapaths end local function getextralibpaths() - if helpers.trace and #extralibpaths~=nofextralib then - nofextralib=listpaths("extra lib",extralibpaths) - end - return extralibpaths + if helpers.trace and #extralibpaths~=nofextralib then + nofextralib=listpaths("extra lib",extralibpaths) + end + return extralibpaths end local function getluapaths() - local luapath=package.path or "" - if oldluapath~=luapath then - luapaths=file.splitpath(luapath,";") - oldluapath=luapath - nofpathlua=-1 - end - if helpers.trace and #luapaths~=nofpathlua then - nofpathlua=listpaths("builtin lua",luapaths) - end - return luapaths + local luapath=package.path or "" + if oldluapath~=luapath then + luapaths=file.splitpath(luapath,";") + oldluapath=luapath + nofpathlua=-1 + end + if helpers.trace and #luapaths~=nofpathlua then + nofpathlua=listpaths("builtin lua",luapaths) + end + return luapaths end local function getlibpaths() - local libpath=package.cpath or "" - if oldlibpath~=libpath then - libpaths=file.splitpath(libpath,";") - oldlibpath=libpath - nofpathlib=-1 - end - if helpers.trace and #libpaths~=nofpathlib then - nofpathlib=listpaths("builtin lib",libpaths) - end - return libpaths + local libpath=package.cpath or "" + if oldlibpath~=libpath then + libpaths=file.splitpath(libpath,";") + oldlibpath=libpath + nofpathlib=-1 + end + if helpers.trace and #libpaths~=nofpathlib then + nofpathlib=listpaths("builtin lib",libpaths) + end + return libpaths end package.luapaths=getluapaths package.libpaths=getlibpaths package.extraluapaths=getextraluapaths package.extralibpaths=getextralibpaths local hashes={ - lua={}, - lib={}, + lua={}, + lib={}, } local function registerpath(tag,what,target,...) - local pathlist={... } - local cleanpath=helpers.cleanpath - local trace=helpers.trace - local report=helpers.report - local hash=hashes[what] - local function add(path) - local path=cleanpath(path) - if not hash[path] then - target[#target+1]=path - hash[path]=true - if trace then - report("registered %s path %s: %s",tag,#target,path) - end - else - if trace then - report("duplicate %s path: %s",tag,path) - end - end + local pathlist={... } + local cleanpath=helpers.cleanpath + local trace=helpers.trace + local report=helpers.report + local hash=hashes[what] + local function add(path) + local path=cleanpath(path) + if not hash[path] then + target[#target+1]=path + hash[path]=true + if trace then + report("registered %s path %s: %s",tag,#target,path) + end + else + if trace then + report("duplicate %s path: %s",tag,path) + end end - for p=1,#pathlist do - local path=pathlist[p] - if type(path)=="table" then - for i=1,#path do - add(path[i]) - end - else - add(path) - end + end + for p=1,#pathlist do + local path=pathlist[p] + if type(path)=="table" then + for i=1,#path do + add(path[i]) + end + else + add(path) end + end end local function pushpath(tag,what,target,path) - local path=helpers.cleanpath(path) - insert(target,1,path) - if helpers.trace then - helpers.report("pushing %s path in front: %s",tag,path) - end + local path=helpers.cleanpath(path) + insert(target,1,path) + if helpers.trace then + helpers.report("pushing %s path in front: %s",tag,path) + end end local function poppath(tag,what,target) - local path=remove(target,1) - if helpers.trace then - if path then - helpers.report("popping %s path from front: %s",tag,path) - else - helpers.report("no %s path to pop",tag) - end + local path=remove(target,1) + if helpers.trace then + if path then + helpers.report("popping %s path from front: %s",tag,path) + else + helpers.report("no %s path to pop",tag) end + end end helpers.registerpath=registerpath function package.extraluapath(...) - registerpath("extra lua","lua",extraluapaths,...) + registerpath("extra lua","lua",extraluapaths,...) end function package.pushluapath(path) - pushpath("extra lua","lua",extraluapaths,path) + pushpath("extra lua","lua",extraluapaths,path) end function package.popluapath() - poppath("extra lua","lua",extraluapaths) + poppath("extra lua","lua",extraluapaths) end function package.extralibpath(...) - registerpath("extra lib","lib",extralibpaths,...) + registerpath("extra lib","lib",extralibpaths,...) end function package.pushlibpath(path) - pushpath("extra lib","lib",extralibpaths,path) + pushpath("extra lib","lib",extralibpaths,path) end function package.poplibpath() - poppath("extra lib","lua",extralibpaths) + poppath("extra lib","lua",extralibpaths) end local function loadedaslib(resolved,rawname) - local base=gsub(rawname,"%.","_") - local init="luaopen_"..gsub(base,"%.","_") - if helpers.trace then - helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) - end - return package.loadlib(resolved,init) + local base=gsub(rawname,"%.","_") + local init="luaopen_"..gsub(base,"%.","_") + if helpers.trace then + helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) + end + return package.loadlib(resolved,init) end helpers.loadedaslib=loadedaslib local function loadedbypath(name,rawname,paths,islib,what) - local trace=helpers.trace - for p=1,#paths do - local path=paths[p] - local resolved=filejoin(path,name) - if trace then - helpers.report("%s path, identifying '%s' on '%s'",what,name,path) - end - if isreadable(resolved) then - if trace then - helpers.report("%s path, '%s' found on '%s'",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + for p=1,#paths do + local path=paths[p] + local resolved=filejoin(path,name) + if trace then + helpers.report("%s path, identifying '%s' on '%s'",what,name,path) + end + if isreadable(resolved) then + if trace then + helpers.report("%s path, '%s' found on '%s'",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + 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 + 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] + return package.loaded[name] end methods["preload table"]=function(name) - return builtin["preload table"](name) + return builtin["preload table"](name) end methods["qualified path"]=function(name) - return loadedbyname(addsuffix(lualibfile(name),"lua"),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") + return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib") end methods["path specification"]=function(name) - getluapaths() - return builtin["path specification"](name) + getluapaths() + return builtin["path specification"](name) end methods["cpath specification"]=function(name) - getlibpaths() - return builtin["cpath specification"](name) + getlibpaths() + return builtin["cpath specification"](name) end methods["all in one fallback"]=function(name) - return builtin["all in one fallback"](name) + return builtin["all in one fallback"](name) end methods["not loaded"]=function(name) - if helpers.trace then - helpers.report("unable to locate '%s'",name or "?") - end - return nil + if helpers.trace then + helpers.report("unable to locate '%s'",name or "?") + end + return nil end local level=0 local used={} helpers.traceused=false function helpers.loaded(name) - local sequence=helpers.sequence - level=level+1 - for i=1,#sequence do - local method=sequence[i] - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) - end - local result,rest=methods[method](name) - if type(result)=="function" then - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) - end - if helpers.traceused then - used[#used+1]={ level=level,name=name } - end - level=level-1 - return result,rest - end + local sequence=helpers.sequence + level=level+1 + for i=1,#sequence do + local method=sequence[i] + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) end - level=level-1 - return nil + local result,rest=methods[method](name) + if type(result)=="function" then + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) + end + if helpers.traceused then + used[#used+1]={ level=level,name=name } + end + level=level-1 + return result,rest + end + end + level=level-1 + return nil end function helpers.showused() - local n=#used - if n>0 then - helpers.report("%s libraries loaded:",n) - helpers.report() - for i=1,n do - local u=used[i] - helpers.report("%i %a",u.level,u.name) - end - helpers.report() - end + local n=#used + if n>0 then + helpers.report("%s libraries loaded:",n) + helpers.report() + for i=1,n do + local u=used[i] + helpers.report("%i %a",u.level,u.name) + end + helpers.report() + end end function helpers.unload(name) - if helpers.trace then - if package.loaded[name] then - helpers.report("unloading, name '%s', %s",name,"done") - else - helpers.report("unloading, name '%s', %s",name,"not loaded") - end + if helpers.trace then + if package.loaded[name] then + helpers.report("unloading, name '%s', %s",name,"done") + else + helpers.report("unloading, name '%s', %s",name,"not loaded") end - package.loaded[name]=nil + end + package.loaded[name]=nil end table.insert(searchers,1,helpers.loaded) +if context then + package.path="" +end end -- of closure @@ -992,14 +1169,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true --- original size: 38582, stripped down to: 20518 +-- original size: 38434, stripped down to: 19310 if not modules then modules={} end modules ['l-lpeg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } lpeg=require("lpeg") local lpeg=lpeg @@ -1010,7 +1187,7 @@ 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 if setinspector then - setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) + setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns @@ -1033,7 +1210,7 @@ local underscore=P("_") local hexdigit=digit+lowercase+uppercase local hexdigits=hexdigit^1 local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") -local newline=P("\r")*(P("\n")+P(true))+P("\n") +local newline=P("\r")*(P("\n")+P(true))+P("\n") local escaped=P("\\")*anything local squote=P("'") local dquote=P('"') @@ -1042,9 +1219,9 @@ 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_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") @@ -1076,7 +1253,7 @@ patterns.utf8character=utf8character patterns.validutf8=validutf8char patterns.validutf8char=validutf8char local eol=S("\n\r") -local spacer=S(" \t\f\v") +local spacer=S(" \t\f\v") local whitespace=eol+spacer local nonspacer=1-spacer local nonwhitespace=1-whitespace @@ -1085,15 +1262,15 @@ 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)) local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0) local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0) -local e_collapser=Cs((whitespace^1*P(-1)/""+nonwhitespace^1+whitespace^1/" ")^0) +local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0) local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0) local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0) -local e_stripper=Cs((spacer^1*P(-1)/""+nonspacer^1+spacer^1/" ")^0) +local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0) local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0) patterns.stripper=stripper patterns.fullstripper=fullstripper @@ -1150,7 +1327,7 @@ patterns.cpfloat=sign^-1*patterns.cpunsigned patterns.number=patterns.float+patterns.integer patterns.cnumber=patterns.cfloat+patterns.integer patterns.cpnumber=patterns.cpfloat+patterns.integer -patterns.oct=zero*octdigits +patterns.oct=zero*octdigits patterns.octal=patterns.oct patterns.HEX=zero*P("X")*(digit+uppercase)^1 patterns.hex=zero*P("x")*(digit+lowercase)^1 @@ -1160,76 +1337,84 @@ patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)* 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/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) -local function anywhere(pattern) - return P { P(pattern)+1*V(1) } +patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0)) +function anywhere(pattern) + return (1-P(pattern))^0*P(pattern) end lpeg.anywhere=anywhere function lpeg.instringchecker(p) - p=anywhere(p) - return function(str) - return lpegmatch(p,str) and true or false - end + p=anywhere(p) + return function(str) + return lpegmatch(p,str) and true or false + end end function lpeg.splitter(pattern,action) + if action then return (((1-P(pattern))^1)/action+1)^0 + else + return (Cs((1-P(pattern))^1)+1)^0 + end end function lpeg.tsplitter(pattern,action) + if action then return Ct((((1-P(pattern))^1)/action+1)^0) + else + return Ct((Cs((1-P(pattern))^1)+1)^0) + end end local splitters_s,splitters_m,splitters_t={},{},{} local function splitat(separator,single) - local splitter=(single and splitters_s[separator]) or splitters_m[separator] - if not splitter then - separator=P(separator) - local other=C((1-separator)^0) - if single then - local any=anything - splitter=other*(separator*C(any^0)+"") - splitters_s[separator]=splitter - else - splitter=other*(separator*other)^0 - splitters_m[separator]=splitter - end + local splitter=(single and splitters_s[separator]) or splitters_m[separator] + if not splitter then + separator=P(separator) + local other=C((1-separator)^0) + if single then + local any=anything + splitter=other*(separator*C(any^0)+"") + splitters_s[separator]=splitter + else + splitter=other*(separator*other)^0 + splitters_m[separator]=splitter end - return splitter + end + return splitter end local function tsplitat(separator) - local splitter=splitters_t[separator] - if not splitter then - splitter=Ct(splitat(separator)) - splitters_t[separator]=splitter - end - return splitter + local splitter=splitters_t[separator] + if not splitter then + splitter=Ct(splitat(separator)) + splitters_t[separator]=splitter + end + return splitter end lpeg.splitat=splitat lpeg.tsplitat=tsplitat function string.splitup(str,separator) - if not separator then - separator="," - end - return lpegmatch(splitters_m[separator] or splitat(separator),str) + if not separator then + separator="," + end + return lpegmatch(splitters_m[separator] or splitat(separator),str) end local cache={} function lpeg.split(separator,str) + local c=cache[separator] + if not c then + c=tsplitat(separator) + cache[separator]=c + end + return lpegmatch(c,str) +end +function string.split(str,separator) + if separator then local c=cache[separator] if not c then - c=tsplitat(separator) - cache[separator]=c + c=tsplitat(separator) + cache[separator]=c end return lpegmatch(c,str) -end -function string.split(str,separator) - if separator then - local c=cache[separator] - if not c then - c=tsplitat(separator) - cache[separator]=c - end - return lpegmatch(c,str) - else - return { str } - end + else + return { str } + end end local spacing=patterns.spacer^0*newline local empty=spacing*Cc("") @@ -1239,505 +1424,463 @@ patterns.textline=content local linesplitter=tsplitat(newline) patterns.linesplitter=linesplitter function string.splitlines(str) - return lpegmatch(linesplitter,str) + return lpegmatch(linesplitter,str) end local cache={} function lpeg.checkedsplit(separator,str) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) end function string.checkedsplit(str,separator) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) -end -local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end -local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) +end +local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end +local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4 patterns.utf8byte=utf8byte local cache={} function lpeg.stripper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs(((S(str)^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs(((str^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs(((S(str)^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs(((str^1)/""+1)^0) + end end local cache={} function lpeg.keeper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs((((1-S(str))^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs((((1-str)^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs((((1-S(str))^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs((((1-str)^1)/""+1)^0) + end end function lpeg.frontstripper(str) - return (P(str)+P(true))*Cs(anything^0) + return (P(str)+P(true))*Cs(anything^0) end function lpeg.endstripper(str) - return Cs((1-P(str)*endofstring)^0) + return Cs((1-P(str)*endofstring)^0) end function lpeg.replacer(one,two,makefunction,isutf) - local pattern - local u=isutf and utf8char or 1 - if type(one)=="table" then - local no=#one - local p=P(false) - if no==0 then - for k,v in next,one do - p=p+P(k)/v - end - pattern=Cs((p+u)^0) - elseif no==1 then - local o=one[1] - one,two=P(o[1]),o[2] - pattern=Cs((one/two+u)^0) - else - for i=1,no do - local o=one[i] - p=p+P(o[1])/o[2] - end - pattern=Cs((p+u)^0) - end - else - pattern=Cs((P(one)/(two or "")+u)^0) + local pattern + local u=isutf and utf8char or 1 + if type(one)=="table" then + local no=#one + local p=P(false) + if no==0 then + for k,v in next,one do + p=p+P(k)/v + end + pattern=Cs((p+u)^0) + elseif no==1 then + local o=one[1] + one,two=P(o[1]),o[2] + pattern=Cs((one/two+u)^0) + else + for i=1,no do + local o=one[i] + p=p+P(o[1])/o[2] + end + pattern=Cs((p+u)^0) end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=Cs((P(one)/(two or "")+u)^0) + end + if makefunction then + return function(str) + return lpegmatch(pattern,str) end + else + return pattern + end end function lpeg.finder(lst,makefunction,isutf) - local pattern - if type(lst)=="table" then - pattern=P(false) - if #lst==0 then - for k,v in next,lst do - pattern=pattern+P(k) - end - else - for i=1,#lst do - pattern=pattern+P(lst[i]) - end - end - else - pattern=P(lst) - end - if isutf then - pattern=((utf8char or 1)-pattern)^0*pattern + local pattern + if type(lst)=="table" then + pattern=P(false) + if #lst==0 then + for k,v in next,lst do + pattern=pattern+P(k) + end else - pattern=(1-pattern)^0*pattern + for i=1,#lst do + pattern=pattern+P(lst[i]) + end end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=P(lst) + end + 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) end + else + return pattern + end end local splitters_f,splitters_s={},{} function lpeg.firstofsplit(separator) - local splitter=splitters_f[separator] - if not splitter then - local pattern=P(separator) - splitter=C((1-pattern)^0) - splitters_f[separator]=splitter - end - return splitter + local splitter=splitters_f[separator] + if not splitter then + local pattern=P(separator) + splitter=C((1-pattern)^0) + splitters_f[separator]=splitter + end + return splitter end function lpeg.secondofsplit(separator) - local splitter=splitters_s[separator] - if not splitter then - local pattern=P(separator) - splitter=(1-pattern)^0*pattern*C(anything^0) - splitters_s[separator]=splitter - end - return splitter + local splitter=splitters_s[separator] + if not splitter then + 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 + 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 + 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 } + left,right=P(left),P(right) + return P { left*((1-left-right)+V(1))^0*right } end function lpeg.counter(pattern,action) - local n=0 - local pattern=(P(pattern)/function() n=n+1 end+anything)^0 - if action then - return function(str) n=0;lpegmatch(pattern,str);action(n) end - else - return function(str) n=0;lpegmatch(pattern,str);return n end - end -end -utf=utf or (unicode and unicode.utf8) or {} -local utfcharacters=utf and utf.characters or string.utfcharacters -local utfgmatch=utf and utf.gmatch -local utfchar=utf and utf.char -lpeg.UP=lpeg.P -if utfcharacters then - function lpeg.US(str) - local p=P(false) - for uc in utfcharacters(str) do - p=p+P(uc) - end - return p - end -elseif utfgmatch then - function lpeg.US(str) - local p=P(false) - for uc in utfgmatch(str,".") do - p=p+P(uc) - end - return p - end -else - function lpeg.US(str) - local p=P(false) - local f=function(uc) - p=p+P(uc) - end - lpegmatch((utf8char/f)^0,str) - return p - end -end -local range=utf8byte*utf8byte+Cc(false) -function lpeg.UR(str,more) - local first,last - if type(str)=="number" then - first=str - last=more or first - else - first,last=lpegmatch(range,str) - if not last then - return P(str) - end - end - if first==last then - return P(str) - elseif utfchar and (last-first<8) then - local p=P(false) - for i=first,last do - p=p+P(utfchar(i)) - end - return p - else - local f=function(b) - return b>=first and b<=last - end - return utf8byte/f - end + local n=0 + local pattern=(P(pattern)/function() n=n+1 end+anything)^0 + if action then + return function(str) n=0;lpegmatch(pattern,str);action(n) end + else + return function(str) n=0;lpegmatch(pattern,str);return n end + end end function lpeg.is_lpeg(p) - return p and lpegtype(p)=="pattern" + return p and lpegtype(p)=="pattern" end function lpeg.oneof(list,...) - if type(list)~="table" then - list={ list,... } - end - local p=P(list[1]) - for l=2,#list do - p=p+P(list[l]) - end - return p + if type(list)~="table" then + list={ list,... } + end + local p=P(list[1]) + for l=2,#list do + p=p+P(list[l]) + end + return p end local sort=table.sort local function copyindexed(old) - local new={} - for i=1,#old do - new[i]=old - end - return new + local new={} + for i=1,#old do + new[i]=old + end + return new end local function sortedkeys(tab) - local keys,s={},0 - for key,_ in next,tab do - s=s+1 - keys[s]=key - end - sort(keys) - return keys + local keys,s={},0 + for key,_ in next,tab do + s=s+1 + keys[s]=key + end + sort(keys) + return keys end function lpeg.append(list,pp,delayed,checked) - local p=pp - if #list>0 then - local keys=copyindexed(list) - sort(keys) - for i=#keys,1,-1 do - local k=keys[i] - if p then - p=P(k)+p - else - p=P(k) - end - end - elseif delayed then - local keys=sortedkeys(list) + local p=pp + if #list>0 then + local keys=copyindexed(list) + sort(keys) + for i=#keys,1,-1 do + local k=keys[i] + if p then + p=P(k)+p + else + p=P(k) + end + end + elseif delayed then + local keys=sortedkeys(list) + if p then + for i=1,#keys,1 do + local k=keys[i] + local v=list[k] + p=P(k)/list+p + end + else + for i=1,#keys do + local k=keys[i] + local v=list[k] if p then - for i=1,#keys,1 do - local k=keys[i] - local v=list[k] - p=P(k)/list+p - end + p=P(k)+p else - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)+p - else - p=P(k) - end - end - if p then - p=p/list - end + p=P(k) end - elseif checked then - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - if k==v then - p=P(k)+p - else - p=P(k)/v+p - end - else - if k==v then - p=P(k) - else - p=P(k)/v - end - end + end + if p then + p=p/list + end + end + elseif checked then + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + if k==v then + p=P(k)+p + else + p=P(k)/v+p end - else - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)/v+p - else - p=P(k)/v - end + else + if k==v then + p=P(k) + else + p=P(k)/v end + end end - return p + else + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + p=P(k)/v+p + else + p=P(k)/v + end + end + end + return p end local p_false=P(false) local p_true=P(true) local lower=utf and utf.lower or string.lower local upper=utf and utf.upper or string.upper function lpeg.setutfcasers(l,u) - lower=l or lower - upper=u or upper + lower=l or lower + upper=u or upper end local function make1(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+P(k)*p_true - elseif v==false then - else - p=p+P(k)*make1(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+P(k)*p_true + elseif v==false then + else + p=p+P(k)*make1(v,v[""]) + end end - return p + end + if rest then + p=p+p_true + end + return p end local function make2(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+(P(lower(k))+P(upper(k)))*p_true - elseif v==false then - else - p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+(P(lower(k))+P(upper(k)))*p_true + elseif v==false then + else + p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) + end end - return p -end -function lpeg.utfchartabletopattern(list,insensitive) - local tree={} - local n=#list - if n==0 then - for s in next,list do - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + end + if rest then + p=p+p_true + end + return p +end +local function utfchartabletopattern(list,insensitive) + local tree={} + local n=#list + if n==0 then + for s in next,list do + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end - else - for i=1,n do - local s=list[i] - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end + end + else + for i=1,n do + local s=list[i] + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end end - return (insensitive and make2 or make1)(tree) + end + return (insensitive and make2 or make1)(tree) +end +lpeg.utfchartabletopattern=utfchartabletopattern +function lpeg.utfreplacer(list,insensitive) + local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0) + return function(str) + return lpegmatch(pattern,str) or str + end end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) - local m=n%step - local d=floor(n/step) - if d>0 then - local v=V(tostring(step)) - local s=result.start - for i=1,d do - if s then - s=v*s - else - s=v - end - end - result.start=s - end - if step>1 and result.start then - local v=V(tostring(step/2)) - result[tostring(step)]=v*v - end - if step>0 then - return nextstep(m,step/2,result) - else - return result + local m=n%step + local d=floor(n/step) + if d>0 then + local v=V(tostring(step)) + local s=result.start + for i=1,d do + if s then + s=v*s + else + s=v + end end + result.start=s + end + if step>1 and result.start then + local v=V(tostring(step/2)) + result[tostring(step)]=v*v + end + if step>0 then + return nextstep(m,step/2,result) + else + return result + end end function lpeg.times(pattern,n) - return P(nextstep(n,2^16,{ "start",["1"]=pattern })) -end -local trailingzeros=zero^0*-digit -local case_1=period*trailingzeros/"" -local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"") -local number=digits*(case_1+case_2) -local stripper=Cs((number+1)^0) -lpeg.patterns.stripzeros=stripper + return P(nextstep(n,2^16,{ "start",["1"]=pattern })) +end +do + local trailingzeros=zero^0*-digit + local stripper=Cs(( + digits*( + period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"") + )+1 + )^0) + lpeg.patterns.stripzeros=stripper + local nonzero=digit-zero + local trailingzeros=zero^1*endofstring + local stripper=Cs((1-period)^0*( + period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring + )) + lpeg.patterns.stripzero=stripper +end local byte_to_HEX={} local byte_to_hex={} local byte_to_dec={} local hex_to_byte={} for i=0,255 do - local H=format("%02X",i) - local h=format("%02x",i) - local d=format("%03i",i) - local c=char(i) - byte_to_HEX[c]=H - byte_to_hex[c]=h - byte_to_dec[c]=d - hex_to_byte[h]=c - hex_to_byte[H]=c + local H=format("%02X",i) + local h=format("%02x",i) + local d=format("%03i",i) + local c=char(i) + byte_to_HEX[c]=H + byte_to_hex[c]=h + byte_to_dec[c]=d + hex_to_byte[h]=c + hex_to_byte[H]=c end local hextobyte=P(2)/hex_to_byte local bytetoHEX=P(1)/byte_to_HEX @@ -1756,32 +1899,47 @@ patterns.bytestoHEX=bytestoHEX patterns.bytestohex=bytestohex patterns.bytestodec=bytestodec function string.toHEX(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestoHEX,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestoHEX,s) + end end function string.tohex(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestohex,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestohex,s) + end end function string.todec(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestodec,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestodec,s) + end end function string.tobytes(s) - if not s or s=="" then - return s - else - return lpegmatch(hextobytes,s) - end + if not s or s=="" then + return s + else + return lpegmatch(hextobytes,s) + end +end +local patterns={} +local function containsws(what) + local p=patterns[what] + if not p then + local p1=P(what)*(whitespace+endofstring)*Cc(true) + local p2=whitespace*P(p1) + p=P(p1)+P(1-p2)^0*p2+Cc(false) + patterns[what]=p + end + return p +end +lpeg.containsws=containsws +function string.containsws(str,what) + return lpegmatch(patterns[what] or containsws(what),str) end @@ -1791,14 +1949,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-function"] = package.loaded["l-function"] or true --- original size: 361, stripped down to: 322 +-- original size: 361, stripped down to: 317 if not modules then modules={} end modules ['l-functions']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } functions=functions or {} function functions.dummy() end @@ -1810,14 +1968,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-string"] = package.loaded["l-string"] or true --- original size: 6461, stripped down to: 3341 +-- original size: 6461, stripped down to: 3255 if not modules then modules={} end modules ['l-string']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local string=string local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower @@ -1825,25 +1983,25 @@ local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote function string.unquoted(str) - return lpegmatch(unquoted,str) or str + return lpegmatch(unquoted,str) or str end function string.quoted(str) - return format("%q",str) + return format("%q",str) end function string.count(str,pattern) - local n=0 - for _ in gmatch(str,pattern) do - n=n+1 - end - return n + local n=0 + for _ in gmatch(str,pattern) do + n=n+1 + end + return n end function string.limit(str,n,sentinel) - if #str>n then - sentinel=sentinel or "..." - return sub(str,1,(n-#sentinel))..sentinel - else - return str - end + if #str>n then + sentinel=sentinel or "..." + return sub(str,1,(n-#sentinel))..sentinel + else + return str + end end local stripper=patterns.stripper local fullstripper=patterns.fullstripper @@ -1851,81 +2009,81 @@ local collapser=patterns.collapser local nospacer=patterns.nospacer local longtostring=patterns.longtostring function string.strip(str) - return str and lpegmatch(stripper,str) or "" + return str and lpegmatch(stripper,str) or "" end function string.fullstrip(str) - return str and lpegmatch(fullstripper,str) or "" + return str and lpegmatch(fullstripper,str) or "" end function string.collapsespaces(str) - return str and lpegmatch(collapser,str) or "" + return str and lpegmatch(collapser,str) or "" end function string.nospaces(str) - return str and lpegmatch(nospacer,str) or "" + return str and lpegmatch(nospacer,str) or "" end function string.longtostring(str) - return str and lpegmatch(longtostring,str) or "" + return str and lpegmatch(longtostring,str) or "" end local pattern=P(" ")^0*P(-1) function string.is_empty(str) - if not str or str=="" then - return true - else - return lpegmatch(pattern,str) and true or false - end + if not str or str=="" then + return true + else + return lpegmatch(pattern,str) and true or false + end end local anything=patterns.anything local allescapes=Cc("%")*S(".-+%?()[]*") -local someescapes=Cc("%")*S(".-+%()[]") -local matchescapes=Cc(".")*S("*?") +local someescapes=Cc("%")*S(".-+%()[]") +local matchescapes=Cc(".")*S("*?") local pattern_a=Cs ((allescapes+anything )^0 ) local pattern_b=Cs ((someescapes+matchescapes+anything )^0 ) local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") ) function string.escapedpattern(str,simple) - return lpegmatch(simple and pattern_b or pattern_a,str) + return lpegmatch(simple and pattern_b or pattern_a,str) end function string.topattern(str,lowercase,strict) - if str=="" or type(str)~="string" then - return ".*" - elseif strict then - str=lpegmatch(pattern_c,str) - else - str=lpegmatch(pattern_b,str) - end - if lowercase then - return lower(str) - else - return str - end + if str=="" or type(str)~="string" then + return ".*" + elseif strict then + str=lpegmatch(pattern_c,str) + else + str=lpegmatch(pattern_b,str) + end + if lowercase then + return lower(str) + else + return str + end end function string.valid(str,default) - return (type(str)=="string" and str~="" and str) or default or nil + return (type(str)=="string" and str~="" and str) or default or nil end string.itself=function(s) return s end local pattern_c=Ct(C(1)^0) local pattern_b=Ct((C(1)/byte)^0) function string.totable(str,bytes) - return lpegmatch(bytes and pattern_b or pattern_c,str) + return lpegmatch(bytes and pattern_b or pattern_c,str) end local replacer=lpeg.replacer("@","%%") function string.tformat(fmt,...) - return format(lpegmatch(replacer,fmt),...) + return format(lpegmatch(replacer,fmt),...) end string.quote=string.quoted string.unquote=string.unquoted if not string.bytetable then - local limit=5000 - function string.bytetable(str) - local n=#str - if n>limit then - local t={ byte(str,1,limit) } - for i=limit+1,n do - t[i]=byte(str,i) - end - return t - else - return { byte(str,1,n) } - end + local limit=5000 + function string.bytetable(str) + local n=#str + if n>limit then + local t={ byte(str,1,limit) } + for i=limit+1,n do + t[i]=byte(str,i) + end + return t + else + return { byte(str,1,n) } end + end end @@ -1935,166 +2093,172 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 40197, stripped down to: 23561 +-- original size: 41298, stripped down to: 21498 if not modules then modules={} end modules ['l-table']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select local table,string=table,string -local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove +local concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable -local getinfo=debug.getinfo local lpegmatch,patterns=lpeg.match,lpeg.patterns local floor=math.floor local stripper=patterns.stripper function table.getn(t) - return t and #t + return t and #t end function table.strip(tab) - local lst,l={},0 - for i=1,#tab do - local s=lpegmatch(stripper,tab[i]) or "" - if s=="" then - else - l=l+1 - lst[l]=s - end + local lst={} + local l=0 + for i=1,#tab do + local s=lpegmatch(stripper,tab[i]) or "" + if s=="" then + else + l=l+1 + lst[l]=s end - return lst + end + return lst end function table.keys(t) - if t then - local keys,k={},0 - for key in next,t do - k=k+1 - keys[k]=key - end - return keys - else - return {} + if t then + local keys={} + local k=0 + for key in next,t do + k=k+1 + keys[k]=key end + return keys + else + return {} + end end local function compare(a,b) - local ta=type(a) - if ta=="number" then - local tb=type(b) - if ta==tb then - return a<b - elseif tb=="string" then - return tostring(a)<b - end - elseif ta=="string" then - local tb=type(b) - if ta==tb then - return a<b - else - return a<tostring(b) - end + local ta=type(a) + if ta=="number" then + local tb=type(b) + if ta==tb then + return a<b + elseif tb=="string" then + return tostring(a)<b end - return tostring(a)<tostring(b) + elseif ta=="string" then + local tb=type(b) + if ta==tb then + return a<b + else + return a<tostring(b) + end + end + return tostring(a)<tostring(b) end local function sortedkeys(tab) - if tab then - local srt,category,s={},0,0 - for key in next,tab do - s=s+1 - srt[s]=key - if category==3 then - elseif category==1 then - if type(key)~="string" then - category=3 - end - elseif category==2 then - if type(key)~="number" then - category=3 - end - else - local tkey=type(key) - if tkey=="string" then - category=1 - elseif tkey=="number" then - category=2 - else - category=3 - end - end - end - if s<2 then - elseif category==3 then - sort(srt,compare) + if tab then + local srt={} + local category=0 + local s=0 + for key in next,tab do + s=s+1 + srt[s]=key + if category==3 then + elseif category==1 then + if type(key)~="string" then + category=3 + end + elseif category==2 then + if type(key)~="number" then + category=3 + end + else + local tkey=type(key) + if tkey=="string" then + category=1 + elseif tkey=="number" then + category=2 else - sort(srt) + category=3 end - return srt + end + end + if s<2 then + elseif category==3 then + sort(srt,compare) else - return {} + sort(srt) end + return srt + else + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="string" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="number" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + return srt + else + return {} + end end local function sortedhashkeys(tab,cmp) - if tab then - local srt,s={},0 - for key in next,tab do - if key then - s=s+1 - srt[s]=key - end - end - if s>1 then - sort(srt,cmp) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if key then + s=s+1 + srt[s]=key + end + end + if s>1 then + sort(srt,cmp) end + return srt + else + return {} + end end function table.allkeys(t) - local keys={} - for k,v in next,t do - for k in next,v do - keys[k]=true - end + local keys={} + for k,v in next,t do + for k in next,v do + keys[k]=true end - return sortedkeys(keys) + end + return sortedkeys(keys) end table.sortedkeys=sortedkeys table.sortedhashonly=sortedhashonly @@ -2102,907 +2266,944 @@ table.sortedindexonly=sortedindexonly table.sortedhashkeys=sortedhashkeys local function nothing() end local function sortedhash(t,cmp) - if t then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local m=#s - if m==1 then - return next,t - elseif m>0 then - local n=0 - return function() - if n<m then - n=n+1 - local k=s[n] - return k,t[k] - end - end + if t then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local m=#s + if m==1 then + return next,t + elseif m>0 then + local n=0 + return function() + if n<m then + n=n+1 + local k=s[n] + return k,t[k] end + end end - return nothing + end + return nothing end table.sortedhash=sortedhash table.sortedpairs=sortedhash function table.append(t,list) - local n=#t - for i=1,#list do - n=n+1 - t[n]=list[i] - end - return t + local n=#t + for i=1,#list do + n=n+1 + t[n]=list[i] + end + return t end function table.prepend(t,list) - local nl=#list - local nt=nl+#t - for i=#t,1,-1 do - t[nt]=t[i] - nt=nt-1 - end - for i=1,#list do - t[i]=list[i] - end - return t + local nl=#list + local nt=nl+#t + for i=#t,1,-1 do + t[nt]=t[i] + nt=nt-1 + end + for i=1,#list do + t[i]=list[i] + end + return t end function table.merge(t,...) - t=t or {} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + if not t then + t={} + end + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.merged(...) - local t={} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + local t={} + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.imerge(t,...) - local nt=#t - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - nt=nt+1 - t[nt]=nst[j] - end + local nt=#t + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + nt=nt+1 + t[nt]=nst[j] end - return t + end + return t end function table.imerged(...) - local tmp,ntmp={},0 - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - ntmp=ntmp+1 - tmp[ntmp]=nst[j] - end + local tmp={} + local ntmp=0 + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + ntmp=ntmp+1 + tmp[ntmp]=nst[j] end - return tmp + end + return tmp end local function fastcopy(old,metatabletoo) - if old then - local new={} - for k,v in next,old do - if type(v)=="table" then - new[k]=fastcopy(v,metatabletoo) - else - new[k]=v - end - end - if metatabletoo then - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + if type(v)=="table" then + new[k]=fastcopy(v,metatabletoo) + else + new[k]=v + end + end + if metatabletoo then + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end end + return new + else + return {} + end end local function copy(t,tables) - tables=tables or {} - local tcopy={} - if not tables[t] then - tables[t]=tcopy - end - for i,v in next,t do - if type(i)=="table" then - if tables[i] then - i=tables[i] - else - i=copy(i,tables) - end - end - if type(v)~="table" then - tcopy[i]=v - elseif tables[v] then - tcopy[i]=tables[v] - else - tcopy[i]=copy(v,tables) - end + if not tables then + tables={} + end + local tcopy={} + if not tables[t] then + tables[t]=tcopy + end + for i,v in next,t do + if type(i)=="table" then + if tables[i] then + i=tables[i] + else + i=copy(i,tables) + end end - local mt=getmetatable(t) - if mt then - setmetatable(tcopy,mt) + if type(v)~="table" then + tcopy[i]=v + elseif tables[v] then + tcopy[i]=tables[v] + else + tcopy[i]=copy(v,tables) end - return tcopy + end + local mt=getmetatable(t) + if mt then + setmetatable(tcopy,mt) + end + return tcopy end table.fastcopy=fastcopy table.copy=copy function table.derive(parent) - local child={} - if parent then - setmetatable(child,{ __index=parent }) - end - return child + local child={} + if parent then + setmetatable(child,{ __index=parent }) + end + return child end function table.tohash(t,value) - local h={} - if t then - if value==nil then value=true end - for _,v in next,t do - h[v]=value - end + local h={} + if t then + if value==nil then value=true end + for _,v in next,t do + h[v]=value end - return h + end + return h end function table.fromhash(t) - local hsh,h={},0 - for k,v in next,t do - if v then - h=h+1 - hsh[h]=k - end + local hsh={} + local h=0 + for k,v in next,t do + if v then + h=h+1 + hsh[h]=k end - return hsh + end + return hsh end local noquotes,hexify,handle,compact,inline,functions,metacheck 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', + '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 is_simple_table(t,hexify) - local nt=#t - if nt>0 then - local n=0 - for _,v in next,t do - n=n+1 - if type(v)=="table" then - return nil - end + local nt=#t + if nt>0 then + local n=0 + for _,v in next,t do + n=n+1 + if type(v)=="table" then + return nil + end + end + local haszero=rawget(t,0) + if n==nt then + local tt={} + for i=1,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i]=format("0x%X",v) + else + tt[i]=v + end + elseif tv=="string" then + tt[i]=format("%q",v) + elseif tv=="boolean" then + tt[i]=v and "true" or "false" + else + return nil end - local haszero=rawget(t,0) - if n==nt then - local tt={} - for i=1,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i]=format("0x%X",v) - else - tt[i]=v - end - elseif tv=="string" then - tt[i]=format("%q",v) - elseif tv=="boolean" then - tt[i]=v and "true" or "false" - else - return nil - end - end - return tt - elseif haszero and (n==nt+1) then - local tt={} - for i=0,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i+1]=format("0x%X",v) - else - tt[i+1]=v - end - elseif tv=="string" then - tt[i+1]=format("%q",v) - elseif tv=="boolean" then - tt[i+1]=v and "true" or "false" - else - return nil - end - end - tt[1]="[0] = "..tt[1] - return tt + end + return tt + elseif haszero and (n==nt+1) then + local tt={} + for i=0,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i+1]=format("0x%X",v) + else + tt[i+1]=v + end + elseif tv=="string" then + tt[i+1]=format("%q",v) + elseif tv=="boolean" then + tt[i+1]=v and "true" or "false" + else + return nil end + end + tt[1]="[0] = "..tt[1] + return tt end - return nil + end + return nil end table.is_simple_table=is_simple_table local propername=patterns.propername local function dummy() end local function do_serialize(root,name,depth,level,indexed) - if level>0 then - depth=depth.." " - if indexed then - handle(format("%s{",depth)) + if level>0 then + depth=depth.." " + if indexed then + handle(format("%s{",depth)) + else + local tn=type(name) + if tn=="number" then + if hexify then + handle(format("%s[0x%X]={",depth,name)) else - local tn=type(name) - if tn=="number" then - if hexify then - handle(format("%s[0x%X]={",depth,name)) - else - handle(format("%s[%s]={",depth,name)) - end - elseif tn=="string" then - if noquotes and not reserved[name] and lpegmatch(propername,name) then - handle(format("%s%s={",depth,name)) - else - handle(format("%s[%q]={",depth,name)) - end - elseif tn=="boolean" then - handle(format("%s[%s]={",depth,name and "true" or "false")) - else - handle(format("%s{",depth)) - end + handle(format("%s[%s]={",depth,name)) end + elseif tn=="string" then + if noquotes and not reserved[name] and lpegmatch(propername,name) then + handle(format("%s%s={",depth,name)) + else + handle(format("%s[%q]={",depth,name)) + end + elseif tn=="boolean" then + handle(format("%s[%s]={",depth,name and "true" or "false")) + else + handle(format("%s{",depth)) + end end - if root and next(root)~=nil then - local first,last=nil,0 - if compact then - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end - end - if last>0 then - first=1 - end + end + if root and next(root)~=nil then + local first=nil + local last=0 + if compact then + last=#root + for k=1,last do + if rawget(root,k)==nil then + last=k-1 + break 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 compact and first and tk=="number" and k>=first and k<=last then - if tv=="number" then - if hexify then - handle(format("%s 0x%X,",depth,v)) - else - handle(format("%s %s,",depth,v)) - end - elseif tv=="string" then - handle(format("%s %q,",depth,v)) - elseif tv=="table" then - if next(v)==nil then - handle(format("%s {},",depth)) - elseif inline then - local st=is_simple_table(v,hexify) - if st then - handle(format("%s { %s },",depth,concat(st,", "))) - else - do_serialize(v,k,depth,level+1,true) - end - else - do_serialize(v,k,depth,level+1,true) - end - 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))) - else - handle(format('%s "function",',depth)) - end - else - handle(format("%s %q,",depth,tostring(v))) - end - elseif k=="__p__" then - if false then - handle(format("%s __p__=nil,",depth)) - end - elseif tv=="number" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=0x%X,",depth,k,v)) - else - handle(format("%s [%s]=%s,",depth,k,v)) - end - elseif tk=="boolean" then - if hexify then - handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) - else - handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) - end - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - if hexify then - handle(format("%s %s=0x%X,",depth,k,v)) - else - handle(format("%s %s=%s,",depth,k,v)) - end - else - if hexify then - handle(format("%s [%q]=0x%X,",depth,k,v)) - else - handle(format("%s [%q]=%s,",depth,k,v)) - end - end - elseif tv=="string" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,v)) - else - handle(format("%s [%s]=%q,",depth,k,v)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) - elseif tk~="string" then - 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 - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={},",depth,k)) - else - handle(format("%s [%s]={},",depth,k)) - end - elseif tk=="boolean" then - handle(format("%s [%s]={},",depth,k and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={},",depth,k)) - else - handle(format("%s [%q]={},",depth,k)) - end - elseif inline then - local st=is_simple_table(v,hexify) - if st then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) - end - elseif tk=="boolean" then - handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) - end - else - do_serialize(v,k,depth,level+1) - end - else - do_serialize(v,k,depth,level+1) - end - elseif tv=="boolean" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) - else - 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),v and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,v and "true" or "false")) - else - handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) - end - elseif tv=="function" then - if functions then - local f=getinfo(v).what=="C" and dump(dummy) or dump(v) - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=load(%q),",depth,k,f)) - else - handle(format("%s [%s]=load(%q),",depth,k,f)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=load(%q),",depth,k,f)) - else - handle(format("%s [%q]=load(%q),",depth,k,f)) - end - end + end + if last>0 then + first=1 + end + 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 compact and first and tk=="number" and k>=first and k<=last then + if tv=="number" then + if hexify then + handle(format("%s 0x%X,",depth,v)) + else + handle(format("%s %s,",depth,v)) + end + elseif tv=="string" then + handle(format("%s %q,",depth,v)) + elseif tv=="table" then + if next(v)==nil then + handle(format("%s {},",depth)) + elseif inline then + local st=is_simple_table(v,hexify) + if st then + handle(format("%s { %s },",depth,concat(st,", "))) else - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) - else - handle(format("%s [%s]=%q,",depth,k,tostring(v))) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%q,",depth,k,tostring(v))) - else - handle(format("%s [%q]=%q,",depth,k,tostring(v))) - end + do_serialize(v,k,depth,level+1,true) end + else + do_serialize(v,k,depth,level+1,true) + end + 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))) + else + handle(format('%s "function",',depth)) + end + else + handle(format("%s %q,",depth,tostring(v))) end - end - if level>0 then - handle(format("%s},",depth)) - end -end -local function serialize(_handle,root,name,specification) - local tname=type(name) - if type(specification)=="table" then - noquotes=specification.noquotes - hexify=specification.hexify - handle=_handle or specification.handle or print - functions=specification.functions - compact=specification.compact - inline=specification.inline and compact - metacheck=specification.metacheck - if functions==nil then - functions=true - end - if compact==nil then - compact=true - end - if inline==nil then - inline=compact - end - if metacheck==nil then - metacheck=true + elseif k=="__p__" then + if false then + handle(format("%s __p__=nil,",depth)) end - else - noquotes=false - hexify=false - handle=_handle or print - compact=true - inline=true - functions=true - metacheck=true - end - if tname=="string" then - if name=="return" then - handle("return {") + elseif tv=="number" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=0x%X,",depth,k,v)) + else + handle(format("%s [%s]=%s,",depth,k,v)) + end + elseif tk=="boolean" then + if hexify then + handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + else + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) + end + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + if hexify then + handle(format("%s %s=0x%X,",depth,k,v)) + else + handle(format("%s %s=%s,",depth,k,v)) + end + else + if hexify then + handle(format("%s [%q]=0x%X,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end + end + elseif tv=="string" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,v)) + else + handle(format("%s [%s]=%q,",depth,k,v)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) else - handle(name.."={") + handle(format("%s [%q]=%q,",depth,k,v)) end - elseif tname=="number" then - if hexify then - handle(format("[0x%X]={",name)) + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={},",depth,k)) + else + handle(format("%s [%s]={},",depth,k)) + end + elseif tk=="boolean" then + handle(format("%s [%s]={},",depth,k and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={},",depth,k)) + else + handle(format("%s [%q]={},",depth,k)) + end + elseif inline then + local st=is_simple_table(v,hexify) + if st then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) + end + elseif tk=="boolean" then + handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) + end + else + do_serialize(v,k,depth,level+1) + end else - handle("["..name.."]={") + do_serialize(v,k,depth,level+1) end - elseif tname=="boolean" then - if name then - handle("return {") + elseif tv=="boolean" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) + else + 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),v and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else - handle("{") + handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) end - else - handle("t={") - end - if root then - if metacheck and getmetatable(root) then - local dummy=root._w_h_a_t_e_v_e_r_ - root._w_h_a_t_e_v_e_r_=nil + elseif tv=="function" then + if functions then + local getinfo=debug and debug.getinfo + if getinfo then + local f=getinfo(v).what=="C" and dump(dummy) or dump(v) + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=load(%q),",depth,k,f)) + else + handle(format("%s [%s]=load(%q),",depth,k,f)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=load(%q),",depth,k,f)) + else + handle(format("%s [%q]=load(%q),",depth,k,f)) + end + end end - if next(root)~=nil then - do_serialize(root,name,"",0) + else + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) + else + handle(format("%s [%s]=%q,",depth,k,tostring(v))) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,tostring(v))) + else + handle(format("%s [%q]=%q,",depth,k,tostring(v))) end + end end - handle("}") + end + if level>0 then + handle(format("%s},",depth)) + end end -function table.serialize(root,name,specification) - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s +local function serialize(_handle,root,name,specification) + local tname=type(name) + if type(specification)=="table" then + noquotes=specification.noquotes + hexify=specification.hexify + handle=_handle or specification.handle or print + functions=specification.functions + compact=specification.compact + inline=specification.inline and compact + metacheck=specification.metacheck + if functions==nil then + functions=true + end + if compact==nil then + compact=true + end + if inline==nil then + inline=compact + end + if metacheck==nil then + metacheck=true + end + else + noquotes=false + hexify=false + handle=_handle or print + compact=true + inline=true + functions=true + metacheck=true + end + if tname=="string" then + if name=="return" then + handle("return {") + else + handle(name.."={") + end + elseif tname=="number" then + if hexify then + handle(format("[0x%X]={",name)) + else + handle("["..name.."]={") + end + elseif tname=="boolean" then + if name then + handle("return {") + else + handle("{") + end + else + handle("t={") + end + if root then + if metacheck and 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)~=nil then + do_serialize(root,name,"",0) end - serialize(flush,root,name,specification) - return concat(t,"\n") + end + handle("}") +end +function table.serialize(root,name,specification) + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + end + serialize(flush,root,name,specification) + return concat(t,"\n") end table.tohandle=serialize local maxtab=2*1024 function table.tofile(filename,root,name,specification) - local f=io.open(filename,'w') - if f then - if maxtab>1 then - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s - if n>maxtab then - f:write(concat(t,"\n"),"\n") - t,n={},0 - end - end - serialize(flush,root,name,specification) - f:write(concat(t,"\n"),"\n") - else - local function flush(s) - f:write(s,"\n") - end - serialize(flush,root,name,specification) + local f=io.open(filename,'w') + if f then + if maxtab>1 then + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + if n>maxtab then + f:write(concat(t,"\n"),"\n") + t={} + n=0 end - f:close() - io.flush() + end + serialize(flush,root,name,specification) + f:write(concat(t,"\n"),"\n") + else + local function flush(s) + f:write(s,"\n") + end + serialize(flush,root,name,specification) end + f:close() + io.flush() + end end local function flattened(t,f,depth) - if f==nil then - f={} - depth=0xFFFF - elseif tonumber(f) then - depth=f - f={} - elseif not depth then - depth=0xFFFF - end - for k,v in next,t do - if type(k)~="number" then - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end - end + if f==nil then + f={} + depth=0xFFFF + elseif tonumber(f) then + depth=f + f={} + elseif not depth then + depth=0xFFFF + end + for k,v in next,t do + if type(k)~="number" then + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v + end end - for k=1,#t do - local v=t[k] - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end + end + for k=1,#t do + local v=t[k] + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v end - return f + end + return f end table.flattened=flattened local function collapsed(t,f,h) - if f==nil then - f={} - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsed(v,f,h) - elseif not h[v] then - f[#f+1]=v - h[v]=true - end + if f==nil then + f={} + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsed(v,f,h) + elseif not h[v] then + f[#f+1]=v + h[v]=true end - return f + end + return f end local function collapsedhash(t,h) - if h==nil then - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsedhash(v,h) - else - h[v]=true - end + if h==nil then + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsedhash(v,h) + else + h[v]=true end - return h + end + return h end -table.collapsed=collapsed +table.collapsed=collapsed table.collapsedhash=collapsedhash local function unnest(t,f) - if not f then - f={} - end - for i=1,#t do - local v=t[i] - if type(v)=="table" then - if type(v[1])=="table" then - unnest(v,f) - else - f[#f+1]=v - end - else - f[#f+1]=v - end + if not f then + f={} + end + for i=1,#t do + local v=t[i] + if type(v)=="table" then + if type(v[1])=="table" then + unnest(v,f) + else + f[#f+1]=v + end + else + f[#f+1]=v end - return f + end + return f end function table.unnest(t) - return unnest(t) + return unnest(t) end local function are_equal(a,b,n,m) - if a==b then - return true - elseif a and b and #a==#b then - n=n or 1 - m=m or #a - for i=n,m do - local ai,bi=a[i],b[i] - if ai==bi then - elseif type(ai)=="table" and type(bi)=="table" then - if not are_equal(ai,bi) then - return false - end - else - return false - end + if a==b then + return true + elseif a and b and #a==#b then + if not n then + n=1 + end + if not m then + m=#a + end + for i=n,m do + local ai,bi=a[i],b[i] + if ai==bi then + elseif type(ai)=="table" and type(bi)=="table" then + if not are_equal(ai,bi) then + return false end - return true - else + else return false + end end + return true + else + return false + end end local function identical(a,b) - if a~=b then - for ka,va in next,a do - local vb=b[ka] - if va==vb then - elseif type(va)=="table" and type(vb)=="table" then - if not identical(va,vb) then - return false - end - else - return false - end - end + if a~=b then + for ka,va in next,a do + local vb=b[ka] + if va==vb then + elseif type(va)=="table" and type(vb)=="table" then + if not identical(va,vb) then + return false + end + else + return false + end end - return true + end + return true end table.identical=identical table.are_equal=are_equal local function sparse(old,nest,keeptables) - local new={} - for k,v in next,old do - if not (v=="" or v==false) then - if nest and type(v)=="table" then - v=sparse(v,nest) - if keeptables or next(v)~=nil then - new[k]=v - end - else - new[k]=v - end - end + local new={} + for k,v in next,old do + if not (v=="" or v==false) then + if nest and type(v)=="table" then + v=sparse(v,nest) + if keeptables or next(v)~=nil then + new[k]=v + end + else + new[k]=v + end end - return new + end + return new end table.sparse=sparse function table.compact(t) - return sparse(t,true,true) + return sparse(t,true,true) end function table.contains(t,v) - if t then - for i=1,#t do - if t[i]==v then - return i - end - end + if t then + for i=1,#t do + if t[i]==v then + return i + end end - return false + end + return false end function table.count(t) - local n=0 - for k,v in next,t do - n=n+1 - end - return n + local n=0 + for k,v in next,t do + n=n+1 + end + return n end function table.swapped(t,s) - local n={} - if s then - for k,v in next,s do - n[k]=v - end + local n={} + if s then + for k,v in next,s do + n[k]=v end - for k,v in next,t do - n[v]=k - end - return n + end + for k,v in next,t do + n[v]=k + end + return n end function table.hashed(t) - for i=1,#t do - t[t[i]]=i - end - return t + for i=1,#t do + t[t[i]]=i + end + return t end function table.mirrored(t) - local n={} - for k,v in next,t do - n[v]=k - n[k]=v - end - return n + local n={} + for k,v in next,t do + n[v]=k + n[k]=v + end + return n end function table.reversed(t) - if t then - local tt,tn={},#t - if tn>0 then - local ttn=0 - for i=tn,1,-1 do - ttn=ttn+1 - tt[ttn]=t[i] - end - end - return tt + if t then + local tt={} + local tn=#t + if tn>0 then + local ttn=0 + for i=tn,1,-1 do + ttn=ttn+1 + tt[ttn]=t[i] + end end + return tt + end end function table.reverse(t) - if t then - local n=#t - for i=1,floor(n/2) do - local j=n-i+1 - t[i],t[j]=t[j],t[i] - end - return t + if t then + local n=#t + local m=n+1 + for i=1,floor(n/2) do + local j=m-i + t[i],t[j]=t[j],t[i] end + return t + end end -function table.sequenced(t,sep,simple) - if not t then - return "" +local function sequenced(t,sep,simple) + if not t then + return "" + elseif type(t)=="string" then + return t + end + local n=#t + local s={} + if n>0 then + for i=1,n do + local v=t[i] + if type(v)=="table" then + s[i]="{"..sequenced(v,sep,simple).."}" + else + s[i]=tostring(t[i]) + end end - local n=#t - local s={} - if n>0 then - for i=1,n do - s[i]=tostring(t[i]) + else + n=0 + for k,v in sortedhash(t) do + if simple then + if v==true then + n=n+1 + s[n]=k + elseif v and v~="" then + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) + end end - else - n=0 - for k,v in sortedhash(t) do - if simple then - if v==true then - n=n+1 - s[n]=k - elseif v and v~="" then - n=n+1 - s[n]=k.."="..tostring(v) - end - else - n=n+1 - s[n]=k.."="..tostring(v) - end + else + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) end + end end - return concat(s,sep or " | ") + end + return concat(s,sep or " | ") end +table.sequenced=sequenced function table.print(t,...) - if type(t)~="table" then - print(tostring(t)) - else - serialize(print,t,...) - end + if type(t)~="table" then + print(tostring(t)) + else + serialize(print,t,...) + end end if setinspector then - setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) + setinspector("table",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) } + return { unpack(t,i,j) } end function table.is_empty(t) - return not t or next(t)==nil + return not t or next(t)==nil end function table.has_one_entry(t) - return t and next(t,next(t))==nil + return t and next(t,next(t))==nil end function table.loweredkeys(t) - local l={} - for k,v in next,t do - l[lower(k)]=v - end - return l + local l={} + for k,v in next,t do + l[lower(k)]=v + end + return l end function table.unique(old) - local hash={} - local new={} - local n=0 - for i=1,#old do - local oi=old[i] - if not hash[oi] then - n=n+1 - new[n]=oi - hash[oi]=true - end - end - return new + local hash={} + local new={} + local n=0 + for i=1,#old do + local oi=old[i] + if not hash[oi] then + n=n+1 + new[n]=oi + hash[oi]=true + end + end + return new end function table.sorted(t,...) - sort(t,...) - return 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 {} + if t then + local values={} + local keys={} + local 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 function table.filtered(t,pattern,sort,cmp) - if t and type(pattern)=="string" then - if sort then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local n=0 - local m=#s - local function kv(s) - while n<m do - n=n+1 - local k=s[n] - if find(k,pattern) then - return k,t[k] - end - end - end - return kv,s - else - local n=next(t) - local function iterator() - while n~=nil do - local k=n - n=next(t,k) - if find(k,pattern) then - return k,t[k] - end - end - end - return iterator,t + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end end - else - return nothing + end + return kv,s + else + local n=next(t) + local function iterator() + while n~=nil do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t end + else + return nothing + end end if not table.move then - function table.move(a1,f,e,t,a2) - if a2 and a1~=a2 then - for i=f,e do - a2[t]=a1[i] - t=t+1 - end - return a2 - else - t=t+e-f - for i=e,f,-1 do - a1[t]=a1[i] - t=t-1 - end - return a1 - end + function table.move(a1,f,e,t,a2) + if a2 and a1~=a2 then + for i=f,e do + a2[t]=a1[i] + t=t+1 + end + return a2 + else + t=t+e-f + for i=e,f,-1 do + a1[t]=a1[i] + t=t-1 + end + return a1 end + end end @@ -3012,14 +3213,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-io"] = package.loaded["l-io"] or true --- original size: 11823, stripped down to: 6945 +-- original size: 11823, stripped down to: 6325 if not modules then modules={} end modules ['l-io']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local io=io local open,flush,write,read=io.open,io.flush,io.write,io.read @@ -3027,334 +3228,334 @@ local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local type=type if string.find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator="\\",";" + io.fileseparator,io.pathseparator="\\",";" else - io.fileseparator,io.pathseparator="/",":" + io.fileseparator,io.pathseparator="/",":" end local large=0x01000000 local medium=0x00100000 local small=0x00020000 local function readall(f) - local size=f:seek("end") - if size>0 then - f:seek("set",0) - return f:read(size) - else - return "" - end + local size=f:seek("end") + if size>0 then + f:seek("set",0) + return f:read(size) + else + return "" + end end io.readall=readall function io.loaddata(filename,textmode) - local f=open(filename,(textmode and 'r') or 'rb') - if f then - local size=f:seek("end") - local data=nil - if size>0 then - f:seek("set",0) - data=f:read(size) - end - f:close() - return data + local f=open(filename,(textmode and 'r') or 'rb') + if f then + local size=f:seek("end") + local data=nil + if size>0 then + f:seek("set",0) + data=f:read(size) end + f:close() + return data + end end function io.copydata(source,target,action) - local f=open(source,"rb") - if f then - local g=open(target,"wb") - if g then - local size=f:seek("end") - if size>0 then - f:seek("set",0) - local data=f:read(size) - if action then - data=action(data) - end - if data then - g:write(data) - end - end - g:close() + local f=open(source,"rb") + if f then + local g=open(target,"wb") + if g then + local size=f:seek("end") + if size>0 then + f:seek("set",0) + local data=f:read(size) + if action then + data=action(data) end - f:close() - flush() + if data then + g:write(data) + end + end + g:close() end + f:close() + flush() + end end function io.savedata(filename,data,joiner) - local f=open(filename,"wb") - if f then - if type(data)=="table" then - f:write(concat(data,joiner or "")) - elseif type(data)=="function" then - data(f) - else - f:write(data or "") - end - f:close() - flush() - return true + local f=open(filename,"wb") + if f then + if type(data)=="table" then + f:write(concat(data,joiner or "")) + elseif type(data)=="function" then + data(f) else - return false + f:write(data or "") end + f:close() + flush() + return true + else + return false + end end if fio and fio.readline then - local readline=fio.readline - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=readline(f) - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + local readline=fio.readline + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=readline(f) + if line then + lines[i]=line else - local line=readline(f) - f:close() - if line and #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=readline(f) + f:close() + if line and #line>0 then + return line + end end + end else - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=f:read("*lines") - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=f:read("*lines") + if line then + lines[i]=line else - local line=f:read("*line") or "" - f:close() - if #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=f:read("*line") or "" + f:close() + if #line>0 then + return line + end end + end end function io.loadchunk(filename,n) - local f=open(filename,'rb') - if f then - local data=f:read(n or 1024) - f:close() - if #data>0 then - return data - end + local f=open(filename,'rb') + if f then + local data=f:read(n or 1024) + f:close() + if #data>0 then + return data end + end end function io.exists(filename) - local f=open(filename) - if f==nil then - return false - else - f:close() - return true - end + local f=open(filename) + if f==nil then + return false + else + f:close() + return true + end end function io.size(filename) - local f=open(filename) - if f==nil then - return 0 - else - local s=f:seek("end") - f:close() - return s - end + local f=open(filename) + if f==nil then + return 0 + else + local s=f:seek("end") + f:close() + return s + end end local function noflines(f) - if type(f)=="string" then - local f=open(filename) - if f then - local n=f and noflines(f) or 0 - f:close() - return n - else - return 0 - end + if type(f)=="string" then + local f=open(filename) + if f then + local n=f and noflines(f) or 0 + f:close() + return n else - local n=0 - for _ in f:lines() do - n=n+1 - end - f:seek('set',0) - return n + return 0 + end + else + local n=0 + for _ in f:lines() do + n=n+1 end + f:seek('set',0) + return n + end end io.noflines=noflines local nextchar={ - [ 4]=function(f) - return f:read(1,1,1,1) - end, - [ 2]=function(f) - return f:read(1,1) - end, - [ 1]=function(f) - return f:read(1) - end, - [-2]=function(f) - local a,b=f:read(1,1) - return b,a - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - return d,c,b,a - end + [ 4]=function(f) + return f:read(1,1,1,1) + end, + [ 2]=function(f) + return f:read(1,1) + end, + [ 1]=function(f) + return f:read(1) + end, + [-2]=function(f) + local a,b=f:read(1,1) + return b,a + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + return d,c,b,a + end } function io.characters(f,n) - if f then - return nextchar[n or 1],f - end + if f then + return nextchar[n or 1],f + end end local nextbyte={ - [4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(a),byte(b),byte(c),byte(d) - end - end, - [3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(a),byte(b),byte(c) - end - end, - [2]=function(f) - local a,b=f:read(1,1) - if b then - return byte(a),byte(b) - end - end, - [1]=function (f) - local a=f:read(1) - if a then - return byte(a) - end - end, - [-2]=function (f) - local a,b=f:read(1,1) - if b then - return byte(b),byte(a) - end - end, - [-3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(c),byte(b),byte(a) - end - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(d),byte(c),byte(b),byte(a) - end + [4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(a),byte(b),byte(c),byte(d) + end + end, + [3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(a),byte(b),byte(c) + end + end, + [2]=function(f) + local a,b=f:read(1,1) + if b then + return byte(a),byte(b) + end + end, + [1]=function (f) + local a=f:read(1) + if a then + return byte(a) + end + end, + [-2]=function (f) + local a,b=f:read(1,1) + if b then + return byte(b),byte(a) + end + end, + [-3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(c),byte(b),byte(a) + end + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(d),byte(c),byte(b),byte(a) end + end } function io.bytes(f,n) - if f then - return nextbyte[n or 1],f - else - return nil,nil - end + if f then + return nextbyte[n or 1],f + else + return nil,nil + end end function io.ask(question,default,options) - while true do - write(question) - if options then - write(format(" [%s]",concat(options,"|"))) - end - if default then - write(format(" [%s]",default)) - end - write(format(" ")) - flush() - local answer=read() - answer=gsub(answer,"^%s*(.*)%s*$","%1") - if answer=="" and default then - return default - elseif not options then - return answer - else - for k=1,#options do - if options[k]==answer then - return answer - end - end - local pattern="^"..answer - for k=1,#options do - local v=options[k] - if find(v,pattern) then - return v - end - end + while true do + write(question) + if options then + write(format(" [%s]",concat(options,"|"))) + end + if default then + write(format(" [%s]",default)) + end + write(format(" ")) + flush() + local answer=read() + answer=gsub(answer,"^%s*(.*)%s*$","%1") + if answer=="" and default then + return default + elseif not options then + return answer + else + for k=1,#options do + if options[k]==answer then + return answer end + end + local pattern="^"..answer + for k=1,#options do + local v=options[k] + if find(v,pattern) then + return v + end + end end + end end local function readnumber(f,n,m) - if m then - f:seek("set",n) - n=m - end - if n==1 then - return byte(f:read(1)) - elseif n==2 then - local a,b=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==3 then - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==4 then - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==8 then - local a,b=readnumber(f,4),readnumber(f,4) - return 0x100*a+b - elseif n==12 then - local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) - return 0x10000*a+0x100*b+c - elseif n==-2 then - local b,a=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==-3 then - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==-4 then - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==-8 then - local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) - return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h - else - return 0 - end + if m then + f:seek("set",n) + n=m + end + if n==1 then + return byte(f:read(1)) + elseif n==2 then + local a,b=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==3 then + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==4 then + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==8 then + local a,b=readnumber(f,4),readnumber(f,4) + return 0x100*a+b + elseif n==12 then + local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) + return 0x10000*a+0x100*b+c + elseif n==-2 then + local b,a=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==-3 then + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==-4 then + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==-8 then + local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) + return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h + else + return 0 + end end io.readnumber=readnumber function io.readstring(f,n,m) - if m then - f:seek("set",n) - n=m - end - local str=gsub(f:read(n),"\000","") - return str + if m then + f:seek("set",n) + n=m + end + local str=gsub(f:read(n),"\000","") + return str end @@ -3364,14 +3565,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-number"] = package.loaded["l-number"] or true --- original size: 5645, stripped down to: 2253 +-- original size: 5720, stripped down to: 2176 if not modules then modules={} end modules ['l-number']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tostring,tonumber=tostring,tonumber local format,floor,match,rep=string.format,math.floor,string.match,string.rep @@ -3381,99 +3582,107 @@ local floor=math.floor number=number or {} local number=number if bit32 then - local bextract=bit32.extract - local t={ - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - } - function number.tobitstring(b,m) - local n=32 - for i=0,31 do - local v=bextract(b,i) - local k=32-i - if v==1 then - n=k - t[k]="1" - else - t[k]="0" - end - end - if m then - m=33-m*8 - if m<1 then - m=1 - end - return concat(t,"",m) - elseif n<8 then - return concat(t) - elseif n<16 then - return concat(t,"",9) - elseif n<24 then - return concat(t,"",17) - else - return concat(t,"",25) - end + local bextract=bit32.extract + local t={ + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + } + function number.tobitstring(b,m,w) + if not w then + w=32 + end + local n=w + for i=0,w-1 do + local v=bextract(b,i) + local k=w-i + if v==1 then + n=k + t[k]="1" + else + t[k]="0" + end + end + if w then + return concat(t,"",1,w) + elseif m then + m=33-m*8 + if m<1 then + m=1 + end + return concat(t,"",1,m) + elseif n<8 then + return concat(t) + elseif n<16 then + return concat(t,"",9) + elseif n<24 then + return concat(t,"",17) + else + return concat(t,"",25) end + end else - function number.tobitstring(n,m) - if n>0 then - local t={} - while n>0 do - insert(t,1,n%2>0 and 1 or 0) - n=floor(n/2) - end - local nn=8-#t%8 - if nn>0 and nn<8 then - for i=1,nn do - insert(t,1,0) - end - end - if m then - m=m*8-#t - if m>0 then - insert(t,1,rep("0",m)) - end - end - return concat(t) - elseif m then - rep("00000000",m) - else - return "00000000" + function number.tobitstring(n,m) + if n>0 then + local t={} + while n>0 do + insert(t,1,n%2>0 and 1 or 0) + n=floor(n/2) + end + local nn=8-#t%8 + if nn>0 and nn<8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m=m*8-#t + if m>0 then + insert(t,1,rep("0",m)) end + end + return concat(t) + elseif m then + rep("00000000",m) + else + return "00000000" end + end end function number.valid(str,default) - return tonumber(str) or default or nil + return tonumber(str) or default or nil end function number.toevenhex(n) - local s=format("%X",n) - if #s%2==0 then - return s - else - return "0"..s - end + local s=format("%X",n) + if #s%2==0 then + return s + else + return "0"..s + end end function number.bytetodecimal(b) - local d=floor(b*100/255+0.5) - if d>100 then - return 100 - elseif d<-100 then - return -100 - else - return d - end + local d=floor(b*100/255+0.5) + if d>100 then + return 100 + elseif d<-100 then + return -100 + else + return d + end end function number.decimaltobyte(d) - local b=floor(d*255/100+0.5) - if b>255 then - return 255 - elseif b<-255 then - return -255 - else - return b - end + local b=floor(d*255/100+0.5) + if b>255 then + return 255 + elseif b<-255 then + return -255 + else + return b + end +end +function number.idiv(i,d) + return floor(i/d) end @@ -3483,14 +3692,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-set"] = package.loaded["l-set"] or true --- original size: 1923, stripped down to: 1133 +-- original size: 1923, stripped down to: 1044 if not modules then modules={} end modules ['l-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } set=set or {} local nums={} @@ -3499,54 +3708,54 @@ local concat=table.concat local next,type=next,type set.create=table.tohash function set.tonumber(t) - if next(t) then - local s="" - for k,v in next,t do - if v then - s=s.." "..k - end - end - local n=nums[s] - if not n then - n=#tabs+1 - tabs[n]=t - nums[s]=n - end - return n - else - return 0 + if next(t) then + local s="" + for k,v in next,t do + if v then + s=s.." "..k + end end + local n=nums[s] + if not n then + n=#tabs+1 + tabs[n]=t + nums[s]=n + end + return n + else + return 0 + end end function set.totable(n) - if n==0 then - return {} - else - return tabs[n] or {} - end + if n==0 then + return {} + else + return tabs[n] or {} + end end function set.tolist(n) - if n==0 or not tabs[n] then - return "" - else - local t,n={},0 - for k,v in next,tabs[n] do - if v then - n=n+1 - t[n]=k - end - end - return concat(t," ") + if n==0 or not tabs[n] then + return "" + else + local t,n={},0 + for k,v in next,tabs[n] do + if v then + n=n+1 + t[n]=k + end end + return concat(t," ") + end end function set.contains(n,s) - if type(n)=="table" then - return n[s] - elseif n==0 then - return false - else - local t=tabs[n] - return t and t[s] - end + if type(n)=="table" then + return n[s] + elseif n==0 then + return false + else + local t=tabs[n] + return t and t[s] + end end @@ -3556,14 +3765,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-os"] = package.loaded["l-os"] or true --- original size: 16268, stripped down to: 9246 +-- original size: 19347, stripped down to: 10258 if not modules then modules={} end modules ['l-os']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local os=os local date,time=os.date,os.time @@ -3571,357 +3780,434 @@ local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string local concat=table.concat local random,ceil,randomseed=math.random,math.ceil,math.randomseed local rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring=rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring -math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) -randomseed(math.initialseed) -if not os.__getenv__ then - os.__getenv__=os.getenv - os.__setenv__=os.setenv - if os.env then - local osgetenv=os.getenv - local ossetenv=os.setenv - local osenv=os.env local _=osenv.PATH - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - if type(v)=="table" then - v=concat(v,";") - end - ossetenv(K,v) - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v - end +do + local selfdir=os.selfdir + if selfdir=="" then + selfdir=nil + end + if not selfdir then + if arg then + for i=1,#arg do + local a=arg[i] + if find(a,"^%-%-[c:]*texmfbinpath=") then + selfdir=gsub(a,"^.-=","") + break end - else - local ossetenv=os.setenv - local osgetenv=os.getenv - local osenv={} - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v + end + end + if not selfdir then + selfdir=os.selfbin or "luatex" + if find(selfdir,"[/\\]") then + selfdir=gsub(selfdir,"[/\\][^/\\]*$","") + elseif os.getenv then + local path=os.getenv("PATH") + local name=gsub(selfdir,"^.*[/\\][^/\\]","") + local patt="[^:]+" + if os.type=="windows" then + patt="[^;]+" + name=name..".exe" + end + local isfile + if lfs then + local attributes=lfs.attributes + isfile=function(name) + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil + end + else + local open=io.open + isfile=function(name) + local f=open(name) + if f then + f:close() + return true end + end end - local function __index(t,k) - return os.getenv(k) - end - local function __newindex(t,k,v) - os.setenv(k,v) + for p in gmatch(path,patt) do + if isfile(p.."/"..name) then + selfdir=p + break + end end - os.env={} - setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end + os.selfdir=selfdir or "." + end +end +math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) +randomseed(math.initialseed) +if not os.__getenv__ then + os.__getenv__=os.getenv + os.__setenv__=os.setenv + if os.env then + local osgetenv=os.getenv + local ossetenv=os.setenv + local osenv=os.env local _=osenv.PATH + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + if type(v)=="table" then + v=concat(v,";") + end + ossetenv(K,v) + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + else + local ossetenv=os.setenv + local osgetenv=os.getenv + local osenv={} + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + local function __index(t,k) + return os.getenv(k) + end + local function __newindex(t,k,v) + os.setenv(k,v) + end + os.env={} + setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end local execute=os.execute local iopopen=io.popen local function resultof(command) - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - else - return "" - end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + else + return "" + end end os.resultof=resultof function os.pipeto(command) - return iopopen(command,"w") + return iopopen(command,"w") end if not io.fileseparator then - if find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" - else - io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" - end + if find(os.getenv("PATH"),";",1,true) then + io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" + else + io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" + end end os.type=os.type or (io.pathseparator==";" and "windows") or "unix" -os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" +os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" if os.type=="windows" then - os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } + os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } else - os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } + os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } end local launchers={ - windows="start %s", - macosx="open %s", - unix="$BROWSER %s &> /dev/null &", + windows="start %s", + macosx="open %s", + unix="xdg-open %s &> /dev/null &", } function os.launch(str) - execute(format(launchers[os.name] or launchers.unix,str)) + execute(format(launchers[os.name] or launchers.unix,str)) end if not os.times then - function os.times() - return { - utime=os.gettimeofday(), - stime=0, - cutime=0, - cstime=0, - } - end + function os.times() + return { + utime=os.gettimeofday(), + stime=0, + cutime=0, + cstime=0, + } + end end local gettimeofday=os.gettimeofday or os.clock os.gettimeofday=gettimeofday local startuptime=gettimeofday() function os.runtime() - return gettimeofday()-startuptime + return gettimeofday()-startuptime end 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 + local r=resolvers[k] + return r and r(t,k) or nil end }) local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or "" if platform~="" then - os.platform=platform + os.platform=platform elseif os.type=="windows" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or "" - if find(architecture,"AMD64",1,true) then - platform="win64" - else - platform="mswin" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("PROCESSOR_ARCHITECTURE") or "" + local platform="" + if find(architecture,"AMD64",1,true) then + platform="win64" + else + platform="mswin" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="linux" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="linux-64" - elseif find(architecture,"ppc",1,true) then - platform="linux-ppc" - else - platform="linux" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform=os.getenv("MTX_PLATFORM") or "" + local musl=find(os.selfdir or "","linuxmusl") + if platform~="" then + elseif find(architecture,"x86_64",1,true) then + platform=musl and "linuxmusl" or "linux-64" + elseif find(architecture,"ppc",1,true) then + platform="linux-ppc" + else + platform=musl and "linuxmusl" or "linux" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="macosx" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("echo $HOSTTYPE") or "" - if architecture=="" then - platform="osx-intel" - elseif find(architecture,"i386",1,true) then - platform="osx-intel" - elseif find(architecture,"x86_64",1,true) then - platform="osx-64" - else - platform="osx-ppc" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=resultof("echo $HOSTTYPE") or "" + local platform="" + if architecture=="" then + platform="osx-intel" + elseif find(architecture,"i386",1,true) then + platform="osx-intel" + elseif find(architecture,"x86_64",1,true) then + platform="osx-64" + else + platform="osx-ppc" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="sunos" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"sparc",1,true) then - platform="solaris-sparc" - else - platform="solaris-intel" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"sparc",1,true) then + platform="solaris-sparc" + else + platform="solaris-intel" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="freebsd" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"amd64",1,true) then - platform="freebsd-amd64" - else - platform="freebsd" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"amd64",1,true) then + platform="freebsd-amd64" + else + platform="freebsd" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="kfreebsd" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="kfreebsd-amd64" - else - platform="kfreebsd-i386" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform="" + if find(architecture,"x86_64",1,true) then + platform="kfreebsd-amd64" + else + platform="kfreebsd-i386" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end else - function resolvers.platform(t,k) - local platform="linux" - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local platform="linux" + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end end os.newline=name=="windows" and "\013\010" or "\010" function resolvers.bits(t,k) - local bits=find(os.platform,"64",1,true) and 64 or 32 - os.bits=bits - return bits + 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", - random(0xFFFF),random(0xFFFF), - random(0x0FFF), - t[ceil(random(4))] or 8,random(0x0FFF), - random(0xFFFF), - random(0xFFFF),random(0xFFFF),random(0xFFFF) - ) + return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", + random(0xFFFF),random(0xFFFF), + random(0x0FFF), + t[ceil(random(4))] or 8,random(0x0FFF), + random(0xFFFF), + random(0xFFFF),random(0xFFFF),random(0xFFFF) + ) end local d function os.timezone(delta) - d=d or tonumber(tonumber(date("%H")-date("!%H"))) - if delta then - if d>0 then - return format("+%02i:00",d) - else - return format("-%02i:00",-d) - end + d=d or tonumber(tonumber(date("%H")-date("!%H"))) + if delta then + if d>0 then + return format("+%02i:00",d) else - return 1 + return format("-%02i:00",-d) end + else + return 1 + end 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=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=format(timeformat,date(dateformat)) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=format(timeformat,date(dateformat)) + end + return lastdate end local dateformat="%Y-%m-%d %H:%M:%S" local lasttime=nil local lastdate=nil function os.localtime(t,default) - t=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=date(dateformat,t) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=date(dateformat,t) + end + return lastdate end function os.converttime(t,default) - local t=tonumber(t) - if t and t>0 then - return date(dateformat,t) - else - return default or "-" - end + local t=tonumber(t) + if t and t>0 then + return date(dateformat,t) + else + return default or "-" + end end local memory={} local function which(filename) - local fullname=memory[filename] - if fullname==nil then - local suffix=file.suffix(filename) - local suffixes=suffix=="" and os.binsuffixes or { suffix } - for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do - local df=file.join(directory,filename) - for i=1,#suffixes do - local dfs=file.addsuffix(df,suffixes[i]) - if io.exists(dfs) then - fullname=dfs - break - end - end - end - if not fullname then - fullname=false + local fullname=memory[filename] + if fullname==nil then + local suffix=file.suffix(filename) + local suffixes=suffix=="" and os.binsuffixes or { suffix } + for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local df=file.join(directory,filename) + for i=1,#suffixes do + local dfs=file.addsuffix(df,suffixes[i]) + if io.exists(dfs) then + fullname=dfs + break end - memory[filename]=fullname + end end - return fullname + if not fullname then + fullname=false + end + memory[filename]=fullname + end + return fullname end os.which=which os.where=which function os.today() - return date("!*t") + return date("!*t") end function os.now() - return date("!%Y-%m-%d %H:%M:%S") + return date("!%Y-%m-%d %H:%M:%S") end if not os.sleep then - local socket=socket - function os.sleep(n) - if not socket then - socket=require("socket") - end - socket.sleep(n) + local socket=socket + function os.sleep(n) + if not socket then + socket=require("socket") end + socket.sleep(n) + end end local function isleapyear(year) - return (year%4==0) and (year%100~=0 or year%400==0) + return (year%4==0) and (year%100~=0 or year%400==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 + 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 + 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 + 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 +local osexit=os.exit +local exitcode=nil +function os.setexitcode(code) + exitcode=code +end +function os.exit(c) + if exitcode~=nil then + return osexit(exitcode) + end + if c~=nil then + return osexit(c) + end + return osexit() end @@ -3931,19 +4217,19 @@ do -- create closure to overcome 200 locals limit package.loaded["l-file"] = package.loaded["l-file"] or true --- original size: 21616, stripped down to: 10359 +-- original size: 21804, stripped down to: 9980 if not modules then modules={} end modules ['l-file']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } file=file or {} local file=file if not lfs then - lfs=optionalrequire("lfs") + lfs=optionalrequire("lfs") end local insert,concat=table.insert,table.concat local match,find,gmatch=string.match,string.find,string.gmatch @@ -3951,24 +4237,22 @@ local lpegmatch=lpeg.match local getcurrentdir,attributes=lfs.currentdir,lfs.attributes local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct -local tricky=S("/\\")*P(-1) local attributes=lfs.attributes -if sandbox then - sandbox.redefine(lfs.isfile,"lfs.isfile") - sandbox.redefine(lfs.isdir,"lfs.isdir") -end function lfs.isdir(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end + return attributes(name,"mode")=="directory" end function lfs.isfile(name) - return attributes(name,"mode")=="file" + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil end function lfs.isfound(name) - return attributes(name,"mode")=="file" and name or nil + local a=attributes(name,"mode") + return (a=="file" or a=="link") and name or nil +end +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir,"lfs.isdir") + sandbox.redefine(lfs.isfound,"lfs.isfound") end local colon=P(":") local period=P(".") @@ -3982,27 +4266,27 @@ local name=noperiod^1 local suffix=period/""*(1-period-slashes)^1*-1 local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) local function pathpart(name,default) - return name and lpegmatch(pattern,name) or default or "" + return name and lpegmatch(pattern,name) or default or "" end local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1 local function basename(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0 local function nameonly(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1 local function suffixonly(name) - return name and lpegmatch(pattern,name) or "" + return name and lpegmatch(pattern,name) or "" end local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("") local function suffixesonly(name) - if name then - return lpegmatch(pattern,name) - else - return "" - end + if name then + return lpegmatch(pattern,name) + else + return "" + end end file.pathpart=pathpart file.basename=basename @@ -4011,7 +4295,7 @@ file.suffixonly=suffixonly file.suffix=suffixonly file.suffixesonly=suffixesonly file.suffixes=suffixesonly -file.dirname=pathpart +file.dirname=pathpart file.extname=suffixonly local drive=C(R("az","AZ"))*colon local path=C((noslashes^0*slashes)^0) @@ -4027,142 +4311,142 @@ local pattern_b=path*base*suffix local pattern_c=C(drive*path)*C(base*suffix) local pattern_d=path*rest function file.splitname(str,splitdrive) - if not str then - elseif splitdrive then - return lpegmatch(pattern_a,str) - else - return lpegmatch(pattern_b,str) - end + if not str then + elseif splitdrive then + return lpegmatch(pattern_a,str) + else + return lpegmatch(pattern_b,str) + end end function file.splitbase(str) - if str then - return lpegmatch(pattern_d,str) - else - return "",str - end + if str then + return lpegmatch(pattern_d,str) + else + return "",str + end end function file.nametotable(str,splitdrive) - if str then - local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) - if splitdrive then - return { - path=path, - drive=drive, - subpath=subpath, - name=name, - base=base, - suffix=suffix, - } - else - return { - path=path, - name=name, - base=base, - suffix=suffix, - } - end + if str then + local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) + if splitdrive then + return { + path=path, + drive=drive, + subpath=subpath, + name=name, + base=base, + suffix=suffix, + } + else + return { + path=path, + name=name, + base=base, + suffix=suffix, + } end + end end local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1) function file.removesuffix(name) - return name and lpegmatch(pattern,name) + return name and lpegmatch(pattern,name) end local suffix=period/""*(1-period-slashes)^1*-1 local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix) function file.addsuffix(filename,suffix,criterium) - if not filename or not suffix or suffix=="" then - return filename - elseif criterium==true then - return filename.."."..suffix - elseif not criterium then - local n,s=lpegmatch(pattern,filename) - if not s or s=="" then - return filename.."."..suffix - else + if not filename or not suffix or suffix=="" then + return filename + elseif criterium==true then + return filename.."."..suffix + elseif not criterium then + local n,s=lpegmatch(pattern,filename) + if not s or s=="" then + return filename.."."..suffix + else + return filename + end + else + local n,s=lpegmatch(pattern,filename) + if s and s~="" then + local t=type(criterium) + if t=="table" then + for i=1,#criterium do + if s==criterium[i] then return filename + end end - else - local n,s=lpegmatch(pattern,filename) - if s and s~="" then - local t=type(criterium) - if t=="table" then - for i=1,#criterium do - if s==criterium[i] then - return filename - end - end - elseif t=="string" then - if s==criterium then - return filename - end - end + elseif t=="string" then + if s==criterium then + return filename end - return (n or filename).."."..suffix + end end + return (n or filename).."."..suffix + end end local suffix=period*(1-period-slashes)^1*-1 local pattern=Cs((1-suffix)^0) function file.replacesuffix(name,suffix) - if name and suffix and suffix~="" then - return lpegmatch(pattern,name).."."..suffix - else - return name - end + if name and suffix and suffix~="" then + return lpegmatch(pattern,name).."."..suffix + else + return name + end end local reslasher=lpeg.replacer(P("\\"),"/") function file.reslash(str) - return str and lpegmatch(reslasher,str) + return str and lpegmatch(reslasher,str) end function file.is_writable(name) - if not name then - elseif lfs.isdir(name) then - name=name.."/m_t_x_t_e_s_t.tmp" - local f=io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f=io.open(name,"ab") - if f then - f:close() - return true - end - else - local f=io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true - end + if not name then + elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true end - return false + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end + end + return false end local readable=P("r")*Cc(true) function file.is_readable(name) - if name then - local a=attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else - return false - end + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end file.isreadable=file.is_readable file.iswritable=file.is_writable function file.size(name) - if name then - local a=attributes(name) - return a and a.size or 0 - else - return 0 - end + if name then + local a=attributes(name) + return a and a.size or 0 + else + return 0 + end end function file.splitpath(str,separator) - return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) + return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) end function file.joinpath(tab,separator) - return tab and concat(tab,separator or io.pathseparator) + return tab and concat(tab,separator or io.pathseparator) end local someslash=S("\\/") local stripper=Cs(P(fwslash)^0/""*reslasher) @@ -4172,30 +4456,30 @@ local hasroot=fwslash^1 local reslasher=lpeg.replacer(S("\\/"),"/") local deslasher=lpeg.replacer(S("\\/")^1,"/") function file.join(one,two,three,...) - if not two then - return one=="" and one or lpegmatch(reslasher,one) - end - if one=="" then - return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) - end - if lpegmatch(isnetwork,one) then - local one=lpegmatch(reslasher,one) - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return one..two - else - return one.."/"..two - end - elseif lpegmatch(isroot,one) then - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return two - else - return "/"..two - end - else - return lpegmatch(deslasher,concat({ one,two,three,... },"/")) - end + if not two then + return one=="" and one or lpegmatch(reslasher,one) + end + if one=="" then + return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) + end + if lpegmatch(isnetwork,one) then + local one=lpegmatch(reslasher,one) + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return one..two + else + return one.."/"..two + end + elseif lpegmatch(isroot,one) then + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return two + else + return "/"..two + end + else + return lpegmatch(deslasher,concat({ one,two,three,... },"/")) + end end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec @@ -4205,56 +4489,56 @@ 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 - return - end - if anchor==true and not lpegmatch(anchors,str) then - str=getcurrentdir().."/"..str - end - if str=="" or str=="." then - return "." - elseif lpegmatch(untouched,str) then - return lpegmatch(reslasher,str) - end - local starter,oldelements=lpegmatch(splitstarter,str) - local newelements={} - local i=#oldelements - while i>0 do - local element=oldelements[i] - if element=='.' then - elseif element=='..' then - local n=i-1 - while n>0 do - local element=oldelements[n] - if element~='..' and element~='.' then - oldelements[n]='.' - break - else - n=n-1 - end - end - if n<1 then - insert(newelements,1,'..') - end - elseif element~="" then - insert(newelements,1,element) - end - i=i-1 - end - if #newelements==0 then - return starter or "." - elseif starter then - return starter..concat(newelements,'/') - elseif lpegmatch(absolute,str) then - return "/"..concat(newelements,'/') - else - newelements=concat(newelements,'/') - if anchor=="." and find(str,"^%./") then - return "./"..newelements + if not str then + return + end + if anchor==true and not lpegmatch(anchors,str) then + str=getcurrentdir().."/"..str + end + if str=="" or str=="." then + return "." + elseif lpegmatch(untouched,str) then + return lpegmatch(reslasher,str) + end + local starter,oldelements=lpegmatch(splitstarter,str) + local newelements={} + local i=#oldelements + while i>0 do + local element=oldelements[i] + if element=='.' then + elseif element=='..' then + local n=i-1 + while n>0 do + local element=oldelements[n] + if element~='..' and element~='.' then + oldelements[n]='.' + break else - return newelements + n=n-1 end - end + end + if n<1 then + insert(newelements,1,'..') + end + elseif element~="" then + insert(newelements,1,element) + end + i=i-1 + end + if #newelements==0 then + return starter or "." + elseif starter then + return starter..concat(newelements,'/') + elseif lpegmatch(absolute,str) then + return "/"..concat(newelements,'/') + else + newelements=concat(newelements,'/') + if anchor=="." and find(str,"^%./") then + return "./"..newelements + else + return newelements + end + end end local validchars=R("az","09","AZ","--","..") local pattern_a=lpeg.replacer(1-validchars) @@ -4262,26 +4546,26 @@ local pattern_a=Cs((validchars+P(1)/"-")^1) local whatever=P("-")^0/"" local pattern_b=Cs(whatever*(1-whatever*-1)^1) function file.robustname(str,strict) - if str then - str=lpegmatch(pattern_a,str) or str - if strict then - return lpegmatch(pattern_b,str) or str - else - return str - end + if str then + str=lpegmatch(pattern_a,str) or str + if strict then + return lpegmatch(pattern_b,str) or str + else + return str end + end end local loaddata=io.loaddata local savedata=io.savedata file.readdata=loaddata file.savedata=savedata function file.copy(oldname,newname) - if oldname and newname then - local data=loaddata(oldname) - if data and data~="" then - savedata(newname,data) - end + if oldname and newname then + local data=loaddata(oldname) + if data and data~="" then + savedata(newname,data) end + end end local letter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4290,40 +4574,44 @@ local rootbased=fwslash+letter*colon lpeg.patterns.qualified=qualified lpeg.patterns.rootbased=rootbased function file.is_qualified_path(filename) - return filename and lpegmatch(qualified,filename)~=nil + return filename and lpegmatch(qualified,filename)~=nil end function file.is_rootbased_path(filename) - return filename and lpegmatch(rootbased,filename)~=nil + return filename and lpegmatch(rootbased,filename)~=nil end function file.strip(name,dir) - if name then - local b,a=match(name,"^(.-)"..dir.."(.*)$") - return a~="" and a or name - end + if name then + local b,a=match(name,"^(.-)"..dir.."(.*)$") + return a~="" and a or name + end end function lfs.mkdirs(path) - local full="" - for sub in gmatch(path,"(/*[^\\/]+)") do - full=full..sub - lfs.mkdir(full) - end + local full="" + for sub in gmatch(path,"(/*[^\\/]+)") do + full=full..sub + lfs.mkdir(full) + end end function file.withinbase(path) - local l=0 - if not find(path,"^/") then - path="/"..path + local l=0 + if not find(path,"^/") then + path="/"..path + end + for dir in gmatch(path,"/([^/]+)") do + if dir==".." then + l=l-1 + elseif dir~="." then + l=l+1 end - for dir in gmatch(path,"/([^/]+)") do - if dir==".." then - l=l-1 - elseif dir~="." then - l=l+1 - end - if l<0 then - return false - end + if l<0 then + return false end - return true + end + return true +end +local symlinkattributes=lfs.symlinkattributes +function lfs.readlink(name) + return symlinkattributes(name,"target") or nil end @@ -4333,51 +4621,51 @@ do -- create closure to overcome 200 locals limit package.loaded["l-gzip"] = package.loaded["l-gzip"] or true --- original size: 1211, stripped down to: 1002 +-- original size: 1211, stripped down to: 951 if not modules then modules={} end modules ['l-gzip']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not gzip then - return + return end local suffix,suffixes=file.suffix,file.suffixes function gzip.load(filename) - local f=io.open(filename,"rb") - if not f then - elseif suffix(filename)=="gz" then - f:close() - local g=gzip.open(filename,"rb") - if g then - local str=g:read("*all") - g:close() - return str - end - else - local str=f:read("*all") - f:close() - return str - end + local f=io.open(filename,"rb") + if not f then + elseif suffix(filename)=="gz" then + f:close() + local g=gzip.open(filename,"rb") + if g then + local str=g:read("*all") + g:close() + return str + end + else + local str=f:read("*all") + f:close() + return str + end end function gzip.save(filename,data) - if suffix(filename)~="gz" then - filename=filename..".gz" - end - local f=io.open(filename,"wb") - if f then - local s=zlib.compress(data or "",9,nil,15+16) - f:write(s) - f:close() - return #s - end + if suffix(filename)~="gz" then + filename=filename..".gz" + end + local f=io.open(filename,"wb") + if f then + local s=zlib.compress(data or "",9,nil,15+16) + f:write(s) + f:close() + return #s + end end function gzip.suffix(filename) - local suffix,extra=suffixes(filename) - local gzipped=extra=="gz" - return suffix,gzipped + local suffix,extra=suffixes(filename) + local gzipped=extra=="gz" + return suffix,gzipped end @@ -4387,87 +4675,119 @@ do -- create closure to overcome 200 locals limit package.loaded["l-md5"] = package.loaded["l-md5"] or true --- original size: 3309, stripped down to: 2314 +-- original size: 3309, stripped down to: 2218 if not modules then modules={} end modules ['l-md5']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not md5 then - md5=optionalrequire("md5") + md5=optionalrequire("md5") end if not md5 then - md5={ - sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, - sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, - } + md5={ + sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, + sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, + } end local md5,file=md5,file local gsub=string.gsub do - local patterns=lpeg and lpeg.patterns - if patterns then - local bytestoHEX=patterns.bytestoHEX - local bytestohex=patterns.bytestohex - local bytestodec=patterns.bytestodec - local lpegmatch=lpeg.match - local md5sum=md5.sum - if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end - if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end - if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end - md5.sumhexa=md5.hex - md5.sumHEXA=md5.HEX - end + local patterns=lpeg and lpeg.patterns + if patterns then + local bytestoHEX=patterns.bytestoHEX + local bytestohex=patterns.bytestohex + local bytestodec=patterns.bytestodec + local lpegmatch=lpeg.match + local md5sum=md5.sum + if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end + if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end + if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end + md5.sumhexa=md5.hex + md5.sumHEXA=md5.HEX + end end function file.needsupdating(oldname,newname,threshold) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime then - local newtime=lfs.attributes(newname,"modification") - if not newtime then - return true - elseif newtime>=oldtime then - return false - elseif oldtime-newtime<(threshold or 1) then - return false - else - return true - end - else - return false - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime then + local newtime=lfs.attributes(newname,"modification") + if not newtime then + return true + elseif newtime>=oldtime then + return false + elseif oldtime-newtime<(threshold or 1) then + return false + else + return true + end + else + return false + end end file.needs_updating=file.needsupdating function file.syncmtimes(oldname,newname) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime and lfs.isfile(newname) then - lfs.touch(newname,oldtime,oldtime) - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) + end end function file.checksum(name) - if md5 then - local data=io.loaddata(name) - if data then - return md5.HEX(data) - end + if md5 then + local data=io.loaddata(name) + if data then + return md5.HEX(data) end - return nil + end + return nil end function file.loadchecksum(name) - if md5 then - local data=io.loaddata(name..".md5") - return data and (gsub(data,"%s","")) - end - return nil + if md5 then + local data=io.loaddata(name..".md5") + return data and (gsub(data,"%s","")) + end + return nil end function file.savechecksum(name,checksum) - if not checksum then checksum=file.checksum(name) end - if checksum then - io.savedata(name..".md5",checksum) - return checksum - end - return nil + if not checksum then checksum=file.checksum(name) end + if checksum then + io.savedata(name..".md5",checksum) + return checksum + end + return nil +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["l-sha"] = package.loaded["l-sha"] or true + +-- original size: 1085, stripped down to: 969 + +if not modules then modules={} end modules ['l-sha']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +if sha2 then + local lpegmatch=lpeg.match + local lpegpatterns=lpeg.patterns + local bytestohex=lpegpatterns.bytestohex + local bytestoHEX=lpegpatterns.bytestoHEX + local digest256=sha2.digest256 + local digest384=sha2.digest384 + local digest512=sha2.digest512 + sha2.hash256=function(str) return lpegmatch(bytestohex,digest256(str)) end + sha2.hash384=function(str) return lpegmatch(bytestohex,digest384(str)) end + sha2.hash512=function(str) return lpegmatch(bytestohex,digest512(str)) end + sha2.HASH256=function(str) return lpegmatch(bytestoHEX,digest256(str)) end + sha2.HASH384=function(str) return lpegmatch(bytestoHEX,digest384(str)) end + sha2.HASH512=function(str) return lpegmatch(bytestoHEX,digest512(str)) end end @@ -4477,14 +4797,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-url"] = package.loaded["l-url"] or true --- original size: 14755, stripped down to: 7236 +-- original size: 14755, stripped down to: 6981 if not modules then modules={} end modules ['l-url']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local char,format,byte=string.char,string.format,string.byte local concat=table.concat @@ -4497,14 +4817,14 @@ local url=url local unescapes={} local escapes={} setmetatable(unescapes,{ __index=function(t,k) - local v=char(tonumber(k,16)) - t[k]=v - return v + local v=char(tonumber(k,16)) + t[k]=v + return v end }) setmetatable(escapes,{ __index=function(t,k) - local v=format("%%%02X",byte(k)) - t[k]=v - return v + local v=format("%%%02X",byte(k)) + t[k]=v + return v end }) local colon=P(":") local qmark=P("?") @@ -4523,21 +4843,21 @@ local escaped=(plus/" ")+escapedchar local noslash=P("/")/"" local plustospace=P("+")/" " local decoder=Cs(( - plustospace+escapedchar+P("\r\n")/"\n"+P(1) - )^0 ) + plustospace+escapedchar+P("\r\n")/"\n"+P(1) + )^0 ) local encoder=Cs(( - R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar - )^0 ) + R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar + )^0 ) lpegpatterns.urldecoder=decoder lpegpatterns.urlencoder=encoder -function url.decode (str) return str and lpegmatch(decoder,str) or str end -function url.encode (str) return str and lpegmatch(encoder,str) or str end +function url.decode (str) return str and lpegmatch(decoder,str) or str end +function url.encode (str) return str and lpegmatch(encoder,str) or str end function url.unescape(str) return str and lpegmatch(unescaper,str) or str end local schemestr=Cs((escaped+(1-colon-slash-qmark-hash))^2) local authoritystr=Cs((escaped+(1- slash-qmark-hash))^0) -local pathstr=Cs((escaped+(1- qmark-hash))^0) -local querystr=Cs(((1- hash))^0) -local fragmentstr=Cs((escaped+(1- endofstring))^0) +local pathstr=Cs((escaped+(1- qmark-hash))^0) +local querystr=Cs(((1- hash))^0) +local fragmentstr=Cs((escaped+(1- endofstring))^0) local scheme=schemestr*colon+nothing local authority=slash*slash*authoritystr+nothing local path=slash*pathstr+nothing @@ -4555,19 +4875,19 @@ lpegpatterns.urlescaper=escaper lpegpatterns.urlunescaper=unescaper lpegpatterns.urlgetcleaner=getcleaner function url.unescapeget(str) - return lpegmatch(getcleaner,str) + return lpegmatch(getcleaner,str) end local function split(str) - return (type(str)=="string" and lpegmatch(parser,str)) or str + return (type(str)=="string" and lpegmatch(parser,str)) or str end local isscheme=schemestr*colon*slash*slash local function hasscheme(str) - if str then - local scheme=lpegmatch(isscheme,str) - return scheme~="" and scheme or false - else - return false - end + if str then + local scheme=lpegmatch(isscheme,str) + return scheme~="" and scheme or false + else + return false + end end local rootletter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4577,161 +4897,161 @@ local barswapper=replacer("|",":") local backslashswapper=replacer("\\","/") local equal=P("=") local amp=P("&") -local key=Cs(((plustospace+escapedchar+1)-equal )^0) +local key=Cs(((plustospace+escapedchar+1)-equal )^0) local value=Cs(((plustospace+escapedchar+1)-amp-endofstring)^0) local splitquery=Cf (Ct("")*P { "sequence", - sequence=V("pair")*(amp*V("pair"))^0, - pair=Cg(key*equal*value), + sequence=V("pair")*(amp*V("pair"))^0, + pair=Cg(key*equal*value), },rawset) local userpart=(1-atsign-colon)^1 local serverpart=(1-colon)^1 local splitauthority=((Cs(userpart)*colon*Cs(userpart)+Cs(userpart)*Cc(nil))*atsign+Cc(nil)*Cc(nil))*Cs(serverpart)*(colon*(serverpart/tonumber)+Cc(nil)) local function hashed(str) - if not str or str=="" then - return { - scheme="invalid", - original=str, - } - end - local detailed=split(str) - local rawscheme="" - local rawquery="" - local somescheme=false - local somequery=false - if detailed then - rawscheme=detailed[1] - rawquery=detailed[4] - somescheme=rawscheme~="" - somequery=rawquery~="" - end - if not somescheme and not somequery then - return { - scheme="file", - authority="", - path=str, - query="", - fragment="", - original=str, - noscheme=true, - filename=str, - } - end - local authority=detailed[2] - local path=detailed[3] - local filename - local username - local password - local host - local port - if authority~="" then - username,password,host,port=lpegmatch(splitauthority,authority) - end - if authority=="" then - filename=path - elseif path=="" then - filename="" - else - filename=authority.."/"..path - end + if not str or str=="" then return { - scheme=rawscheme, - authority=authority, - path=path, - query=lpegmatch(unescaper,rawquery), - queries=lpegmatch(splitquery,rawquery), - fragment=detailed[5], - original=str, - noscheme=false, - filename=filename, - host=host, - port=port, + scheme="invalid", + original=str, } + end + local detailed=split(str) + local rawscheme="" + local rawquery="" + local somescheme=false + local somequery=false + if detailed then + rawscheme=detailed[1] + rawquery=detailed[4] + somescheme=rawscheme~="" + somequery=rawquery~="" + end + if not somescheme and not somequery then + return { + scheme="file", + authority="", + path=str, + query="", + fragment="", + original=str, + noscheme=true, + filename=str, + } + end + local authority=detailed[2] + local path=detailed[3] + local filename + local username + local password + local host + local port + if authority~="" then + username,password,host,port=lpegmatch(splitauthority,authority) + end + if authority=="" then + filename=path + elseif path=="" then + filename="" + else + filename=authority.."/"..path + end + return { + scheme=rawscheme, + authority=authority, + path=path, + query=lpegmatch(unescaper,rawquery), + queries=lpegmatch(splitquery,rawquery), + fragment=detailed[5], + original=str, + noscheme=false, + filename=filename, + host=host, + port=port, + } end url.split=split url.hasscheme=hasscheme url.hashed=hashed function url.addscheme(str,scheme) - if hasscheme(str) then - return str - elseif not scheme then - return "file:///"..str - else - return scheme..":///"..str - end + if hasscheme(str) then + return str + elseif not scheme then + return "file:///"..str + else + return scheme..":///"..str + end end function url.construct(hash) - local result,r={},0 - local scheme=hash.scheme - local authority=hash.authority - local path=hash.path - local queries=hash.queries - local fragment=hash.fragment - if scheme and scheme~="" then - r=r+1;result[r]=lpegmatch(escaper,scheme) - r=r+1;result[r]="://" - end - if authority and authority~="" then - r=r+1;result[r]=lpegmatch(escaper,authority) - end - if path and path~="" then - r=r+1;result[r]="/" - r=r+1;result[r]=lpegmatch(escaper,path) - end - if queries then - local done=false - for k,v in sortedhash(queries) do - r=r+1;result[r]=done and "&" or "?" - r=r+1;result[r]=lpegmatch(escaper,k) - r=r+1;result[r]="=" - r=r+1;result[r]=lpegmatch(escaper,v) - done=true - end - end - if fragment and fragment~="" then - r=r+1;result[r]="#" - r=r+1;result[r]=lpegmatch(escaper,fragment) - end - return concat(result) + local result,r={},0 + local scheme=hash.scheme + local authority=hash.authority + local path=hash.path + local queries=hash.queries + local fragment=hash.fragment + if scheme and scheme~="" then + r=r+1;result[r]=lpegmatch(escaper,scheme) + r=r+1;result[r]="://" + end + if authority and authority~="" then + r=r+1;result[r]=lpegmatch(escaper,authority) + end + if path and path~="" then + r=r+1;result[r]="/" + r=r+1;result[r]=lpegmatch(escaper,path) + end + if queries then + local done=false + for k,v in sortedhash(queries) do + r=r+1;result[r]=done and "&" or "?" + r=r+1;result[r]=lpegmatch(escaper,k) + r=r+1;result[r]="=" + r=r+1;result[r]=lpegmatch(escaper,v) + done=true + end + end + if fragment and fragment~="" then + r=r+1;result[r]="#" + r=r+1;result[r]=lpegmatch(escaper,fragment) + end + return concat(result) end local pattern=Cs(slash^-1/""*R("az","AZ")*((S(":|")/":")+P(":"))*slash*P(1)^0) function url.filename(filename) - local spec=hashed(filename) - local path=spec.path - return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename + local spec=hashed(filename) + local path=spec.path + return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename end local function escapestring(str) - return lpegmatch(escaper,str) + return lpegmatch(escaper,str) end url.escape=escapestring function url.query(str) - if type(str)=="string" then - return lpegmatch(splitquery,str) or "" - else - return str - end + if type(str)=="string" then + return lpegmatch(splitquery,str) or "" + else + return str + end end function url.toquery(data) - local td=type(data) - if td=="string" then - return #str and escape(data) or nil - elseif td=="table" then - if next(data) then - local t={} - for k,v in next,data do - t[#t+1]=format("%s=%s",k,escapestring(v)) - end - return concat(t,"&") - end - else + local td=type(data) + if td=="string" then + return #str and escape(data) or nil + elseif td=="table" then + if next(data) then + local t={} + for k,v in next,data do + t[#t+1]=format("%s=%s",k,escapestring(v)) + end + return concat(t,"&") end + else + end end local pattern=Cs(noslash^0*(1-noslash*P(-1))^0) function url.barepath(path) - if not path or path=="" then - return "" - else - return lpegmatch(pattern,path) - end + if not path or path=="" then + return "" + else + return lpegmatch(pattern,path) + end end @@ -4741,14 +5061,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 17703, stripped down to: 11691 +-- original size: 18002, stripped down to: 10681 if not modules then modules={} end modules ['l-dir']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,select=type,select local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub @@ -4760,471 +5080,478 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir +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 onwindows then - local tricky=S("/\\")*P(-1) - isdir=function(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end - end - isfile=function(name) - return attributes(name,"mode")=="file" + local tricky=S("/\\")*P(-1) + isdir=function(name) + if lpegmatch(tricky,name) then + return attributes(name,"mode")=="directory" + else + return attributes(name.."/.","mode")=="directory" end - lfs.isdir=isdir - lfs.isfile=isfile + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile else - isdir=function(name) - return attributes(name,"mode")=="directory" - end - isfile=function(name) - return attributes(name,"mode")=="file" - end - lfs.isdir=isdir - lfs.isfile=isfile + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile end function dir.current() - return (gsub(currentdir(),"\\","/")) + return (gsub(currentdir(),"\\","/")) end local function glob_pattern_function(path,patt,recurse,action) - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - action(full) - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end - if dirs then - for i=1,#dirs do - glob_pattern_function(dirs[i],patt,recurse,action) - end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if dirs then + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } + end end + end + end + if dirs then + for i=1,nofdirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end end + end end local function glob_pattern_table(path,patt,recurse,result) - if not result then - result={} - end - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - result[#result+1]=full - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end + if not result then + result={} + end + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + local noffiles=#result + for name,a in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + noffiles=noffiles+1 + result[noffiles]=full + end + elseif recurse and mode=="directory" then if dirs then - for i=1,#dirs do - glob_pattern_table(dirs[i],patt,recurse,result) - end + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } end + end end - return result + end + if dirs then + for i=1,nofdirs do + glob_pattern_table(dirs[i],patt,recurse,result) + end + end + return result end local function globpattern(path,patt,recurse,method) - local kind=type(method) - if patt and sub(patt,1,-3)==path then - patt=false - end - if kind=="function" then - return glob_pattern_function(path,patt,recurse,method) - elseif kind=="table" then - return glob_pattern_table(path,patt,recurse,method) - else - return glob_pattern_table(path,patt,recurse,{}) - end + local kind=type(method) + if patt and sub(patt,1,-3)==path then + patt=false + end + local okay=isdir(path) + if kind=="function" then + return okay and glob_pattern_function(path,patt,recurse,method) or {} + elseif kind=="table" then + return okay and glob_pattern_table(path,patt,recurse,method) or method + else + return okay and glob_pattern_table(path,patt,recurse,{}) or {} + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) - local ok,scanner - result=result or {} - if path=="/" then - ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) - else - ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) - end - if ok and type(scanner)=="function" then - if not find(path,"/$") then - path=path..'/' - end - for name in scanner,first do - if name=="." then - elseif name==".." then - else - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then - result[name]=attr - end - elseif recurse and mode=="directory" then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr - end - end + local ok,scanner + result=result or {} + if path=="/" then + ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) + else + ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) + end + if ok and type(scanner)=="function" then + if not find(path,"/$") then + path=path..'/' + end + for name in scanner,first do + if name=="." then + elseif name==".." then + else + local full=path..name + local attr=attributes(full) + local mode=attr.mode + if mode=='file' then + if find(full,patt) then + result[name]=attr + end + elseif recurse and mode=="directory" then + attr.list=collectpattern(full,patt,recurse) + result[name]=attr end + end end - return result + end + return result end dir.collectpattern=collectpattern local separator,pattern if onwindows then - local slash=S("/\\")/"/" - pattern={ - [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) - } + local slash=S("/\\")/"/" + pattern={ + [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={ - [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), - [2]=C(((1-S("*?/"))^0*P("/"))^0), - [3]=C(P(1)^0) - } + pattern={ + [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) + P("**")/".*"+P("*")/"[^/]*"+P("?")/"[^/]"+P(".")/"%%."+P("+")/"%%+"+P("-")/"%%-"+P(1) )^0 ) local function glob(str,t) - if type(t)=="function" then - if type(str)=="table" then - for s=1,#str do - glob(str[s],t) - end - elseif isfile(str) then - t(str) - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,t) - end - end + if type(t)=="function" then + if type(str)=="table" then + for s=1,#str do + glob(str[s],t) + end + elseif isfile(str) then + t(str) + else + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + globpattern(start,result,recurse,t) + end + end + else + if type(str)=="table" then + local t=t or {} + for s=1,#str do + glob(str[s],t) + end + return t + elseif isfile(str) then + if t then + t[#t+1]=str + return t + else + return { str } + end else - if type(str)=="table" then - local t=t or {} - for s=1,#str do - glob(str[s],t) - end - return t - elseif isfile(str) then - if t then - t[#t+1]=str - return t - else - return { str } - end - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - return globpattern(start,result,recurse,t) - else - return {} - end - end + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + return globpattern(start,result,recurse,t) + else + return {} + end end + end end dir.glob=glob local function globfiles(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if recurse then - globfiles(path.."/"..name,recurse,func,files) - end - elseif mode=="file" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if recurse then + globfiles(path.."/"..name,recurse,func,files) + end + elseif mode=="file" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name end + end end - return files + end + return files end dir.globfiles=globfiles local function globdirs(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - if recurse then - globdirs(path.."/"..name,recurse,func,files) - end - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name + if recurse then + globdirs(path.."/"..name,recurse,func,files) + end end + end end - return files + end + return files end dir.globdirs=globdirs function dir.ls(pattern) - return concat(glob(pattern),"\n") + return concat(glob(pattern),"\n") end local make_indeed=true if onwindows then - function dir.mkdirs(...) - local n=select("#",...) - local str - if n==1 then - str=select(1,...) - if isdir(str) then - return str,true - end + function dir.mkdirs(...) + 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="" - for i=1,n do - local s=select(i,...) - if s=="" then - elseif str=="" then - str=s - else - str=str.."/"..s - end - end + str=str.."/"..s end - local pth="" - local drive=false - local first,middle,last=match(str,"^(//)(//*)(.*)$") - if first then + end + end + local pth="" + local drive=false + local first,middle,last=match(str,"^(//)(//*)(.*)$") + if first then + else + first,last=match(str,"^(//)/*(.-)$") + if first then + middle,last=match(str,"([^/]+)/+(.-)$") + if middle then + pth="//"..middle else - first,last=match(str,"^(//)/*(.-)$") - if first then - middle,last=match(str,"([^/]+)/+(.-)$") - if middle then - pth="//"..middle - else - pth="//"..last - last="" - end - else - first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") - if first then - pth,drive=first..middle,true - else - middle,last=match(str,"^(/*)(.-)$") - if not middle then - last=str - end - end - end + pth="//"..last + last="" end - for s in gmatch(last,"[^/]+") do - if pth=="" then - pth=s - elseif drive then - pth,drive=pth..s,false - else - pth=pth.."/"..s - end - if make_indeed and not isdir(pth) then - mkdir(pth) - end + else + first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") + if first then + pth,drive=first..middle,true + else + middle,last=match(str,"^(/*)(.-)$") + if not middle then + last=str + end end - return pth,(isdir(pth)==true) + end end + for s in gmatch(last,"[^/]+") do + if pth=="" then + pth=s + elseif drive then + pth,drive=pth..s,false + else + pth=pth.."/"..s + end + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end + return pth,(isdir(pth)==true) + end else - function dir.mkdirs(...) - 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 + function dir.mkdirs(...) + 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 - str=gsub(str,"/+","/") - if find(str,"^/") then - pth="/" - for s in gmatch(str,"[^/]+") do - local first=(pth=="/") - if first then - pth=pth..s - else - pth=pth.."/"..s - end - if make_indeed and not first and not isdir(pth) then - mkdir(pth) - end - end + end + end + str=gsub(str,"/+","/") + if find(str,"^/") then + pth="/" + for s in gmatch(str,"[^/]+") do + local first=(pth=="/") + if first then + pth=pth..s else - pth="." - for s in gmatch(str,"[^/]+") do - pth=pth.."/"..s - if make_indeed and not isdir(pth) then - mkdir(pth) - end - end + pth=pth.."/"..s end - return pth,(isdir(pth)==true) + if make_indeed and not first and not isdir(pth) then + mkdir(pth) + end + end + else + pth="." + for s in gmatch(str,"[^/]+") do + pth=pth.."/"..s + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end end + return pth,(isdir(pth)==true) + end end dir.makedirs=dir.mkdirs do - local chdir=sandbox and sandbox.original(chdir) or chdir - if onwindows then - local xcurrentdir=dir.current - function dir.expandname(str) - local first,nothing,last=match(str,"^(//)(//*)(.*)$") - if first then - first=xcurrentdir().."/" - end - if not first then - first,last=match(str,"^(//)/*(.*)$") - end - if not first then - first,last=match(str,"^([a-zA-Z]:)(.*)$") - if first and not find(last,"^/") then - local d=currentdir() - if chdir(first) then - first=xcurrentdir() - end - chdir(d) - end - end - if not first then - first,last=xcurrentdir(),str - end - last=gsub(last,"//","/") - last=gsub(last,"/%./","/") - last=gsub(last,"^/*","") - first=gsub(first,"/*$","") - if last=="" or last=="." then - return first - else - return first.."/"..last - end - end - else - function dir.expandname(str) - if not find(str,"^/") then - str=currentdir().."/"..str - end - str=gsub(str,"//","/") - str=gsub(str,"/%./","/") - str=gsub(str,"(.)/%.$","%1") - return str + local chdir=sandbox and sandbox.original(chdir) or chdir + if onwindows then + local xcurrentdir=dir.current + function dir.expandname(str) + local first,nothing,last=match(str,"^(//)(//*)(.*)$") + if first then + first=xcurrentdir().."/" + end + if not first then + first,last=match(str,"^(//)/*(.*)$") + end + if not first then + first,last=match(str,"^([a-zA-Z]:)(.*)$") + if first and not find(last,"^/") then + local d=currentdir() + if chdir(first) then + first=xcurrentdir() + end + chdir(d) end + end + if not first then + first,last=xcurrentdir(),str + end + last=gsub(last,"//","/") + last=gsub(last,"/%./","/") + last=gsub(last,"^/*","") + first=gsub(first,"/*$","") + if last=="" or last=="." then + return first + else + return first.."/"..last + end end + else + function dir.expandname(str) + if not find(str,"^/") then + str=currentdir().."/"..str + end + str=gsub(str,"//","/") + str=gsub(str,"/%./","/") + str=gsub(str,"(.)/%.$","%1") + return str + end + end end file.expandname=dir.expandname local stack={} function dir.push(newdir) - local curdir=currentdir() - insert(stack,curdir) - if newdir and newdir~="" then - chdir(newdir) - return newdir - else - return curdir - end + local curdir=currentdir() + insert(stack,curdir) + if newdir and newdir~="" then + chdir(newdir) + return newdir + else + return curdir + end end function dir.pop() - local d=remove(stack) - if d then - chdir(d) - end - return d + local d=remove(stack) + if d then + chdir(d) + end + return d end local function found(...) - for i=1,select("#",...) do - local path=select(i,...) - local kind=type(path) - if kind=="string" then - if isdir(path) then - return path - end - elseif kind=="table" then - local path=found(unpack(path)) - if path then - return path - end - end + for i=1,select("#",...) do + local path=select(i,...) + local kind=type(path) + if kind=="string" then + if isdir(path) then + return path + end + elseif kind=="table" then + local path=found(unpack(path)) + if path then + return path + end end + end end dir.found=found @@ -5235,69 +5562,69 @@ do -- create closure to overcome 200 locals limit package.loaded["l-boolean"] = package.loaded["l-boolean"] or true --- original size: 1850, stripped down to: 1568 +-- original size: 1850, stripped down to: 1498 if not modules then modules={} end modules ['l-boolean']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber=type,tonumber boolean=boolean or {} local boolean=boolean function boolean.tonumber(b) - if b then return 1 else return 0 end + if b then return 1 else return 0 end end function toboolean(str,tolerant) - if str==nil then - return false - elseif str==false then - return false - elseif str==true then - return true - elseif str=="true" then - return true - elseif str=="false" then - return false - elseif not tolerant then - return false - elseif str==0 then - return false - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str==nil then + return false + elseif str==false then + return false + elseif str==true then + return true + elseif str=="true" then + return true + elseif str=="false" then + return false + elseif not tolerant then + return false + elseif str==0 then + return false + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end string.toboolean=toboolean function string.booleanstring(str) - if str=="0" then - return false - elseif str=="1" then - return true - elseif str=="" then - return false - elseif str=="false" then - return false - elseif str=="true" then - return true - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str=="0" then + return false + elseif str=="1" then + return true + elseif str=="" then + return false + elseif str=="false" then + return false + elseif str=="true" then + return true + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end function string.is_boolean(str,default,strict) - if type(str)=="string" then - if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then - return true - elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then - return false - end + if type(str)=="string" then + if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then + return true + elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then + return false end - return default + end + return default end @@ -5307,18 +5634,24 @@ do -- create closure to overcome 200 locals limit package.loaded["l-unicode"] = package.loaded["l-unicode"] or true --- original size: 40036, stripped down to: 17837 +-- original size: 41047, stripped down to: 17171 if not modules then modules={} end modules ['l-unicode']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -utf=utf or (unicode and unicode.utf8) or {} -utf.characters=utf.characters or string.utfcharacters -utf.values=utf.values or string.utfvalues +utf=utf or {} +unicode=nil +if not string.utfcharacters then + local gmatch=string.gmatch + function string.characters(str) + return gmatch(str,".[\128-\191]*") + end +end +utf.characters=string.utfcharacters local type=type local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch local concat=table.concat @@ -5329,345 +5662,340 @@ local tabletopattern=lpeg.utfchartabletopattern local bytepairs=string.bytepairs local finder=lpeg.finder 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.utf8character +local p_utf8character=patterns.utf8character +local p_utf8char=patterns.utf8char local p_utf8byte=patterns.utf8byte local p_utfbom=patterns.utfbom local p_newline=patterns.newline local p_whitespace=patterns.whitespace -if not unicode then - unicode={ utf=utf } -end if not utf.char then - utf.char=string.utfcharacter or (utf8 and utf8.char) - if not utf.char then - local char=string.char - if bit32 then - local rshift=bit32.rshift - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+rshift(n,6), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+rshift(n,12), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+rshift(n,18), - 0x80+(rshift(n,12)%0x40), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + utf.char=string.utfcharacter or (utf8 and utf8.char) + if not utf.char then + local char=string.char + if bit32 then + local rshift=bit32.rshift + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+rshift(n,6), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+rshift(n,12), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+rshift(n,18), + 0x80+(rshift(n,12)%0x40), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) else - local floor=math.floor - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+floor(n/0x40), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+floor(n/0x1000), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+floor(n/0x40000), - 0x80+(floor(n/0x1000)%0x40), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + return "" end + end + else + local floor=math.floor + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+floor(n/0x40), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+floor(n/0x1000), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+floor(n/0x40000), + 0x80+(floor(n/0x1000)%0x40), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + else + return "" + end + end end + end end if not utf.byte then - utf.byte=string.utfvalue or (utf8 and utf8.codepoint) - if not utf.byte then - local utf8byte=patterns.utf8byte - function utf.byte(c) - return lpegmatch(utf8byte,c) - end + utf.byte=string.utfvalue or (utf8 and utf8.codepoint) + if not utf.byte then + function utf.byte(c) + return lpegmatch(p_utf8byte,c) end + end end local utfchar,utfbyte=utf.char,utf.byte function utf.filetype(data) - return data and lpegmatch(p_utftype,data) or "unknown" + return data and lpegmatch(p_utftype,data) or "unknown" end local toentities=Cs ( - ( - patterns.utf8one+( - patterns.utf8two+patterns.utf8three+patterns.utf8four - )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end - )^0 + ( + patterns.utf8one+( + patterns.utf8two+patterns.utf8three+patterns.utf8four + )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end + )^0 ) patterns.toentities=toentities function utf.toentities(str) - return lpegmatch(toentities,str) + return lpegmatch(toentities,str) end local one=P(1) local two=C(1)*C(1) local four=C(R(utfchar(0xD8),utfchar(0xFF)))*C(1)*C(1)*C(1) local pattern=P("\254\255")*Cs(( - four/function(a,b,c,d) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(a,b) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 )+P("\255\254")*Cs(( - four/function(b,a,d,c) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(b,a) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 ) + four/function(a,b,c,d) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(a,b) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 )+P("\255\254")*Cs(( + four/function(b,a,d,c) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(b,a) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 ) function string.toutf(s) - return lpegmatch(pattern,s) or s + return lpegmatch(pattern,s) or s end local validatedutf=Cs ( - ( - patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" - )^0 + ( + patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" + )^0 ) patterns.validatedutf=validatedutf function utf.is_valid(str) - return type(str)=="string" and lpegmatch(validatedutf,str) or false + return type(str)=="string" and lpegmatch(validatedutf,str) or false end if not utf.len then - utf.len=string.utflength or (utf8 and utf8.len) - if not utf.len then - local n,f=0,1 - local utfcharcounter=patterns.utfbom^-1*Cmt ( - Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, - function(_,t,d) - n=n+(t-f)/d - f=t - return true - end - )^0 - function utf.len(str) - n,f=0,1 - lpegmatch(utfcharcounter,str or "") - return n - end + utf.len=string.utflength or (utf8 and utf8.len) + if not utf.len then + local n,f=0,1 + local utfcharcounter=patterns.utfbom^-1*Cmt ( + Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, + function(_,t,d) + n=n+(t-f)/d + f=t + return true + end + )^0 + function utf.len(str) + n,f=0,1 + lpegmatch(utfcharcounter,str or "") + return n end + end end utf.length=utf.len if not utf.sub then - local utflength=utf.length - local b,e,n,first,last=0,0,0,0,0 - local function slide_zero(s,p) - n=n+1 - if n>=last then - e=p-1 - else - return p - end + local utflength=utf.length + local b,e,n,first,last=0,0,0,0,0 + local function slide_zero(s,p) + n=n+1 + if n>=last then + e=p-1 + else + return p end - local function slide_one(s,p) - n=n+1 - if n==first then - b=p - end - if n>=last then - e=p-1 - else - return p - end + end + local function slide_one(s,p) + n=n+1 + if n==first then + b=p end - local function slide_two(s,p) - n=n+1 - if n==first then - b=p - else - return true - end + if n>=last then + e=p-1 + else + return p end - local pattern_zero=Cmt(p_utf8char,slide_zero)^0 - local pattern_one=Cmt(p_utf8char,slide_one )^0 - local pattern_two=Cmt(p_utf8char,slide_two )^0 - local pattern_first=C(patterns.utf8character) - function utf.sub(str,start,stop) - if not start then - return str - end - if start==0 then - start=1 - end - if not stop then - if start<0 then - local l=utflength(str) - start=l+start - else - start=start-1 - end - b,n,first=0,0,start - lpegmatch(pattern_two,str) - if n>=first then - return sub(str,b) - else - return "" - end - end - if start<0 or stop<0 then - local l=utf.length(str) - if start<0 then - start=l+start - if start<=0 then - start=1 - else - start=start+1 - end - end - if stop<0 then - stop=l+stop - if stop==0 then - stop=1 - else - stop=stop+1 - end - end + end + local function slide_two(s,p) + n=n+1 + if n==first then + b=p + else + return true + end + end + local pattern_zero=Cmt(p_utf8character,slide_zero)^0 + local pattern_one=Cmt(p_utf8character,slide_one )^0 + local pattern_two=Cmt(p_utf8character,slide_two )^0 + local pattern_first=C(p_utf8character) + function utf.sub(str,start,stop) + if not start then + return str + end + if start==0 then + start=1 + end + if not stop then + if start<0 then + local l=utflength(str) + start=l+start + else + start=start-1 + end + b,n,first=0,0,start + lpegmatch(pattern_two,str) + if n>=first then + return sub(str,b) + else + return "" + end + end + if start<0 or stop<0 then + local l=utf.length(str) + if start<0 then + start=l+start + if start<=0 then + start=1 + else + start=start+1 end - if start==1 and stop==1 then - return lpegmatch(pattern_first,str) or "" - elseif start>stop then - return "" - elseif start>1 then - b,e,n,first,last=0,0,0,start-1,stop - lpegmatch(pattern_one,str) - if n>=first and e==0 then - e=#str - end - return sub(str,b,e) + end + if stop<0 then + stop=l+stop + if stop==0 then + stop=1 else - b,e,n,last=1,0,0,stop - lpegmatch(pattern_zero,str) - if e==0 then - e=#str - end - return sub(str,b,e) + stop=stop+1 end + end end + if start==1 and stop==1 then + return lpegmatch(pattern_first,str) or "" + elseif start>stop then + return "" + elseif start>1 then + b,e,n,first,last=0,0,0,start-1,stop + lpegmatch(pattern_one,str) + if n>=first and e==0 then + e=#str + end + return sub(str,b,e) + else + b,e,n,last=1,0,0,stop + lpegmatch(pattern_zero,str) + if e==0 then + e=#str + end + return sub(str,b,e) + end + end end function utf.remapper(mapping,option,action) - local variant=type(mapping) - if variant=="table" then - action=action or mapping - if option=="dynamic" then - local pattern=false - table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) - return function(str) - if not str or str=="" then - return "" - else - if not pattern then - pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - end - return lpegmatch(pattern,str) - end - end - elseif option=="pattern" then - return Cs((tabletopattern(mapping)/action+p_utf8char)^0) + local variant=type(mapping) + if variant=="table" then + action=action or mapping + if option=="dynamic" then + local pattern=false + table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + if not pattern then + pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + end + return lpegmatch(pattern,str) end - elseif variant=="function" then - if option=="pattern" then - return Cs((p_utf8char/mapping+p_utf8char)^0) + end + elseif option=="pattern" then + return Cs((tabletopattern(mapping)/action+p_utf8character)^0) + else + local pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((p_utf8char/mapping+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + return lpegmatch(pattern,str) end + end,pattern + end + elseif variant=="function" then + if option=="pattern" then + return Cs((p_utf8character/mapping+p_utf8character)^0) else - return function(str) - return str or "" + local pattern=Cs((p_utf8character/mapping+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" + else + return lpegmatch(pattern,str) end + end,pattern end -end -function utf.replacer(t) - local r=replacer(t,false,false,true) + else return function(str) - return lpegmatch(r,str) + return str or "" end + end +end +function utf.replacer(t) + local r=replacer(t,false,false,true) + return function(str) + return lpegmatch(r,str) + end end function utf.subtituter(t) - local f=finder (t) - local r=replacer(t,false,false,true) - return function(str) - local i=lpegmatch(f,str) - if not i then - return str - elseif i>#str then - return str - else - return lpegmatch(r,str) - end + local f=finder (t) + local r=replacer(t,false,false,true) + return function(str) + local i=lpegmatch(f,str) + if not i then + return str + elseif i>#str then + return str + else + return lpegmatch(r,str) end + end end local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline) -local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0) -local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0) -local utfcharsplitter_raw=Ct(C(p_utf8char)^0) +local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8character)^0) +local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8character))^0) +local utfcharsplitter_raw=Ct(C(p_utf8character)^0) patterns.utflinesplitter=utflinesplitter function utf.splitlines(str) - return lpegmatch(utflinesplitter,str or "") + return lpegmatch(utflinesplitter,str or "") end function utf.split(str,ignorewhitespace) - if ignorewhitespace then - return lpegmatch(utfcharsplitter_iws,str or "") - else - return lpegmatch(utfcharsplitter_ows,str or "") - end + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end end function utf.totable(str) - return lpegmatch(utfcharsplitter_raw,str) + return lpegmatch(utfcharsplitter_raw,str) end function utf.magic(f) - local str=f:read(4) or "" - local off=lpegmatch(p_utfoffset,str) - if off<4 then - f:seek('set',off) - end - return lpegmatch(p_utftype,str) + local str=f:read(4) or "" + local off=lpegmatch(p_utfoffset,str) + if off<4 then + f:seek('set',off) + end + return lpegmatch(p_utftype,str) end local utf16_to_utf8_be,utf16_to_utf8_le local utf32_to_utf8_be,utf32_to_utf8_le @@ -5681,36 +6009,36 @@ local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_n local utf_32_le_linesplitter=utf_32_le_getbom*lpeg.tsplitat(patterns.utf_32_le_nl) local more=0 local p_utf16_to_utf8_be=C(1)*C(1)/function(left,right) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf16_to_utf8_le=C(1)*C(1)/function(right,left) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf32_to_utf8_be=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) + return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) end local p_utf32_to_utf8_le=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) + return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) end p_utf16_to_utf8_be=P(true)/function() more=0 end*utf_16_be_getbom*Cs(p_utf16_to_utf8_be^0) p_utf16_to_utf8_le=P(true)/function() more=0 end*utf_16_le_getbom*Cs(p_utf16_to_utf8_le^0) @@ -5721,88 +6049,88 @@ patterns.utf16_to_utf8_le=p_utf16_to_utf8_le patterns.utf32_to_utf8_be=p_utf32_to_utf8_be patterns.utf32_to_utf8_le=p_utf32_to_utf8_le utf16_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_be,s) + else + return s + end end local utf16_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_be,s) end - return t + end + return t end utf16_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_le,s) + else + return s + end end local utf16_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_le,s) end - return t + end + return t end utf32_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_be,s) + else + return s + end end local utf32_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_be,s) end - return t + end + return t end utf32_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_le,s) + else + return s + end end local utf32_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_le,s) end - return t + end + return t end utf.utf16_to_utf8_le_t=utf16_to_utf8_le_t utf.utf16_to_utf8_be_t=utf16_to_utf8_be_t @@ -5813,189 +6141,225 @@ 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(t) - return type(t)=="string" and lpegmatch(utflinesplitter,t) or t + return type(t)=="string" and lpegmatch(utflinesplitter,t) or t end function utf.utf16_to_utf8_t(t,endian) - return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t + return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t end function utf.utf32_to_utf8_t(t,endian) - return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t + return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t end local function little(b) - if b<0x10000 then - return char(b%256,rshift(b,8)) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) - end + if b<0x10000 then + return char(b%256,rshift(b,8)) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) + end end local function big(b) - if b<0x10000 then - return char(rshift(b,8),b%256) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) - end + if b<0x10000 then + return char(rshift(b,8),b%256) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) + end end local l_remap=Cs((p_utf8byte/little+P(1)/"")^0) local b_remap=Cs((p_utf8byte/big+P(1)/"")^0) local function utf8_to_utf16_be(str,nobom) - if nobom then - return lpegmatch(b_remap,str) - else - return char(254,255)..lpegmatch(b_remap,str) - end + if nobom then + return lpegmatch(b_remap,str) + else + return char(254,255)..lpegmatch(b_remap,str) + end end local function utf8_to_utf16_le(str,nobom) - if nobom then - return lpegmatch(l_remap,str) - else - return char(255,254)..lpegmatch(l_remap,str) - end + if nobom then + return lpegmatch(l_remap,str) + else + return char(255,254)..lpegmatch(l_remap,str) + end end utf.utf8_to_utf16_be=utf8_to_utf16_be utf.utf8_to_utf16_le=utf8_to_utf16_le function utf.utf8_to_utf16(str,littleendian,nobom) - if littleendian then - return utf8_to_utf16_le(str,nobom) - else - return utf8_to_utf16_be(str,nobom) - end + if littleendian then + return utf8_to_utf16_le(str,nobom) + else + return 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 + (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 ) function utf.tocodes(str,separator) - return lpegmatch(pattern,str,1,separator or " ") + return lpegmatch(pattern,str,1,separator or " ") end function utf.ustring(s) - return format("U+%05X",type(s)=="number" and s or utfbyte(s)) + return format("U+%05X",type(s)=="number" and s or utfbyte(s)) end function utf.xstring(s) - return format("0x%05X",type(s)=="number" and s or utfbyte(s)) + return format("0x%05X",type(s)=="number" and s or utfbyte(s)) end function utf.toeight(str) - if not str or str=="" then - return nil - end - local utftype=lpegmatch(p_utfstricttype,str) - if utftype=="utf-8" then - return sub(str,4) - elseif utftype=="utf-16-be" then - return utf16_to_utf8_be(str) - elseif utftype=="utf-16-le" then - return utf16_to_utf8_le(str) - else - return str - end -end -local p_nany=p_utf8char/"" -if utfgmatch then - function utf.count(str,what) - if type(what)=="string" then - local n=0 - for _ in utfgmatch(str,what) do - n=n+1 - end - return n - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end -else - local cache={} - function utf.count(str,what) - if type(what)=="string" then - local p=cache[what] - if not p then - p=Cs((P(what)/" "+p_nany)^0) - cache[p]=p - end - return #lpegmatch(p,str) - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end + if not str or str=="" then + return nil + end + local utftype=lpegmatch(p_utfstricttype,str) + if utftype=="utf-8" then + return sub(str,4) + elseif utftype=="utf-16-be" then + return utf16_to_utf8_be(str) + elseif utftype=="utf-16-le" then + return utf16_to_utf8_le(str) + else + return str + end end -if not utf.characters then - function utf.characters(str) - return gmatch(str,".[\128-\191]*") +do + local p_nany=p_utf8character/"" + local cache={} + function utf.count(str,what) + if type(what)=="string" then + local p=cache[what] + if not p then + p=Cs((P(what)/" "+p_nany)^0) + cache[p]=p + end + return #lpegmatch(p,str) + else + return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) end - string.utfcharacters=utf.characters + end end -if not utf.values then - local find=string.find - local dummy=function() - end - function utf.values(str) - local n=#str - if n==0 then - return dummy - elseif n==1 then - return function() return utfbyte(str) end - else - local p=1 - return function() - local b,e=find(str,".[\128-\191]*",p) - if b then - p=e+1 - return utfbyte(sub(str,b,e)) - end - end - end +if not string.utfvalues then + local find=string.find + local dummy=function() + end + function string.utfvalues(str) + local n=#str + if n==0 then + return dummy + elseif n==1 then + return function() return utfbyte(str) end + else + local p=1 + return function() + local b,e=find(str,".[\128-\191]*",p) + if b then + p=e+1 + return utfbyte(sub(str,b,e)) + end + end end - string.utfvalues=utf.values + end end +utf.values=string.utfvalues 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 + 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 if bit32 then - local extract=bit32.extract - local char=string.char - function unicode.toutf32string(n) - if n<=0xFF then - return - char(n).."\000\000\000" - elseif n<=0xFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" - elseif n<=0xFFFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" - else - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) - end - end + local extract=bit32.extract + local char=string.char + function utf.toutf32string(n) + if n<=0xFF then + return + char(n).."\000\000\000" + elseif n<=0xFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" + elseif n<=0xFFFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" + else + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) + end + end end local len=utf.len local rep=rep function string.utfpadd(s,n) - if n and n~=0 then - local l=len(s) - if n>0 then - local d=n-l - if d>0 then - return rep(c or " ",d)..s - end - else - local d=- n-l - if d>0 then - return s..rep(c or " ",d) - end - end + if n and n~=0 then + local l=len(s) + if n>0 then + local d=n-l + if d>0 then + return rep(c or " ",d)..s + end + else + local d=- n-l + if d>0 then + return s..rep(c or " ",d) + end end - return s + end + return s +end +do + local utfcharacters=utf.characters or string.utfcharacters + local utfchar=utf.char or string.utfcharacter + lpeg.UP=P + if utfcharacters then + function lpeg.US(str) + local p=P(false) + for uc in utfcharacters(str) do + p=p+P(uc) + end + return p + end + else + function lpeg.US(str) + local p=P(false) + local f=function(uc) + p=p+P(uc) + end + lpegmatch((p_utf8char/f)^0,str) + return p + end + end + local range=p_utf8byte*p_utf8byte+Cc(false) + function lpeg.UR(str,more) + local first,last + if type(str)=="number" then + first=str + last=more or first + else + first,last=lpegmatch(range,str) + if not last then + return P(str) + end + end + if first==last then + return P(str) + end + if not utfchar then + utfchar=utf.char + end + if utfchar and (last-first<8) then + local p=P(false) + for i=first,last do + p=p+P(utfchar(i)) + end + return p + else + local f=function(b) + return b>=first and b<=last + end + return p_utf8byte/f + end + end end @@ -6005,93 +6369,93 @@ do -- create closure to overcome 200 locals limit package.loaded["l-math"] = package.loaded["l-math"] or true --- original size: 2555, stripped down to: 1900 +-- original size: 2555, stripped down to: 1831 if not modules then modules={} end modules ['l-math']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not math.ceiling then - math.ceiling=math.ceil + math.ceiling=math.ceil end if not math.round then - local floor=math.floor - function math.round(x) return floor(x+0.5) end + local floor=math.floor + function math.round(x) return floor(x+0.5) end end if not math.div then - local floor=math.floor - function math.div(n,m) return floor(n/m) end + local floor=math.floor + function math.div(n,m) return floor(n/m) end end if not math.mod then - function math.mod(n,m) return n%m end + function math.mod(n,m) return n%m end end if not math.sind then - local sin,cos,tan=math.sin,math.cos,math.tan - local pipi=2*math.pi/360 - function math.sind(d) return sin(d*pipi) end - function math.cosd(d) return cos(d*pipi) end - function math.tand(d) return tan(d*pipi) end + local sin,cos,tan=math.sin,math.cos,math.tan + local pipi=2*math.pi/360 + function math.sind(d) return sin(d*pipi) end + function math.cosd(d) return cos(d*pipi) end + function math.tand(d) return tan(d*pipi) end end if not math.odd then - function math.odd (n) return n%2~=0 end - function math.even(n) return n%2==0 end + function math.odd (n) return n%2~=0 end + function math.even(n) return n%2==0 end end if not math.cosh then - local exp=math.exp - function math.cosh(x) - local xx=exp(x) - return (xx+1/xx)/2 - end - function math.sinh(x) - local xx=exp(x) - return (xx-1/xx)/2 - end - function math.tanh(x) - local xx=exp(x) - return (xx-1/xx)/(xx+1/xx) - end + local exp=math.exp + function math.cosh(x) + local xx=exp(x) + return (xx+1/xx)/2 + end + function math.sinh(x) + local xx=exp(x) + return (xx-1/xx)/2 + end + function math.tanh(x) + local xx=exp(x) + return (xx-1/xx)/(xx+1/xx) + end end if not math.pow then - function math.pow(x,y) - return x^y - end + function math.pow(x,y) + return x^y + end end if not math.atan2 then - math.atan2=math.atan + math.atan2=math.atan end if not math.ldexp then - function math.ldexp(x,e) - return x*2.0^e - end + function math.ldexp(x,e) + return x*2.0^e + end end if not math.log10 then - local log=math.log - function math.log10(x) - return log(x,10) - end + local log=math.log + function math.log10(x) + return log(x,10) + end end if not math.type then - function math.type() - return "float" - end + function math.type() + return "float" + end end if not math.tointeger then - math.mininteger=-0x4FFFFFFFFFFF - math.maxinteger=0x4FFFFFFFFFFF - local floor=math.floor - function math.tointeger(n) - local f=floor(n) - return f==n and f or nil - end + math.mininteger=-0x4FFFFFFFFFFF + math.maxinteger=0x4FFFFFFFFFFF + local floor=math.floor + function math.tointeger(n) + local f=floor(n) + return f==n and f or nil + end end if not math.ult then - local floor=math.floor - function math.tointeger(m,n) - return floor(m)<floor(n) - end + local floor=math.floor + function math.tointeger(m,n) + return floor(m)<floor(n) + end end @@ -6101,14 +6465,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 38734, stripped down to: 22142 +-- original size: 43539, stripped down to: 21641 if not modules then modules={} end modules ['util-str']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.strings=utilities.strings or {} @@ -6121,624 +6485,657 @@ 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,utflen=utf.char,utf.byte,utf.len -local loadstripped=nil -local oldfashioned=LUAVERSION<5.2 -if oldfashioned 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 +local 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 if not number then number={} end -local stripper=patterns.stripzeros +local stripzero=patterns.stripzero +local stripzeros=patterns.stripzeros local newline=patterns.newline local endofstring=patterns.endofstring +local anything=patterns.anything local whitespace=patterns.whitespace +local space=patterns.space local spacer=patterns.spacer local spaceortab=patterns.spaceortab +local digit=patterns.digit +local sign=patterns.sign +local period=patterns.period +local ptf=1/65536 +local bpf=(7200/7227)/65536 local function points(n) - n=tonumber(n) - return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*ptf + if n%1==0 then + return format("%ipt",n) + end + return lpegmatch(stripzeros,format("%.5fpt",n)) 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)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*bpf + if n%1==0 then + return format("%ibp",n) + end + return lpegmatch(stripzeros,format("%.5fbp",n)) end number.points=points number.basepoints=basepoints local rubish=spaceortab^0*newline local anyrubish=spaceortab+newline -local anything=patterns.anything local stripped=(spaceortab^1/"")*newline local leading=rubish^0/"" local trailing=(anyrubish^1*endofstring)/"" local redundant=rubish^3/"\n" local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) function strings.collapsecrlf(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local repeaters={} function strings.newrepeater(str,offset) - offset=offset or 0 - local s=repeaters[str] - if not s then - s={} - repeaters[str]=s - end - local t=s[offset] - if t then - return t - end - t={} - setmetatable(t,{ __index=function(t,k) - if not k then - return "" - end - local n=k+offset - local s=n>0 and rep(str,n) or "" - t[k]=s - return s - end }) - s[offset]=t + offset=offset or 0 + local s=repeaters[str] + if not s then + s={} + repeaters[str]=s + end + local t=s[offset] + if t then return t + end + t={} + setmetatable(t,{ __index=function(t,k) + if not k then + return "" + end + local n=k+offset + local s=n>0 and rep(str,n) or "" + t[k]=s + return s + end }) + s[offset]=t + return t end local extra,tab,start=0,0,4,0 local nspaces=strings.newrepeater(" ") string.nspaces=nspaces local pattern=Carg(1)/function(t) - extra,tab,start=0,t or 7,1 - end*Cs(( + extra,tab,start=0,t or 7,1 + end*Cs(( Cp()*patterns.tab/function(position) - local current=(position-start+1)+extra - local spaces=tab-(current-1)%tab - if spaces>0 then - extra=extra+spaces-1 - return nspaces[spaces] - else - return "" - end + local current=(position-start+1)+extra + local spaces=tab-(current-1)%tab + if spaces>0 then + extra=extra+spaces-1 + return nspaces[spaces] + else + return "" + end end+newline*Cp()/function(position) - extra,start=0,position - end+patterns.anything - )^1) + extra,start=0,position + end+anything + )^1) function strings.tabtospace(str,tab) - return lpegmatch(pattern,str,1,tab or 7) + return lpegmatch(pattern,str,1,tab or 7) end function string.utfpadding(s,n) - if not n or n==0 then - return "" - end - local l=utflen(s) - if n>0 then - return nspaces[n-l] - else - return nspaces[-n-l] - end -end -local space=spacer^0 -local nospace=space/"" + if not n or n==0 then + return "" + end + local l=utflen(s) + if n>0 then + return nspaces[n-l] + else + return nspaces[-n-l] + end +end +local optionalspace=spacer^0 +local nospace=optionalspace/"" local endofline=nospace*newline local stripend=(whitespace^1*endofstring)/"" -local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) +local normalline=(nospace*((1-optionalspace*(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 intospace=whitespace^1/" " +local noleading=whitespace^1/"" +local notrailing=noleading*endofstring 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_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^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, - ["collapse"]=patterns.collapser, + ["prune"]=p_prune_normal, + ["prune and collapse"]=p_prune_collapse, + ["prune and no empty"]=p_prune_noempty, + ["prune and to space"]=p_prune_intospace, + ["retain"]=p_retain_normal, + ["retain and collapse"]=p_retain_collapse, + ["retain and no empty"]=p_retain_noempty, + ["collapse"]=patterns.collapser, } setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end }) strings.striplinepatterns=striplinepatterns function strings.striplines(str,how) - return str and lpegmatch(striplinepatterns[how],str) or str + return str and lpegmatch(striplinepatterns[how],str) or str +end +function strings.collapse(str) + return str and lpegmatch(p_prune_intospace,str) or str end strings.striplong=strings.striplines function strings.nice(str) - str=gsub(str,"[:%-+_]+"," ") - return str + str=gsub(str,"[:%-+_]+"," ") + return str end local n=0 local sequenced=table.sequenced function string.autodouble(s,sep) - if s==nil then - return '""' - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ('"'..sequenced(s,sep or ",")..'"') - end - return ('"'..tostring(s)..'"') + if s==nil then + return '""' + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ('"'..sequenced(s,sep or ",")..'"') + end + return ('"'..tostring(s)..'"') end function string.autosingle(s,sep) - if s==nil then - return "''" - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ("'"..sequenced(s,sep or ",").."'") - end - return ("'"..tostring(s).."'") + if s==nil then + return "''" + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ("'"..sequenced(s,sep or ",").."'") + end + return ("'"..tostring(s).."'") end local tracedchars={ [0]= - "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", - "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", - "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", - "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", - "[space]", + "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", + "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", + "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", + "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", + "[space]", } string.tracedchars=tracedchars strings.tracers=tracedchars function string.tracedchar(b) - if type(b)=="number" then - return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") - else - local c=utfbyte(b) - return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") - end + if type(b)=="number" then + return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") + else + local c=utfbyte(b) + return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") + end end function number.signed(i) - if i>0 then - return "+",i - else - return "-",-i - end -end -local digit=patterns.digit -local period=patterns.period -local three=digit*digit*digit + if i>0 then + return "+",i + else + return "-",-i + end +end +local two=digit*digit +local three=two*digit +local prefix=(Carg(1)*three)^1 local splitter=Cs ( - (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2) + (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2) +) +local splitter3=Cs ( + three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit ) patterns.formattednumber=splitter function number.formatted(n,sep1,sep2) - local s=type(s)=="string" and n or format("%0.2f",n) + if sep1==false then + if type(n)=="number" then + n=tostring(n) + end + return lpegmatch(splitter3,n,1,sep2 or ".") + else + if type(n)=="number" then + n=format("%0.2f",n) + end if sep1==true then - return lpegmatch(splitter,s,1,".",",") + return lpegmatch(splitter,n,1,".",",") elseif sep1=="." then - return lpegmatch(splitter,s,1,sep1,sep2 or ",") + return lpegmatch(splitter,n,1,sep1,sep2 or ",") elseif sep1=="," then - return lpegmatch(splitter,s,1,sep1,sep2 or ".") + return lpegmatch(splitter,n,1,sep1,sep2 or ".") else - return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") + return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".") end + end end local p=Cs( - P("-")^0*(P("0")^1/"")^0*(1-P("."))^0*(P(".")*P("0")^1*P(-1)/""+P(".")^0)*P(1-P("0")^1*P(-1))^0 - ) + P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0 + ) function number.compactfloat(n,fmt) - if n==0 then - return "0" - elseif n==1 then - return "1" - end - n=lpegmatch(p,format(fmt or "%0.3f",n)) - if n=="." or n=="" or n=="-" then - return "0" - end - return n + if n==0 then + return "0" + elseif n==1 then + return "1" + end + n=lpegmatch(p,format(fmt or "%0.3f",n)) + if n=="." or n=="" or n=="-" then + return "0" + end + return n end local zero=P("0")^1/"" local plus=P("+")/"" local minus=P("-") -local separator=S(".") -local digit=R("09") +local separator=period 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 exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1)) local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) -local pattern_b=Cs((exponent+P(1))^0) +local pattern_b=Cs((exponent+anything)^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)) + 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 - return tostring(n) + 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 hf={} local hs={} setmetatable(hf,{ __index=function(t,k) - local v="%."..k.."f" - t[k]=v - return v + local v="%."..k.."f" + t[k]=v + return v end } ) setmetatable(hs,{ __index=function(t,k) - local v="%"..k.."s" - t[k]=v - return v + local v="%"..k.."s" + t[k]=v + return v end } ) function number.formattedfloat(n,b,a) - local s=format(hf[a],n) - local l=(b or 0)+(a or 0)+1 - if #s<l then - return format(hs[l],s) - else - return s - end + local s=format(hf[a],n) + local l=(b or 0)+(a or 0)+1 + if #s<l then + return format(hs[l],s) + else + return s + end end local template=[[ %s %s return function(%s) return %s end ]] -local preamble,environment="",{} -if oldfashioned 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 utfpadding=string.utfpadding -local tracedchar=string.tracedchar -local autosingle=string.autosingle -local autodouble=string.autodouble -local sequenced=table.sequenced -local formattednumber=number.formatted -local sparseexponent=number.sparseexponent -local formattedfloat=number.formattedfloat - ]] -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, - utfpadding=string.utfpadding, - tracedchar=string.tracedchar, - autosingle=string.autosingle, - autodouble=string.autodouble, - sequenced=table.sequenced, - formattednumber=number.formatted, - sparseexponent=number.sparseexponent, - formattedfloat=number.formattedfloat, - } -end +local preamble="" +local 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, + utfpadding=string.utfpadding, + tracedchar=string.tracedchar, + autosingle=string.autosingle, + autodouble=string.autodouble, + sequenced=table.sequenced, + formattednumber=number.formatted, + sparseexponent=number.sparseexponent, + formattedfloat=number.formattedfloat, + stripzero=lpeg.patterns.stripzero, + stripzeros=lpeg.patterns.stripzeros, + FORMAT=string.f9, +} local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) - local v=t[k-1]..",a"..k - t[k]=v - return v - end + local v=t[k-1]..",a"..k + t[k]=v + return v + end }) -local prefix_any=C((S("+- .")+R("09"))^0) -local prefix_sub=(C((S("+-")+R("09"))^0)+Cc(0))*P(".")*(C((S("+-")+R("09"))^0)+Cc(0)) +local prefix_any=C((sign+space+period+digit)^0) +local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(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 - return format("format('%%%ss',a%s)",f,n) - else - return format("(a%s or '')",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',a%s)",f,n) + else + return format("(a%s or '')",n) + end end local format_S=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%ss',tostring(a%s))",f,n) - else - return format("tostring(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',tostring(a%s))",f,n) + else + return format("tostring(a%s)",n) + end end local format_right=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - elseif f>0 then - return format("utfpadding(a%s,%i)..a%s",n,f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + elseif f>0 then + return format("utfpadding(a%s,%i)..a%s",n,f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,f) + end end local format_left=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - end - if f<0 then - return format("utfpadding(a%s,%i)..a%s",n,-f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,-f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + end + if f<0 then + return format("utfpadding(a%s,%i)..a%s",n,-f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,-f) + end end local format_q=function() - n=n+1 - return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) + n=n+1 + return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) end local format_Q=function() - n=n+1 - return format("format('%%q',tostring(a%s))",n) + n=n+1 + return format("format('%%q',tostring(a%s))",n) end local format_i=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%si',a%s)",f,n) - else - return format("format('%%i',a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%si',a%s)",f,n) + else + return format("format('%%i',a%s)",n) + end end local format_d=format_i local format_I=function(f) - n=n+1 - return format("format('%%s%%%si',signed(a%s))",f,n) + n=n+1 + return format("format('%%s%%%si',signed(a%s))",f,n) end local format_f=function(f) - n=n+1 - return format("format('%%%sf',a%s)",f,n) + n=n+1 + return format("format('%%%sf',a%s)",f,n) end local format_F=function(f) - n=n+1 - if not f or f=="" then - return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) - else - return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) - end + n=n+1 + if not f or f=="" then + return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) + else + return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) + end end local format_k=function(b,a) - n=n+1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) + n=n+1 + return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) end local format_g=function(f) - n=n+1 - return format("format('%%%sg',a%s)",f,n) + n=n+1 + return format("format('%%%sg',a%s)",f,n) end local format_G=function(f) - n=n+1 - return format("format('%%%sG',a%s)",f,n) + n=n+1 + return format("format('%%%sG',a%s)",f,n) end local format_e=function(f) - n=n+1 - return format("format('%%%se',a%s)",f,n) + n=n+1 + return format("format('%%%se',a%s)",f,n) end local format_E=function(f) - n=n+1 - return format("format('%%%sE',a%s)",f,n) + 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) + 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) + 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) + n=n+1 + return format("format('%%%sx',a%s)",f,n) end local format_X=function(f) - n=n+1 - return format("format('%%%sX',a%s)",f,n) + n=n+1 + return format("format('%%%sX',a%s)",f,n) end local format_o=function(f) - n=n+1 - return format("format('%%%so',a%s)",f,n) + n=n+1 + return format("format('%%%so',a%s)",f,n) end local format_c=function() - n=n+1 - return format("utfchar(a%s)",n) + n=n+1 + return format("utfchar(a%s)",n) end local format_C=function() - n=n+1 - return format("tracedchar(a%s)",n) + n=n+1 + return format("tracedchar(a%s)",n) end local format_r=function(f) - n=n+1 - return format("format('%%%s.0f',a%s)",f,n) + n=n+1 + return format("format('%%%s.0f',a%s)",f,n) end local format_h=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_H=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_u=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_U=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_p=function() - n=n+1 - return format("points(a%s)",n) + n=n+1 + return format("points(a%s)",n) end local format_b=function() - n=n+1 - return format("basepoints(a%s)",n) + n=n+1 + return format("basepoints(a%s)",n) end local format_t=function(f) - n=n+1 - if f and f~="" then - return format("concat(a%s,%q)",n,f) - else - return format("concat(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("concat(a%s,%q)",n,f) + else + return format("concat(a%s)",n) + end end local format_T=function(f) - n=n+1 - if f and f~="" then - return format("sequenced(a%s,%q)",n,f) - else - return format("sequenced(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("sequenced(a%s,%q)",n,f) + else + return format("sequenced(a%s)",n) + end end local format_l=function() - n=n+1 - return format("(a%s and 'true' or 'false')",n) + n=n+1 + return format("(a%s and 'true' or 'false')",n) end local format_L=function() - n=n+1 - return format("(a%s and 'TRUE' or 'FALSE')",n) + n=n+1 + return format("(a%s and 'TRUE' or 'FALSE')",n) end -local format_N=function() - n=n+1 - return format("tostring(tonumber(a%s) or a%s)",n,n) +local format_n=function() + n=n+1 + return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n) +end +local format_N=function(f) + n=n+1 + if not f or f=="" then + f=".9" + end + return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n) end local format_a=function(f) - n=n+1 - if f and f~="" then - return format("autosingle(a%s,%q)",n,f) - else - return format("autosingle(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autosingle(a%s,%q)",n,f) + else + return format("autosingle(a%s)",n) + end end local format_A=function(f) - n=n+1 - if f and f~="" then - return format("autodouble(a%s,%q)",n,f) - else - return format("autodouble(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autodouble(a%s,%q)",n,f) + else + return format("autodouble(a%s)",n) + end end local format_w=function(f) - n=n+1 - f=tonumber(f) - if f then - return format("nspaces[%s+a%s]",f,n) - else - return format("nspaces[a%s]",n) - end + n=n+1 + f=tonumber(f) + if f then + return format("nspaces[%s+a%s]",f,n) + else + return format("nspaces[a%s]",n) + end end local format_W=function(f) - return format("nspaces[%s]",tonumber(f) or 0) + return format("nspaces[%s]",tonumber(f) or 0) end local format_m=function(f) - n=n+1 - if not f or f=="" then - f="," - end + n=n+1 + if not f or f=="" then + f="," + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,".")]],n,f) + end end local format_M=function(f) - n=n+1 - if not f or f=="" then - f="." - end + n=n+1 + if not f or f=="" then + f="." + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,",")]],n,f) + end end local format_z=function(f) - n=n+(tonumber(f) or 1) - return "''" + n=n+(tonumber(f) or 1) + return "''" end local format_rest=function(s) - return format("%q",s) + return format("%q",s) end local format_extension=function(extensions,f,name) - local extension=extensions[name] or "tostring(%s)" - local f=tonumber(f) or 1 - local w=find(extension,"%.%.%.") + local extension=extensions[name] or "tostring(%s)" + local f=tonumber(f) or 1 + local w=find(extension,"%.%.%.") + if w then if f==0 then - if w then - extension=gsub(extension,"%.%.%.","") - end - return extension + extension=gsub(extension,"%.%.%.","") + return extension elseif f==1 then - if w then - extension=gsub(extension,"%.%.%.","%%s") - end - n=n+1 - local a="a"..n - return format(extension,a,a) + extension=gsub(extension,"%.%.%.","%%s") + n=n+1 + local a="a"..n + return format(extension,a,a) elseif f<0 then - local a="a"..(n+f+1) - return format(extension,a,a) + local a="a"..(n+f+1) + return format(extension,a,a) else - if w then - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - end - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + local t={} + for i=1,f do + n=n+1 + t[i]="a"..n + end + return format(extension,unpack(t)) end + else + extension=gsub(extension,"%%s",function() + n=n+1 + return "a"..n + end) + return extension + end end local builder=Cs { "start", - start=( - ( - P("%")/""*( - V("!") + start=( + ( + P("%")/""*( + V("!") +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("N") +V("k") +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") @@ -6750,160 +7147,156 @@ local builder=Cs { "start", +V("z") +V(">") +V("<") - )+V("*") - )*(P(-1)+Carg(1)) - )^0, - ["s"]=(prefix_any*P("s"))/format_s, - ["q"]=(prefix_any*P("q"))/format_q, - ["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, - ["E"]=(prefix_any*P("E"))/format_E, - ["x"]=(prefix_any*P("x"))/format_x, - ["X"]=(prefix_any*P("X"))/format_X, - ["o"]=(prefix_any*P("o"))/format_o, - ["S"]=(prefix_any*P("S"))/format_S, - ["Q"]=(prefix_any*P("Q"))/format_Q, - ["N"]=(prefix_any*P("N"))/format_N, - ["k"]=(prefix_sub*P("k"))/format_k, - ["c"]=(prefix_any*P("c"))/format_c, - ["C"]=(prefix_any*P("C"))/format_C, - ["r"]=(prefix_any*P("r"))/format_r, - ["h"]=(prefix_any*P("h"))/format_h, - ["H"]=(prefix_any*P("H"))/format_H, - ["u"]=(prefix_any*P("u"))/format_u, - ["U"]=(prefix_any*P("U"))/format_U, - ["p"]=(prefix_any*P("p"))/format_p, - ["b"]=(prefix_any*P("b"))/format_b, - ["t"]=(prefix_tab*P("t"))/format_t, - ["T"]=(prefix_tab*P("T"))/format_T, - ["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, - ["<"]=(prefix_any*P("<"))/format_left, - [">"]=(prefix_any*P(">"))/format_right, - ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, - ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, - ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, + )+V("*") + )*(endofstring+Carg(1)) + )^0, + ["s"]=(prefix_any*P("s"))/format_s, + ["q"]=(prefix_any*P("q"))/format_q, + ["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, + ["E"]=(prefix_any*P("E"))/format_E, + ["x"]=(prefix_any*P("x"))/format_x, + ["X"]=(prefix_any*P("X"))/format_X, + ["o"]=(prefix_any*P("o"))/format_o, + ["S"]=(prefix_any*P("S"))/format_S, + ["Q"]=(prefix_any*P("Q"))/format_Q, + ["n"]=(prefix_any*P("n"))/format_n, + ["N"]=(prefix_any*P("N"))/format_N, + ["k"]=(prefix_sub*P("k"))/format_k, + ["c"]=(prefix_any*P("c"))/format_c, + ["C"]=(prefix_any*P("C"))/format_C, + ["r"]=(prefix_any*P("r"))/format_r, + ["h"]=(prefix_any*P("h"))/format_h, + ["H"]=(prefix_any*P("H"))/format_H, + ["u"]=(prefix_any*P("u"))/format_u, + ["U"]=(prefix_any*P("U"))/format_U, + ["p"]=(prefix_any*P("p"))/format_p, + ["b"]=(prefix_any*P("b"))/format_b, + ["t"]=(prefix_tab*P("t"))/format_t, + ["T"]=(prefix_tab*P("T"))/format_T, + ["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_any*P("m"))/format_m, + ["M"]=(prefix_any*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, + ["<"]=(prefix_any*P("<"))/format_left, + [">"]=(prefix_any*P(">"))/format_right, + ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, + ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, + ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } local xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end }) local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end }) local preset={ - ["%02x"]=function(n) return xx[n] end, - ["%02X"]=function(n) return XX[n] end, + ["%02x"]=function(n) return xx[n] end, + ["%02X"]=function(n) return XX[n] end, } -local direct=P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] +local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]] local function make(t,str) - local f=preset[str] - if f then - return f - end - local p=lpegmatch(direct,str) - if p then - f=loadstripped(p)() + local f=preset[str] + if f then + return f + end + local p=lpegmatch(direct,str) + if p then + f=loadstripped(p)() + else + n=0 + 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,t._environment_)() else - n=0 - 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,t._environment_)() - else - f=function() return str end - end + f=function() return str end end - t[str]=f - return f + end + t[str]=f + return f end local function use(t,fmt,...) - return t[fmt](...) + return t[fmt](...) end strings.formatters={} -if oldfashioned 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 +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 local formatters=strings.formatters.new() string.formatters=formatters 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 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 + if type(t)=="table" and t._type_=="formatter" then + t._extensions_[name]=template or "%s" + 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 -patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) -patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) +patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+anything)^0) +patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^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 oldfashioned 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 +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 }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 -local space=patterns.space local cquote=Cc('"') -local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +Cs(cquote*(equote-space)^0*space*equote^0*cquote) function string.optionalquoted(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local pattern=Cs((newline/(os.newline or "\r")+1)^0) function string.replacenewlines(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function strings.newcollector() - local result,r={},0 - return - function(fmt,str,...) - r=r+1 - result[r]=str==nil and fmt or formatters[fmt](str,...) - end, - function(connector) - if result then - local str=concat(result,connector) - result,r={},0 - return str - end - end + local result,r={},0 + return + function(fmt,str,...) + r=r+1 + result[r]=str==nil and fmt or formatters[fmt](str,...) + end, + function(connector) + if result then + local str=concat(result,connector) + result,r={},0 + return str + end + end +end +local f_16_16=formatters["%0.5N"] +function number.to16dot16(n) + return f_16_16(n/65536.0) end @@ -6913,14 +7306,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tab"] = package.loaded["util-tab"] or true --- original size: 27741, stripped down to: 17085 +-- original size: 28772, stripped down to: 16111 if not modules then modules={} end modules ['util-tab']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.tables=utilities.tables or {} @@ -6935,219 +7328,220 @@ local formatters=string.formatters local utftoeight=utf.toeight local splitter=lpeg.tsplitat(".") 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=composed.."."..name - t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) - else - composed=name - if not nofirst then - t[#t+1]=formatters["%s = %s or { }"](composed,composed) - end - end - end + local composed=nil + local t={} + local snippets=lpegmatch(splitter,target) + for i=1,#snippets-(nolast and 1 or 0) do + local name=snippets[i] if composed then - if nolast then - composed=composed.."."..snippets[#snippets] - end - return concat(t,"\n"),composed + composed=composed.."."..name + t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) else - return "",target + composed=name + if not nofirst then + t[#t+1]=formatters["%s = %s or { }"](composed,composed) + end + end + end + if composed then + if nolast then + composed=composed.."."..snippets[#snippets] end + return concat(t,"\n"),composed + else + return "",target + end end function tables.definedtable(...) - local t=_G - for i=1,select("#",...) do - local li=select(i,...) - local tl=t[li] - if not tl then - tl={} - t[li]=tl - end - t=tl - end - return t + local t=_G + for i=1,select("#",...) do + local li=select(i,...) + local tl=t[li] + if not tl then + tl={} + t[li]=tl + end + t=tl + end + return t end function tables.accesstable(target,root) - local t=root or _G - for name in gmatch(target,"([^%.]+)") do - t=t[name] - if not t then - return - end + local t=root or _G + for name in gmatch(target,"([^%.]+)") do + t=t[name] + if not t then + return end - return t + end + return t end function tables.migratetable(target,v,root) - local t=root or _G - local names=lpegmatch(splitter,target) - for i=1,#names-1 do - local name=names[i] - t[name]=t[name] or {} - t=t[name] - if not t then - return - end + local t=root or _G + local names=lpegmatch(splitter,target) + for i=1,#names-1 do + local name=names[i] + t[name]=t[name] or {} + t=t[name] + if not t then + return end - t[names[#names]]=v + end + t[names[#names]]=v end function tables.removevalue(t,value) - if value then - for i=1,#t do - if t[i]==value then - remove(t,i) - end - end + if value then + for i=1,#t do + if t[i]==value then + remove(t,i) + end end + end end function tables.replacevalue(t,oldvalue,newvalue) - if oldvalue and newvalue then - for i=1,#t do - if t[i]==oldvalue then - t[i]=newvalue - end - end + if oldvalue and newvalue then + for i=1,#t do + if t[i]==oldvalue then + t[i]=newvalue + end end + end end function tables.insertbeforevalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i,extra) + return end - insert(t,1,extra) + end + insert(t,1,extra) end function tables.insertaftervalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i+1,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i+1,extra) + return end - insert(t,#t+1,extra) + end + insert(t,#t+1,extra) end local escape=Cs(Cc('"')*((P('"')/'""'+P(1))^0)*Cc('"')) function table.tocsv(t,specification) - if t and #t>0 then - local result={} - local r={} - specification=specification or {} - local fields=specification.fields - if type(fields)~="string" then - fields=sortedkeys(t[1]) - end - local separator=specification.separator or "," - local noffields=#fields - if specification.preamble==true then - for f=1,noffields do - r[f]=lpegmatch(escape,tostring(fields[f])) - end - result[1]=concat(r,separator) - end - for i=1,#t do - local ti=t[i] - for f=1,noffields do - local field=ti[fields[f]] - if type(field)=="string" then - r[f]=lpegmatch(escape,field) - else - r[f]=tostring(field) - end - end - result[i+1]=concat(r,separator) + if t and #t>0 then + local result={} + local r={} + specification=specification or {} + local fields=specification.fields + if type(fields)~="string" then + fields=sortedkeys(t[1]) + end + local separator=specification.separator or "," + local noffields=#fields + if specification.preamble==true then + for f=1,noffields do + r[f]=lpegmatch(escape,tostring(fields[f])) + end + result[1]=concat(r,separator) + end + for i=1,#t do + local ti=t[i] + for f=1,noffields do + local field=ti[fields[f]] + if type(field)=="string" then + r[f]=lpegmatch(escape,field) + else + r[f]=tostring(field) end - return concat(result,"\n") - else - return "" + end + result[i+1]=concat(r,separator) end + return concat(result,"\n") + else + return "" + end end local nspaces=utilities.strings.newrepeater(" ") local function toxml(t,d,result,step) - local r=#result - for k,v in sortedpairs(t) do - local s=nspaces[d] - local tk=type(k) - local tv=type(v) - if tv=="table" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</entry>"](s,k) - else - r=r+1 result[r]=formatters["%s<%s>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</%s>"](s,k) - end - elseif tv=="string" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) - end - elseif tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) - end + local r=#result + for k,v in sortedpairs(t) do + local s=nspaces[d] + local tk=type(k) + local tv=type(v) + if tv=="table" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</entry>"](s,k) + else + r=r+1 result[r]=formatters["%s<%s>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</%s>"](s,k) + end + elseif tv=="string" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) + end + elseif tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) end + end end function table.toxml(t,specification) - specification=specification or {} - local name=specification.name - local noroot=name==false - local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } - local indent=specification.indent or 0 - local spaces=specification.spaces or 1 - if noroot then - toxml(t,indent,result,spaces) - else - toxml({ [name or "data"]=t },indent,result,spaces) - end - return concat(result,"\n") + specification=specification or {} + local name=specification.name + local noroot=name==false + local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } + local indent=specification.indent or 0 + local spaces=specification.spaces or 1 + if noroot then + toxml(t,indent,result,spaces) + else + toxml({ [name or "data"]=t },indent,result,spaces) + end + return concat(result,"\n") end function tables.encapsulate(core,capsule,protect) - if type(capsule)~="table" then - protect=true - capsule={} - end + if type(capsule)~="table" then + protect=true + capsule={} + end + for key,value in next,core do + if capsule[key] then + print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) + os.exit() + else + capsule[key]=value + end + end + if protect then for key,value in next,core do + core[key]=nil + end + setmetatable(core,{ + __index=capsule, + __newindex=function(t,key,value) if capsule[key] then - print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) - os.exit() + print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) + os.exit() else - capsule[key]=value + rawset(t,key,value) end - end - if protect then - for key,value in next,core do - core[key]=nil - end - setmetatable(core,{ - __index=capsule, - __newindex=function(t,key,value) - if capsule[key] then - print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) - os.exit() - else - rawset(t,key,value) - end - end - } ) - end + end + } ) + end end local f_hashed_string=formatters["[%q]=%q,"] local f_hashed_number=formatters["[%q]=%s,"] @@ -7161,157 +7555,157 @@ 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 + 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 - for k,v in next,t do - 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 + end + for k,v in next,t do + 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 - m=m+1 - if outer then - r[m]="}" - else - r[m]="}," + 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 - return r + end end - return concat(fastserialize(t,true)) + m=m+1 + if outer then + r[m]="}" + else + r[m]="}," + end + return r + end + return concat(fastserialize(t,true)) end function table.deserialize(str) - if not str or str=="" then - return - end - local code=load(str) - if not code then - return - end - code=code() - if not code then - return - end - return code + if not str or str=="" then + return + end + local code=load(str) + if not code then + return + end + code=code() + if not code then + return + end + return code end 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() - if type(t)=="table" then - return t - end - end + 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() + if type(t)=="table" then + return t end + end end + end end function table.save(filename,t,n,...) - io.savedata(filename,table.serialize(t,n==nil and true or n,...)) + io.savedata(filename,table.serialize(t,n==nil and true or n,...)) end 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 - local ti=t[i] - local j=0 - for k,v in next,ti do - j=j+1 - l[j]=f_key_value(k,v) - end - r[i]=f_add_table(l) - end - return f_return_table(r) + local r={} + local l={} + for i=1,#t do + local ti=t[i] + local j=0 + for k,v in next,ti do + j=j+1 + l[j]=f_key_value(k,v) + end + r[i]=f_add_table(l) + end + 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] - m=m+1 r[m]=" {" - for k,v in next,ti do - m=m+1 r[m]=f_key_value(k,v) - end - m=m+1 r[m]="},\n" - end - m=m+1 - r[m]="}" - return concat(r) + local r={ "return {\n" } + local m=1 + for i=1,#t do + local ti=t[i] + m=m+1 r[m]=" {" + for k,v in next,ti do + m=m+1 r[m]=f_key_value(k,v) + end + m=m+1 r[m]="},\n" + end + m=m+1 + r[m]="}" + return concat(r) end function table.drop(t,slow) - if #t==0 then - return "return { }" - elseif slow==true then - return slowdrop(t) - else - return fastdrop(t) - end + if #t==0 then + return "return { }" + elseif slow==true then + return slowdrop(t) + else + return fastdrop(t) + end end local selfmapper={ __index=function(t,k) t[k]=k return k end } -function table.twowaymapper(t) - if not t then - t={} - else - local zero=rawget(t,0) - for i=zero and 0 or 1,#t do - local ti=t[i] - if ti then - local i=tostring(i) - t[i]=ti - t[ti]=i - end - end +function table.twowaymapper(t) + if not t then + t={} + else + local zero=rawget(t,0) + for i=zero and 0 or 1,#t do + local ti=t[i] + if ti then + local i=tostring(i) + t[i]=ti + t[ti]=i + end end - setmetatable(t,selfmapper) - return t + end + setmetatable(t,selfmapper) + return t end local f_start_key_idx=formatters["%w{"] local f_start_key_num=formatters["%w[%s]={"] @@ -7349,187 +7743,223 @@ local spaces=utilities.strings.newrepeater(" ") local original_serialize=table.serialize local is_simple_table=table.is_simple_table local function serialize(root,name,specification) - if type(specification)=="table" then - return original_serialize(root,name,specification) - end - local t - local n=1 - local unknown=false - 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) + if type(specification)=="table" then + return original_serialize(root,name,specification) + end + local t + local n=1 + local unknown=false + 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)~=nil then + local first=nil + local last=0 + last=#root + for k=1,last do + if rawget(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<=last and k>=first 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 next(v)==nil then + n=n+1 t[n]=f_val_not(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)~=nil then - local first=nil - local last=0 - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end + local st=is_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 - if last>0 then - first=1 + elseif tv=="boolean" then + n=n+1 t[n]=f_val_boo(depth,v) + elseif unknown then + n=n+1 t[n]=f_val_str(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) + end + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_not(depth,k) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_not(depth,k) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_not(depth,k) + elseif unknown then + n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) 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<=last and k>=first 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 next(v)==nil then - n=n+1 t[n]=f_val_not(depth) - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_val_str(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) - end - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - n=n+1 t[n]=f_key_num_value_not(depth,k) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_not(depth,k) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_not(depth,k) - elseif unknown then - n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) - end - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_seq(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) - end - else - if tk=="number" then - n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(v)) - end - end + else + local st=is_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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_seq(depth,tostring(k),st) 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() } + 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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) + end else - t={ f_table_direct() } + if tk=="number" then + n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(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("t") } + t={ f_table_name(name) } 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)~=nil then - local st=is_simple_table(root) - if st then - return t[1]..f_fin_seq(st) - else - do_serialize(root,name,1,0) - end - 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)~=nil then + local st=is_simple_table(root) + if st then + return t[1]..f_fin_seq(st) + else + do_serialize(root,name,1,0) + end end - n=n+1 - t[n]=f_table_finish() - return concat(t,"\n") + end + n=n+1 + t[n]=f_table_finish() + return concat(t,"\n") end table.serialize=serialize if setinspector then - setinspector("table",function(v) - if type(v)=="table" then - print(serialize(v,"table",{ metacheck=false })) - return true - end - end) + setinspector("table",function(v) + if type(v)=="table" then + print(serialize(v,"table",{ metacheck=false })) + return true + end + end) +end +local mt={ + __newindex=function(t,k,v) + local n=t.last+1 + t.last=n + t.list[n]=k + t.hash[k]=v + end, + __index=function(t,k) + return t.hash[k] + end, + __len=function(t) + return t.last + end, +} +function table.orderedhash() + return setmetatable({ list={},hash={},last=0 },mt) +end +function table.ordered(t) + local n=t.last + if n>0 then + local l=t.list + local i=1 + local h=t.hash + local f=function() + if i<=n then + local k=i + local v=h[l[k]] + i=i+1 + return k,v + end + end + return f,1,h[l[1]] + else + return function() end + end end @@ -7539,15 +7969,16 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7787, stripped down to: 5858 +-- original size: 8607, stripped down to: 6727 if not modules then modules={} end modules ['util-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } +local tonumber=tonumber local byte=string.byte local char=string.char utilities=utilities or {} @@ -7555,251 +7986,280 @@ local files={} utilities.files=files local zerobased={} function files.open(filename,zb) - local f=io.open(filename,"rb") - if f then - zerobased[f]=zb or false - end - return f + local f=io.open(filename,"rb") + if f then + zerobased[f]=zb or false + end + return f end function files.close(f) - zerobased[f]=nil - f:close() + zerobased[f]=nil + f:close() end function files.size(f) - local current=f:seek() - local size=f:seek("end") - f:seek("set",current) - return size + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) - if zerobased[f] then - f:seek("set",n) - else - f:seek("set",n-1) - end + if zerobased[f] then + f:seek("set",n) + else + f:seek("set",n-1) + end end function files.getposition(f) - if zerobased[f] then - return f:seek() - else - return f:seek()+1 - end + if zerobased[f] then + return f:seek() + else + return f:seek()+1 + end end function files.look(f,n,chars) - local p=f:seek() - local s=f:read(n) - f:seek("set",p) - if chars then - return s - else - return byte(s,1,#s) - end + local p=f:seek() + local s=f:read(n) + f:seek("set",p) + if chars then + return s + else + return byte(s,1,#s) + end end function files.skip(f,n) - if n==1 then - f:read(n) - else - f:seek("set",f:seek()+n) - end + if n==1 then + f:read(n) + else + f:seek("set",f:seek()+n) + end end function files.readbyte(f) - return byte(f:read(1)) + return byte(f:read(1)) end function files.readbytes(f,n) - return byte(f:read(n),1,n) + return byte(f:read(n),1,n) end function files.readbytetable(f,n) - local s=f:read(n or 1) - return { byte(s,1,#s) } + local s=f:read(n or 1) + return { byte(s,1,#s) } end function files.readchar(f) - return f:read(1) + return f:read(1) end function files.readstring(f,n) - return f:read(n or 1) + return f:read(n or 1) end -function files.readinteger1(f) - local n=byte(f:read(1)) - if n>=0x80 then - return n-0x100 - else - return n - end +function files.readinteger1(f) + local n=byte(f:read(1)) + if n>=0x80 then + return n-0x100 + else + return n + end end -files.readcardinal1=files.readbyte +files.readcardinal1=files.readbyte files.readcardinal=files.readcardinal1 files.readinteger=files.readinteger1 files.readsignedbyte=files.readinteger1 function files.readcardinal2(f) - local a,b=byte(f:read(2),1,2) - return 0x100*a+b + local a,b=byte(f:read(2),1,2) + return 0x100*a+b end function files.readcardinal2le(f) - local b,a=byte(f:read(2),1,2) - return 0x100*a+b + local b,a=byte(f:read(2),1,2) + return 0x100*a+b end function files.readinteger2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readinteger2le(f) - local b,a=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local b,a=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readcardinal3(f) - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readcardinal3le(f) - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readinteger3(f) - local a,b,c=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local a,b,c=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readinteger3le(f) - local c,b,a=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local c,b,a=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readcardinal4(f) - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readcardinal4le(f) - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readinteger4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readinteger4le(f) - local d,c,b,a=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local d,c,b,a=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readfixed2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return (a-0x100)+b/0x100 - else - return (a )+b/0x100 - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function files.readfixed4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end if bit32 then - local extract=bit32.extract - local band=bit32.band - function files.read2dot14(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local extract=bit32.extract + local band=bit32.band + function files.read2dot14(f) + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) + else + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function files.skipshort(f,n) - f:read(2*(n or 1)) + f:read(2*(n or 1)) end function files.skiplong(f,n) - f:read(4*(n or 1)) + f:read(4*(n or 1)) end if bit32 then - local rshift=bit32.rshift - function files.writecardinal2(f,n) - local a=char(n%256) - n=rshift(n,8) - local b=char(n%256) - f:write(b,a) - end -else - local floor=math.floor - function files.writecardinal2(f,n) - local a=char(n%256) - n=floor(n/256) - local b=char(n%256) - f:write(b,a) - end -end -function files.writecardinal4(f,n) + local rshift=bit32.rshift + function files.writecardinal2(f,n) local a=char(n%256) n=rshift(n,8) local b=char(n%256) - n=rshift(n,8) - local c=char(n%256) - n=rshift(n,8) - local d=char(n%256) - f:write(d,c,b,a) + f:write(b,a) + end +else + local floor=math.floor + function files.writecardinal2(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + f:write(b,a) + end +end +function files.writecardinal4(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(d,c,b,a) end function files.writestring(f,s) - f:write(char(byte(s,1,#s))) + f:write(char(byte(s,1,#s))) end function files.writebyte(f,b) - f:write(char(b)) + f:write(char(b)) end if fio and fio.readcardinal1 then - files.readcardinal1=fio.readcardinal1 - files.readcardinal2=fio.readcardinal2 - files.readcardinal3=fio.readcardinal3 - files.readcardinal4=fio.readcardinal4 - files.readinteger1=fio.readinteger1 - files.readinteger2=fio.readinteger2 - files.readinteger3=fio.readinteger3 - files.readinteger4=fio.readinteger4 - files.readfixed2=fio.readfixed2 - files.readfixed4=fio.readfixed4 - files.read2dot14=fio.read2dot14 - files.setposition=fio.setposition - files.getposition=fio.getposition - files.readbyte=files.readcardinal1 - files.readsignedbyte=files.readinteger1 - files.readcardinal=files.readcardinal1 - files.readinteger=files.readinteger1 - local skipposition=fio.skipposition - files.skipposition=skipposition - files.readbytes=fio.readbytes - files.readbytetable=fio.readbytetable - function files.skipshort(f,n) - skipposition(f,2*(n or 1)) - end - function files.skiplong(f,n) - skipposition(f,4*(n or 1)) - end + files.readcardinal1=fio.readcardinal1 + files.readcardinal2=fio.readcardinal2 + files.readcardinal3=fio.readcardinal3 + files.readcardinal4=fio.readcardinal4 + files.readinteger1=fio.readinteger1 + files.readinteger2=fio.readinteger2 + files.readinteger3=fio.readinteger3 + files.readinteger4=fio.readinteger4 + files.readfixed2=fio.readfixed2 + files.readfixed4=fio.readfixed4 + files.read2dot14=fio.read2dot14 + files.setposition=fio.setposition + files.getposition=fio.getposition + files.readbyte=files.readcardinal1 + files.readsignedbyte=files.readinteger1 + files.readcardinal=files.readcardinal1 + files.readinteger=files.readinteger1 + local skipposition=fio.skipposition + files.skipposition=skipposition + files.readbytes=fio.readbytes + files.readbytetable=fio.readbytetable + function files.skipshort(f,n) + skipposition(f,2*(n or 1)) + end + function files.skiplong(f,n) + skipposition(f,4*(n or 1)) + end +end +if fio and fio.readcardinaltable then + files.readcardinaltable=fio.readcardinaltable + files.readintegertable=fio.readintegertable +else + local readcardinal1=files.readcardinal1 + local readcardinal2=files.readcardinal2 + local readcardinal3=files.readcardinal3 + local readcardinal4=files.readcardinal4 + function files.readcardinaltable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end + return t + end + local readinteger1=files.readinteger1 + local readinteger2=files.readinteger2 + local readinteger3=files.readinteger3 + local readinteger4=files.readinteger4 + function files.readintegertable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end + return t + end end @@ -7809,338 +8269,412 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sac"] = package.loaded["util-sac"] or true --- original size: 8716, stripped down to: 6754 +-- original size: 11065, stripped down to: 8209 if not modules then modules={} end modules ['util-sac']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local byte,sub=string.byte,string.sub -local extract=bit32 and bit32.extract +local tonumber=tonumber utilities=utilities or {} local streams={} utilities.streams=streams function streams.open(filename,zerobased) - local f=io.loaddata(filename) + local f=filename and io.loaddata(filename) + if f then return { f,1,#f,zerobased or false } + end +end +function streams.openstring(f,zerobased) + if f then + return { f,1,#f,zerobased or false } + end end function streams.close() end function streams.size(f) - return f and f[3] or 0 + return f and f[3] or 0 end function streams.setposition(f,i) - if f[4] then - if i<=0 then - f[2]=1 - else - f[2]=i+1 - end + if f[4] then + if i<=0 then + f[2]=1 else - if i<=1 then - f[2]=1 - else - f[2]=i - end + f[2]=i+1 end -end -function streams.getposition(f) - if f[4] then - return f[2]-1 + else + if i<=1 then + f[2]=1 else - return f[2] + f[2]=i end + end +end +function streams.getposition(f) + if f[4] then + return f[2]-1 + else + return f[2] + end end function streams.look(f,n,chars) - local b=f[2] - local e=b+n-1 - if chars then - return sub(f[1],b,e) - else - return byte(f[1],b,e) - end + local b=f[2] + local e=b+n-1 + if chars then + return sub(f[1],b,e) + else + return byte(f[1],b,e) + end end function streams.skip(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readbyte(f) - local i=f[2] - f[2]=i+1 - return byte(f[1],i) + local i=f[2] + f[2]=i+1 + return byte(f[1],i) end function streams.readbytes(f,n) - local i=f[2] - local j=i+n - f[2]=j - return byte(f[1],i,j-1) + local i=f[2] + local j=i+n + f[2]=j + return byte(f[1],i,j-1) end function streams.readbytetable(f,n) - local i=f[2] - local j=i+n - f[2]=j - return { byte(f[1],i,j-1) } + local i=f[2] + local j=i+n + f[2]=j + return { byte(f[1],i,j-1) } end function streams.skipbytes(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readchar(f) - local i=f[2] - f[2]=i+1 - return sub(f[1],i,i) + local i=f[2] + f[2]=i+1 + return sub(f[1],i,i) end function streams.readstring(f,n) - local i=f[2] - local j=i+n - f[2]=j - return sub(f[1],i,j-1) -end -function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - local n=byte(f[1],i) - if n>=0x80 then - return n-0x100 - else - return n - end + local i=f[2] + local j=i+n + f[2]=j + return sub(f[1],i,j-1) +end +function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + local n=byte(f[1],i) + if n>=0x80 then + return n-0x100 + else + return n + end end -streams.readcardinal1=streams.readbyte +streams.readcardinal1=streams.readbyte streams.readcardinal=streams.readcardinal1 streams.readinteger=streams.readinteger1 function streams.readcardinal2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + return 0x100*a+b end function streams.readcardinal2LE(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + return 0x100*a+b end function streams.readinteger2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readinteger2le(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readcardinal3(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readcardinal3le(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readinteger3(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readinteger3le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readcardinal4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - return 0x1000000*a+0x10000*b+0x100*c+d + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + return 0x1000000*a+0x10000*b+0x100*c+d end function streams.readinteger4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function streams.readinteger4le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local d,c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local d,c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end +end +function streams.readfixed2(f) + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function streams.readfixed4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end -function streams.readfixed2(f) +if bit32 then + local extract=bit32.extract + local band=bit32.band + function streams.read2dot14(f) local i=f[2] local j=i+1 f[2]=j+1 local a,b=byte(f[1],i,j) if a>=0x80 then - return (a-0x100)+b/0x100 + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) else - return (a )+b/0x100 - end -end -if extract then - local extract=bit32.extract - local band=bit32.band - function streams.read2dot14(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function streams.skipshort(f,n) - f[2]=f[2]+2*(n or 1) + f[2]=f[2]+2*(n or 1) end function streams.skiplong(f,n) - f[2]=f[2]+4*(n or 1) + f[2]=f[2]+4*(n or 1) end if sio and sio.readcardinal2 then - local readcardinal1=sio.readcardinal1 - local readcardinal2=sio.readcardinal2 - local readcardinal3=sio.readcardinal3 - local readcardinal4=sio.readcardinal4 - local readinteger1=sio.readinteger1 - local readinteger2=sio.readinteger2 - local readinteger3=sio.readinteger3 - local readinteger4=sio.readinteger4 - local readfixed2=sio.readfixed2 - local readfixed4=sio.readfixed4 - local read2dot14=sio.read2dot14 - local readbytes=sio.readbytes - local readbytetable=sio.readbytetable - function streams.readcardinal1(f) - local i=f[2] - f[2]=i+1 - return readcardinal1(f[1],i) - end - function streams.readcardinal2(f) - local i=f[2] - f[2]=i+2 - return readcardinal2(f[1],i) - end - function streams.readcardinal3(f) - local i=f[2] - f[2]=i+3 - return readcardinal3(f[1],i) - end - function streams.readcardinal4(f) - local i=f[2] - f[2]=i+4 - return readcardinal4(f[1],i) - end - function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - return readinteger1(f[1],i) - end - function streams.readinteger2(f) - local i=f[2] - f[2]=i+2 - return readinteger2(f[1],i) - end - function streams.readinteger3(f) - local i=f[2] - f[2]=i+3 - return readinteger3(f[1],i) - end - function streams.readinteger4(f) - local i=f[2] - f[2]=i+4 - return readinteger4(f[1],i) - end - function streams.read2dot4(f) - local i=f[2] - f[2]=i+2 - return read2dot4(f[1],i) - end - function streams.readbytes(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytes(f[1],i,n) + local readcardinal1=sio.readcardinal1 + local readcardinal2=sio.readcardinal2 + local readcardinal3=sio.readcardinal3 + local readcardinal4=sio.readcardinal4 + local readinteger1=sio.readinteger1 + local readinteger2=sio.readinteger2 + local readinteger3=sio.readinteger3 + local readinteger4=sio.readinteger4 + local readfixed2=sio.readfixed2 + local readfixed4=sio.readfixed4 + local read2dot14=sio.read2dot14 + local readbytes=sio.readbytes + local readbytetable=sio.readbytetable + function streams.readcardinal1(f) + local i=f[2] + f[2]=i+1 + return readcardinal1(f[1],i) + end + function streams.readcardinal2(f) + local i=f[2] + f[2]=i+2 + return readcardinal2(f[1],i) + end + function streams.readcardinal3(f) + local i=f[2] + f[2]=i+3 + return readcardinal3(f[1],i) + end + function streams.readcardinal4(f) + local i=f[2] + f[2]=i+4 + return readcardinal4(f[1],i) + end + function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + return readinteger1(f[1],i) + end + function streams.readinteger2(f) + local i=f[2] + f[2]=i+2 + return readinteger2(f[1],i) + end + function streams.readinteger3(f) + local i=f[2] + f[2]=i+3 + return readinteger3(f[1],i) + end + function streams.readinteger4(f) + local i=f[2] + f[2]=i+4 + return readinteger4(f[1],i) + end + function streams.read2dot4(f) + local i=f[2] + f[2]=i+2 + return read2dot4(f[1],i) + end + function streams.readbytes(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p end - function streams.readbytetable(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytetable(f[1],i,n) + return readbytes(f[1],i,n) + end + function streams.readbytetable(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readbytetable(f[1],i,n) + end + streams.readbyte=streams.readcardinal1 + streams.readsignedbyte=streams.readinteger1 + streams.readcardinal=streams.readcardinal1 + streams.readinteger=streams.readinteger1 +end +if sio and sio.readcardinaltable then + local readcardinaltable=sio.readcardinaltable + local readintegertable=sio.readintegertable + function utilities.streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readcardinaltable(f[1],i,n,b) + end + function utilities.streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readintegertable(f[1],i,n,b) + end +else + local readcardinal1=streams.readcardinal1 + local readcardinal2=streams.readcardinal2 + local readcardinal3=streams.readcardinal3 + local readcardinal4=streams.readcardinal4 + function streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p end - streams.readbyte=streams.readcardinal1 - streams.readsignedbyte=streams.readinteger1 - streams.readcardinal=streams.readcardinal1 - streams.readinteger=streams.readinteger1 + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end + return t + end + local readinteger1=streams.readinteger1 + local readinteger2=streams.readinteger2 + local readinteger3=streams.readinteger3 + local readinteger4=streams.readinteger4 + function streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end + return t + end end @@ -8150,156 +8684,168 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sto"] = package.loaded["util-sto"] or true --- original size: 6449, stripped down to: 3069 +-- original size: 6661, stripped down to: 3074 if not modules then modules={} end modules ['util-sto']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local setmetatable,getmetatable,rawset,type=setmetatable,getmetatable,rawset,type utilities=utilities or {} utilities.storage=utilities.storage or {} local storage=utilities.storage function storage.mark(t) - if not t then - print("\nfatal error: storage cannot be marked\n") - os.exit() - return - end - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + if not t then + print("\nfatal error: storage cannot be marked\n") + os.exit() + return + end + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.allocate(t) - t=t or {} - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + t=t or {} + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.marked(t) - local m=getmetatable(t) - return m and m.__storage__ + local m=getmetatable(t) + return m and m.__storage__ end function storage.checked(t) - if not t then - report("\nfatal error: storage has not been allocated\n") - os.exit() - return - end - return t + if not t then + report("\nfatal error: storage has not been allocated\n") + os.exit() + return + end + return t end function storage.setinitializer(data,initialize) - local m=getmetatable(data) or {} - m.__index=function(data,k) - m.__index=nil - initialize() - return data[k] - end - setmetatable(data,m) + local m=getmetatable(data) or {} + m.__index=function(data,k) + m.__index=nil + initialize() + return data[k] + end + setmetatable(data,m) end local keyisvalue={ __index=function(t,k) - t[k]=k - return k + t[k]=k + return k end } function storage.sparse(t) - t=t or {} - setmetatable(t,keyisvalue) - return t -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 + t=t or {} + setmetatable(t,keyisvalue) + return t +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 f_index={ - ["empty"]=f_empty, - ["self"]=f_self, - ["table"]=f_table, - ["number"]=f_number, + ["empty"]=f_empty, + ["self"]=f_self, + ["table"]=f_table, + ["number"]=f_number, } function table.setmetatableindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - else - setmetatable(t,{ __index=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + else + setmetatable(t,{ __index=i }) + end + return t end local f_index={ - ["ignore"]=f_ignore, + ["ignore"]=f_ignore, } function table.setmetatablenewindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__newindex=i - else - setmetatable(t,{ __newindex=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__newindex=i + else + setmetatable(t,{ __newindex=i }) + end + return t end function table.setmetatablecall(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - if m then - m.__call=f - else - setmetatable(t,{ __call=f }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + if m then + m.__call=f + else + setmetatable(t,{ __call=f }) + end + return t end function table.setmetatableindices(t,f,n,c) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - m.__newindex=n - m.__call=c - else - setmetatable(t,{ - __index=i, - __newindex=n, - __call=c, - }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + m.__newindex=n + m.__call=c + else + setmetatable(t,{ + __index=i, + __newindex=n, + __call=c, + }) + end + return t end function table.setmetatablekey(t,key,value) - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m[key]=value - return t + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m[key]=value + return t end function table.getmetatablekey(t,key,value) - local m=getmetatable(t) - return m and m[key] + local m=getmetatable(t) + return m and m[key] +end +function table.makeweak(t) + if not t then + t={} + end + local m=getmetatable(t) + if m then + m.__mode="v" + else + setmetatable(t,{ __mode="v" }) + end + return t end @@ -8309,14 +8855,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-prs"] = package.loaded["util-prs"] or true --- original size: 22956, stripped down to: 16106 +-- original size: 23460, stripped down to: 15834 if not modules then modules={} end modules ['util-prs']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } 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 @@ -8338,6 +8884,7 @@ utilities.parsers.hashes=hashes local digit=R("09") local space=P(' ') local equal=P("=") +local colon=P(":") local comma=P(",") local lbrace=P("{") local rbrace=P("}") @@ -8357,8 +8904,8 @@ local noparent=1-(lparent+rparent) local nobracket=1-(lbracket+rbracket) local escape,left,right=P("\\"),P('{'),P('}') lpegpatterns.balanced=P { - [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, - [2]=left*V(1)*right + [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, + [2]=left*V(1)*right } local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace } local nestedparents=P { lparent*(noparent+V(1))^0*rparent } @@ -8366,311 +8913,329 @@ local nestedbrackets=P { lbracket*(nobracket+V(1))^0*rbracket } local spaces=space^0 local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/"")) local content=(1-endofstring)^0 -lpegpatterns.nestedbraces=nestedbraces +lpegpatterns.nestedbraces=nestedbraces lpegpatterns.nestedparents=nestedparents -lpegpatterns.nested=nestedbraces +lpegpatterns.nested=nestedbraces lpegpatterns.argument=argument lpegpatterns.content=content -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local key=C((1-equal-comma)^1) local pattern_a=(space+comma)^0*(key*equal*value+key*C("")) local pattern_c=(space+comma)^0*(key*equal*value) +local pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C("")) local key=C((1-space-equal-comma)^1) local pattern_b=spaces*comma^0*spaces*(key*((spaces*equal*spaces*value)+C(""))) local hash={} local function set(key,value) - hash[key]=value + hash[key]=value end local pattern_a_s=(pattern_a/set)^1 local pattern_b_s=(pattern_b/set)^1 local pattern_c_s=(pattern_c/set)^1 +local pattern_d_s=(pattern_d/set)^1 patterns.settings_to_hash_a=pattern_a_s patterns.settings_to_hash_b=pattern_b_s patterns.settings_to_hash_c=pattern_c_s +patterns.settings_to_hash_d=pattern_d_s function parsers.make_settings_to_hash_pattern(set,how) - if how=="strict" then - return (pattern_c/set)^1 - elseif how=="tolerant" then - return (pattern_b/set)^1 - else - return (pattern_a/set)^1 - end + if how=="strict" then + return (pattern_c/set)^1 + elseif how=="tolerant" then + return (pattern_b/set)^1 + else + return (pattern_a/set)^1 + end end function parsers.settings_to_hash(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_a_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_a_s,str) + return hash + end +end +function parsers.settings_to_hash_colon_too(str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + else + hash={} + lpegmatch(pattern_d_s,str) + return hash + end end function parsers.settings_to_hash_tolerant(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_b_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_b_s,str) + return hash + end end function parsers.settings_to_hash_strict(str,existing) - if not str or str=="" then - return nil - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end - elseif str and str~="" then - hash=existing or {} - lpegmatch(pattern_c_s,str) - return next(hash) and hash + if not str or str=="" then + return nil + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting + else + return str end + elseif str and str~="" then + hash=existing or {} + lpegmatch(pattern_c_s,str) + return next(hash) and hash + end end local separator=comma*space^0 -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) patterns.settings_to_array=pattern function parsers.settings_to_array(str,strict) - if not str or str=="" then - return {} - elseif type(str)=="table" then - return str - elseif strict then - if find(str,"{",1,true) then - return lpegmatch(pattern,str) - else - return { str } - end - elseif find(str,",",1,true) then - return lpegmatch(pattern,str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + elseif strict then + if find(str,"{",1,true) then + return lpegmatch(pattern,str) else - return { str } + return { str } end + elseif find(str,",",1,true) then + return lpegmatch(pattern,str) + else + return { str } + end end function parsers.settings_to_numbers(str) - if not str or str=="" then - return {} - end - if type(str)=="table" then - elseif find(str,",",1,true) then - str=lpegmatch(pattern,str) - else - return { tonumber(str) } - end - for i=1,#str do - str[i]=tonumber(str[i]) - end - return str -end -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) + if not str or str=="" then + return {} + end + if type(str)=="table" then + elseif find(str,",",1,true) then + str=lpegmatch(pattern,str) + else + return { tonumber(str) } + end + for i=1,#str do + str[i]=tonumber(str[i]) + end + return str +end +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_obey_fences(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache_a={} local cache_b={} function parsers.groupedsplitat(symbol,withaction) - if not symbol then - symbol="," - end - local pattern=(withaction and cache_b or cache_a)[symbol] - if not pattern then - local symbols=S(symbol) - local separator=space^0*symbols*space^0 - local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) - if withaction then - local withvalue=Carg(1)*value/function(f,s) return f(s) end - pattern=spaces*withvalue*(separator*withvalue)^0 - cache_b[symbol]=pattern - else - pattern=spaces*Ct(value*(separator*value)^0) - cache_a[symbol]=pattern - end - end - return pattern + if not symbol then + symbol="," + end + local pattern=(withaction and cache_b or cache_a)[symbol] + if not pattern then + local symbols=S(symbol) + local separator=space^0*symbols*space^0 + local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) + if withaction then + local withvalue=Carg(1)*value/function(f,s) return f(s) end + pattern=spaces*withvalue*(separator*withvalue)^0 + cache_b[symbol]=pattern + else + pattern=spaces*Ct(value*(separator*value)^0) + cache_a[symbol]=pattern + end + end + return pattern end local pattern_a=parsers.groupedsplitat(",",false) local pattern_b=parsers.groupedsplitat(",",true) function parsers.stripped_settings_to_array(str) - if not str or str=="" then - return {} - else - return lpegmatch(pattern_a,str) - end + 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 + if not str or str=="" then + return {} + else + return lpegmatch(pattern_b,str,1,action) + end end local function set(t,v) - t[#t+1]=v + t[#t+1]=v end local value=P(Carg(1)*value)/set local pattern=value*(separator*value)^0*Carg(1) function parsers.add_settings_to_array(t,str) - return lpegmatch(pattern,str,nil,t) + return lpegmatch(pattern,str,nil,t) end function parsers.hash_to_string(h,separator,yes,no,strict,omit) - if h then - local t,tn,s={},0,sortedkeys(h) - omit=omit and tohash(omit) - for i=1,#s do - local key=s[i] - if not omit or not omit[key] then - local value=h[key] - if type(value)=="boolean" then - if yes and no then - if value then - tn=tn+1 - t[tn]=key..'='..yes - elseif not strict then - tn=tn+1 - t[tn]=key..'='..no - end - elseif value or not strict then - tn=tn+1 - t[tn]=key..'='..tostring(value) - end - else - tn=tn+1 - t[tn]=key..'='..value - end - end + if h then + local t={} + local tn=0 + local s=sortedkeys(h) + omit=omit and tohash(omit) + for i=1,#s do + local key=s[i] + if not omit or not omit[key] then + local value=h[key] + if type(value)=="boolean" then + if yes and no then + if value then + tn=tn+1 + t[tn]=key..'='..yes + elseif not strict then + tn=tn+1 + t[tn]=key..'='..no + end + elseif value or not strict then + tn=tn+1 + t[tn]=key..'='..tostring(value) + end + else + tn=tn+1 + t[tn]=key..'='..value end - return concat(t,separator or ",") - else - return "" + end end + return concat(t,separator or ",") + else + return "" + end end function parsers.array_to_string(a,separator) - if a then - return concat(a,separator or ",") - else - return "" - end + if a then + return concat(a,separator or ",") + else + return "" + end end local pattern=Cf(Ct("")*Cg(C((1-S(", "))^1)*S(", ")^0*Cc(true))^1,rawset) function utilities.parsers.settings_to_set(str) - return str and lpegmatch(pattern,str) or {} + return str and lpegmatch(pattern,str) or {} end hashes.settings_to_set=table.setmetatableindex(function(t,k) - local v=k and lpegmatch(pattern,k) or {} - t[k]=v - return v + local v=k and lpegmatch(pattern,k) or {} + t[k]=v + return v end) getmetatable(hashes.settings_to_set).__mode="kv" function parsers.simple_hash_to_string(h,separator) - local t,tn={},0 - for k,v in sortedhash(h) do - if v then - tn=tn+1 - t[tn]=k - end + local t={} + local tn=0 + for k,v in sortedhash(h) do + if v then + tn=tn+1 + t[tn]=k end - return concat(t,separator or ",") + end + return concat(t,separator or ",") end local str=Cs(lpegpatterns.unquoted)+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 {} + return str and lpegmatch(splitter,str,1,target or {}) or {} end local splitter=lpeg.tsplitat(" ") function utilities.parsers.options_to_array(str) - return str and lpegmatch(splitter,str) or {} + return str and lpegmatch(splitter,str) 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) - if not n then - return str + if not n then + return str + else + local s=lpegmatch(pattern_a,str) + if n==1 then + return unpack(s) else - local s=lpegmatch(pattern_a,str) - if n==1 then - return unpack(s) - else - local t,tn={},0 - for i=1,n do - for j=1,#s do - tn=tn+1 - t[tn]=s[j] - end - end - return unpack(t) + local t={} + local tn=0 + for i=1,n do + for j=1,#s do + tn=tn+1 + t[tn]=s[j] end + end + return unpack(t) end + end end local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+(C(digit^1)/tonumber*lparent*Cs((noparent+nestedparents)^1)*rparent)/repeater+C((nestedbraces+(1-comma))^1) local pattern_b=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_with_repeat(str,expand) - if expand then - return lpegmatch(pattern_b,str) or {} - else - return lpegmatch(pattern_a,str) or {} - end + if expand then + return lpegmatch(pattern_b,str) or {} + else + return lpegmatch(pattern_a,str) or {} + end end local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace local pattern=Ct((space+value)^0) function parsers.arguments_to_table(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function parsers.getparameters(self,class,parentclass,settings) - local sc=self[class] - if not sc then - sc={} - self[class]=sc - if parentclass then - local sp=self[parentclass] - if not sp then - sp={} - self[parentclass]=sp - end - setmetatableindex(sc,sp) - end + local sc=self[class] + if not sc then + sc={} + self[class]=sc + if parentclass then + local sp=self[parentclass] + if not sp then + sp={} + self[parentclass]=sp + end + setmetatableindex(sc,sp) end - parsers.settings_to_hash(settings,sc) + end + parsers.settings_to_hash(settings,sc) end function parsers.listitem(str) - return gmatch(str,"[^, ]+") + return gmatch(str,"[^, ]+") end local pattern=Cs { "start", - start=V("one")+V("two")+V("three"), - rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, - thousand=digit*digit*digit, - one=digit*V("rest"), - two=digit*digit*V("rest"), - three=V("thousand")*V("rest"), + start=V("one")+V("two")+V("three"), + rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, + thousand=digit*digit*digit, + one=digit*V("rest"), + two=digit*digit*V("rest"), + three=V("thousand")*V("rest"), } lpegpatterns.splitthousands=pattern function parsers.splitthousands(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local optionalwhitespace=whitespace^0 lpegpatterns.words=Ct((Cs((1-punctuation-whitespace)^1)+anything)^1) @@ -8684,75 +9249,75 @@ local key=C((1-equal)^1) local value=dquote*C((1-dquote-escape*dquote)^0)*dquote local pattern=Cf(Ct("")*(Cg(key*equal*value)*separator^0)^1,rawset)^0*P(-1) function parsers.keq_to_hash(str) - if str and str~="" then - return lpegmatch(pattern,str) - else - return {} - end + if str and str~="" then + return lpegmatch(pattern,str) + else + return {} + end end local defaultspecification={ separator=",",quote='"' } function parsers.csvsplitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=specification.quote - local separator=S(separator~="" and separator or ",") - local whatever=C((1-separator-newline)^0) - if quotechar and quotechar~="" then - local quotedata=nil - for chr in gmatch(quotechar,".") do - local quotechar=P(chr) - local quoteword=quotechar*C((1-quotechar)^0)*quotechar - if quotedata then - quotedata=quotedata+quoteword - else - quotedata=quoteword - end - end - whatever=quotedata+whatever - end - local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) - return function(data) - return lpegmatch(parser,data) + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=specification.quote + local separator=S(separator~="" and separator or ",") + local whatever=C((1-separator-newline)^0) + if quotechar and quotechar~="" then + local quotedata=nil + for chr in gmatch(quotechar,".") do + local quotechar=P(chr) + local quoteword=quotechar*C((1-quotechar)^0)*quotechar + if quotedata then + quotedata=quotedata+quoteword + else + quotedata=quoteword + end end + whatever=quotedata+whatever + end + local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) + return function(data) + return lpegmatch(parser,data) + end end function parsers.rfc4180splitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=P(specification.quote) - local dquotechar=quotechar*quotechar + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=P(specification.quote) + local dquotechar=quotechar*quotechar /specification.quote - 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+Cc("") - local record=Ct(field*(separator*field)^1) - local headerline=record*Cp() - local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 - local headeryes=Ct(morerecords) - local headernop=Ct(record*morerecords) - return function(data,getheader) - if getheader then - local header,position=lpegmatch(headerline,data) - local data=lpegmatch(headeryes,data,position) - return data,header - else - return lpegmatch(headernop,data) - end - end + 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+Cc("") + local record=Ct(field*(separator*field)^1) + local headerline=record*Cp() + local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 + local headeryes=Ct(morerecords) + local headernop=Ct(record*morerecords) + return function(data,getheader) + if getheader then + local header,position=lpegmatch(headerline,data) + local data=lpegmatch(headeryes,data,position) + return data,header + else + return lpegmatch(headernop,data) + end + end end local function ranger(first,last,n,action) - if not first then - elseif last==true then - for i=first,n or first do - action(i) - end - elseif last then - for i=first,last do - action(i) - end - else - action(first) + if not first then + elseif last==true then + for i=first,n or first do + action(i) end + elseif last then + for i=first,last do + action(i) + end + else + action(first) + end end local cardinal=lpegpatterns.cardinal/tonumber local spacers=lpegpatterns.spacer^0 @@ -8760,89 +9325,89 @@ local endofstring=lpegpatterns.endofstring local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1 local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring function parsers.stepper(str,n,action) - if type(n)=="function" then - lpegmatch(stepper,str,1,false,n or print) - else - lpegmatch(stepper,str,1,n,action or print) - end + if type(n)=="function" then + lpegmatch(stepper,str,1,false,n or print) + else + lpegmatch(stepper,str,1,n,action or print) + end end local pattern_math=Cs((P("%")/"\\percent "+P("^")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) local pattern_text=Cs((P("%")/"\\percent "+(P("^")/"\\high")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) patterns.unittotex=pattern function parsers.unittotex(str,textmode) - return lpegmatch(textmode and pattern_text or pattern_math,str) + return lpegmatch(textmode and pattern_text or pattern_math,str) end local pattern=Cs((P("^")/"<sup>"*lpegpatterns.integer*Cc("</sup>")+anything)^0) function parsers.unittoxml(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache={} local spaces=lpegpatterns.space^0 local dummy=function() end setmetatableindex(cache,function(t,k) - local separator=P(k) - local value=(1-separator)^0 - local pattern=spaces*C(value)*separator^0*Cp() - t[k]=pattern - return pattern + local separator=P(k) + local value=(1-separator)^0 + local pattern=spaces*C(value)*separator^0*Cp() + t[k]=pattern + return pattern end) local commalistiterator=cache[","] function utilities.parsers.iterator(str,separator) - local n=#str - if n==0 then - return dummy - else - local pattern=separator and cache[separator] or commalistiterator - local p=1 - return function() - if p<=n then - local s,e=lpegmatch(pattern,str,p) - if e then - p=e - return s - end - end + local n=#str + if n==0 then + return dummy + else + local pattern=separator and cache[separator] or commalistiterator + local p=1 + return function() + if p<=n then + local s,e=lpegmatch(pattern,str,p) + if e then + p=e + return s end + end end + end end local function initialize(t,name) - local source=t[name] - if source then - local result={} - for k,v in next,t[name] do - result[k]=v - end - return result - else - return {} + local source=t[name] + if source then + local result={} + for k,v in next,t[name] do + result[k]=v end + return result + else + return {} + end end local function fetch(t,name) - return t[name] or {} + return t[name] or {} end local function process(result,more) - for k,v in next,more do - result[k]=v - end - return result + for k,v in next,more do + result[k]=v + end + return result end local name=C((1-S(", "))^1) local parser=(Carg(1)*name/initialize)*(S(", ")^1*(Carg(1)*name/fetch))^0 local merge=Cf(parser,process) function utilities.parsers.mergehashes(hash,list) - return lpegmatch(merge,list,1,hash) + 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 + 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 local spacing=whitespace^0 local apply=P("->") @@ -8850,11 +9415,11 @@ local method=C((1-apply)^1) local token=lbrace*C((1-rbrace)^1)*rbrace+C(anything^1) local pattern=spacing*(method*spacing*apply+Carg(1))*spacing*token function utilities.parsers.splitmethod(str,default) - if str then - return lpegmatch(pattern,str,1,default or false) - else - return default or false,"" - end + if str then + return lpegmatch(pattern,str,1,default or false) + else + return default or false,"" + end end @@ -8864,14 +9429,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fmt"] = package.loaded["util-fmt"] or true --- original size: 2274, stripped down to: 1781 +-- original size: 2541, stripped down to: 1624 if not modules then modules={} end modules ['util-fmt']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.formatters=utilities.formatters or {} @@ -8882,61 +9447,2887 @@ local strip=string.strip local lpegmatch=lpeg.match local stripper=lpeg.patterns.stripzeros function formatters.stripzeros(str) - return lpegmatch(stripper,str) + return lpegmatch(stripper,str) end function formatters.formatcolumns(result,between) - if result and #result>0 then - between=between or " " - local widths,numbers={},{} - local first=result[1] - local n=#first - for i=1,n do - widths[i]=0 + if result and #result>0 then + between=between or " " + local widths,numbers={},{} + local first=result[1] + local n=#first + for i=1,n do + widths[i]=0 + end + for i=1,#result do + local r=result[i] + for j=1,n do + local rj=r[j] + local tj=type(rj) + if tj=="number" then + numbers[j]=true + rj=tostring(rj) + elseif tj~="string" then + rj=tostring(rj) + r[j]=rj + end + local w=#rj + if w>widths[j] then + widths[j]=w end - for i=1,#result do - local r=result[i] - for j=1,n do - local rj=r[j] - local tj=type(rj) - if tj=="number" then - numbers[j]=true - end - if tj~="string" then - rj=tostring(rj) - r[j]=rj - end - local w=#rj - if w>widths[j] then - widths[j]=w - end + end + end + for i=1,n do + local w=widths[i] + if numbers[i] then + if w>80 then + widths[i]="%s"..between + else + widths[i]="%0"..w.."i"..between + end + else + if w>80 then + widths[i]="%s"..between + elseif w>0 then + widths[i]="%-"..w.."s"..between + else + widths[i]="%s" + end + end + end + local template=strip(concat(widths)) + for i=1,#result do + local str=format(template,unpack(result[i])) + result[i]=strip(str) + end + end + return result +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-reset"] = package.loaded["util-soc-imp-reset"] or true + +-- original size: 374, stripped down to: 282 + +local loaded=package.loaded +loaded["socket"]=nil +loaded["copas"]=nil +loaded["ltn12"]=nil +loaded["mbox"]=nil +loaded["mime"]=nil +loaded["socket.url"]=nil +loaded["socket.headers"]=nil +loaded["socket.tp"]=nil +loaded["socket.http"]=nil +loaded["socket.ftp"]=nil +loaded["socket.smtp"]=nil + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-socket"] = package.loaded["util-soc-imp-socket"] or true + +-- original size: 4870, stripped down to: 3527 + + +local type,tostring,setmetatable=type,tostring,setmetatable +local min=math.min +local format=string.format +local socket=require("socket.core") +local connect=socket.connect +local tcp4=socket.tcp4 +local tcp6=socket.tcp6 +local getaddrinfo=socket.dns.getaddrinfo +local defaulthost="0.0.0.0" +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("socket") + report(fmt,first,...) + elseif fmt then + fmt="socket: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +socket.report=report +function socket.connect4(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet") +end +function socket.connect6(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet6") +end +function socket.bind(host,port,backlog) + if host=="*" or host=="" then + host=defaulthost + end + local addrinfo,err=getaddrinfo(host) + if not addrinfo then + return nil,err + end + for i=1,#addrinfo do + local alt=addrinfo[i] + local sock,err=(alt.family=="inet" and tcp4 or tcp6)() + if not sock then + return nil,err or "unknown error" + end + sock:setoption("reuseaddr",true) + local res,err=sock:bind(alt.addr,port) + if res then + res,err=sock:listen(backlog) + if res then + return sock + else + sock:close() + end + else + sock:close() + end + end + return nil,"invalid address" +end +socket.try=socket.newtry() +function socket.choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local f=list[name or "nil"] + if f then + return f(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end +end +local sourcet={} +local sinkt={} +socket.sourcet=sourcet +socket.sinkt=sinkt +socket.BLOCKSIZE=2048 +sinkt["close-when-done"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + sock:close() + return 1 + end + end + } + ) +end +sinkt["keep-open"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + return 1 + end + end + } + ) +end +sinkt["default"]=sinkt["keep-open"] +socket.sink=socket.choose(sinkt) +sourcet["by-length"]=function(sock,length) + local blocksize=socket.BLOCKSIZE + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function() + if length<=0 then + return nil + end + local chunk,err=sock:receive(min(blocksize,length)) + if err then + return nil,err + end + length=length-#chunk + return chunk + end + } + ) +end +sourcet["until-closed"]=function(sock) + local blocksize=socket.BLOCKSIZE + local done=false + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + if done then + return nil + end + local chunk,status,partial=sock:receive(blocksize) + if not status then + return chunk + elseif status=="closed" then + sock:close() + done=true + return partial + else + return nil,status + end + end + } + ) +end +sourcet["default"]=sourcet["until-closed"] +socket.source=socket.choose(sourcet) +_G.socket=socket +package.loaded["socket"]=socket + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-copas"] = package.loaded["util-soc-imp-copas"] or true + +-- original size: 25844, stripped down to: 14821 + + +local socket=socket or require("socket") +local ssl=ssl or nil +local WATCH_DOG_TIMEOUT=120 +local UDP_DATAGRAM_MAX=8192 +local type,next,pcall,getmetatable,tostring=type,next,pcall,getmetatable,tostring +local min,max,random=math.min,math.max,math.random +local find=string.find +local insert,remove=table.insert,table.remove +local gettime=socket.gettime +local selectsocket=socket.select +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.yield +local runningcoroutine=coroutine.running +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("copas") + report(fmt,first,...) + elseif fmt then + fmt="copas: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local copas={ + _COPYRIGHT="Copyright (C) 2005-2016 Kepler Project", + _DESCRIPTION="Coroutine Oriented Portable Asynchronous Services", + _VERSION="Copas 2.0.1", + autoclose=true, + running=false, + report=report, +} +local function statushandler(status,...) + if status then + return... + end + local err=(...) + if type(err)=="table" then + err=err[1] + end + report("error: %s",tostring(err)) + return nil,err +end +function socket.protect(func) + return function(...) + return statushandler(pcall(func,...)) + end +end +function socket.newtry(finalizer) + return function (...) + local status=(...) + if not status then + local detail=select(2,...) + pcall(finalizer,detail) + report("error: %s",tostring(detail)) + return + end + return... + end +end +local function newset() + local reverse={} + local set={} + local queue={} + setmetatable(set,{ + __index={ + insert=function(set,value) + if not reverse[value] then + local n=#set+1 + set[n]=value + reverse[value]=n + end + end, + remove=function(set,value) + local index=reverse[value] + if index then + reverse[value]=nil + local n=#set + local top=set[n] + set[n]=nil + if top~=value then + reverse[top]=index + set[index]=top end + end + end, + push=function (set,key,itm) + local entry=queue[key] + if entry==nil then + queue[key]={ itm } + else + entry[#entry+1]=itm + end + end, + pop=function (set,key) + local top=queue[key] + if top~=nil then + local ret=remove(top,1) + if top[1]==nil then + queue[key]=nil + end + return ret + end end - for i=1,n do - local w=widths[i] - if numbers[i] then - if w>80 then - widths[i]="%s"..between - else - widths[i]="%0"..w.."i"..between - end - else - if w>80 then - widths[i]="%s"..between - elseif w>0 then - widths[i]="%-"..w.."s"..between - else - widths[i]="%s" - end + } + } ) + return set +end +local _sleeping={ + times={}, + cos={}, + lethargy={}, + insert=function() + end, + remove=function() + end, + push=function(self,sleeptime,co) + if not co then + return + end + if sleeptime<0 then + self.lethargy[co]=true + return + else + sleeptime=gettime()+sleeptime + end + local t=self.times + local c=self.cos + local i=1 + local n=#t + while i<=n and t[i]<=sleeptime do + i=i+1 + end + insert(t,i,sleeptime) + insert(c,i,co) + end, + getnext= + function(self) + local t=self.times + local delay=t[1] and t[1]-gettime() or nil + return delay and max(delay,0) or nil + end, + pop= + function(self,time) + local t=self.times + local c=self.cos + if #t==0 or time<t[1] then + return + end + local co=c[1] + remove(t,1) + remove(c,1) + return co + end, + wakeup=function(self,co) + local let=self.lethargy + if let[co] then + self:push(0,co) + let[co]=nil + else + local c=self.cos + local t=self.times + for i=1,#c do + if c[i]==co then + remove(c,i) + remove(t,i) + self:push(0,co) + return end + end end - local template=strip(concat(widths)) - for i=1,#result do - local str=format(template,unpack(result[i])) - result[i]=strip(str) + end +} +local _servers=newset() +local _reading=newset() +local _writing=newset() +local _reading_log={} +local _writing_log={} +local _is_timeout={ + timeout=true, + wantread=true, + wantwrite=true, +} +local function isTCP(socket) + return not find(tostring(socket),"^udp") +end +local function copasreceive(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local current_log=_reading_log + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (not _is_timeout[err]) then + current_log[client]=nil + return s,err,part + end + if err=="wantwrite" then + current_log=_writing_log + current_log[client]=gettime() + yieldcoroutine(client,_writing) + else + current_log=_reading_log + current_log[client]=gettime() + yieldcoroutine(client,_reading) + end + until false +end +local function copasreceivefrom(client,size) + local s,err,port + if not size or size==0 then + size=UDP_DATAGRAM_MAX + end + repeat + s,err,port=client:receivefrom(size) + if s or err~="timeout" then + _reading_log[client]=nil + return s,err,port + end + _reading_log[client]=gettime() + yieldcoroutine(client,_reading) + until false +end +local function copasreceivepartial(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local logger=_reading_log + local queue=_reading + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (type(pattern)=="number" and part~="" and part) or not _is_timeout[err] then + logger[client]=nil + return s,err,part + end + if err=="wantwrite" then + logger=_writing_log + queue=_writing + else + logger=_reading_log + queue=_reading + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassend(client,data,from,to) + if not from then + from=1 + end + local lastIndex=from-1 + local logger=_writing_log + local queue=_writing + local s,err + repeat + s,err,lastIndex=client:send(data,lastIndex+1,to) + if random(100)>90 then + logger[client]=gettime() + yieldcoroutine(client,queue) + end + if s or not _is_timeout[err] then + logger[client]=nil + return s,err,lastIndex + end + if err=="wantread" then + logger=_reading_log + queue=_reading + else + logger=_writing_log + queue=_writing + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassendto(client,data,ip,port) + repeat + local s,err=client:sendto(data,ip,port) + if random(100)>90 then + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + end + if s or err~="timeout" then + _writing_log[client]=nil + return s,err + end + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + until false +end +local function copasconnect(skt,host,port) + skt:settimeout(0) + local ret,err,tried_more_than_once + repeat + ret,err=skt:connect (host,port) + if ret or (err~="timeout" and err~="Operation already in progress") then + if not ret and err=="already connected" and tried_more_than_once then + ret=1 + err=nil + end + _writing_log[skt]=nil + return ret,err + end + tried_more_than_once=tried_more_than_once or true + _writing_log[skt]=gettime() + yieldcoroutine(skt,_writing) + until false +end +local function copasdohandshake(skt,sslt) + if not ssl then + ssl=require("ssl") + end + if not ssl then + report("error: no ssl library") + return + end + local nskt,err=ssl.wrap(skt,sslt) + if not nskt then + report("error: %s",tostring(err)) + return + end + nskt:settimeout(0) + local queue + repeat + local success,err=nskt:dohandshake() + if success then + return nskt + elseif err=="wantwrite" then + queue=_writing + elseif err=="wantread" then + queue=_reading + else + report("error: %s",tostring(err)) + return + end + yieldcoroutine(nskt,queue) + until false +end +local function copasflush(client) +end +copas.connect=copassconnect +copas.send=copassend +copas.sendto=copassendto +copas.receive=copasreceive +copas.receivefrom=copasreceivefrom +copas.copasreceivepartial=copasreceivepartial +copas.copasreceivePartial=copasreceivepartial +copas.dohandshake=copasdohandshake +copas.flush=copasflush +local function _skt_mt_tostring(self) + return tostring(self.socket).." (copas wrapped)" +end +local _skt_mt_tcp_index={ + send=function(self,data,from,to) + return copassend (self.socket,data,from,to) + end, + receive=function (self,pattern,prefix) + if self.timeout==0 then + return copasreceivePartial(self.socket,pattern,prefix) + else + return copasreceive(self.socket,pattern,prefix) + end + end, + flush=function (self) + return copasflush(self.socket) + end, + settimeout=function (self,time) + self.timeout=time + return true + end, + connect=function(self,...) + local res,err=copasconnect(self.socket,...) + if res and self.ssl_params then + res,err=self:dohandshake() + end + return res,err + end, + close=function(self,...) + return self.socket:close(...) + end, + bind=function(self,...) + return self.socket:bind(...) + end, + getsockname=function(self,...) + return self.socket:getsockname(...) + end, + getstats=function(self,...) + return self.socket:getstats(...) + end, + setstats=function(self,...) + return self.socket:setstats(...) + end, + listen=function(self,...) + return self.socket:listen(...) + end, + accept=function(self,...) + return self.socket:accept(...) + end, + setoption=function(self,...) + return self.socket:setoption(...) + end, + getpeername=function(self,...) + return self.socket:getpeername(...) + end, + shutdown=function(self,...) + return self.socket:shutdown(...) + end, + dohandshake=function(self,sslt) + self.ssl_params=sslt or self.ssl_params + local nskt,err=copasdohandshake(self.socket,self.ssl_params) + if not nskt then + return nskt,err + end + self.socket=nskt + return self + end, +} +local _skt_mt_tcp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_tcp_index, +} +local _skt_mt_udp_index={ + sendto=function (self,...) + return copassendto(self.socket,...) + end, + receive=function (self,size) + return copasreceive(self.socket,size or UDP_DATAGRAM_MAX) + end, + receivefrom=function (self,size) + return copasreceivefrom(self.socket,size or UDP_DATAGRAM_MAX) + end, + setpeername=function(self,...) + return self.socket:getpeername(...) + end, + setsockname=function(self,...) + return self.socket:setsockname(...) + end, + close=function(self,...) + return true + end +} +local _skt_mt_udp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_udp_index, +} +for k,v in next,_skt_mt_tcp_index do + if not _skt_mt_udp_index[k] then + _skt_mt_udp_index[k]=v + end +end +local function wrap(skt,sslt) + if getmetatable(skt)==_skt_mt_tcp or getmetatable(skt)==_skt_mt_udp then + return skt + end + skt:settimeout(0) + if isTCP(skt) then + return setmetatable ({ socket=skt,ssl_params=sslt },_skt_mt_tcp) + else + return setmetatable ({ socket=skt },_skt_mt_udp) + end +end +copas.wrap=wrap +function copas.handler(handler,sslparams) + return function (skt,...) + skt=wrap(skt) + if sslparams then + skt:dohandshake(sslparams) + end + return handler(skt,...) + end +end +local _errhandlers={} +function copas.setErrorHandler(err) + local co=runningcoroutine() + if co then + _errhandlers[co]=err + end +end +local function _deferror (msg,co,skt) + report("%s (%s) (%s)",msg,tostring(co),tostring(skt)) +end +local function _doTick (co,skt,...) + if not co then + return + end + local ok,res,new_q=resumecoroutine(co,skt,...) + if ok and res and new_q then + new_q:insert(res) + new_q:push(res,co) + else + if not ok then + pcall(_errhandlers[co] or _deferror,res,co,skt) + end + if skt and copas.autoclose and isTCP(skt) then + skt:close() + end + _errhandlers[co]=nil + end +end +local function _accept(input,handler) + local client=input:accept() + if client then + client:settimeout(0) + local co=createcoroutine(handler) + _doTick (co,client) + end + return client +end +local function _tickRead(skt) + _doTick(_reading:pop(skt),skt) +end +local function _tickWrite(skt) + _doTick(_writing:pop(skt),skt) +end +local function addTCPserver(server,handler,timeout) + server:settimeout(timeout or 0) + _servers[server]=handler + _reading:insert(server) +end +local function addUDPserver(server,handler,timeout) + server:settimeout(timeout or 0) + local co=createcoroutine(handler) + _reading:insert(server) + _doTick(co,server) +end +function copas.addserver(server,handler,timeout) + if isTCP(server) then + addTCPserver(server,handler,timeout) + else + addUDPserver(server,handler,timeout) + end +end +function copas.removeserver(server,keep_open) + local s=server + local mt=getmetatable(server) + if mt==_skt_mt_tcp or mt==_skt_mt_udp then + s=server.socket + end + _servers[s]=nil + _reading:remove(s) + if keep_open then + return true + end + return server:close() +end +function copas.addthread(handler,...) + local thread=createcoroutine(function(_,...) return handler(...) end) + _doTick(thread,nil,...) + return thread +end +local _tasks={} +local function addtaskRead(task) + task.def_tick=_tickRead + _tasks[task]=true +end +local function addtaskWrite(task) + task.def_tick=_tickWrite + _tasks[task]=true +end +local function tasks() + return next,_tasks +end +local _readable_t={ + events=function(self) + local i=0 + return function () + i=i+1 + return self._evs[i] + end + end, + tick=function(self,input) + local handler=_servers[input] + if handler then + input=_accept(input,handler) + else + _reading:remove(input) + self.def_tick(input) + end + end +} +addtaskRead(_readable_t) +local _writable_t={ + events=function(self) + local i=0 + return function() + i=i+1 + return self._evs[i] + end + end, + tick=function(self,output) + _writing:remove(output) + self.def_tick(output) + end +} +addtaskWrite(_writable_t) +local _sleeping_t={ + tick=function(self,time,...) + _doTick(_sleeping:pop(time),...) + end +} +function copas.sleep(sleeptime) + yieldcoroutine((sleeptime or 0),_sleeping) +end +function copas.wakeup(co) + _sleeping:wakeup(co) +end +local last_cleansing=0 +local function _select(timeout) + local now=gettime() + local r_evs,w_evs,err=selectsocket(_reading,_writing,timeout) + _readable_t._evs=r_evs + _writable_t._evs=w_evs + if (last_cleansing-now)>WATCH_DOG_TIMEOUT then + last_cleansing=now + for skt,time in next,_reading_log do + if not r_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#r_evs+1 + _reading_log[skt]=nil + r_evs[n]=skt + r_evs[skt]=n + end + end + for skt,time in next,_writing_log do + if not w_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#w_evs+1 + _writing_log[skt]=nil + w_evs[n]=skt + w_evs[skt]=n + end + end + end + if err=="timeout" and #r_evs+#w_evs>0 then + return nil + else + return err + end +end +local function copasfinished() + return not (next(_reading) or next(_writing) or _sleeping:getnext()) +end +local function copasstep(timeout) + _sleeping_t:tick(gettime()) + local nextwait=_sleeping:getnext() + if nextwait then + timeout=timeout and min(nextwait,timeout) or nextwait + elseif copasfinished() then + return false + end + local err=_select(timeout) + if err then + if err=="timeout" then + return false + end + return nil,err + end + for task in tasks() do + for event in task:events() do + task:tick(event) + end + end + return true +end +copas.finished=copasfinished +copas.step=copasstep +function copas.loop(timeout) + copas.running=true + while not copasfinished() do + copasstep(timeout) + end + copas.running=false +end +package.loaded["copas"]=copas + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ltn12"] = package.loaded["util-soc-imp-ltn12"] or true + +-- original size: 8709, stripped down to: 5411 + + +local select,unpack=select,unpack +local insert,remove=table.insert,table.remove +local sub=string.sub +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("ltn12") + report(fmt,first,...) + elseif fmt then + fmt="ltn12: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local filter={} +local source={} +local sink={} +local pump={} +local ltn12={ + _VERSION="LTN12 1.0.3", + BLOCKSIZE=2048, + filter=filter, + source=source, + sink=sink, + pump=pump, + report=report, +} +function filter.cycle(low,ctx,extra) + if low then + return function(chunk) + return (low(ctx,chunk,extra)) + end + end +end +function filter.chain(...) + local arg={... } + local n=select('#',...) + local top=1 + local index=1 + local retry="" + return function(chunk) + retry=chunk and retry + while true do + local action=arg[index] + if index==top then + chunk=action(chunk) + if chunk=="" or top==n then + return chunk + elseif chunk then + index=index+1 + else + top=top+1 + index=top + end + else + chunk=action(chunk or "") + if chunk=="" then + index=index-1 + chunk=retry + elseif chunk then + if index==n then + return chunk + else + index=index+1 + end + else + report("error: filter returned inappropriate 'nil'") + return end + end end - return result + end +end +local function empty() + return nil +end +function source.empty() + return empty +end +local function sourceerror(err) + return function() + return nil,err + end +end +source.error=sourceerror +function source.file(handle,io_err) + if handle then + local blocksize=ltn12.BLOCKSIZE + return function() + local chunk=handle:read(blocksize) + if not chunk then + handle:close() + end + return chunk + end + else + return sourceerror(io_err or "unable to open file") + end +end +function source.simplify(src) + return function() + local chunk,err_or_new=src() + if err_or_new then + src=err_or_new + end + if chunk then + return chunk + else + return nil,err_or_new + end + end +end +function source.string(s) + if s then + local blocksize=ltn12.BLOCKSIZE + local i=1 + return function() + local nexti=i+blocksize + local chunk=sub(s,i,nexti-1) + i=nexti + if chunk~="" then + return chunk + else + return nil + end + end + else return source.empty() end +end +function source.rewind(src) + local t={} + return function(chunk) + if chunk then + insert(t,chunk) + else + chunk=remove(t) + if chunk then + return chunk + else + return src() + end + end + end +end +function source.chain(src,f,...) + if... then + f=filter.chain(f,...) + end + local last_in="" + local last_out="" + local state="feeding" + local err + return function() + if not last_out then + report("error: source is empty") + return + end + while true do + if state=="feeding" then + last_in,err=src() + if err then + return nil,err + end + last_out=f(last_in) + if not last_out then + if last_in then + report("error: filter returned inappropriate 'nil'") + end + return nil + elseif last_out~="" then + state="eating" + if last_in then + last_in="" + end + return last_out + end + else + last_out=f(last_in) + if last_out=="" then + if last_in=="" then + state="feeding" + else + report("error: filter returned nothing") + return + end + elseif not last_out then + if last_in then + report("filter returned inappropriate 'nil'") + end + return nil + else + return last_out + end + end + end + end +end +function source.cat(...) + local arg={... } + local src=remove(arg,1) + return function() + while src do + local chunk,err=src() + if chunk then + return chunk + end + if err then + return nil,err + end + src=remove(arg,1) + end + end +end +function sink.table(t) + if not t then + t={} + end + local f=function(chunk,err) + if chunk then + insert(t,chunk) + end + return 1 + end + return f,t +end +function sink.simplify(snk) + return function(chunk,err) + local ret,err_or_new=snk(chunk,err) + if not ret then + return nil,err_or_new + end + if err_or_new then + snk=err_or_new + end + return 1 + end +end +local function null() + return 1 +end +function sink.null() + return null +end +local function sinkerror(err) + return function() + return nil,err + end +end +sink.error=sinkerror +function sink.file(handle,io_err) + if handle then + return function(chunk,err) + if not chunk then + handle:close() + return 1 + else + return handle:write(chunk) + end + end + else + return sinkerror(io_err or "unable to open file") + end +end +function sink.chain(f,snk,...) + if... then + local args={ f,snk,... } + snk=remove(args,#args) + f=filter.chain(unpack(args)) + end + return function(chunk,err) + if chunk~="" then + local filtered=f(chunk) + local done=chunk and "" + while true do + local ret,snkerr=snk(filtered,err) + if not ret then + return nil,snkerr + end + if filtered==done then + return 1 + end + filtered=f(done) + end + else + return 1 + end + end +end +function pump.step(src,snk) + local chunk,src_err=src() + local ret,snk_err=snk(chunk,src_err) + if chunk and ret then + return 1 + else + return nil,src_err or snk_err + end +end +function pump.all(src,snk,step) + if not step then + step=pump.step + end + while true do + local ret,err=step(src,snk) + if not ret then + if err then + return nil,err + else + return 1 + end + end + end +end +package.loaded["ltn12"]=ltn12 + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-mime"] = package.loaded["util-soc-imp-mime"] or true + +-- original size: 2328, stripped down to: 1874 + + +local type,tostring=type,tostring +local mime=require("mime.core") +local ltn12=ltn12 or require("ltn12") +local filtercycle=ltn12.filter.cycle +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("mime") + report(fmt,first,...) + elseif fmt then + fmt="mime: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +mime.report=report +local encodet={} +local decodet={} +local wrapt={} +mime.encodet=encodet +mime.decodet=decodet +mime.wrapt=wrapt +local mime_b64=mime.b64 +local mime_qp=mime.qp +local mime_unb64=mime.unb64 +local mime_unqp=mime.unqp +local mime_wrp=mime.wrp +local mime_qpwrp=mime.qpwrp +local mime_eol=mime_eol +local mime_dot=mime_dot +encodet['base64']=function() + return filtercycle(mime_b64,"") +end +encodet['quoted-printable']=function(mode) + return filtercycle(mime_qp,"",mode=="binary" and "=0D=0A" or "\r\n") +end +decodet['base64']=function() + return filtercycle(mime_unb64,"") +end +decodet['quoted-printable']=function() + return filtercycle(mime_unqp,"") +end +local wraptext=function(length) + if not length then + length=76 + end + return filtercycle(mime_wrp,length,length) +end +local wrapquoted=function() + return filtercycle(mime_qpwrp,76,76) +end +wrapt['text']=wraptext +wrapt['base64']=wraptext +wrapt['default']=wraptext +wrapt['quoted-printable']=wrapquoted +function mime.normalize(marker) + return filtercycle(mime_eol,0,marker) +end +function mime.stuff() + return filtercycle(mime_dot,2) +end +local function choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local filter=list[name or "nil"] + if filter then + return filter(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end end +mime.encode=choose(encodet) +mime.decode=choose(decodet) +mime.wrap=choose(wrapt) +package.loaded["mime"]=mime + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-url"] = package.loaded["util-soc-imp-url"] or true + +-- original size: 6863, stripped down to: 5269 + + +local tonumber,tostring,type=tonumber,tostring,type +local gsub,sub,match,find,format,byte,char=string.gsub,string.sub,string.match,string.find,string.format,string.byte,string.char +local insert=table.insert +local socket=socket or require("socket") +local url={ + _VERSION="URL 1.0.3", +} +socket.url=url +function url.escape(s) + return (gsub(s,"([^A-Za-z0-9_])",function(c) + return format("%%%02x",byte(c)) + end)) +end +local function make_set(t) + local s={} + for i=1,#t do + s[t[i]]=true + end + return s +end +local segment_set=make_set { + "-","_",".","!","~","*","'","(", + ")",":","@","&","=","+","$",",", +} +local function protect_segment(s) + return gsub(s,"([^A-Za-z0-9_])",function(c) + if segment_set[c] then + return c + else + return format("%%%02X",byte(c)) + end + end) +end +function url.unescape(s) + return (gsub(s,"%%(%x%x)",function(hex) + return char(tonumber(hex,16)) + end)) +end +local function absolute_path(base_path,relative_path) + if find(relative_path,"^/") then + return relative_path + end + local path=gsub(base_path,"[^/]*$","") + path=path..relative_path + path=gsub(path,"([^/]*%./)",function (s) + if s~="./" then + return s + else + return "" + end + end) + path=gsub(path,"/%.$","/") + local reduced + while reduced~=path do + reduced=path + path=gsub(reduced,"([^/]*/%.%./)",function (s) + if s~="../../" then + return "" + else + return s + end + end) + end + path=gsub(reduced,"([^/]*/%.%.)$",function (s) + if s~="../.." then + return "" + else + return s + end + end) + return path +end +function url.parse(url,default) + local parsed={} + for k,v in next,default or parsed do + parsed[k]=v + end + if not url or url=="" then + return nil,"invalid url" + end + url=gsub(url,"#(.*)$",function(f) + parsed.fragment=f + return "" + end) + url=gsub(url,"^([%w][%w%+%-%.]*)%:",function(s) + parsed.scheme=s + return "" + end) + url=gsub(url,"^//([^/]*)",function(n) + parsed.authority=n + return "" + end) + url=gsub(url,"%?(.*)",function(q) + parsed.query=q + return "" + end) + url=gsub(url,"%;(.*)",function(p) + parsed.params=p + return "" + end) + if url~="" then + parsed.path=url + end + local authority=parsed.authority + if not authority then + return parsed + end + authority=gsub(authority,"^([^@]*)@",function(u) + parsed.userinfo=u + return "" + end) + authority=gsub(authority,":([^:%]]*)$",function(p) + parsed.port=p + return "" + end) + if authority~="" then + parsed.host=match(authority,"^%[(.+)%]$") or authority + end + local userinfo=parsed.userinfo + if not userinfo then + return parsed + end + userinfo=gsub(userinfo,":([^:]*)$",function(p) + parsed.password=p + return "" + end) + parsed.user=userinfo + return parsed +end +function url.build(parsed) + local url=parsed.path or "" + if parsed.params then + url=url..";"..parsed.params + end + if parsed.query then + url=url.."?"..parsed.query + end + local authority=parsed.authority + if parsed.host then + authority=parsed.host + if find(authority,":") then + authority="["..authority.."]" + end + if parsed.port then + authority=authority..":"..tostring(parsed.port) + end + local userinfo=parsed.userinfo + if parsed.user then + userinfo=parsed.user + if parsed.password then + userinfo=userinfo..":"..parsed.password + end + end + if userinfo then authority=userinfo.."@"..authority end + end + if authority then + url="//"..authority..url + end + if parsed.scheme then + url=parsed.scheme..":"..url + end + if parsed.fragment then + url=url.."#"..parsed.fragment + end + return url +end +function url.absolute(base_url,relative_url) + local base_parsed + if type(base_url)=="table" then + base_parsed=base_url + base_url=url.build(base_parsed) + else + base_parsed=url.parse(base_url) + end + local relative_parsed=url.parse(relative_url) + if not base_parsed then + return relative_url + elseif not relative_parsed then + return base_url + elseif relative_parsed.scheme then + return relative_url + else + relative_parsed.scheme=base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority=base_parsed.authority + if not relative_parsed.path then + relative_parsed.path=base_parsed.path + if not relative_parsed.params then + relative_parsed.params=base_parsed.params + if not relative_parsed.query then + relative_parsed.query=base_parsed.query + end + end + else + relative_parsed.path=absolute_path(base_parsed.path or "",relative_parsed.path) + end + end + return url.build(relative_parsed) + end +end +function url.parse_path(path) + local parsed={} + path=path or "" + gsub(path,"([^/]+)",function (s) + insert(parsed,s) + end) + for i=1,#parsed do + parsed[i]=url.unescape(parsed[i]) + end + if sub(path,1,1)=="/" then + parsed.is_absolute=1 + end + if sub(path,-1,-1)=="/" then + parsed.is_directory=1 + end + return parsed +end +function url.build_path(parsed,unsafe) + local path="" + local n=#parsed + if unsafe then + for i=1,n-1 do + path=path..parsed[i].."/" + end + if n>0 then + path=path..parsed[n] + if parsed.is_directory then + path=path.."/" + end + end + else + for i=1,n-1 do + path=path..protect_segment(parsed[i]).."/" + end + if n>0 then + path=path..protect_segment(parsed[n]) + if parsed.is_directory then + path=path.."/" + end + end + end + if parsed.is_absolute then + path="/"..path + end + return path +end +package.loaded["socket.url"]=url + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-headers"] = package.loaded["util-soc-imp-headers"] or true + +-- original size: 5721, stripped down to: 3754 + + +local next=next +local lower=string.lower +local concat=table.concat +local socket=socket or require("socket") +local headers={} +socket.headers=headers +local canonic={ + ["accept"]="Accept", + ["accept-charset"]="Accept-Charset", + ["accept-encoding"]="Accept-Encoding", + ["accept-language"]="Accept-Language", + ["accept-ranges"]="Accept-Ranges", + ["action"]="Action", + ["alternate-recipient"]="Alternate-Recipient", + ["age"]="Age", + ["allow"]="Allow", + ["arrival-date"]="Arrival-Date", + ["authorization"]="Authorization", + ["bcc"]="Bcc", + ["cache-control"]="Cache-Control", + ["cc"]="Cc", + ["comments"]="Comments", + ["connection"]="Connection", + ["content-description"]="Content-Description", + ["content-disposition"]="Content-Disposition", + ["content-encoding"]="Content-Encoding", + ["content-id"]="Content-ID", + ["content-language"]="Content-Language", + ["content-length"]="Content-Length", + ["content-location"]="Content-Location", + ["content-md5"]="Content-MD5", + ["content-range"]="Content-Range", + ["content-transfer-encoding"]="Content-Transfer-Encoding", + ["content-type"]="Content-Type", + ["cookie"]="Cookie", + ["date"]="Date", + ["diagnostic-code"]="Diagnostic-Code", + ["dsn-gateway"]="DSN-Gateway", + ["etag"]="ETag", + ["expect"]="Expect", + ["expires"]="Expires", + ["final-log-id"]="Final-Log-ID", + ["final-recipient"]="Final-Recipient", + ["from"]="From", + ["host"]="Host", + ["if-match"]="If-Match", + ["if-modified-since"]="If-Modified-Since", + ["if-none-match"]="If-None-Match", + ["if-range"]="If-Range", + ["if-unmodified-since"]="If-Unmodified-Since", + ["in-reply-to"]="In-Reply-To", + ["keywords"]="Keywords", + ["last-attempt-date"]="Last-Attempt-Date", + ["last-modified"]="Last-Modified", + ["location"]="Location", + ["max-forwards"]="Max-Forwards", + ["message-id"]="Message-ID", + ["mime-version"]="MIME-Version", + ["original-envelope-id"]="Original-Envelope-ID", + ["original-recipient"]="Original-Recipient", + ["pragma"]="Pragma", + ["proxy-authenticate"]="Proxy-Authenticate", + ["proxy-authorization"]="Proxy-Authorization", + ["range"]="Range", + ["received"]="Received", + ["received-from-mta"]="Received-From-MTA", + ["references"]="References", + ["referer"]="Referer", + ["remote-mta"]="Remote-MTA", + ["reply-to"]="Reply-To", + ["reporting-mta"]="Reporting-MTA", + ["resent-bcc"]="Resent-Bcc", + ["resent-cc"]="Resent-Cc", + ["resent-date"]="Resent-Date", + ["resent-from"]="Resent-From", + ["resent-message-id"]="Resent-Message-ID", + ["resent-reply-to"]="Resent-Reply-To", + ["resent-sender"]="Resent-Sender", + ["resent-to"]="Resent-To", + ["retry-after"]="Retry-After", + ["return-path"]="Return-Path", + ["sender"]="Sender", + ["server"]="Server", + ["smtp-remote-recipient"]="SMTP-Remote-Recipient", + ["status"]="Status", + ["subject"]="Subject", + ["te"]="TE", + ["to"]="To", + ["trailer"]="Trailer", + ["transfer-encoding"]="Transfer-Encoding", + ["upgrade"]="Upgrade", + ["user-agent"]="User-Agent", + ["vary"]="Vary", + ["via"]="Via", + ["warning"]="Warning", + ["will-retry-until"]="Will-Retry-Until", + ["www-authenticate"]="WWW-Authenticate", + ["x-mailer"]="X-Mailer", +} +headers.canonic=setmetatable(canonic,{ + __index=function(t,k) + socket.report("invalid header: %s",k) + t[k]=k + return k + end +}) +function headers.normalize(headers) + if not headers then + return {} + end + local normalized={} + for k,v in next,headers do + normalized[#normalized+1]=canonic[k]..": "..v + end + normalized[#normalized+1]="" + normalized[#normalized+1]="" + return concat(normalized,"\r\n") +end +function headers.lower(lowered,headers) + if not lowered then + return {} + end + if not headers then + lowered,headers={},lowered + end + for k,v in next,headers do + lowered[lower(k)]=v + end + return lowered +end +socket.headers=headers +package.loaded["socket.headers"]=headers + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-tp"] = package.loaded["util-soc-imp-tp"] or true + +-- original size: 3116, stripped down to: 2533 + + +local setmetatable,next,type,tonumber=setmetatable,next,type,tonumber +local find,upper=string.find,string.upper +local socket=socket or require("socket") +local ltn12=ltn12 or require("ltn12") +local skipsocket=socket.skip +local sinksocket=socket.sink +local tcpsocket=socket.tcp +local ltn12pump=ltn12.pump +local pumpall=ltn12pump.all +local pumpstep=ltn12pump.step +local tp={ + TIMEOUT=60, +} +socket.tp=tp +local function get_reply(c) + local line,err=c:receive() + local reply=line + if err then return + nil,err + end + local code,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + if not code then + return nil,"invalid server reply" + end + if sep=="-" then + local current + repeat + line,err=c:receive() + if err then + return nil,err + end + current,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + reply=reply.."\n"..line + until code==current and sep==" " + end + return code,reply +end +local methods={} +local mt={ __index=methods } +function methods.getpeername(self) + return self.c:getpeername() +end +function methods.getsockname(self) + return self.c:getpeername() +end +function methods.check(self,ok) + local code,reply=get_reply(self.c) + if not code then + return nil,reply + end + local c=tonumber(code) + local t=type(ok) + if t=="function" then + return ok(c,reply) + elseif t=="table" then + for i=1,#ok do + if find(code,ok[i]) then + return c,reply + end + end + return nil,reply + elseif find(code,ok) then + return c,reply + else + return nil,reply + end +end +function methods.command(self,cmd,arg) + cmd=upper(cmd) + if arg then + cmd=cmd.." "..arg.."\r\n" + else + cmd=cmd.."\r\n" + end + return self.c:send(cmd) +end +function methods.sink(self,snk,pat) + local chunk,err=self.c:receive(pat) + return snk(chunk,err) +end +function methods.send(self,data) + return self.c:send(data) +end +function methods.receive(self,pat) + return self.c:receive(pat) +end +function methods.getfd(self) + return self.c:getfd() +end +function methods.dirty(self) + return self.c:dirty() +end +function methods.getcontrol(self) + return self.c +end +function methods.source(self,source,step) + local sink=sinksocket("keep-open",self.c) + local ret,err=pumpall(source,sink,step or pumpstep) + return ret,err +end +function methods.close(self) + self.c:close() + return 1 +end +function tp.connect(host,port,timeout,create) + local c,e=(create or tcpsocket)() + if not c then + return nil,e + end + c:settimeout(timeout or tp.TIMEOUT) + local r,e=c:connect(host,port) + if not r then + c:close() + return nil,e + end + return setmetatable({ c=c },mt) +end +package.loaded["socket.tp"]=tp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-http"] = package.loaded["util-soc-imp-http"] or true + +-- original size: 12577, stripped down to: 9577 + + +local tostring,tonumber,setmetatable,next,type=tostring,tonumber,setmetatable,next,type +local find,lower,format,gsub,match=string.find,string.lower,string.format,string.gsub,string.match +local concat=table.concat +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local ltn12=ltn12 or require("ltn12") +local mime=mime or require("mime") +local headers=socket.headers or require("socket.headers") +local normalizeheaders=headers.normalize +local parseurl=url.parse +local buildurl=url.build +local absoluteurl=url.absolute +local unescapeurl=url.unescape +local skipsocket=socket.skip +local sinksocket=socket.sink +local sourcesocket=socket.source +local trysocket=socket.try +local tcpsocket=socket.tcp +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local emptysource=ltn12.source.empty +local stringsource=ltn12.source.string +local rewindsource=ltn12.source.rewind +local pumpstep=ltn12.pump.step +local pumpall=ltn12.pump.all +local sinknull=ltn12.sink.null +local sinktable=ltn12.sink.table +local lowerheaders=headers.lower +local mimeb64=mime.b64 +local http={ + TIMEOUT=60, + USERAGENT=socket._VERSION, +} +socket.http=http +local PORT=80 +local SCHEMES={ + http=true, +} +local function receiveheaders(sock,headers) + if not headers then + headers={} + end + local line,err=sock:receive() + if err then + return nil,err + end + while line~="" do + local name,value=skipsocket(2,find(line,"^(.-):%s*(.*)")) + if not (name and value) then + return nil,"malformed reponse headers" + end + name=lower(name) + line,err=sock:receive() + if err then + return nil,err + end + while find(line,"^%s") do + value=value..line + line=sock:receive() + if err then + return nil,err + end + end + local found=headers[name] + if found then + value=found..", "..value + end + headers[name]=value + end + return headers +end +socket.sourcet["http-chunked"]=function(sock,headers) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + local line,err=sock:receive() + if err then + return nil,err + end + local size=tonumber(gsub(line,";.*",""),16) + if not size then + return nil,"invalid chunk size" + end + if size>0 then + local chunk,err,part=sock:receive(size) + if chunk then + sock:receive() + end + return chunk,err + else + headers,err=receiveheaders(sock,headers) + if not headers then + return nil,err + end + end + end + } + ) +end +socket.sinkt["http-chunked"]=function(sock) + return setmetatable( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if not chunk then + chunk="" + end + return sock:send(format("%X\r\n%s\r\n",#chunk,chunk)) + end + }) +end +local methods={} +local mt={ __index=methods } +local function openhttp(host,port,create) + local c=trysocket((create or tcpsocket)()) + local h=setmetatable({ c=c },mt) + local try=newtrysocket(function() h:close() end) + h.try=try + try(c:settimeout(http.TIMEOUT)) + try(c:connect(host,port or PORT)) + return h +end +http.open=openhttp +function methods.sendrequestline(self,method,uri) + local requestline=format("%s %s HTTP/1.1\r\n",method or "GET",uri) + return self.try(self.c:send(requestline)) +end +function methods.sendheaders(self,headers) + self.try(self.c:send(normalizeheaders(headers))) + return 1 +end +function methods.sendbody(self,headers,source,step) + if not source then + source=emptysource() + end + if not step then + step=pumpstep + end + local mode="http-chunked" + if headers["content-length"] then + mode="keep-open" + end + return self.try(pumpall(source,sinksocket(mode,self.c),step)) +end +function methods.receivestatusline(self) + local try=self.try + local status=try(self.c:receive(5)) + if status~="HTTP/" then + return nil,status + end + status=try(self.c:receive("*l",status)) + local code=skipsocket(2,find(status,"HTTP/%d*%.%d* (%d%d%d)")) + return try(tonumber(code),status) +end +function methods.receiveheaders(self) + return self.try(receiveheaders(self.c)) +end +function methods.receivebody(self,headers,sink,step) + if not sink then + sink=sinknull() + end + if not step then + step=pumpstep + end + local length=tonumber(headers["content-length"]) + local encoding=headers["transfer-encoding"] + local mode="default" + if encoding and encoding~="identity" then + mode="http-chunked" + elseif length then + mode="by-length" + end + return self.try(pumpall(sourcesocket(mode,self.c,length),sink,step)) +end +function methods.receive09body(self,status,sink,step) + local source=rewindsource(sourcesocket("until-closed",self.c)) + source(status) + return self.try(pumpall(source,sink,step)) +end +function methods.close(self) + return self.c:close() +end +local function adjusturi(request) + if not request.proxy and not http.PROXY then + request={ + path=trysocket(request.path,"invalid path 'nil'"), + params=request.params, + query=request.query, + fragment=request.fragment, + } + end + return buildurl(request) +end +local function adjustheaders(request) + local headers={ + ["user-agent"]=http.USERAGENT, + ["host"]=gsub(request.authority,"^.-@",""), + ["connection"]="close, TE", + ["te"]="trailers" + } + local username=request.user + local password=request.password + if username and password then + headers["authorization"]="Basic "..(mimeb64(username..":"..unescapeurl(password))) + end + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + local username=proxy.user + local password=proxy.password + if username and password then + headers["proxy-authorization"]="Basic "..(mimeb64(username..":"..password)) + end + end + local requestheaders=request.headers + if requestheaders then + headers=lowerheaders(headers,requestheaders) + end + return headers +end +local default={ + host="", + port=PORT, + path="/", + scheme="http" +} +local function adjustrequest(originalrequest) + local url=originalrequest.url + local request=url and parseurl(url,default) or {} + for k,v in next,originalrequest do + request[k]=v + end + local host=request.host + local port=request.port + local uri=request.uri + if not host or host=="" then + trysocket(nil,"invalid host '"..tostring(host).."'") + end + if port=="" then + request.port=PORT + end + if not uri or uri=="" then + request.uri=adjusturi(request) + end + request.headers=adjustheaders(request) + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + request.host=proxy.host + request.port=proxy.port or 3128 + end + return request +end +local maxredericts=4 +local validredirects={ [301]=true,[302]=true,[303]=true,[307]=true } +local validmethods={ [false]=true,GET=true,HEAD=true } +local function shouldredirect(request,code,headers) + local location=headers.location + if not location then + return false + end + location=gsub(location,"%s","") + if location=="" then + return false + end + local scheme=match(location,"^([%w][%w%+%-%.]*)%:") + if scheme and not SCHEMES[scheme] then + return false + end + local method=request.method + local redirect=request.redirect + local redirects=request.nredirects or 0 + return redirect and validredirects[code] and validmethods[method] and redirects<=maxredericts +end +local function shouldreceivebody(request,code) + if request.method=="HEAD" then + return nil + end + if code==204 or code==304 then + return nil + end + if code>=100 and code<200 then + return nil + end + return 1 +end +local tredirect,trequest,srequest +tredirect=function(request,location) + local result,code,headers,status=trequest { + url=absoluteurl(request.url,location), + source=request.source, + sink=request.sink, + headers=request.headers, + proxy=request.proxy, + nredirects=(request.nredirects or 0)+1, + create=request.create, + } + if not headers then + headers={} + end + if not headers.location then + headers.location=location + end + return result,code,headers,status +end +trequest=function(originalrequest) + local request=adjustrequest(originalrequest) + local connection=openhttp(request.host,request.port,request.create) + local headers=request.headers + connection:sendrequestline(request.method,request.uri) + connection:sendheaders(headers) + if request.source then + connection:sendbody(headers,request.source,request.step) + end + local code,status=connection:receivestatusline() + if not code then + connection:receive09body(status,request.sink,request.step) + return 1,200 + end + while code==100 do + headers=connection:receiveheaders() + code,status=connection:receivestatusline() + end + headers=connection:receiveheaders() + if shouldredirect(request,code,headers) and not request.source then + connection:close() + return tredirect(originalrequest,headers.location) + end + if shouldreceivebody(request,code) then + connection:receivebody(headers,request.sink,request.step) + end + connection:close() + return 1,code,headers,status +end +local function genericform(url,body) + local buffer={} + local request={ + url=url, + sink=sinktable(buffer), + target=buffer, + } + if body then + request.source=stringsource(body) + request.method="POST" + request.headers={ + ["content-length"]=#body, + ["content-type"]="application/x-www-form-urlencoded" + } + end + return request +end +http.genericform=genericform +srequest=function(url,body) + local request=genericform(url,body) + local _,code,headers,status=trequest(request) + return concat(request.target),code,headers,status +end +http.request=protectsocket(function(request,body) + if type(request)=="string" then + return srequest(request,body) + else + return trequest(request) + end +end) +package.loaded["socket.http"]=http + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ftp"] = package.loaded["util-soc-imp-ftp"] or true + +-- original size: 10357, stripped down to: 8548 + + +local setmetatable,type,next=setmetatable,type,next +local find,format,gsub,match=string.find,string.format,string.gsub,string.match +local concat=table.concat +local mod=math.mod +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local tp=socket.tp or require("socket.tp") +local ltn12=ltn12 or require("ltn12") +local tcpsocket=socket.tcp +local trysocket=socket.try +local skipsocket=socket.skip +local sinksocket=socket.sink +local selectsocket=socket.select +local bindsocket=socket.bind +local newtrysocket=socket.newtry +local sourcesocket=socket.source +local protectsocket=socket.protect +local parseurl=url.parse +local unescapeurl=url.unescape +local pumpall=ltn12.pump.all +local pumpstep=ltn12.pump.step +local sourcestring=ltn12.source.string +local sinktable=ltn12.sink.table +local ftp={ + TIMEOUT=60, + USER="ftp", + PASSWORD="anonymous@anonymous.org", +} +socket.ftp=ftp +local PORT=21 +local methods={} +local mt={ __index=methods } +function ftp.open(server,port,create) + local tp=trysocket(tp.connect(server,port or PORT,ftp.TIMEOUT,create)) + local f=setmetatable({ tp=tp },metat) + f.try=newtrysocket(function() f:close() end) + return f +end +function methods.portconnect(self) + local try=self.try + local server=self.server + try(server:settimeout(ftp.TIMEOUT)) + self.data=try(server:accept()) + try(self.data:settimeout(ftp.TIMEOUT)) +end +function methods.pasvconnect(self) + local try=self.try + self.data=try(tcpsocket()) + self(self.data:settimeout(ftp.TIMEOUT)) + self(self.data:connect(self.pasvt.address,self.pasvt.port)) +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("user",user or ftp.USER)) + local code,reply=try(tp:check{"2..",331}) + if code==331 then + try(tp:command("pass",password or ftp.PASSWORD)) + try(tp:check("2..")) + end + return 1 +end +function methods.pasv(self) + local try=self.try + local tp=self.tp + try(tp:command("pasv")) + local code,reply=try(self.tp:check("2..")) + local pattern="(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a,b,c,d,p1,p2=skipsocket(2,find(reply,pattern)) + try(a and b and c and d and p1 and p2,reply) + local address=format("%d.%d.%d.%d",a,b,c,d) + local port=p1*256+p2 + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if server then + server:close() + self.server=nil + end + return address,port +end +function methods.epsv(self) + local try=self.try + local tp=self.tp + try(tp:command("epsv")) + local code,reply=try(tp:check("229")) + local pattern="%((.)(.-)%1(.-)%1(.-)%1%)" + local d,prt,address,port=match(reply,pattern) + try(port,"invalid epsv response") + local address=tp:getpeername() + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if self.server then + server:close() + self.server=nil + end + return address,port +end +function methods.port(self,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local pl=mod(port,256) + local ph=(port-pl)/256 + local arg=gsub(format("%s,%d,%d",address,ph,pl),"%.",",") + try(tp:command("port",arg)) + try(tp:check("2..")) + return 1 +end +function methods.eprt(self,family,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local arg=format("|%s|%s|%d|",family,address,port) + try(tp:command("eprt",arg)) + try(tp:check("2..")) + return 1 +end +function methods.send(self,sendt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then + self:pasvconnect() + end + local argument=sendt.argument or unescapeurl(gsub(sendt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=sendt.command or "stor" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"2..","1.."}) + if not self.pasvt then + self:portconnect() + end + local step=sendt.step or pumpstep + local readt={ tp } + local checkstep=function(src,snk) + local readyt=selectsocket(readt,nil,0) + if readyt[tp] then + code=try(tp:check("2..")) + end + return step(src,snk) + end + local sink=sinksocket("close-when-done",self.data) + try(pumpall(sendt.source,sink,checkstep)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + local sent=skipsocket(1,self.data:getstats()) + self.data=nil + return sent +end +function methods.receive(self,recvt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument=recvt.argument or unescapeurl(gsub(recvt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=recvt.command or "retr" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"1..","2.."}) + if code>=200 and code<=299 then + recvt.sink(reply) + return 1 + end + if not self.pasvt then + self:portconnect() + end + local source=sourcesocket("until-closed",self.data) + local step=recvt.step or pumpstep + try(pumpall(source,recvt.sink,step)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + self.data=nil + return 1 +end +function methods.cwd(self,dir) + local try=self.try + local tp=self.tp + try(tp:command("cwd",dir)) + try(tp:check(250)) + return 1 +end +function methods.type(self,typ) + local try=self.try + local tp=self.tp + try(tp:command("type",typ)) + try(tp:check(200)) + return 1 +end +function methods.greet(self) + local try=self.try + local tp=self.tp + local code=try(tp:check{"1..","2.."}) + if find(code,"1..") then + try(tp:check("2..")) + end + return 1 +end +function methods.quit(self) + local try=self.try + try(self.tp:command("quit")) + try(self.tp:check("2..")) + return 1 +end +function methods.close(self) + local data=self.data + if data then + data:close() + end + local server=self.server + if server then + server:close() + end + local tp=self.tp + if tp then + tp:close() + end +end +local function override(t) + if t.url then + local u=parseurl(t.url) + for k,v in next,t do + u[k]=v + end + return u + else + return t + end +end +local function tput(putt) + putt=override(putt) + local host=putt.host + trysocket(host,"missing hostname") + local f=ftp.open(host,putt.port,putt.create) + f:greet() + f:login(putt.user,putt.password) + local typ=putt.type + if typ then + f:type(typ) + end + f:epsv() + local sent=f:send(putt) + f:quit() + f:close() + return sent +end +local default={ + path="/", + scheme="ftp", +} +local function genericform(u) + local t=trysocket(parseurl(u,default)) + trysocket(t.scheme=="ftp","wrong scheme '"..t.scheme.."'") + trysocket(t.host,"missing hostname") + local pat="^type=(.)$" + if t.params then + local typ=skipsocket(2,find(t.params,pat)) + t.type=typ + trysocket(typ=="a" or typ=="i","invalid type '"..typ.."'") + end + return t +end +ftp.genericform=genericform +local function sput(u,body) + local putt=genericform(u) + putt.source=sourcestring(body) + return tput(putt) +end +ftp.put=protectsocket(function(putt,body) + if type(putt)=="string" then + return sput(putt,body) + else + return tput(putt) + end +end) +local function tget(gett) + gett=override(gett) + local host=gett.host + trysocket(host,"missing hostname") + local f=ftp.open(host,gett.port,gett.create) + f:greet() + f:login(gett.user,gett.password) + if gett.type then + f:type(gett.type) + end + f:epsv() + f:receive(gett) + f:quit() + return f:close() +end +local function sget(u) + local gett=genericform(u) + local t={} + gett.sink=sinktable(t) + tget(gett) + return concat(t) +end +ftp.command=protectsocket(function(cmdt) + cmdt=override(cmdt) + local command=cmdt.command + local argument=cmdt.argument + local check=cmdt.check + local host=cmdt.host + trysocket(host,"missing hostname") + trysocket(command,"missing command") + local f=ftp.open(host,cmdt.port,cmdt.create) + local try=f.try + local tp=f.tp + f:greet() + f:login(cmdt.user,cmdt.password) + if type(command)=="table" then + local argument=argument or {} + for i=1,#command do + local cmd=command[i] + try(tp:command(cmd,argument[i])) + if check and check[i] then + try(tp:check(check[i])) + end + end + else + try(tp:command(command,argument)) + if check then + try(tp:check(check)) + end + end + f:quit() + return f:close() +end) +ftp.get=protectsocket(function(gett) + if type(gett)=="string" then + return sget(gett) + else + return tget(gett) + end +end) +package.loaded["socket.ftp"]=ftp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-smtp"] = package.loaded["util-soc-imp-smtp"] or true + +-- original size: 7018, stripped down to: 5883 + + +local type,setmetatable,next=type,setmetatable,next +local find,lower,format=string.find,string.lower,string.format +local osdate,osgetenv=os.date,os.getenv +local random=math.random +local socket=socket or require("socket") +local headers=socket.headers or require("socket.headers") +local ltn12=ltn12 or require("ltn12") +local tp=socket.tp or require("socket.tp") +local mime=mime or require("mime") +local mimeb64=mime.b64 +local mimestuff=mime.stuff +local skipsocket=socket.skip +local trysocket=socket.try +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local normalizeheaders=headers.normalize +local lowerheaders=headers.lower +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.resume +local smtp={ + TIMEOUT=60, + SERVER="localhost", + PORT=25, + DOMAIN=osgetenv("SERVER_NAME") or "localhost", + ZONE="-0000", +} +socket.smtp=smtp +local methods={} +local mt={ __index=methods } +function methods.greet(self,domain) + local try=self.try + local tp=self.tp + try(tp:check("2..")) + try(tp:command("EHLO",domain or _M.DOMAIN)) + return skipsocket(1,try(tp:check("2.."))) +end +function methods.mail(self,from) + local try=self.try + local tp=self.tp + try(tp:command("MAIL","FROM:"..from)) + return try(tp:check("2..")) +end +function methods.rcpt(self,to) + local try=self.try + local tp=self.tp + try(tp:command("RCPT","TO:"..to)) + return try(tp:check("2..")) +end +function methods.data(self,src,step) + local try=self.try + local tp=self.tp + try(tp:command("DATA")) + try(tp:check("3..")) + try(tp:source(src,step)) + try(tp:send("\r\n.\r\n")) + return try(tp:check("2..")) +end +function methods.quit(self) + local try=self.try + local tp=self.tp + try(tp:command("QUIT")) + return try(tp:check("2..")) +end +function methods.close(self) + return self.tp:close() +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("AUTH","LOGIN")) + try(tp:check("3..")) + try(tp:send(mimeb64(user).."\r\n")) + try(tp:check("3..")) + try(tp:send(mimeb64(password).."\r\n")) + return try(tp:check("2..")) +end +function methods.plain(self,user,password) + local try=self.try + local tp=self.tp + local auth="PLAIN "..mimeb64("\0"..user.."\0"..password) + try(tp:command("AUTH",auth)) + return try(tp:check("2..")) +end +function methods.auth(self,user,password,ext) + if not user or not password then + return 1 + end + local try=self.try + if find(ext,"AUTH[^\n]+LOGIN") then + return self:login(user,password) + elseif find(ext,"AUTH[^\n]+PLAIN") then + return self:plain(user,password) + else + try(nil,"authentication not supported") + end +end +function methods.send(self,mail) + self:mail(mail.from) + local receipt=mail.rcpt + if type(receipt)=="table" then + for i=1,#receipt do + self:rcpt(receipt[i]) + end + elseif receipt then + self:rcpt(receipt) + end + self:data(ltn12.source.chain(mail.source,mimestuff()),mail.step) +end +local function opensmtp(self,server,port,create) + if not server or server=="" then + server=smtp.SERVER + end + if not port or port=="" then + port=smtp.PORT + end + local s={ + tp=trysocket(tp.connect(server,port,smtp.TIMEOUT,create)), + try=newtrysocket(function() + s:close() + end), + } + setmetatable(s,mt) + return s +end +smtp.open=opensmtp +local nofboundaries=0 +local function newboundary() + nofboundaries=nofboundaries+1 + return format('%s%05d==%05u',osdate('%d%m%Y%H%M%S'),random(0,99999),nofboundaries) +end +local send_message +local function send_headers(headers) + yieldcoroutine(normalizeheaders(headers)) +end +local function send_multipart(message) + local boundary=newboundary() + local headers=lowerheaders(message.headers) + local body=message.body + local preamble=body.preamble + local epilogue=body.epilogue + local content=headers['content-type'] or 'multipart/mixed' + headers['content-type']=content..'; boundary="'..boundary..'"' + send_headers(headers) + if preamble then + yieldcoroutine(preamble) + yieldcoroutine("\r\n") + end + for i=1,#body do + yieldcoroutine("\r\n--"..boundary.."\r\n") + send_message(body[i]) + end + yieldcoroutine("\r\n--"..boundary.."--\r\n\r\n") + if epilogue then + yieldcoroutine(epilogue) + yieldcoroutine("\r\n") + end +end +local default_content_type='text/plain; charset="UTF-8"' +local function send_source(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + local getchunk=message.body + while true do + local chunk,err=getchunk() + if err then + yieldcoroutine(nil,err) + elseif chunk then + yieldcoroutine(chunk) + else + break + end + end +end +local function send_string(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + yieldcoroutine(message.body) +end +function send_message(message) + local body=message.body + if type(body)=="table" then + send_multipart(message) + elseif type(body)=="function" then + send_source(message) + else + send_string(message) + end +end +local function adjust_headers(message) + local headers=lowerheaders(message.headers) + if not headers["date"] then + headers["date"]=osdate("!%a, %d %b %Y %H:%M:%S ")..(message.zone or smtp.ZONE) + end + if not headers["x-mailer"] then + headers["x-mailer"]=socket._VERSION + end + headers["mime-version"]="1.0" + return headers +end +function smtp.message(message) + message.headers=adjust_headers(message) + local action=createcoroutine(function() + send_message(message) + end) + return function() + local ret,a,b=resumecoroutine(action) + if ret then + return a,b + else + return nil,a + end + end +end +smtp.send=protectsocket(function(mail) + local snd=opensmtp(smtp,mail.server,mail.port,mail.create) + local ext=snd:greet(mail.domain) + snd:auth(mail.user,mail.password,ext) + snd:send(mail) + snd:quit() + return snd:close() +end) +package.loaded["socket.smtp"]=smtp end -- of closure @@ -8945,14 +12336,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-set"] = package.loaded["trac-set"] or true --- original size: 13044, stripped down to: 9231 +-- original size: 13340, stripped down to: 8826 if not modules then modules={} end modules ['trac-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber=type,next,tostring,tonumber local concat,sortedhash=table.concat,table.sortedhash @@ -8967,305 +12358,318 @@ utilities.setters=setters local data={} local trace_initialize=false function setters.initialize(filename,name,values) - local setter=data[name] - if setter then - frozen=true - local data=setter.data - if data then - for key,newvalue in sortedhash(values) do - local newvalue=is_boolean(newvalue,newvalue,true) - local functions=data[key] - if functions then - local oldvalue=functions.value - if functions.frozen then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) - end - elseif #functions>0 and not oldvalue then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) - end - for i=1,#functions do - functions[i](newvalue) - end - functions.value=newvalue - functions.frozen=functions.frozen or frozen - else - if trace_initialize then - setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) - end - end - else - functions={ default=newvalue,frozen=frozen } - data[key]=functions - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) - end - end + local setter=data[name] + if setter then + frozen=true + local data=setter.data + if data then + for key,newvalue in sortedhash(values) do + local newvalue=is_boolean(newvalue,newvalue,true) + local functions=data[key] + if functions then + local oldvalue=functions.value + if functions.frozen then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) + end + elseif #functions>0 and not oldvalue then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) + end + for i=1,#functions do + functions[i](newvalue) + end + functions.value=newvalue + functions.frozen=functions.frozen or frozen + else + if trace_initialize then + setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) end - return true + end + else + functions={ default=newvalue,frozen=frozen } + data[key]=functions + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) + end end + end + return true end + end end local function set(t,what,newvalue) - local data=t.data - if not data.frozen then - local done=t.done - if type(what)=="string" then - what=settings_to_hash(what) - end - if type(what)~="table" then - return - end - if not done then - done={} - t.done=done - end - for w,value in sortedhash(what) do - if value=="" then - value=newvalue - elseif not value then - value=false - else - value=is_boolean(value,value,true) - end - w=topattern(w,true,true) - for name,functions in sortedhash(data) do - if done[name] then - elseif find(name,w) then - done[name]=true - for i=1,#functions do - functions[i](value) - end - functions.value=value - end - end + local data=t.data + if not data.frozen then + local done=t.done + if type(what)=="string" then + what=settings_to_hash(what) + end + if type(what)~="table" then + return + end + if not done then + done={} + t.done=done + end + for w,value in sortedhash(what) do + if value=="" then + value=newvalue + elseif not value then + value=false + else + value=is_boolean(value,value,true) + end + w=topattern(w,true,true) + for name,functions in sortedhash(data) do + if done[name] then + elseif find(name,w) then + done[name]=true + for i=1,#functions do + functions[i](value) + end + functions.value=value end + end end + end end local function reset(t) - local data=t.data - if not data.frozen then - for name,functions in sortedthash(data) do - for i=1,#functions do - functions[i](false) - end - functions.value=false - end + local data=t.data + if not data.frozen then + for name,functions in sortedthash(data) do + for i=1,#functions do + functions[i](false) + end + functions.value=false end + end end local function enable(t,what) - set(t,what,true) + set(t,what,true) end local function disable(t,what) - local data=t.data - if not what or what=="" then - t.done={} - reset(t) - else - set(t,what,false) - end + local data=t.data + if not what or what=="" then + t.done={} + reset(t) + else + set(t,what,false) + end end function setters.register(t,what,...) - local data=t.data - what=lower(what) - local functions=data[what] - if not functions then - functions={} - data[what]=functions - if trace_initialize then - t.report("defining %a",what) - end - end - local default=functions.default - for i=1,select("#",...) do - local fnc=select(i,...) - local typ=type(fnc) - if typ=="string" then - if trace_initialize then - t.report("coupling %a to %a",what,fnc) - end - local s=fnc - fnc=function(value) set(t,s,value) end - elseif typ~="function" then - fnc=nil - end - if fnc then - functions[#functions+1]=fnc - local value=functions.value or default - if value~=nil then - fnc(value) - functions.value=value - end - end + local data=t.data + what=lower(what) + local functions=data[what] + if not functions then + functions={} + data[what]=functions + if trace_initialize then + t.report("defining %a",what) + end + end + local default=functions.default + for i=1,select("#",...) do + local fnc=select(i,...) + local typ=type(fnc) + if typ=="string" then + if trace_initialize then + t.report("coupling %a to %a",what,fnc) + end + local s=fnc + fnc=function(value) set(t,s,value) end + elseif typ~="function" then + fnc=nil + end + if fnc then + functions[#functions+1]=fnc + local value=functions.value or default + if value~=nil then + fnc(value) + functions.value=value + end end - return false + end + return false end function setters.enable(t,what) - local e=t.enable - t.enable,t.done=enable,{} - enable(t,what) - t.enable,t.done=e,{} + local e=t.enable + t.enable,t.done=enable,{} + enable(t,what) + t.enable,t.done=e,{} end function setters.disable(t,what) - local e=t.disable - t.disable,t.done=disable,{} - disable(t,what) - t.disable,t.done=e,{} + local e=t.disable + t.disable,t.done=disable,{} + disable(t,what) + t.disable,t.done=e,{} end function setters.reset(t) - t.done={} - reset(t) + t.done={} + reset(t) end function setters.list(t) - local list=table.sortedkeys(t.data) - local user,system={},{} - for l=1,#list do - local what=list[l] - if find(what,"^%*") then - system[#system+1]=what - else - user[#user+1]=what - end + local list=table.sortedkeys(t.data) + local user,system={},{} + for l=1,#list do + local what=list[l] + if find(what,"^%*") then + system[#system+1]=what + else + user[#user+1]=what end - return user,system + end + return user,system end function setters.show(t) - local list=setters.list(t) - t.report() - for k=1,#list do - local name=list[k] - local functions=t.data[name] - if functions then - local value=functions.value - local default=functions.default - local modules=#functions - if default==nil then - default="unset" - elseif type(default)=="table" then - default=concat(default,"|") - else - default=tostring(default) - end - if value==nil then - value="unset" - elseif type(value)=="table" then - value=concat(value,"|") - else - value=tostring(value) - end - t.report(name) - t.report(" modules : %i",modules) - t.report(" default : %s",default) - t.report(" value : %s",value) - t.report() - end + local list=setters.list(t) + t.report() + for k=1,#list do + local name=list[k] + local functions=t.data[name] + if functions then + local value=functions.value + local default=functions.default + local modules=#functions + if default==nil then + default="unset" + elseif type(default)=="table" then + default=concat(default,"|") + else + default=tostring(default) + end + if value==nil then + value="unset" + elseif type(value)=="table" then + value=concat(value,"|") + else + value=tostring(value) + end + t.report(name) + t.report(" modules : %i",modules) + t.report(" default : %s",default) + t.report(" value : %s",value) + t.report() end + end end local enable,disable,register,list,show=setters.enable,setters.disable,setters.register,setters.list,setters.show function setters.report(setter,...) - print(format("%-15s : %s\n",setter.name,format(...))) + print(format("%-15s : %s\n",setter.name,format(...))) end local function default(setter,name) - local d=setter.data[name] - return d and d.default + local d=setter.data[name] + return d and d.default end local function value(setter,name) - local d=setter.data[name] - return d and (d.value or d.default) + local d=setter.data[name] + return d and (d.value or d.default) end function setters.new(name) - local setter - setter={ - data=allocate(), - name=name, - report=function(...) setters.report (setter,...) end, - enable=function(...) enable (setter,...) end, - disable=function(...) disable (setter,...) end, - reset=function(...) reset (setter,...) end, - register=function(...) register(setter,...) end, - list=function(...) list (setter,...) end, - show=function(...) show (setter,...) end, - default=function(...) return default (setter,...) end, - value=function(...) return value (setter,...) end, - } - data[name]=setter - return setter + local setter + setter={ + data=allocate(), + name=name, + report=function(...) setters.report (setter,...) end, + enable=function(...) enable (setter,...) end, + disable=function(...) disable (setter,...) end, + reset=function(...) reset (setter,...) end, + register=function(...) register(setter,...) end, + list=function(...) list (setter,...) end, + show=function(...) show (setter,...) end, + default=function(...) return default (setter,...) end, + value=function(...) return value (setter,...) end, + } + data[name]=setter + return setter end trackers=setters.new("trackers") directives=setters.new("directives") experiments=setters.new("experiments") -local t_enable,t_disable=trackers .enable,trackers .disable +local t_enable,t_disable=trackers .enable,trackers .disable local d_enable,d_disable=directives .enable,directives .disable local e_enable,e_disable=experiments.enable,experiments.disable -local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) -local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) +local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) +local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) function directives.enable(...) - if trace_directives then - directives.report("enabling: % t",{...}) - end - d_enable(...) + if trace_directives then + directives.report("enabling: % t",{...}) + end + d_enable(...) end function directives.disable(...) - if trace_directives then - directives.report("disabling: % t",{...}) - end - d_disable(...) + if trace_directives then + directives.report("disabling: % t",{...}) + end + d_disable(...) end function experiments.enable(...) - if trace_experiments then - experiments.report("enabling: % t",{...}) - end - e_enable(...) + if trace_experiments then + experiments.report("enabling: % t",{...}) + end + e_enable(...) end function experiments.disable(...) - if trace_experiments then - experiments.report("disabling: % t",{...}) - end - e_disable(...) + if trace_experiments then + experiments.report("disabling: % t",{...}) + end + e_disable(...) end directives.register("system.nostatistics",function(v) - if statistics then - statistics.enable=not v - else - end + if statistics then + statistics.enable=not v + else + end end) directives.register("system.nolibraries",function(v) - if libraries then - libraries=nil - else - end + if libraries then + libraries=nil + else + end end) if environment then - local engineflags=environment.engineflags - if engineflags then - local list=engineflags["c:trackers"] or engineflags["trackers"] - if type(list)=="string" then - setters.initialize("commandline flags","trackers",settings_to_hash(list)) - end - local list=engineflags["c:directives"] or engineflags["directives"] - if type(list)=="string" then - setters.initialize("commandline flags","directives",settings_to_hash(list)) - end + local engineflags=environment.engineflags + if engineflags then + local list=engineflags["c:trackers"] or engineflags["trackers"] + if type(list)=="string" then + setters.initialize("commandline flags","trackers",settings_to_hash(list)) end -end -if texconfig then - local function set(k,v) - v=tonumber(v) - if v then - texconfig[k]=v - end + local list=engineflags["c:directives"] or engineflags["directives"] + if type(list)=="string" then + setters.initialize("commandline flags","directives",settings_to_hash(list)) end - directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) - directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) - directives.register("luatex.nestsize",function(v) set("nest_size",v) end) - directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) - directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) - directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) - directives.register("luatex.paramsize",function(v) set("param_size",v) end) - directives.register("luatex.savesize",function(v) set("save_size",v) end) - directives.register("luatex.stacksize",function(v) set("stack_size",v) end) + end end +if texconfig then + local function set(k,v) + v=tonumber(v) + if v then + texconfig[k]=v + end + end + directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) + directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) + directives.register("luatex.nestsize",function(v) set("nest_size",v) end) + directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) + directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) + directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) + directives.register("luatex.paramsize",function(v) set("param_size",v) end) + directives.register("luatex.savesize",function(v) set("save_size",v) end) + directives.register("luatex.stacksize",function(v) set("stack_size",v) end) +end +local data=table.setmetatableindex("table") +updaters={ + register=function(what,f) + local d=data[what] + d[#d+1]=f + end, + apply=function(what,...) + local d=data[what] + for i=1,#d do + d[i](...) + end + end, +} end -- of closure @@ -9274,14 +12678,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-log"] = package.loaded["trac-log"] or true --- original size: 32922, stripped down to: 23011 +-- original size: 32608, stripped down to: 20925 if not modules then modules={} end modules ['trac-log']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,select,print=next,type,select,print local format,gmatch,find=string.format,string.gmatch,string.find @@ -9292,7 +12696,7 @@ local datetime=os.date local openfile=io.open local runningtex=tex and (tex.jobname or tex.formatname) local write_nl=runningtex and texio and texio.write_nl or print -local write=runningtex and texio and texio.write or io.write +local write=runningtex and texio and texio.write or io.write local setmetatableindex=table.setmetatableindex local formatters=string.formatters local settings_to_hash=utilities.parsers.settings_to_hash @@ -9308,404 +12712,404 @@ webpage : http://www.pragma-ade.nl / http://tex.aanhet.net wiki : http://contextgarden.net ]] formatters.add ( - formatters,"unichr", - [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] + formatters,"unichr", + [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] ) formatters.add ( - formatters,"chruni", - [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] + formatters,"chruni", + [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] ) 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,setlogfile,settimedlog,setprocessor,setformatters,newline if runningtex then - if texio.setescape then - texio.setescape(0) - end - if arg then - for k,v in next,arg do - if v=="--ansi" or v=="--c:ansi" then - variant="ansi" - break - end - end - end - local function useluawrites() - local texio_write_nl=texio.write_nl - local texio_write=texio.write - local io_write=io.write - write_nl=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write_nl("log",...) - texio_write_nl("term","") - io_write(...) - elseif target=="log" then - texio_write_nl("log",...) - elseif target=="term" then - texio_write_nl("term","") - io_write(...) - elseif type(target)=="number" then - texio_write_nl(target,...) - elseif target~="none" then - texio_write_nl("log",target,...) - texio_write_nl("term","") - io_write(target,...) - end - end - write=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write("log",...) - io_write(...) - elseif target=="log" then - texio_write("log",...) - elseif target=="term" then - io_write(...) - elseif type(target)=="number" then - texio_write(target,...) - elseif target~="none" then - texio_write("log",target,...) - io_write(target,...) - end - end - texio.write=write - texio.write_nl=write_nl - useluawrites=ignore - end - local whereto="both" - local target=nil - local targets=nil - local formats=table.setmetatableindex("self") - local translations=table.setmetatableindex("self") - local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes - local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s > %s\n"], - report_nop=formatters["%-15s >\n"], - direct_yes=formatters["%-15s > %s"], - direct_nop=formatters["%-15s >"], - subreport_yes=formatters["%-15s > %s > %s\n"], - subreport_nop=formatters["%-15s > %s >\n"], - subdirect_yes=formatters["%-15s > %s > %s"], - subdirect_nop=formatters["%-15s > %s >"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - targets={ - logfile="log", - log="log", - file="log", - console="term", - terminal="term", - both="term and log", - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], - report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], - direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], - direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], - subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], - subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], - subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], - subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], - status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], - }, - targets={ - logfile="none", - log="none", - file="none", - console="term", - terminal="term", - both="term", - }, - } - } - logs.flush=io.flush - writer=function(...) - write_nl(target,...) - end - newline=function() - write_nl(target,"\n") - end - report=function(a,b,c,...) - if c~=nil then - write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,report_yes(translations[a],formats[b])) - elseif a then - write_nl(target,report_nop(translations[a])) - else - write_nl(target,"\n") - end - end - direct=function(a,b,c,...) - if c~=nil then - return direct_yes(translations[a],formatters[formats[b]](c,...)) - elseif b then - return direct_yes(translations[a],formats[b]) - elseif a then - return direct_nop(translations[a]) - else - return "" - end - end - subreport=function(a,s,b,c,...) - if c~=nil then - write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) - elseif a then - write_nl(target,subreport_nop(translations[a],translations[s])) - else - write_nl(target,"\n") - end - end - subdirect=function(a,s,b,c,...) - if c~=nil then - return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) - elseif b then - return subdirect_yes(translations[a],translations[s],formats[b]) - elseif a then - return subdirect_nop(translations[a],translations[s]) - else - return "" - end + if texio.setescape then + texio.setescape(0) + end + if arg then + for k,v in next,arg do + if v=="--ansi" or v=="--c:ansi" then + variant="ansi" + break + end end - status=function(a,b,c,...) - if c~=nil then - write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,status_yes(translations[a],formats[b])) - elseif a then - write_nl(target,status_nop(translations[a])) - else - write_nl(target,"\n") - end + end + local function useluawrites() + local texio_write_nl=texio.write_nl + local texio_write=texio.write + local io_write=io.write + write_nl=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write_nl("log",...) + texio_write_nl("term","") + io_write(...) + elseif target=="log" then + texio_write_nl("log",...) + elseif target=="term" then + texio_write_nl("term","") + io_write(...) + elseif type(target)=="number" then + texio_write_nl(target,...) + elseif target~="none" then + texio_write_nl("log",target,...) + texio_write_nl("term","") + io_write(target,...) + end end - settarget=function(askedwhereto) - whereto=askedwhereto or whereto or "both" - target=targets[whereto] - if not target then - whereto="both" - target=targets[whereto] - end - if target=="term" or target=="term and log" then - logs.flush=io.flush - else - logs.flush=ignore - end + write=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write("log",...) + io_write(...) + elseif target=="log" then + texio_write("log",...) + elseif target=="term" then + io_write(...) + elseif type(target)=="number" then + texio_write(target,...) + elseif target~="none" then + texio_write("log",target,...) + io_write(target,...) + end end - local stack={} - pushtarget=function(newtarget) - insert(stack,target) - settarget(newtarget) + texio.write=write + texio.write_nl=write_nl + useluawrites=ignore + end + local whereto="both" + local target=nil + local targets=nil + local formats=table.setmetatableindex("self") + local translations=table.setmetatableindex("self") + local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes + local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s > %s\n"], + report_nop=formatters["%-15s >\n"], + direct_yes=formatters["%-15s > %s"], + direct_nop=formatters["%-15s >"], + subreport_yes=formatters["%-15s > %s > %s\n"], + subreport_nop=formatters["%-15s > %s >\n"], + subdirect_yes=formatters["%-15s > %s > %s"], + subdirect_nop=formatters["%-15s > %s >"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + targets={ + logfile="log", + log="log", + file="log", + console="term", + terminal="term", + both="term and log", + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], + report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], + direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], + direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], + subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], + subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], + subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], + subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], + status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], + }, + targets={ + logfile="none", + log="none", + file="none", + console="term", + terminal="term", + both="term", + }, + } + } + logs.flush=io.flush + writer=function(...) + write_nl(target,...) + end + newline=function() + write_nl(target,"\n") + end + report=function(a,b,c,...) + if c~=nil then + write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,report_yes(translations[a],formats[b])) + elseif a then + write_nl(target,report_nop(translations[a])) + else + write_nl(target,"\n") end - poptarget=function() - if #stack>0 then - settarget(remove(stack)) - end + end + direct=function(a,b,c,...) + if c~=nil then + return direct_yes(translations[a],formatters[formats[b]](c,...)) + elseif b then + return direct_yes(translations[a],formats[b]) + elseif a then + return direct_nop(translations[a]) + else + return "" end - setformats=function(f) - formats=f + end + subreport=function(a,s,b,c,...) + if c~=nil then + write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) + elseif a then + write_nl(target,subreport_nop(translations[a],translations[s])) + else + write_nl(target,"\n") end - settranslations=function(t) - translations=t + end + subdirect=function(a,s,b,c,...) + if c~=nil then + return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) + elseif b then + return subdirect_yes(translations[a],translations[s],formats[b]) + elseif a then + return subdirect_nop(translations[a],translations[s]) + else + return "" end - setprocessor=function(f) - local writeline=write_nl - write_nl=function(target,...) - writeline(target,f(...)) - end + end + status=function(a,b,c,...) + if c~=nil then + write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,status_yes(translations[a],formats[b])) + elseif a then + write_nl(target,status_nop(translations[a])) + else + write_nl(target,"\n") + end + end + settarget=function(askedwhereto) + whereto=askedwhereto or whereto or "both" + target=targets[whereto] + if not target then + whereto="both" + target=targets[whereto] + end + if target=="term" or target=="term and log" then + logs.flush=io.flush + else + logs.flush=ignore + end + end + local stack={} + pushtarget=function(newtarget) + insert(stack,target) + settarget(newtarget) + end + poptarget=function() + if #stack>0 then + settarget(remove(stack)) + end + end + setformats=function(f) + formats=f + end + settranslations=function(t) + translations=t + end + setprocessor=function(f) + local writeline=write_nl + write_nl=function(target,...) + writeline(target,f(...)) + end + end + setformatters=function(specification) + local t=nil + local f=nil + local d=variants.default + if not specification then + elseif type(specification)=="table" then + t=specification.targets + f=specification.formats or specification + else + local v=variants[specification] + if v then + t=v.targets + f=v.formats + variant=specification + end end - setformatters=function(specification) - local t=nil - local f=nil - local d=variants.default - if not specification then - elseif type(specification)=="table" then - t=specification.targets - f=specification.formats or specification - else - local v=variants[specification] - if v then - t=v.targets - f=v.formats - variant=specification - end - end - targets=t or d.targets - target=targets[whereto] or target - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - direct_yes=f.direct_yes - direct_nop=f.direct_nop - subdirect_yes=f.subdirect_yes - subdirect_nop=f.subdirect_nop - status_yes=f.status_yes - status_nop=f.status_nop - if variant=="ansi" then - useluawrites() - end - settarget(whereto) - end - setformatters(variant) - setlogfile=ignore - settimedlog=ignore + targets=t or d.targets + target=targets[whereto] or target + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + direct_yes=f.direct_yes + direct_nop=f.direct_nop + subdirect_yes=f.subdirect_yes + subdirect_nop=f.subdirect_nop + status_yes=f.status_yes + status_nop=f.status_nop + if variant=="ansi" then + useluawrites() + end + settarget(whereto) + end + setformatters(variant) + setlogfile=ignore + settimedlog=ignore else - local report_yes,subreport_yes,status_yes - local report_nop,subreport_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s | %s"], - report_nop=formatters["%-15s |"], - subreport_yes=formatters["%-15s | %s | %s"], - subreport_nop=formatters["%-15s | %s |"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], - report_nop=formatters["[0;32m%-15s [0;1m|[0m"], - subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], - subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], - status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], - }, - }, - } - logs.flush=ignore - writer=function(s) - write_nl(s) - end - newline=function() - write_nl("\n") + local report_yes,subreport_yes,status_yes + local report_nop,subreport_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s | %s"], + report_nop=formatters["%-15s |"], + subreport_yes=formatters["%-15s | %s | %s"], + subreport_nop=formatters["%-15s | %s |"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], + report_nop=formatters["[0;32m%-15s [0;1m|[0m"], + subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], + subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], + status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], + }, + }, + } + logs.flush=ignore + writer=function(s) + write_nl(s) + end + newline=function() + write_nl("\n") + end + report=function(a,b,c,...) + if c then + write_nl(report_yes(a,formatters[b](c,...))) + elseif b then + write_nl(report_yes(a,b)) + elseif a then + write_nl(report_nop(a)) + else + write_nl("") end - report=function(a,b,c,...) - if c then - write_nl(report_yes(a,formatters[b](c,...))) - elseif b then - write_nl(report_yes(a,b)) - elseif a then - write_nl(report_nop(a)) - else - write_nl("") - end + end + subreport=function(a,sub,b,c,...) + if c then + write_nl(subreport_yes(a,sub,formatters[b](c,...))) + elseif b then + write_nl(subreport_yes(a,sub,b)) + elseif a then + write_nl(subreport_nop(a,sub)) + else + write_nl("") end - subreport=function(a,sub,b,c,...) - if c then - write_nl(subreport_yes(a,sub,formatters[b](c,...))) - elseif b then - write_nl(subreport_yes(a,sub,b)) - elseif a then - write_nl(subreport_nop(a,sub)) - else - write_nl("") + end + status=function(a,b,c,...) + if c then + write_nl(status_yes(a,formatters[b](c,...))) + elseif b then + write_nl(status_yes(a,b)) + elseif a then + write_nl(status_nop(a)) + else + write_nl("\n") + end + end + direct=ignore + subdirect=ignore + settarget=ignore + pushtarget=ignore + poptarget=ignore + setformats=ignore + settranslations=ignore + setprocessor=function(f) + local writeline=write_nl + write_nl=function(s) + writeline(f(s)) + end + end + setformatters=function(specification) + local f=nil + local d=variants.default + if specification then + if type(specification)=="table" then + f=specification.formats or specification + else + local v=variants[specification] + if v then + f=v.formats end + end end - status=function(a,b,c,...) - if c then - write_nl(status_yes(a,formatters[b](c,...))) - elseif b then - write_nl(status_yes(a,b)) - elseif a then - write_nl(status_nop(a)) - else - write_nl("\n") - end - end - direct=ignore - subdirect=ignore - settarget=ignore - pushtarget=ignore - poptarget=ignore - setformats=ignore - settranslations=ignore - setprocessor=function(f) - local writeline=write_nl + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + status_yes=f.status_yes + status_nop=f.status_nop + end + setformatters(variant) + 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(f(s)) - end - end - setformatters=function(specification) - local f=nil - local d=variants.default - if specification then - if type(specification)=="table" then - f=specification.formats or specification - else - local v=variants[specification] - if v then - f=v.formats - end - end - end - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - status_yes=f.status_yes - status_nop=f.status_nop - end - setformatters(variant) - 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 + writeline(s) + f:write(localtime()," | ",s,"\n") end - setlogfile=ignore - end - settimedlog=function() - local localtime=os.localtime - local writeline=write_nl + else write_nl=function(s) - writeline(localtime().." | "..s) + writeline(s) + local f=io.open(name,"ab") + f:write(localtime()," | ",s,"\n") + f:close() end - settimedlog=ignore + 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 @@ -9727,198 +13131,186 @@ local data={} local states=nil local force=false function logs.reporter(category,subcategory) - local logger=data[category] - if not logger then - local state=states==true - if not state and type(states)=="table" then - for c,_ in next,states do - if find(category,c) then - state=true - break - end - end + local logger=data[category] + if not logger then + local state=states==true + if not state and type(states)=="table" then + for c,_ in next,states do + if find(category,c) then + state=true + break end - logger={ - reporters={}, - state=state, - } - data[category]=logger - end - local reporter=logger.reporters[subcategory or "default"] - if not reporter then - if subcategory then - reporter=function(...) - if force or not logger.state then - subreport(category,subcategory,...) - end - end - logger.reporters[subcategory]=reporter - else - local tag=category - reporter=function(...) - if force or not logger.state then - report(category,...) - end - end - logger.reporters.default=reporter + end + end + logger={ + reporters={}, + state=state, + } + data[category]=logger + end + local reporter=logger.reporters[subcategory or "default"] + if not reporter then + if subcategory then + reporter=function(...) + if force or not logger.state then + subreport(category,subcategory,...) end + end + logger.reporters[subcategory]=reporter + else + local tag=category + reporter=function(...) + if force or not logger.state then + report(category,...) + end + end + logger.reporters.default=reporter end - return reporter + end + return reporter end logs.new=logs.reporter local ctxreport=logs.writer function logs.setmessenger(m) - ctxreport=m + ctxreport=m end function logs.messenger(category,subcategory) - if subcategory then - return function(...) - ctxreport(subdirect(category,subcategory,...)) - end - else - return function(...) - ctxreport(direct(category,...)) - end + if subcategory then + return function(...) + ctxreport(subdirect(category,subcategory,...)) end + else + return function(...) + ctxreport(direct(category,...)) + end + end end local function setblocked(category,value) - if category==true or category=="all" then - category,value="*",true - elseif category==false then - category,value="*",false - elseif value==nil then - value=true - end - if category=="*" then - states=value + if category==true or category=="all" then + category,value="*",true + elseif category==false then + category,value="*",false + elseif value==nil then + value=true + end + if category=="*" then + states=value + for k,v in next,data do + v.state=value + end + else + alllocked=false + states=settings_to_hash(category,type(states)=="table" and states or nil) + for c in next,states do + local v=data[c] + if v then + v.state=value + else + c=topattern(c,true,true) for k,v in next,data do + if find(k,c) then v.state=value + end end - else - alllocked=false - states=settings_to_hash(category,type(states)=="table" and states or nil) - for c in next,states do - local v=data[c] - if v then - v.state=value - else - c=topattern(c,true,true) - for k,v in next,data do - if find(k,c) then - v.state=value - end - end - end - end + end end + end end function logs.disable(category,value) - setblocked(category,value==nil and true or value) + setblocked(category,value==nil and true or value) end function logs.enable(category) - setblocked(category,false) + setblocked(category,false) end function logs.categories() - return sortedkeys(data) + return sortedkeys(data) end function logs.show() - local n,c,s,max=0,0,0,0 - for category,v in table.sortedpairs(data) do - n=n+1 - local state=v.state - local reporters=v.reporters - local nc=#category - if nc>c then - c=nc - end - for subcategory,_ in next,reporters do - local ns=#subcategory - if ns>c then - s=ns - end - local m=nc+ns - if m>max then - max=m - end - end - local subcategories=concat(sortedkeys(reporters),", ") - if state==true then - state="disabled" - elseif state==false then - state="enabled" - else - state="unknown" - end - report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + local n,c,s,max=0,0,0,0 + for category,v in table.sortedpairs(data) do + n=n+1 + local state=v.state + local reporters=v.reporters + local nc=#category + if nc>c then + c=nc + end + for subcategory,_ in next,reporters do + local ns=#subcategory + if ns>c then + s=ns + end + local m=nc+ns + if m>max then + max=m + end + end + local subcategories=concat(sortedkeys(reporters),", ") + if state==true then + state="disabled" + elseif state==false then + state="enabled" + else + state="unknown" end - report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) + report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + end + report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) end local delayed_reporters={} setmetatableindex(delayed_reporters,function(t,k) - local v=logs.reporter(k.name) - t[k]=v - return v + local v=logs.reporter(k.name) + t[k]=v + return v end) function utilities.setters.report(setter,...) - delayed_reporters[setter](...) + delayed_reporters[setter](...) end directives.register("logs.blocked",function(v) - setblocked(v,true) + setblocked(v,true) end) directives.register("logs.target",function(v) - settarget(v) + settarget(v) end) if tex then - local report=logs.reporter("pages") - local texgetcount=tex and tex.getcount - local real,user,sub - function logs.start_page_number() - real=texgetcount("realpageno") - user=texgetcount("userpageno") - sub=texgetcount("subpageno") - end - local timing=false - local starttime=nil - local lasttime=nil - trackers.register("pages.timing",function(v) - starttime=os.clock() - timing=true - end) - function logs.stop_page_number() - if timing then - local elapsed,average - local stoptime=os.clock() - if not lasttime or real<2 then - elapsed=stoptime - average=stoptime - starttime=stoptime - else - elapsed=stoptime-lasttime - average=(stoptime-starttime)/(real-1) - end - lasttime=stoptime - if real<=0 then - report("flushing page, time %0.04f / %0.04f",elapsed,average) - elseif user<=0 then - report("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average) - elseif sub<=0 then - report("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average) - else - report("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average) - end - else - if real<=0 then - report("flushing page") - elseif user<=0 then - report("flushing realpage %s",real) - elseif sub<=0 then - report("flushing realpage %s, userpage %s",real,user) - else - report("flushing realpage %s, userpage %s, subpage %s",real,user,sub) - end - end - logs.flush() + local report=logs.reporter("pages") + local texgetcount=tex and tex.getcount + local real,user,sub=0,0,0 + function logs.start_page_number() + real=texgetcount("realpageno") + user=texgetcount("userpageno") + sub=texgetcount("subpageno") + end + local timing=false + local lasttime=nil + trackers.register("pages.timing",function(v) + timing="" + end) + function logs.stop_page_number() + if timing then + local elapsed=statistics.currenttime(statistics) + local average,page + if not lasttime or real<2 then + average=elapsed + page=elapsed + else + average=elapsed/(real-1) + page=elapsed-lasttime + end + lasttime=elapsed + timing=formatters[", total %0.03f, page %0.03f, average %0.03f"](elapsed,page,average) end + if real<=0 then + report("flushing page%s",timing) + elseif user<=0 then + report("flushing realpage %s%s",real,timing) + elseif sub<=0 then + report("flushing realpage %s, userpage %s%s",real,user,timing) + else + report("flushing realpage %s, userpage %s, subpage %s%s",real,user,sub,timing) + end + logs.flush() + end end local nesting=0 local verbose=false @@ -9942,222 +13334,222 @@ logs.help=ignore local Carg,C,lpegmatch=lpeg.Carg,lpeg.C,lpeg.match local p_newline=lpeg.patterns.newline local linewise=( - Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline + Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline )^1 local function reportlines(t,str) - if str then - lpegmatch(linewise,str,1,t) - end + if str then + lpegmatch(linewise,str,1,t) + end end local function reportbanner(t) - local banner=t.banner - if banner then - t.report(banner) - t.report() - end + local banner=t.banner + if banner then + t.report(banner) + t.report() + end end local function reportversion(t) - local banner=t.banner - if banner then - t.report(banner) - end + local banner=t.banner + if banner then + t.report(banner) + end end local function reporthelp(t,...) - local helpinfo=t.helpinfo - if type(helpinfo)=="string" then - reportlines(t,helpinfo) - elseif type(helpinfo)=="table" then - for i=1,select("#",...) do - reportlines(t,t.helpinfo[select(i,...)]) - if i<n then - t.report() - end - end + local helpinfo=t.helpinfo + if type(helpinfo)=="string" then + reportlines(t,helpinfo) + elseif type(helpinfo)=="table" then + for i=1,select("#",...) do + reportlines(t,t.helpinfo[select(i,...)]) + if i<n then + t.report() + end end + end end local function reportinfo(t) - t.report() - reportlines(t,t.moreinfo) + t.report() + reportlines(t,t.moreinfo) end local function reportexport(t,method) - report(t.helpinfo) + report(t.helpinfo) end local reporters={ - lines=reportlines, - banner=reportbanner, - version=reportversion, - help=reporthelp, - info=reportinfo, - export=reportexport, + lines=reportlines, + banner=reportbanner, + version=reportversion, + help=reporthelp, + info=reportinfo, + export=reportexport, } local exporters={ } logs.reporters=reporters logs.exporters=exporters function logs.application(t) - t.name=t.name or "unknown" - t.banner=t.banner - t.moreinfo=moreinfo - t.report=logs.reporter(t.name) - t.help=function(...) - reporters.banner(t) - reporters.help(t,...) - reporters.info(t) - end - t.export=function(...) - reporters.export(t,...) - end - t.identify=function() - reporters.banner(t) - end - t.version=function() - reporters.version(t) - end - return t + t.name=t.name or "unknown" + t.banner=t.banner + t.moreinfo=moreinfo + t.report=logs.reporter(t.name) + t.help=function(...) + reporters.banner(t) + reporters.help(t,...) + reporters.info(t) + end + t.export=function(...) + reporters.export(t,...) + end + t.identify=function() + reporters.banner(t) + end + t.version=function() + reporters.version(t) + end + return t end local f_syslog=formatters["%s %s => %s => %s => %s\r"] function logs.system(whereto,process,jobname,category,fmt,arg,...) - local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) - for i=1,10 do - local f=openfile(whereto,"a") - if f then - f:write(message) - f:close() - break - else - sleep(0.1) - end + local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) + for i=1,10 do + local f=openfile(whereto,"a") + if f then + f:write(message) + f:close() + break + else + sleep(0.1) end + end end local report_system=logs.reporter("system","logs") function logs.obsolete(old,new) - local o=loadstring("return "..new)() - if type(o)=="function" then - return function(...) - report_system("function %a is obsolete, use %a",old,new) - loadstring(old.."="..new.." return "..old)()(...) - end - elseif type(o)=="table" then - local t,m={},{} - m.__index=function(t,k) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - return o[k] - end - m.__newindex=function(t,k,v) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - o[k]=v - end - if libraries then - libraries.obsolete[old]=t - end - setmetatable(t,m) - return t + local o=loadstring("return "..new)() + if type(o)=="function" then + return function(...) + report_system("function %a is obsolete, use %a",old,new) + loadstring(old.."="..new.." return "..old)()(...) + end + elseif type(o)=="table" then + local t,m={},{} + m.__index=function(t,k) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + return o[k] + end + m.__newindex=function(t,k,v) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + o[k]=v + end + if libraries then + libraries.obsolete[old]=t end + setmetatable(t,m) + return t + end end if utilities then - utilities.report=report_system + utilities.report=report_system end if tex and tex.error then - function logs.texerrormessage(...) - tex.error(format(...),{}) - end + function logs.texerrormessage(...) + tex.error(format(...)) + end else - function logs.texerrormessage(...) - print(format(...)) - end + function logs.texerrormessage(...) + print(format(...)) + end end io.stdout:setvbuf('no') io.stderr:setvbuf('no') if package.helpers.report then - package.helpers.report=logs.reporter("package loader") + package.helpers.report=logs.reporter("package loader") end if tex then - local finalactions={} - local fatalerrors={} - local possiblefatal={} - local loggingerrors=false - function logs.loggingerrors() - return loggingerrors - end - directives.register("logs.errors",function(v) - loggingerrors=v - if type(v)=="string" then - fatalerrors=settings_to_hash(v) - else - fatalerrors={} - end - end) - function logs.registerfinalactions(...) - insert(finalactions,...) - end - local what=nil - local report=nil - local state=nil - local target=nil - local function startlogging(t,r,w,s) - target=t - state=force - force=true - report=type(r)=="function" and r or logs.reporter(r) - what=w - pushtarget(target) + local finalactions={} + local fatalerrors={} + local possiblefatal={} + local loggingerrors=false + function logs.loggingerrors() + return loggingerrors + end + directives.register("logs.errors",function(v) + loggingerrors=v + if type(v)=="string" then + fatalerrors=settings_to_hash(v) + else + fatalerrors={} + end + end) + function logs.registerfinalactions(...) + insert(finalactions,...) + end + local what=nil + local report=nil + local state=nil + local target=nil + local function startlogging(t,r,w,s) + target=t + state=force + force=true + report=type(r)=="function" and r or logs.reporter(r) + what=w + pushtarget(target) + newline() + if s then + report("start %s: %s",what,s) + else + report("start %s",what) + end + if target=="logfile" then + newline() + end + return report + end + local function stoplogging() + if target=="logfile" then + newline() + end + report("stop %s",what) + if target=="logfile" then + newline() + end + poptarget() + state=oldstate + end + function logs.startfilelogging(...) + return startlogging("logfile",...) + end + logs.stopfilelogging=stoplogging + local done=false + function logs.starterrorlogging(r,w,...) + if not done then + pushtarget("terminal") + newline() + logs.report("error logging","start possible issues") + poptarget() + done=true + end + if fatalerrors[w] then + possiblefatal[w]=true + end + return startlogging("terminal",r,w,...) + end + logs.stoperrorlogging=stoplogging + function logs.finalactions() + if #finalactions>0 then + for i=1,#finalactions do + finalactions[i]() + end + if done then + pushtarget("terminal") newline() - if s then - report("start %s: %s",what,s) - else - report("start %s",what) - end - if target=="logfile" then - newline() - end - return report - end - local function stoplogging() - if target=="logfile" then - newline() - end - report("stop %s",what) - if target=="logfile" then - newline() - end + logs.report("error logging","stop possible issues") poptarget() - state=oldstate - end - function logs.startfilelogging(...) - return startlogging("logfile",...) - end - logs.stopfilelogging=stoplogging - local done=false - function logs.starterrorlogging(r,w,...) - if not done then - pushtarget("terminal") - newline() - logs.report("error logging","start possible issues") - poptarget() - done=true - end - if fatalerrors[w] then - possiblefatal[w]=true - end - return startlogging("terminal",r,w,...) - end - logs.stoperrorlogging=stoplogging - function logs.finalactions() - if #finalactions>0 then - for i=1,#finalactions do - finalactions[i]() - end - if done then - pushtarget("terminal") - newline() - logs.report("error logging","stop possible issues") - poptarget() - end - return next(possiblefatal) and sortedkeys(possiblefatal) or false - end + end + return next(possiblefatal) and sortedkeys(possiblefatal) or false end + end end @@ -10167,14 +13559,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8097, stripped down to: 5534 +-- original size: 9072, stripped down to: 6055 if not modules then modules={} end modules ['trac-inf']={ - version=1.001, - comment="companion to trac-inf.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-inf.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber,select=type,tonumber,select local format,lower,find=string.format,string.lower,string.find @@ -10189,161 +13581,191 @@ statistics.enable=true statistics.threshold=0.01 local statusinfo,n,registered,timers={},0,{},{} setmetatableindex(timers,function(t,k) - local v={ timing=0,loadtime=0 } - t[k]=v - return v + local v={ timing=0,loadtime=0 } + t[k]=v + return v end) local function hastiming(instance) - return instance and timers[instance] + return instance and timers[instance] end local function resettiming(instance) - timers[instance or "notimer"]={ timing=0,loadtime=0 } + timers[instance or "notimer"]={ timing=0,loadtime=0 } end local ticks=clock local seconds=function(n) return n or 0 end -local function starttiming(instance) - local timer=timers[instance or "notimer"] - local it=timer.timing - if it==0 then - timer.starttime=ticks() - if not timer.loadtime then - timer.loadtime=0 - end - end - timer.timing=it+1 +local function starttiming(instance,reset) + local timer=timers[instance or "notimer"] + local it=timer.timing + if reset then + it=0 + timer.loadtime=0 + end + if it==0 then + timer.starttime=ticks() + if not timer.loadtime then + timer.loadtime=0 + end + end + timer.timing=it+1 end local function stoptiming(instance) + local timer=timers[instance or "notimer"] + local it=timer.timing + if it>1 then + timer.timing=it-1 + else + local starttime=timer.starttime + if starttime and starttime>0 then + local stoptime=ticks() + local loadtime=stoptime-starttime + timer.stoptime=stoptime + timer.loadtime=timer.loadtime+loadtime + timer.timing=0 + timer.starttime=0 + return loadtime + end + end + return 0 +end +local function elapsed(instance) + if type(instance)=="number" then + return instance + else + local timer=timers[instance or "notimer"] + return timer and seconds(timer.loadtime) or 0 + end +end +local function currenttime(instance) + if type(instance)=="number" then + return instance + else local timer=timers[instance or "notimer"] local it=timer.timing if it>1 then - timer.timing=it-1 else - local starttime=timer.starttime - if starttime and starttime>0 then - local stoptime=ticks() - local loadtime=stoptime-starttime - timer.stoptime=stoptime - timer.loadtime=timer.loadtime+loadtime - timer.timing=0 - timer.starttime=0 - return loadtime - end + local starttime=timer.starttime + if starttime and starttime>0 then + return seconds(timer.loadtime+ticks()-starttime) + end end return 0 -end -local function elapsed(instance) - if type(instance)=="number" then - return instance - else - local timer=timers[instance or "notimer"] - return timer and seconds(timer.loadtime) or 0 - end + end end local function elapsedtime(instance) - return format("%0.3f",elapsed(instance)) + return format("%0.3f",elapsed(instance)) end local function elapsedindeed(instance) - return elapsed(instance)>statistics.threshold + return elapsed(instance)>statistics.threshold end local function elapsedseconds(instance,rest) - if elapsedindeed(instance) then - return format("%0.3f seconds %s",elapsed(instance),rest or "") - end + if elapsedindeed(instance) then + return format("%0.3f seconds %s",elapsed(instance),rest or "") + end end statistics.hastiming=hastiming statistics.resettiming=resettiming statistics.starttiming=starttiming statistics.stoptiming=stoptiming +statistics.currenttime=currenttime statistics.elapsed=elapsed statistics.elapsedtime=elapsedtime statistics.elapsedindeed=elapsedindeed statistics.elapsedseconds=elapsedseconds function statistics.register(tag,fnc) - if statistics.enable and type(fnc)=="function" then - local rt=registered[tag] or (#statusinfo+1) - statusinfo[rt]={ tag,fnc } - registered[tag]=rt - if #tag>n then n=#tag end - end + if statistics.enable and type(fnc)=="function" then + local rt=registered[tag] or (#statusinfo+1) + statusinfo[rt]={ tag,fnc } + registered[tag]=rt + if #tag>n then n=#tag end + end end 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("used engine",function() - return format("%s version %s with functionality level %s, banner: %s", - LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) - end) - register("control sequences",function() - return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) - end) - register("callbacks",statistics.callbacks) - if TEXENGINE=="luajittex" and JITSUPPORTED then - local jitstatus=jit.status - if jitstatus then - local jitstatus={ jitstatus() } - if jitstatus[1] then - register("luajit options",concat(jitstatus," ",2)) - end - end - end - register("lua properties",function() - local hashchar=tonumber(status.luatex_hashchars) - local hashtype=status.luatex_hashtype - local mask=lua.mask or "ascii" - return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", - jit and "luajit" or "lua", - LUAVERSION, - statistics.memused(), - 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 - local s=statusinfo[i] - local r=s[2]() - if r then - report("%s: %s",s[1],r) - end + 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("used engine",function() + return format("%s version %s with functionality level %s, banner: %s", + LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) + end) + register("control sequences",function() + return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) + end) + register("callbacks",statistics.callbacks) + if TEXENGINE=="luajittex" and JITSUPPORTED then + local jitstatus=jit.status + if jitstatus then + local jitstatus={ jitstatus() } + if jitstatus[1] then + register("luajit options",concat(jitstatus," ",2)) end - statistics.enable=false + end end + register("lua properties",function() + local hashchar=tonumber(status.luatex_hashchars) + local hashtype=status.luatex_hashtype + local mask=lua.mask or "ascii" + return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", + jit and "luajit" or "lua", + LUAVERSION, + statistics.memused(), + 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 + local s=statusinfo[i] + local r=s[2]() + if r then + report("%s: %s",s[1],r) + end + end + statistics.enable=false + end end function statistics.memused() - local round=math.round or math.floor - return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) + local round=math.round or math.floor + return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) end starttiming(statistics) function statistics.formatruntime(runtime) - return format("%s seconds",runtime) + return format("%s seconds",runtime) end function statistics.runtime() - stoptiming(statistics) - return statistics.formatruntime(elapsedtime(statistics)) + stoptiming(statistics) + local runtime=lua.getruntime and lua.getruntime() or elapsedtime(statistics) + return statistics.formatruntime(runtime) end local report=logs.reporter("system") -function statistics.timed(action) - starttiming("run") - action() - stoptiming("run") - report("total runtime: %s seconds",elapsedtime("run")) +function statistics.timed(action,all) + starttiming("run") + action() + stoptiming("run") + local runtime=tonumber(elapsedtime("run")) + if all then + local alltime=tonumber(lua.getruntime and lua.getruntime() or elapsedtime(statistics)) + if alltime and alltime>0 then + report("total runtime: %0.3f seconds of %0.3f seconds",runtime,alltime) + return + end + end + report("total runtime: %0.3f seconds",runtime) 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 + 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 @@ -10353,144 +13775,144 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-pro"] = package.loaded["trac-pro"] or true --- original size: 5841, stripped down to: 3511 +-- original size: 5841, stripped down to: 3352 if not modules then modules={} end modules ['trac-pro']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local getmetatable,setmetatable,rawset,type,next=getmetatable,setmetatable,rawset,type,next -local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) +local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) local report_system=logs.reporter("system","protection") namespaces=namespaces or {} 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) - debugger.showtraceback(report_system) - else - report_system("reference to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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) - debugger.showtraceback(report_system) - else - report_system("assignment to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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 end local function register(name) - local data=name=="global" and _G or _G[name] - if not data then - return - end - registered[name]=data - local m=getmetatable(data) - if not m then - m={} - setmetatable(data,m) - end - local index,newindex={},{} - m.__saved__index=m.__index - m.__no__index=function(t,k) - if not index[k] then - index[k]=true - report_index(k,name) - end - return nil + local data=name=="global" and _G or _G[name] + if not data then + return + end + registered[name]=data + local m=getmetatable(data) + if not m then + m={} + setmetatable(data,m) + end + local index,newindex={},{} + m.__saved__index=m.__index + m.__no__index=function(t,k) + if not index[k] then + index[k]=true + report_index(k,name) end - m.__saved__newindex=m.__newindex - m.__no__newindex=function(t,k,v) - if not newindex[k] then - newindex[k]=true - report_newindex(k,name) - end - rawset(t,k,v) + return nil + end + m.__saved__newindex=m.__newindex + m.__no__newindex=function(t,k,v) + if not newindex[k] then + newindex[k]=true + report_newindex(k,name) end - m.__protection__depth=0 + rawset(t,k,v) + end + m.__protection__depth=0 end local function private(name) - local data=registered[name] + local data=registered[name] + if not data then + data=_G[name] if not data then - data=_G[name] - if not data then - data={} - _G[name]=data - end - register(name) + data={} + _G[name]=data end - return data + register(name) + end + return data end local function protect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>0 then - m.__protection__depth=pd+1 - else - m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex - m.__index,m.__newindex=m.__no__index,m.__no__newindex - m.__protection__depth=1 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>0 then + m.__protection__depth=pd+1 + else + m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex + m.__index,m.__newindex=m.__no__index,m.__no__newindex + m.__protection__depth=1 + end end local function unprotect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>1 then - m.__protection__depth=pd-1 - else - m.__index,m.__newindex=m.__saved__index,m.__saved__newindex - m.__protection__depth=0 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>1 then + m.__protection__depth=pd-1 + else + m.__index,m.__newindex=m.__saved__index,m.__saved__newindex + m.__protection__depth=0 + end end local function protectall() - for name,_ in next,registered do - if name~="global" then - protect(name) - end + for name,_ in next,registered do + if name~="global" then + protect(name) end + end end local function unprotectall() - for name,_ in next,registered do - if name~="global" then - unprotect(name) - end + for name,_ in next,registered do + if name~="global" then + unprotect(name) end + end end -namespaces.register=register -namespaces.private=private +namespaces.register=register +namespaces.private=private namespaces.protect=protect namespaces.unprotect=unprotect namespaces.protectall=protectall namespaces.unprotectall=unprotectall namespaces.private("namespaces") registered={} register("global") directives.register("system.protect",function(v) - if v then - protectall() - else - unprotectall() - end + if v then + protectall() + else + unprotectall() + end end) directives.register("system.checkglobals",function(v) - if v then - report_system("enabling global namespace guard") - protect("global") - else - report_system("disabling global namespace guard") - unprotect("global") - end + if v then + report_system("enabling global namespace guard") + protect("global") + else + report_system("disabling global namespace guard") + unprotect("global") + end end) @@ -10500,15 +13922,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lua"] = package.loaded["util-lua"] or true --- original size: 6621, stripped down to: 4764 +-- original size: 6664, stripped down to: 4589 if not modules then modules={} end modules ['util-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - comment="the strip code is written by Peter Cawley", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + comment="the strip code is written by Peter Cawley", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local rep,sub,byte,dump,format=string.rep,string.sub,string.byte,string.dump,string.format local load,loadfile,type,collectgarbage=load,loadfile,type,collectgarbage @@ -10519,150 +13941,151 @@ local report_lua=logs.reporter("system","lua") local report_mem=logs.reporter("system","lua memory") local tracestripping=false local tracememory=false -luautilities.stripcode=true +luautilities.stripcode=true luautilities.alwaysstripcode=false luautilities.nofstrippedchunks=0 luautilities.nofstrippedbytes=0 local strippedchunks={} luautilities.strippedchunks=strippedchunks luautilities.suffixes={ - tma="tma", - tmc=jit and "tmb" or "tmc", - lua="lua", - luc=jit and "lub" or "luc", - lui="lui", - luv="luv", - luj="luj", - tua="tua", - tuc="tuc", + tma="tma", + tmc=jit and "tmb" or "tmc", + lua="lua", + luc=jit and "lub" or "luc", + lui="lui", + luv="luv", + luj="luj", + tua="tua", + tuc="tuc", } 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 + 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 -end -function luautilities.loadedluacode(fullname,forcestrip,name,macros) - name=name or fullname - if macros then - macros=lua.macros - end - local code,message - if macros then - code,message=macros.loaded(fullname,true,false) - else - code,message=loadfile(fullname) - end + local code=io.loaddata(luafile) + if code and code~="" then + code=load(code) if code then - code() - else - report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") - end - if forcestrip and luautilities.stripcode then - if type(forcestrip)=="function" then - forcestrip=forcestrip(fullname) - end - if forcestrip or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end - elseif 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 + io.savedata(lucfile,code) + return true,0 + end else - return code,0 + 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 +end +function luautilities.loadedluacode(fullname,forcestrip,name,macros) + name=name or fullname + if macros then + macros=lua.macros + end + local code,message + if macros then + code,message=macros.loaded(fullname,true,false) + else + code,message=loadfile(fullname) + end + if code then + code() + else + report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") + code,message=loadfile(fullname) + end + if forcestrip and luautilities.stripcode then + if type(forcestrip)=="function" then + forcestrip=forcestrip(fullname) + end + 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 end function luautilities.strippedloadstring(code,name,forcestrip) - 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 - if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end + 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 + if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 + else + return code,0 + end end function luautilities.loadstring(code,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 - return code,0 + 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 + return 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 - end - return done + 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 + end + return done end function luautilities.loadstripped(...) - local l=load(...) - if l then - return load(dump(l,true)) - end + local l=load(...) + if l then + return load(dump(l,true)) + end end local finalizers={} setmetatable(finalizers,{ - __gc=function(t) - for i=1,#t do - pcall(t[i]) - end + __gc=function(t) + for i=1,#t do + pcall(t[i]) end + end } ) function luautilities.registerfinalizer(f) - finalizers[#finalizers+1]=f + finalizers[#finalizers+1]=f end function luautilities.checkmemory(previous,threshold,trace) - local current=collectgarbage("count") - if previous then - local checked=(threshold or 64)*1024 - local delta=current-previous - if current-previous>checked then - collectgarbage("collect") - local afterwards=collectgarbage("count") - if trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB, afterwards %i MB", - previous/1024,current/1024,delta/1024,threshold,afterwards) - end - return afterwards - elseif trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB", - previous/1024,current/1024,delta/1024,threshold) - end + local current=collectgarbage("count") + if previous then + local checked=(threshold or 64)*1024 + local delta=current-previous + if current-previous>checked then + collectgarbage("collect") + local afterwards=collectgarbage("count") + if trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB", + previous/1024,current/1024,delta/1024,threshold,afterwards) + end + return afterwards + elseif trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB", + previous/1024,current/1024,delta/1024,threshold) end - return current + end + return current end @@ -10672,17 +14095,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-deb"] = package.loaded["util-deb"] or true --- original size: 8984, stripped down to: 6573 +-- original size: 9955, stripped down to: 6693 if not modules then modules={} end modules ['util-deb']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local debug=require "debug" -local getinfo,sethook=debug.getinfo,debug.sethook local type,next,tostring,tonumber=type,next,tostring,tonumber local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub local insert,remove,sort=table.insert,table.remove,table.sort @@ -10700,228 +14121,266 @@ local names={} local initialize=false if not (FFISUPPORTED and ffi) then elseif os.type=="windows" then - initialize=function() - local kernel=ffilib("kernel32","system") - if kernel then - local tonumber=ffi.number or tonumber - ffi.cdef[[ + initialize=function() + local kernel=ffilib("kernel32","system") + if kernel then + local tonumber=ffi.number or tonumber + ffi.cdef[[ int QueryPerformanceFrequency(int64_t *lpFrequency); int QueryPerformanceCounter(int64_t *lpPerformanceCount); ]] - local target=ffi.new("__int64[1]") - ticks=function() - if kernel.QueryPerformanceCounter(target)==1 then - return tonumber(target[0]) - else - return 0 - end - end - local target=ffi.new("__int64[1]") - seconds=function(ticks) - if kernel.QueryPerformanceFrequency(target)==1 then - return ticks/tonumber(target[0]) - else - return 0 - end - end + local target=ffi.new("__int64[1]") + ticks=function() + if kernel.QueryPerformanceCounter(target)==1 then + return tonumber(target[0]) + else + return 0 end - initialize=false + end + local target=ffi.new("__int64[1]") + seconds=function(ticks) + if kernel.QueryPerformanceFrequency(target)==1 then + return ticks/tonumber(target[0]) + else + return 0 + end + end end + initialize=false + end elseif os.type=="unix" then - initialize=function() - local C=ffi.C - local tonumber=ffi.number or tonumber - ffi.cdef [[ + initialize=function() + local C=ffi.C + local tonumber=ffi.number or tonumber + ffi.cdef [[ /* what a mess */ typedef int clk_id_t; typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID } clk_id; typedef struct timespec { long sec; long nsec; } ctx_timespec; int clock_gettime(clk_id_t timerid, struct timespec *t); ]] - local target=ffi.new("ctx_timespec[?]",1) - local clock=C.CLOCK_PROCESS_CPUTIME_ID - ticks=function () - C.clock_gettime(clock,target) - return tonumber(target[0].sec*1000000000+target[0].nsec) - end - seconds=function(ticks) - return ticks/1000000000 - end - initialize=false + local target=ffi.new("ctx_timespec[?]",1) + local clock=C.CLOCK_PROCESS_CPUTIME_ID + ticks=function () + C.clock_gettime(clock,target) + return tonumber(target[0].sec*1000000000+target[0].nsec) + end + seconds=function(ticks) + return ticks/1000000000 end + initialize=false + end end setmetatableindex(names,function(t,name) - local v=setmetatableindex(function(t,source) - local v=setmetatableindex(function(t,line) - local v={ total=0,count=0 } - t[line]=v - return v - end) - t[source]=v - return v + local v=setmetatableindex(function(t,source) + local v=setmetatableindex(function(t,line) + local v={ total=0,count=0,nesting=0 } + t[line]=v + return v end) - t[name]=v + t[source]=v return v + end) + t[name]=v + return v end) +local getinfo=nil +local sethook=nil local function hook(where) - local f=getinfo(2,"nSl") - if f then - local source=f.short_src - if not source then - return - end - local line=f.linedefined or 0 - local name=f.name - if not name then - local what=f.what - if what=="C" then - name="<anonymous>" - else - name=f.namewhat or what or "<unknown>" - end - end - local data=names[name][source][line] - if where=="call" then - data.count=data.count+1 - insert(data,ticks()) - elseif where=="return" then - local t=remove(data) - if t then - data.total=data.total+ticks()-t - end + local f=getinfo(2,"nSl") + if f then + local source=f.short_src + if not source then + return + end + local line=f.linedefined or 0 + local name=f.name + if not name then + local what=f.what + if what=="C" then + name="<anonymous>" + else + name=f.namewhat or what or "<unknown>" + end + end + local data=names[name][source][line] + if where=="call" then + local nesting=data.nesting + if nesting==0 then + data.count=data.count+1 + insert(data,ticks()) + data.nesting=1 + else + data.nesting=nesting+1 + end + elseif where=="return" then + local nesting=data.nesting + if nesting==1 then + local t=remove(data) + if t then + data.total=data.total+ticks()-t end + data.nesting=0 + else + data.nesting=nesting-1 + end end + end end function debugger.showstats(printer,threshold) - local printer=printer or report - local calls=0 - local functions=0 - local dataset={} - local length=0 - local realtime=0 - local totaltime=0 - local threshold=threshold or 0 - for name,sources in next,names do - for source,lines in next,sources do - for line,data in next,lines do - local count=data.count - if count>threshold then - if #name>length then - length=#name - end - local total=data.total - local real=total - if real>0 then - real=total-(count*overhead/dummycalls) - if real<0 then - real=0 - end - realtime=realtime+real - end - totaltime=totaltime+total - if line<0 then - line=0 - end - dataset[#dataset+1]={ real,total,count,name,source,line } - end - end + local printer=printer or report + local calls=0 + local functions=0 + local dataset={} + local length=0 + local realtime=0 + local totaltime=0 + local threshold=threshold or 0 + for name,sources in next,names do + for source,lines in next,sources do + for line,data in next,lines do + local count=data.count + if count>threshold then + if #name>length then + length=#name + end + local total=data.total + local real=total + if real>0 then + real=total-(count*overhead/dummycalls) + if real<0 then + real=0 + end + realtime=realtime+real + end + totaltime=totaltime+total + if line<0 then + line=0 + end + dataset[#dataset+1]={ real,total,count,name,source,line } end + end end - sort(dataset,function(a,b) - if a[1]==b[1] then - if a[2]==b[2] then - if a[3]==b[3] then - if a[4]==b[4] then - if a[5]==b[5] then - return a[6]<b[6] - else - return a[5]<b[5] - end - else - return a[4]<b[4] - end - else - return b[3]<a[3] - end + end + sort(dataset,function(a,b) + if a[1]==b[1] then + if a[2]==b[2] then + if a[3]==b[3] then + if a[4]==b[4] then + if a[5]==b[5] then + return a[6]<b[6] else - return b[2]<a[2] + return a[5]<b[5] end + else + return a[4]<b[4] + end else - return b[1]<a[1] + return b[3]<a[3] end - end) - if length>50 then - length=50 - end - local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] - for i=1,#dataset do - local data=dataset[i] - local real=data[1] - local total=data[2] - local count=data[3] - local name=data[4] - local source=data[5] - local line=data[6] - calls=calls+count - functions=functions+1 - name=gsub(name,"%s+"," ") - if #name>length then - name=sub(name,1,length) - end - printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) - end - printer("") - printer(format("functions : %i",functions)) - printer(format("calls : %i",calls)) - printer(format("overhead : %f",seconds(overhead/1000))) + else + return b[2]<a[2] + end + else + return b[1]<a[1] + end + end) + if length>50 then + length=50 + end + local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] + for i=1,#dataset do + local data=dataset[i] + local real=data[1] + local total=data[2] + local count=data[3] + local name=data[4] + local source=data[5] + local line=data[6] + calls=calls+count + functions=functions+1 + name=gsub(name,"%s+"," ") + if #name>length then + name=sub(name,1,length) + end + printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) + end + printer("") + printer(format("functions : %i",functions)) + printer(format("calls : %i",calls)) + printer(format("overhead : %f",seconds(overhead/1000))) +end +local function getdebug() + if sethook and getinfo then + return + end + if not debug then + local okay + okay,debug=pcall(require,"debug") + end + if type(debug)~="table" then + return + end + getinfo=debug.getinfo + sethook=debug.sethook + if type(getinfo)~="function" then + getinfo=nil + end + if type(sethook)~="function" then + sethook=nil + end end function debugger.savestats(filename,threshold) - local f=io.open(filename,'w') - if f then - debugger.showstats(function(str) f:write(str,"\n") end,threshold) - f:close() - end + local f=io.open(filename,'w') + if f then + debugger.showstats(function(str) f:write(str,"\n") end,threshold) + f:close() + end end function debugger.enable() - if nesting==0 then - running=true - if initialize then - initialize() - end - sethook(hook,"cr") - local function dummy() end - local t=ticks() - for i=1,dummycalls do - dummy() - end - overhead=ticks()-t - end - if nesting>0 then - nesting=nesting+1 - end + getdebug() + if sethook and getinfo and nesting==0 then + running=true + if initialize then + initialize() + end + sethook(hook,"cr") + local function dummy() end + local t=ticks() + for i=1,dummycalls do + dummy() + end + overhead=ticks()-t + end + if nesting>0 then + nesting=nesting+1 + end end function debugger.disable() - if nesting>0 then - nesting=nesting-1 - end - if nesting==0 then - sethook() - end + if nesting>0 then + nesting=nesting-1 + end + if sethook and getinfo and nesting==0 then + sethook() + end end local function showtraceback(rep) + getdebug() + if getinfo then local level=2 local reporter=rep or report while true do - local info=getinfo(level,"Sl") - if not info then - break - elseif info.what=="C" then - reporter("%2i : %s",level-1,"C function") - else - reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) - end - level=level+1 + local info=getinfo(level,"Sl") + if not info then + break + elseif info.what=="C" then + reporter("%2i : %s",level-1,"C function") + else + reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) + end + level=level+1 end + end end debugger.showtraceback=showtraceback @@ -10932,91 +14391,91 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tpl"] = package.loaded["util-tpl"] or true --- original size: 7112, stripped down to: 3988 +-- original size: 7112, stripped down to: 3887 if not modules then modules={} end modules ['util-tpl']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities.templates=utilities.templates or {} local templates=utilities.templates -local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) +local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) local report_template=logs.reporter("template") local tostring,next=tostring,next 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] - if not v then - if trace_template then - report_template("unknown key %a",k) - end - return "" + local v=t[k] + if not v then + if trace_template then + report_template("unknown key %a",k) + end + return "" + else + v=tostring(v) + if trace_template then + report_template("setting key %a to value %a",k,v) + end + if recursive then + return lpegmatch(replacer,v,1,t,how,recursive) else - v=tostring(v) - if trace_template then - report_template("setting key %a to value %a",k,v) - end - if recursive then - return lpegmatch(replacer,v,1,t,how,recursive) - else - return v - end + return v end + end end local sqlescape=lpeg.replacer { - { "'","''" }, - { "\\","\\\\" }, - { "\r\n","\\n" }, - { "\r","\\n" }, + { "'","''" }, + { "\\","\\\\" }, + { "\r\n","\\n" }, + { "\r","\\n" }, } local sqlquoted=Cs(Cc("'")*sqlescape*Cc("'")) lpegpatterns.sqlescape=sqlescape lpegpatterns.sqlquoted=sqlquoted local luaescape=lpegpatterns.luaescape local escapers={ - lua=function(s) - return lpegmatch(luaescape,s) - end, - sql=function(s) - return lpegmatch(sqlescape,s) - end, + lua=function(s) + return lpegmatch(luaescape,s) + end, + sql=function(s) + return lpegmatch(sqlescape,s) + end, } local quotedescapers={ - lua=function(s) - return format("%q",s) - end, - sql=function(s) - return lpegmatch(sqlquoted,s) - end, + lua=function(s) + return format("%q",s) + end, + sql=function(s) + return lpegmatch(sqlquoted,s) + end, } local luaescaper=escapers.lua local quotedluaescaper=quotedescapers.lua local function replacekeyunquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and escapers[how] or luaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and escapers[how] or luaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replacekeyquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and quotedescapers[how] or quotedluaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and quotedescapers[how] or quotedluaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replaceoptional(l,m,r,t,how,recurse) - local v=t[l] - return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" + local v=t[l] + return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" end -local single=P("%") +local single=P("%") local double=P("%%") local lquoted=P("%[") local rquoted=P("]%") @@ -11033,41 +14492,41 @@ local noloptional=P("%?")/'' local noroptional=P("?%")/'' local nomoptional=P(":")/'' local args=Carg(1)*Carg(2)*Carg(3) -local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle -local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq -local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted +local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle +local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq +local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted local optional=noloptional*((C((1-nomoptional)^1)*nomoptional*C((1-noroptional)^1)*args)/replaceoptional)*noroptional local any=P(1) replacer=Cs((unquoted+quoted+escape+optional+key+any)^0) local function replace(str,mapping,how,recurse) - if mapping and str then - return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str - else - return str - end + if mapping and str then + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + else + return str + 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 + 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 - return replace(data,mapping,how,recurse) - else - return data - end + local data=io.loaddata(filename) or "" + if mapping and next(mapping) then + return replace(data,mapping,how,recurse) + else + return data + end end function templates.resolve(t,mapping,how,recurse) - if not mapping then - mapping=t - end - for k,v in next,t do - t[k]=replace(v,mapping,how,recurse) - end - return t + if not mapping then + mapping=t + end + for k,v in next,t do + t[k]=replace(v,mapping,how,recurse) + end + return t end @@ -11077,14 +14536,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sbx"] = package.loaded["util-sbx"] or true --- original size: 20393, stripped down to: 13924 +-- original size: 20393, stripped down to: 13121 if not modules then modules={} end modules ['util-sbx']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not sandbox then require("l-sandbox") end local next,type=next,type @@ -11117,144 +14576,144 @@ local report=logs.reporter("sandbox") trackers.register("sandbox",function(v) trace=v end) sandbox.setreporter(report) sandbox.finalizer { - category="files", - action=function() - finalized=true - end + category="files", + action=function() + finalized=true + end } local function registerroot(root,what) - if finalized then - report("roots are already finalized") - else - if type(root)=="table" then - root,what=root[1],root[2] - end - if type(root)=="string" and root~="" then - root=collapsepath(expandname(root)) - if what=="r" or what=="ro" or what=="readable" then - what="read" - elseif what=="w" or what=="wo" or what=="writable" then - what="write" - end - validroots[root]=what=="write" or false - end + if finalized then + report("roots are already finalized") + else + if type(root)=="table" then + root,what=root[1],root[2] + end + if type(root)=="string" and root~="" then + root=collapsepath(expandname(root)) + if what=="r" or what=="ro" or what=="readable" then + what="read" + elseif what=="w" or what=="wo" or what=="writable" then + what="write" + end + validroots[root]=what=="write" or false end + end end sandbox.finalizer { - category="files", - action=function() + category="files", + action=function() + if p_validroot then + report("roots are already initialized") + else + sandbox.registerroot(".","write") + for name in sortedhash(validroots) do if p_validroot then - report("roots are already initialized") + p_validroot=P(name)+p_validroot else - sandbox.registerroot(".","write") - for name in sortedhash(validroots) do - if p_validroot then - p_validroot=P(name)+p_validroot - else - p_validroot=P(name) - end - end - p_validroot=p_validroot/validroots + p_validroot=P(name) end + end + p_validroot=p_validroot/validroots end + end } local function registerbinary(name) - if finalized then - report("binaries are already finalized") - elseif type(name)=="string" and name~="" then - if not validbinaries then - return - end - if validbinaries==true then - validbinaries={ [name]=true } - else - validbinaries[name]=true - end - elseif name==true then - validbinaries={} + if finalized then + report("binaries are already finalized") + elseif type(name)=="string" and name~="" then + if not validbinaries then + return + end + if validbinaries==true then + validbinaries={ [name]=true } + else + validbinaries[name]=true end + elseif name==true then + validbinaries={} + end end local function registerlibrary(name) - if finalized then - report("libraries are already finalized") - elseif type(name)=="string" and name~="" then - if not validlibraries then - return - end - if validlibraries==true then - validlibraries={ [nameonly(name)]=true } - else - validlibraries[nameonly(name)]=true - end - elseif name==true then - validlibraries={} + if finalized then + report("libraries are already finalized") + elseif type(name)=="string" and name~="" then + if not validlibraries then + return + end + if validlibraries==true then + validlibraries={ [nameonly(name)]=true } + else + validlibraries[nameonly(name)]=true end + elseif name==true then + validlibraries={} + end end local p_write=S("wa") p_write=(1-p_write)^0*p_write -local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path +local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path local function normalized(name) - if platform=="windows" then - name=gsub(name,"/","\\") - end - return name + if platform=="windows" then + name=gsub(name,"/","\\") + end + return name end function sandbox.possiblepath(name) - return lpegmatch(p_path,name) and true or false + return lpegmatch(p_path,name) and true or false end local filenamelogger=false function sandbox.setfilenamelogger(l) - filenamelogger=type(l)=="function" and l or false + filenamelogger=type(l)=="function" and l or false end local function validfilename(name,what) - if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then - local asked=collapsepath(expandname(name)) - local okay=lpegmatch(p_validroot,asked) - if okay==true then - if filenamelogger then - filenamelogger(name,"w",asked,true) - end - return name - elseif okay==false then - if not what then - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - elseif lpegmatch(p_write,what) then - if filenamelogger then - filenamelogger(name,"w",asked,false) - end - return - else - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - end - elseif filenamelogger then - filenamelogger(name,"*",name,false) + if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then + local asked=collapsepath(expandname(name)) + local okay=lpegmatch(p_validroot,asked) + if okay==true then + if filenamelogger then + filenamelogger(name,"w",asked,true) + end + return name + elseif okay==false then + if not what then + if filenamelogger then + filenamelogger(name,"r",asked,true) end - else return name + elseif lpegmatch(p_write,what) then + if filenamelogger then + filenamelogger(name,"w",asked,false) + end + return + else + if filenamelogger then + filenamelogger(name,"r",asked,true) + end + return name + end + elseif filenamelogger then + filenamelogger(name,"*",name,false) end + else + return name + end end local function readable(name,finalized) - return validfilename(name,"r") + return validfilename(name,"r") end local function normalizedreadable(name,finalized) - local valid=validfilename(name,"r") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"r") + if valid then + return normalized(valid) + end end local function writeable(name,finalized) - return validfilename(name,"w") + return validfilename(name,"w") end local function normalizedwriteable(name,finalized) - local valid=validfilename(name,"w") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"w") + if valid then + return normalized(valid) + end end validators.readable=readable validators.writeable=normalizedwriteable @@ -11262,316 +14721,316 @@ validators.normalizedreadable=normalizedreadable validators.normalizedwriteable=writeable validators.filename=readable table.setmetatableindex(validators,function(t,k) - if k then - t[k]=readable - end - return readable + if k then + t[k]=readable + end + return readable end) function validators.string(s,finalized) - if finalized and suspicious(s) then - return "" - else - return s - end + if finalized and suspicious(s) then + return "" + else + return s + end end function validators.cache(s) - if finalized then - return basename(s) - else - return s - end + if finalized then + return basename(s) + else + return s + end end function validators.url(s) - if finalized and find("^file:") then - return "" - else - return s - end + if finalized and find("^file:") then + return "" + else + return s + end end local function filehandlerone(action,one,...) - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - else - end + local checkedone=validfilename(one) + if checkedone then + return action(one,...) + else + end end local function filehandlertwo(action,one,two,...) - local checkedone=validfilename(one) - if checkedone then - local checkedtwo=validfilename(two) - if checkedtwo then - return action(one,two,...) - else - end + local checkedone=validfilename(one) + if checkedone then + local checkedtwo=validfilename(two) + if checkedtwo then + return action(one,two,...) else end + else + end end local function iohandler(action,one,...) - if type(one)=="string" then - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - end - elseif one then - return action(one,...) - else - return action() + if type(one)=="string" then + local checkedone=validfilename(one) + if checkedone then + return action(one,...) end + elseif one then + return action(one,...) + else + return action() + end end local osexecute=sandbox.original(os.execute) local iopopen=sandbox.original(io.popen) local reported={} local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict) - if validbinaries~=false and (validbinaries==true or validbinaries[program]) then - if variables then - for variable,value in next,variables do - local checker=validators[checkers[variable]] - if checker then - value=checker(unquoted(value),strict) - if value then - variables[variable]=optionalquoted(value) - else - report("variable %a with value %a fails the check",variable,value) - return - end - else - report("variable %a has no checker",variable) - return - end - end - for variable,default in next,defaults do - local value=variables[variable] - if not value or value=="" then - local checker=validators[checkers[variable]] - if checker then - default=checker(unquoted(default),strict) - if default then - variables[variable]=optionalquoted(default) - else - report("variable %a with default %a fails the check",variable,default) - return - end - end - end - end - end - local command=program.." "..replace(template,variables) - if reporter then - reporter("executing runner %a: %s",name,command) - elseif trace then - report("executing runner %a: %s",name,command) - end - return command - elseif not reported[name] then - report("executing program %a of runner %a is not permitted",program,name) - reported[name]=true - end -end -local runners={ - resultof=function(...) - local command=validcommand(...) - if command then - if trace then - report("resultof: %s",command) - end - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - end - end - end, - execute=function(...) - local command=validcommand(...) - if command then - if trace then - report("execute: %s",command) - end - return osexecute(command) + if validbinaries~=false and (validbinaries==true or validbinaries[program]) then + if variables then + for variable,value in next,variables do + local checker=validators[checkers[variable]] + if checker then + value=checker(unquoted(value),strict) + if value then + variables[variable]=optionalquoted(value) + else + report("variable %a with value %a fails the check",variable,value) + return + end + else + report("variable %a has no checker",variable) + return end - end, - pipeto=function(...) - local command=validcommand(...) - if command then - if trace then - report("pipeto: %s",command) + end + for variable,default in next,defaults do + local value=variables[variable] + if not value or value=="" then + local checker=validators[checkers[variable]] + if checker then + default=checker(unquoted(default),strict) + if default then + variables[variable]=optionalquoted(default) + else + report("variable %a with default %a fails the check",variable,default) + return end - return iopopen(command,"w") - end - end, -} -function sandbox.registerrunner(specification) - if type(specification)=="string" then - local wrapped=validrunners[specification] - inspect(table.sortedkeys(validrunners)) - if wrapped then - return wrapped - else - report("unknown predefined runner %a",specification) - return + end end + end end - if type(specification)~="table" then - report("specification should be a table (or string)") - return - end - local name=specification.name - if type(name)~="string" then - report("invalid name, string expected",name) - return - end - if validrunners[name] then - report("invalid name, runner %a already defined") - return - end - local program=specification.program - if type(program)=="string" then - elseif type(program)=="table" then - program=program[platform] or program.default or program.unix - end - if type(program)~="string" or program=="" then - report("invalid runner %a specified for platform %a",name,platform) - return + local command=program.." "..replace(template,variables) + if reporter then + reporter("executing runner %a: %s",name,command) + elseif trace then + report("executing runner %a: %s",name,command) end - local template=specification.template - if not template then - report("missing template for runner %a",name) - return + return command + elseif not reported[name] then + report("executing program %a of runner %a is not permitted",program,name) + reported[name]=true + end +end +local runners={ + resultof=function(...) + local command=validcommand(...) + if command then + if trace then + report("resultof: %s",command) + end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + end end - local method=specification.method or "execute" - local checkers=specification.checkers or {} - local defaults=specification.defaults or {} - local runner=runners[method] - if runner then - local finalized=finalized - local wrapped=function(variables) - return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) - end - validrunners[name]=wrapped - return wrapped - else - validrunners[name]=nil - report("invalid method for runner %a",name) + end, + execute=function(...) + local command=validcommand(...) + if command then + if trace then + report("execute: %s",command) + end + return osexecute(command) + end + end, + pipeto=function(...) + local command=validcommand(...) + if command then + if trace then + report("pipeto: %s",command) + end + return iopopen(command,"w") end + end, +} +function sandbox.registerrunner(specification) + if type(specification)=="string" then + local wrapped=validrunners[specification] + inspect(table.sortedkeys(validrunners)) + if wrapped then + return wrapped + else + report("unknown predefined runner %a",specification) + return + end + end + if type(specification)~="table" then + report("specification should be a table (or string)") + return + end + local name=specification.name + if type(name)~="string" then + report("invalid name, string expected",name) + return + end + if validrunners[name] then + report("invalid name, runner %a already defined") + return + end + local program=specification.program + if type(program)=="string" then + elseif type(program)=="table" then + program=program[platform] or program.default or program.unix + end + if type(program)~="string" or program=="" then + report("invalid runner %a specified for platform %a",name,platform) + return + end + local template=specification.template + if not template then + report("missing template for runner %a",name) + return + end + local method=specification.method or "execute" + local checkers=specification.checkers or {} + local defaults=specification.defaults or {} + local runner=runners[method] + if runner then + local finalized=finalized + local wrapped=function(variables) + return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) + end + validrunners[name]=wrapped + return wrapped + else + validrunners[name]=nil + report("invalid method for runner %a",name) + end end function sandbox.getrunner(name) - return name and validrunners[name] + return name and validrunners[name] end local function suspicious(str) - return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false + return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false end local function binaryrunner(action,command,...) - if validbinaries==false then - report("no binaries permitted, ignoring command: %s",command) - return - end - if type(command)~="string" then - report("command should be a string") - return - end - local program=lpegmatch(p_split,command) - if not program or program=="" then - report("unable to filter binary from command: %s",command) - return - end - if validbinaries==true then - elseif not validbinaries[program] then - report("binary not permitted, ignoring command: %s",command) - return - elseif suspicious(command) then - report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) - return - end - return action(command,...) + if validbinaries==false then + report("no binaries permitted, ignoring command: %s",command) + return + end + if type(command)~="string" then + report("command should be a string") + return + end + local program=lpegmatch(p_split,command) + if not program or program=="" then + report("unable to filter binary from command: %s",command) + return + end + if validbinaries==true then + elseif not validbinaries[program] then + report("binary not permitted, ignoring command: %s",command) + return + elseif suspicious(command) then + report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) + return + end + return action(command,...) end local function dummyrunner(action,command,...) - if type(command)=="table" then - command=concat(command," ",command[0] and 0 or 1) - end - report("ignoring command: %s",command) + if type(command)=="table" then + command=concat(command," ",command[0] and 0 or 1) + end + report("ignoring command: %s",command) end sandbox.filehandlerone=filehandlerone sandbox.filehandlertwo=filehandlertwo sandbox.iohandler=iohandler function sandbox.disablerunners() - validbinaries=false + validbinaries=false end function sandbox.disablelibraries() - validlibraries=false + validlibraries=false end if FFISUPPORTED and ffi then - function sandbox.disablelibraries() - validlibraries=false - for k,v in next,ffi do - if k~="gc" then - ffi[k]=nil - end - end + function sandbox.disablelibraries() + validlibraries=false + for k,v in next,ffi do + if k~="gc" then + ffi[k]=nil + end end - local fiiload=ffi.load - if fiiload then - local reported={} - function ffi.load(name,...) - if validlibraries==false then - elseif validlibraries==true then - return fiiload(name,...) - elseif validlibraries[nameonly(name)] then - return fiiload(name,...) - else - end - if not reported[name] then - report("using library %a is not permitted",name) - reported[name]=true - end - return nil - end + end + local fiiload=ffi.load + if fiiload then + local reported={} + function ffi.load(name,...) + if validlibraries==false then + elseif validlibraries==true then + return fiiload(name,...) + elseif validlibraries[nameonly(name)] then + return fiiload(name,...) + else + end + if not reported[name] then + report("using library %a is not permitted",name) + reported[name]=true + end + return nil end + end end local overload=sandbox.overload local register=sandbox.register - overload(loadfile,filehandlerone,"loadfile") + overload(loadfile,filehandlerone,"loadfile") if io then - overload(io.open,filehandlerone,"io.open") - overload(io.popen,binaryrunner,"io.popen") - overload(io.input,iohandler,"io.input") - overload(io.output,iohandler,"io.output") - overload(io.lines,filehandlerone,"io.lines") + overload(io.open,filehandlerone,"io.open") + overload(io.popen,binaryrunner,"io.popen") + overload(io.input,iohandler,"io.input") + overload(io.output,iohandler,"io.output") + overload(io.lines,filehandlerone,"io.lines") end if os then - overload(os.execute,binaryrunner,"os.execute") - overload(os.spawn,dummyrunner,"os.spawn") - overload(os.exec,dummyrunner,"os.exec") - overload(os.resultof,binaryrunner,"os.resultof") - overload(os.pipeto,binaryrunner,"os.pipeto") - overload(os.rename,filehandlertwo,"os.rename") - overload(os.remove,filehandlerone,"os.remove") + overload(os.execute,binaryrunner,"os.execute") + overload(os.spawn,dummyrunner,"os.spawn") + overload(os.exec,dummyrunner,"os.exec") + overload(os.resultof,binaryrunner,"os.resultof") + overload(os.pipeto,binaryrunner,"os.pipeto") + overload(os.rename,filehandlertwo,"os.rename") + overload(os.remove,filehandlerone,"os.remove") end if lfs then - overload(lfs.chdir,filehandlerone,"lfs.chdir") - overload(lfs.mkdir,filehandlerone,"lfs.mkdir") - overload(lfs.rmdir,filehandlerone,"lfs.rmdir") - overload(lfs.isfile,filehandlerone,"lfs.isfile") - overload(lfs.isdir,filehandlerone,"lfs.isdir") - overload(lfs.attributes,filehandlerone,"lfs.attributes") - overload(lfs.dir,filehandlerone,"lfs.dir") - overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") - overload(lfs.touch,filehandlerone,"lfs.touch") - overload(lfs.link,filehandlertwo,"lfs.link") - overload(lfs.setmode,filehandlerone,"lfs.setmode") - overload(lfs.readlink,filehandlerone,"lfs.readlink") - overload(lfs.shortname,filehandlerone,"lfs.shortname") - overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") + overload(lfs.chdir,filehandlerone,"lfs.chdir") + overload(lfs.mkdir,filehandlerone,"lfs.mkdir") + overload(lfs.rmdir,filehandlerone,"lfs.rmdir") + overload(lfs.isfile,filehandlerone,"lfs.isfile") + overload(lfs.isdir,filehandlerone,"lfs.isdir") + overload(lfs.attributes,filehandlerone,"lfs.attributes") + overload(lfs.dir,filehandlerone,"lfs.dir") + overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") + overload(lfs.touch,filehandlerone,"lfs.touch") + overload(lfs.link,filehandlertwo,"lfs.link") + overload(lfs.setmode,filehandlerone,"lfs.setmode") + overload(lfs.readlink,filehandlerone,"lfs.readlink") + overload(lfs.shortname,filehandlerone,"lfs.shortname") + overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") end if zip then - zip.open=register(zip.open,filehandlerone,"zip.open") + zip.open=register(zip.open,filehandlerone,"zip.open") end if fontloader then - fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") - fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") + fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") + fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") end if epdf then - epdf.open=register(epdf.open,filehandlerone,"epdf.open") + epdf.open=register(epdf.open,filehandlerone,"epdf.open") end sandbox.registerroot=registerroot sandbox.registerbinary=registerbinary @@ -11585,14 +15044,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-mrg"] = package.loaded["util-mrg"] or true --- original size: 7757, stripped down to: 6015 +-- original size: 7819, stripped down to: 5881 if not modules then modules={} end modules ['util-mrg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gsub,format=string.gsub,string.format local concat=table.concat @@ -11620,19 +15079,19 @@ local m_report=[[ ]] local m_preloaded=[[package.loaded[%q] = package.loaded[%q] or true]] local function self_fake() - return m_faked + return m_faked end local function self_nothing() - return "" + return "" end local function self_load(name) - local data=io.loaddata(name) or "" - if data=="" then - report("unknown file %a",name) - else - report("inserting file %a",name) - end - return data or "" + local data=io.loaddata(name) or "" + if data=="" then + report("unknown file %a",name) + else + report("inserting file %a",name) + end + return data or "" end local space=patterns.space local eol=patterns.newline @@ -11661,98 +15120,99 @@ local mandatespacing=(eol+space)^1/"" local pack=digit*space^1*operator4*optionalspacing+optionalspacing*operator1*optionalspacing+optionalspacing*operator2*optionalspaces+mandatespacing*operator3*mandatespaces+optionalspaces*separator*optionalspaces local lines=emptyline^2/"\n" local spaces=(space*space)/" " +local spaces=(space*space*space*space)/" " local compact=Cs (( - ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 + ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 )^1 ) local strip=Cs((emptyline^2/"\n"+1)^0) local stripreturn=Cs((1-P("return")*space^1*P(1-space-eol)^1*(space+eol)^0*P(-1))^1) function merger.compact(data) - return lpegmatch(strip,lpegmatch(compact,data)) + return lpegmatch(strip,lpegmatch(compact,data)) end local function self_compact(data) - local delta=0 - if merger.strip_comment then - local before=#data - data=lpegmatch(compact,data) - data=lpegmatch(strip,data) - local after=#data - delta=before-after - report("original size %s, compacted to %s, stripped %s",before,after,delta) - data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) - end - return lpegmatch(stripreturn,data) or data,delta + local delta=0 + if merger.strip_comment then + local before=#data + data=lpegmatch(compact,data) + data=lpegmatch(strip,data) + local after=#data + delta=before-after + report("original size %s, compacted to %s, stripped %s",before,after,delta) + data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) + end + return lpegmatch(stripreturn,data) or data,delta end local function self_save(name,data) - if data~="" then - io.savedata(name,data) - report("saving %s with size %s",name,#data) - end + if data~="" then + io.savedata(name,data) + report("saving %s with size %s",name,#data) + end end local function self_swap(data,code) - return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" + return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" end local function self_libs(libs,list) - local result,f,frozen,foundpath={},nil,false,nil - result[#result+1]="\n" - if type(libs)=='string' then libs={ libs } end - if type(list)=='string' then list={ list } end + local result,f,frozen,foundpath={},nil,false,nil + result[#result+1]="\n" + if type(libs)=='string' then libs={ libs } end + if type(list)=='string' then list={ list } end + for i=1,#libs do + local lib=libs[i] + for j=1,#list do + local pth=gsub(list[j],"\\","/") + report("checking library path %a",pth) + local name=pth.."/"..lib + if lfs.isfile(name) then + foundpath=pth + end + end + if foundpath then break end + end + if foundpath then + report("using library path %a",foundpath) + local right,wrong,original,stripped={},{},0,0 for i=1,#libs do - local lib=libs[i] - for j=1,#list do - local pth=gsub(list[j],"\\","/") - report("checking library path %a",pth) - local name=pth.."/"..lib - if lfs.isfile(name) then - foundpath=pth - end - end - if foundpath then break end - end - if foundpath then - report("using library path %a",foundpath) - local right,wrong,original,stripped={},{},0,0 - for i=1,#libs do - local lib=libs[i] - local fullname=foundpath.."/"..lib - if lfs.isfile(fullname) then - report("using library %a",fullname) - local preloaded=file.nameonly(lib) - local data=io.loaddata(fullname,true) - original=original+#data - local data,delta=self_compact(data) - right[#right+1]=lib - result[#result+1]=m_begin_closure - result[#result+1]=format(m_preloaded,preloaded,preloaded) - result[#result+1]=data - result[#result+1]=m_end_closure - stripped=stripped+delta - else - report("skipping library %a",fullname) - wrong[#wrong+1]=lib - end - end - right=#right>0 and concat(right," ") or "-" - wrong=#wrong>0 and concat(wrong," ") or "-" - report("used libraries: %a",right) - report("skipped libraries: %a",wrong) - report("original bytes: %a",original) - report("stripped bytes: %a",stripped) - result[#result+1]=format(m_report,right,wrong,original,stripped) - else - report("no valid library path found") + local lib=libs[i] + local fullname=foundpath.."/"..lib + if lfs.isfile(fullname) then + report("using library %a",fullname) + local preloaded=file.nameonly(lib) + local data=io.loaddata(fullname,true) + original=original+#data + local data,delta=self_compact(data) + right[#right+1]=lib + result[#result+1]=m_begin_closure + result[#result+1]=format(m_preloaded,preloaded,preloaded) + result[#result+1]=data + result[#result+1]=m_end_closure + stripped=stripped+delta + else + report("skipping library %a",fullname) + wrong[#wrong+1]=lib + end end - return concat(result,"\n\n") + right=#right>0 and concat(right," ") or "-" + wrong=#wrong>0 and concat(wrong," ") or "-" + report("used libraries: %a",right) + report("skipped libraries: %a",wrong) + report("original bytes: %a",original) + report("stripped bytes: %a",stripped) + result[#result+1]=format(m_report,right,wrong,original,stripped) + else + report("no valid library path found") + end + return concat(result,"\n\n") end function merger.selfcreate(libs,list,target) - if target then - self_save(target,self_swap(self_fake(),self_libs(libs,list))) - end + if target then + self_save(target,self_swap(self_fake(),self_libs(libs,list))) + end end function merger.selfmerge(name,libs,list,target) - self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) + self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) end function merger.selfclean(name) - self_save(name,self_swap(self_load(name),self_nothing())) + self_save(name,self_swap(self_load(name),self_nothing())) end @@ -11762,14 +15222,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 9400, stripped down to: 5499 +-- original size: 9738, stripped down to: 5531 if not modules then modules={} end modules ['util-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find @@ -11781,178 +15241,193 @@ local setlocale=os.setlocale setlocale(nil,nil) local report=logs.reporter("system") function os.setlocale(a,b) - if a or b then - if report then - report() - report("You're messing with os.locale in a supposedly locale neutral enviroment. From") - report("now on are on your own and without support. Crashes or unexpected side effects") - report("can happen but don't bother the luatex and context developer team with it.") - report() - report=nil - end - setlocale(a,b) - end + if a or b then + if report then + report() + report("You're messing with os.locale in a supposedly locale neutral enviroment. From") + report("now on are on your own and without support. Crashes or unexpected side effects") + report("can happen but don't bother the luatex and context developer team with it.") + report() + report=nil + end + setlocale(a,b) + end end local validengines=allocate { - ["luatex"]=true, - ["luajittex"]=true, + ["luatex"]=true, + ["luajittex"]=true, } local basicengines=allocate { - ["luatex"]="luatex", - ["texlua"]="luatex", - ["texluac"]="luatex", - ["luajittex"]="luajittex", - ["texluajit"]="luajittex", + ["luatex"]="luatex", + ["texlua"]="luatex", + ["texluac"]="luatex", + ["luajittex"]="luajittex", + ["texluajit"]="luajittex", } local luaengines=allocate { - ["lua"]=true, - ["luajit"]=true, + ["lua"]=true, + ["luajit"]=true, } environment.validengines=validengines environment.basicengines=basicengines if not arg then - environment.used_as_library=true + environment.used_as_library=true elseif luaengines[file.removesuffix(arg[-1])] then elseif validengines[file.removesuffix(arg[0])] then - if arg[1]=="--luaonly" then - arg[-1]=arg[0] - arg[ 0]=arg[2] - for k=3,#arg do - arg[k-2]=arg[k] - end - remove(arg) - remove(arg) - else - end - local originalzero=file.basename(arg[0]) - local specialmapping={ luatools=="base" } - if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then + if arg[1]=="--luaonly" then + arg[-1]=arg[0] + arg[ 0]=arg[2] + for k=3,#arg do + arg[k-2]=arg[k] + end + remove(arg) + remove(arg) + else + end + local originalzero=file.basename(arg[0]) + local specialmapping={ luatools=="base" } + if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then arg[0]=specialmapping[originalzero] or originalzero insert(arg,0,"--script") insert(arg,0,"mtxrun") - end + end end environment.arguments=allocate() environment.files=allocate() environment.sortedflags=nil function environment.initializearguments(arg) - local arguments,files={},{} - environment.arguments,environment.files,environment.sortedflags=arguments,files,nil - for index=1,#arg do - local argument=arg[index] - if index>0 then - local flag,value=match(argument,"^%-+(.-)=(.-)$") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=unquoted(value or "") - else - flag=match(argument,"^%-+(.+)") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=true - else - files[#files+1]=argument - end - end + local arguments={} + local files={} + environment.arguments=arguments + environment.files=files + environment.sortedflags=nil + for index=1,#arg do + local argument=arg[index] + if index>0 then + local flag,value=match(argument,"^%-+(.-)=(.-)$") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=unquoted(value or "") + else + flag=match(argument,"^%-+(.+)") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=true + else + files[#files+1]=argument end + end + end + end + if not environment.ownname then + if os.selfpath and os.selfname then + environment.ownname=file.addsuffix(file.join(os.selfpath,os.selfname),"lua") end - environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') + end + environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') end function environment.setargument(name,value) - environment.arguments[name]=value + environment.arguments[name]=value end function environment.getargument(name,partial) - local arguments,sortedflags=environment.arguments,environment.sortedflags - if arguments[name] then - return arguments[name] - elseif partial then - if not sortedflags then - sortedflags=allocate(table.sortedkeys(arguments)) - for k=1,#sortedflags do - sortedflags[k]="^"..sortedflags[k] - end - environment.sortedflags=sortedflags - end - for k=1,#sortedflags do - local v=sortedflags[k] - if find(name,v) then - return arguments[sub(v,2,#v)] - end - end + local arguments,sortedflags=environment.arguments,environment.sortedflags + if arguments[name] then + return arguments[name] + elseif partial then + if not sortedflags then + sortedflags=allocate(table.sortedkeys(arguments)) + for k=1,#sortedflags do + sortedflags[k]="^"..sortedflags[k] + end + environment.sortedflags=sortedflags end - return nil + for k=1,#sortedflags do + local v=sortedflags[k] + if find(name,v) then + return arguments[sub(v,2,#v)] + end + end + end + return nil end environment.argument=environment.getargument function environment.splitarguments(separator) - local done,before,after=false,{},{} - local originalarguments=environment.originalarguments - for k=1,#originalarguments do - local v=originalarguments[k] - if not done and v==separator then - done=true - elseif done then - after[#after+1]=v - else - before[#before+1]=v - end + local done,before,after=false,{},{} + local originalarguments=environment.originalarguments + for k=1,#originalarguments do + local v=originalarguments[k] + if not done and v==separator then + done=true + elseif done then + after[#after+1]=v + else + before[#before+1]=v end - return before,after + end + return before,after end function environment.reconstructcommandline(arg,noquote) - local resolveprefix=resolvers.resolve - arg=arg or environment.originalarguments - if noquote and #arg==1 then - return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) - elseif #arg>0 then - local result={} - for i=1,#arg do - result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) - end - return concat(result," ") - else - return "" + local resolveprefix=resolvers.resolve + arg=arg or environment.originalarguments + if noquote and #arg==1 then + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) + elseif #arg>0 then + local result={} + for i=1,#arg do + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end + return concat(result," ") + else + return "" + end end function environment.relativepath(path,root) - if not path then - path="" + if not path then + path="" + end + if not file.is_rootbased_path(path) then + if not root then + root=file.pathpart(environment.ownscript or environment.ownname or ".") end - if not file.is_rootbased_path(path) then - if not root then - root=file.pathpart(environment.ownscript or environment.ownname or ".") - end - if root=="" then - root="." - end - path=root.."/"..path + if root=="" then + root="." end - return file.collapsepath(path,true) + path=root.."/"..path + end + return file.collapsepath(path,true) end if arg then - local newarg,instring={},false - for index=1,#arg do - local argument=arg[index] - if find(argument,"^\"") then - newarg[#newarg+1]=gsub(argument,"^\"","") - if not find(argument,"\"$") then - instring=true - end - elseif find(argument,"\"$") then - newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") - instring=false - elseif instring then - newarg[#newarg]=newarg[#newarg].." "..argument - else - newarg[#newarg+1]=argument - end - end - for i=1,-5,-1 do - newarg[i]=arg[i] + local newarg,instring={},false + for index=1,#arg do + local argument=arg[index] + if find(argument,"^\"") then + if find(argument,"\"$") then + newarg[#newarg+1]=gsub(argument,"^\"(.-)\"$","%1") + instring=false + else + newarg[#newarg+1]=gsub(argument,"^\"","") + instring=true + end + elseif find(argument,"\"$") then + if instring then + newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") + instring=false + else + newarg[#newarg+1]=argument + end + elseif instring then + newarg[#newarg]=newarg[#newarg].." "..argument + else + newarg[#newarg+1]=argument end - environment.initializearguments(newarg) - environment.originalarguments=mark(newarg) - environment.rawarguments=mark(arg) - arg={} + end + for i=1,-5,-1 do + newarg[i]=arg[i] + end + environment.initializearguments(newarg) + environment.originalarguments=mark(newarg) + environment.rawarguments=mark(arg) + arg={} end @@ -11962,17 +15437,18 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-env"] = package.loaded["luat-env"] or true --- original size: 5820, stripped down to: 4155 +-- original size: 6134, stripped down to: 4118 if not modules then modules={} end modules ['luat-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local rawset,rawget,loadfile,assert=rawset,rawget,loadfile,assert -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local rawset,rawget,loadfile=rawset,rawget,loadfile +local gsub=string.gsub +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_lua=logs.reporter("resolvers","lua") local luautilities=utilities.lua local luasuffixes=luautilities.suffixes @@ -11980,133 +15456,146 @@ local texgettoks=tex and tex.gettoks environment=environment or {} local environment=environment local mt={ - __index=function(_,k) - if k=="version" then - local version=texgettoks and texgettoks("contextversiontoks") - if version and version~="" then - rawset(environment,"version",version) - return version - else - return "unknown" - end - elseif k=="kind" then - local kind=texgettoks and texgettoks("contextkindtoks") - if kind and kind~="" then - rawset(environment,"kind",kind) - return kind - else - return "unknown" - end - elseif k=="jobname" or k=="formatname" then - local name=tex and tex[k] - if name or name=="" then - rawset(environment,k,name) - return name - else - return "unknown" - end - elseif k=="outputfilename" then - local name=environment.jobname - rawset(environment,k,name) - return name - end + __index=function(_,k) + if k=="version" then + local version=texgettoks and texgettoks("contextversiontoks") + if version and version~="" then + rawset(environment,"version",version) + return version + else + return "unknown" + end + elseif k=="kind" then + local kind=texgettoks and texgettoks("contextkindtoks") + if kind and kind~="" then + rawset(environment,"kind",kind) + return kind + else + return "unknown" + end + elseif k=="jobname" or k=="formatname" then + local name=tex and tex[k] + if name or name=="" then + rawset(environment,k,name) + return name + else + return "unknown" + end + elseif k=="outputfilename" then + local name=environment.jobname + rawset(environment,k,name) + return name end + end } setmetatable(environment,mt) function environment.texfile(filename) - return resolvers.findfile(filename,'tex') + return resolvers.findfile(filename,'tex') end function environment.luafile(filename) - local resolved=resolvers.findfile(filename,'tex') or "" - if resolved~="" then - return resolved - end - resolved=resolvers.findfile(filename,'texmfscripts') or "" - if resolved~="" then - return resolved - end - return resolvers.findfile(filename,'luatexlibs') or "" -end -local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) + local resolved=resolvers.findfile(filename,'tex') or "" + if resolved~="" then + return resolved + end + resolved=resolvers.findfile(filename,'texmfscripts') or "" + if resolved~="" then + return resolved + end + return resolvers.findfile(filename,'luatexlibs') or "" +end +local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) local function strippable(filename) - if stripindeed then - local modu=modules[file.nameonly(filename)] - return modu and modu.dataonly - else - return false - end + if stripindeed then + local modu=modules[file.nameonly(filename)] + return modu and modu.dataonly + else + return false + end end function environment.luafilechunk(filename,silent,macros) - filename=file.replacesuffix(filename,"lua") - local fullname=environment.luafile(filename) - if fullname and fullname~="" then - local data=luautilities.loadedluacode(fullname,strippable,filename,macros) - if not silent then - report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") - end - return data - else - if not silent then - report_lua("unknown file %a",filename) - end - return nil + filename=file.replacesuffix(filename,"lua") + local fullname=environment.luafile(filename) + if fullname and fullname~="" then + local data=luautilities.loadedluacode(fullname,strippable,filename,macros) + if not silent then + report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") + end + return data + else + if not silent then + report_lua("unknown file %a",filename) end + return nil + end end function environment.loadluafile(filename,version) - local lucname,luaname,chunk - local basename=file.removesuffix(filename) - if basename==filename then - luaname=file.addsuffix(basename,luasuffixes.lua) - lucname=file.addsuffix(basename,luasuffixes.luc) - else - luaname=basename - lucname=nil - end - local fullname=(lucname and environment.luafile(lucname)) or "" - if fullname~="" then + local lucname,luaname,chunk + local basename=file.removesuffix(filename) + if basename==filename then + luaname=file.addsuffix(basename,luasuffixes.lua) + lucname=file.addsuffix(basename,luasuffixes.luc) + else + luaname=filename + lucname=nil + end + local fullname=(lucname and environment.luafile(lucname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) + end + chunk=loadfile(fullname) + end + if chunk then + chunk() + if version then + local v=version + if modules and modules[filename] then + v=modules[filename].version + elseif versions and versions[filename] then + v=versions[filename] + end + if v==version then + return true + else if trace_locating then - report_lua("loading %a",fullname) + report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) end - chunk=loadfile(fullname) + environment.loadluafile(filename) + end + else + return true end - if chunk then - assert(chunk)() - if version then - local v=version - if modules and modules[filename] then - v=modules[filename].version - elseif versions and versions[filename] then - v=versions[filename] - end - if v==version then - return true - else - if trace_locating then - report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) - end - environment.loadluafile(filename) - end - else - return true - end + end + fullname=(luaname and environment.luafile(luaname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) end - fullname=(luaname and environment.luafile(luaname)) or "" - if fullname~="" then - if trace_locating then - report_lua("loading %a",fullname) - end - chunk=loadfile(fullname) - if not chunk then - if trace_locating then - report_lua("unknown file %a",filename) - end - else - assert(chunk)() - return true - end + chunk=loadfile(fullname) + if not chunk then + if trace_locating then + report_lua("unknown file %a",filename) + end + else + chunk() + return true end - return false + end + return false end +environment.filenames=setmetatable({},{ + __index=function(t,k) + local v=environment.files[k] + if v then + return (gsub(v,"%.+$","")) + end + end, + __newindex=function(t,k) + end, + __len=function(t) + return #environment.files + end, +} ) end -- of closure @@ -12115,16 +15604,16 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true --- original size: 60383, stripped down to: 38562 +-- original size: 60383, stripped down to: 35698 if not modules then modules={} end modules ['lxml-tab']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_entities=false trackers.register("xml.entities",function(v) trace_entities=v end) +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 {} @@ -12142,17 +15631,17 @@ xml.xmlns=xml.xmlns or {} local check=P(false) local parse=check function xml.registerns(namespace,pattern) - check=check+C(P(lower(pattern)))/namespace - parse=P { P(check)+1*V(1) } + check=check+C(P(lower(pattern)))/namespace + parse=P { P(check)+1*V(1) } end function xml.checkns(namespace,url) - local ns=lpegmatch(parse,lower(url)) - if ns and namespace~=ns then - xml.xmlns[namespace]=ns - end + local ns=lpegmatch(parse,lower(url)) + if ns and namespace~=ns then + xml.xmlns[namespace]=ns + end end function xml.resolvens(url) - return lpegmatch(parse,lower(url)) or "" + return lpegmatch(parse,lower(url)) or "" end end local nsremap,resolvens=xml.xmlns,xml.resolvens @@ -12170,661 +15659,661 @@ local handle_dec_entity local handle_any_entity_dtd local handle_any_entity_text local function preparexmlstate(settings) - if settings then - linenumbers=settings.linenumbers - stack={} - level=0 - top={} - at={} - mt={} - dt={} - nt=0 - xmlns={} - errorstr=nil - strip=settings.strip_cm_and_dt - utfize=settings.utfize_entities - resolve=settings.resolve_entities - resolve_predefined=settings.resolve_predefined_entities - unify_predefined=settings.unify_predefined_entities - cleanup=settings.text_cleanup - entities=settings.entities or {} - currentfilename=settings.currentresource - currentline=1 - parameters={} - reported_at_errors={} - dcache={} - hcache={} - acache={} - if utfize==nil then - settings.utfize_entities=true - utfize=true - end - if resolve_predefined==nil then - settings.resolve_predefined_entities=true - resolve_predefined=true - end - else - linenumbers=false - stack=nil - level=nil - top=nil - at=nil - mt=nil - dt=nil - nt=nil - xmlns=nil - errorstr=nil - strip=nil - utfize=nil - resolve=nil - resolve_predefined=nil - unify_predefined=nil - cleanup=nil - entities=nil - parameters=nil - reported_at_errors=nil - dcache=nil - hcache=nil - acache=nil - currentfilename=nil - currentline=1 - end + if settings then + linenumbers=settings.linenumbers + stack={} + level=0 + top={} + at={} + mt={} + dt={} + nt=0 + xmlns={} + errorstr=nil + strip=settings.strip_cm_and_dt + utfize=settings.utfize_entities + resolve=settings.resolve_entities + resolve_predefined=settings.resolve_predefined_entities + unify_predefined=settings.unify_predefined_entities + cleanup=settings.text_cleanup + entities=settings.entities or {} + currentfilename=settings.currentresource + currentline=1 + parameters={} + reported_at_errors={} + dcache={} + hcache={} + acache={} + if utfize==nil then + settings.utfize_entities=true + utfize=true + end + if resolve_predefined==nil then + settings.resolve_predefined_entities=true + resolve_predefined=true + end + else + linenumbers=false + stack=nil + level=nil + top=nil + at=nil + mt=nil + dt=nil + nt=nil + xmlns=nil + errorstr=nil + strip=nil + utfize=nil + resolve=nil + resolve_predefined=nil + unify_predefined=nil + cleanup=nil + entities=nil + parameters=nil + reported_at_errors=nil + dcache=nil + hcache=nil + acache=nil + currentfilename=nil + currentline=1 + end end local function initialize_mt(root) - mt={ __index=root } + mt={ __index=root } end function xml.setproperty(root,k,v) - getmetatable(root).__index[k]=v + getmetatable(root).__index[k]=v end function xml.checkerror(top,toclose) - return "" + return "" end local checkns=xml.checkns local function add_attribute(namespace,tag,value) - if cleanup and value~="" then - value=cleanup(value) - end - if tag=="xmlns" then - xmlns[#xmlns+1]=resolvens(value) - at[tag]=value - elseif namespace=="" then - at[tag]=value - elseif namespace=="xmlns" then - checkns(tag,value) - at["xmlns:"..tag]=value - else - at[namespace..":"..tag]=value - end + if cleanup and value~="" then + value=cleanup(value) + end + if tag=="xmlns" then + xmlns[#xmlns+1]=resolvens(value) + at[tag]=value + elseif namespace=="" then + at[tag]=value + elseif namespace=="xmlns" then + checkns(tag,value) + at["xmlns:"..tag]=value + else + at[namespace..":"..tag]=value + end end local function add_empty(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - top=stack[level] - dt=top.dt - nt=#dt+1 - local t=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - cf=currentfilename, - cl=currentline, - __p__=top, - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - __p__=top, - } - dt[nt]=t - setmetatable(t,mt) - if at.xmlns then - remove(xmlns) - end - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + top=stack[level] + dt=top.dt + nt=#dt+1 + local t=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + cf=currentfilename, + cl=currentline, + __p__=top, + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + __p__=top, + } + dt[nt]=t + setmetatable(t,mt) + if at.xmlns then + remove(xmlns) + end + at={} end local function add_begin(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - dt={} - top=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - cf=currentfilename, - cl=currentline, - __p__=stack[level], - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - __p__=stack[level], - } - setmetatable(top,mt) - nt=0 - level=level+1 - stack[level]=top - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + dt={} + top=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + cf=currentfilename, + cl=currentline, + __p__=stack[level], + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + __p__=stack[level], + } + setmetatable(top,mt) + nt=0 + level=level+1 + stack[level]=top + at={} end local function add_end(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local toclose=stack[level] - level=level-1 - top=stack[level] - if level<1 then - errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - elseif toclose.tg~=tag then - errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - end - dt=top.dt - nt=#dt+1 - dt[nt]=toclose - toclose.ni=nt - if toclose.at.xmlns then - remove(xmlns) - end + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local toclose=stack[level] + level=level-1 + top=stack[level] + if level<1 then + errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + elseif toclose.tg~=tag then + errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + end + dt=top.dt + nt=#dt+1 + dt[nt]=toclose + toclose.ni=nt + if toclose.at.xmlns then + remove(xmlns) + end end local function add_text(text) - if text=="" then - return - end - if cleanup then - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..cleanup(text) - else - nt=nt+1 - dt[nt]=cleanup(text) - end - else - nt=1 - dt[1]=cleanup(text) - end + if text=="" then + return + end + if cleanup then + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..cleanup(text) + else + nt=nt+1 + dt[nt]=cleanup(text) + end else - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..text - else - nt=nt+1 - dt[nt]=text - end - else - nt=1 - dt[1]=text - end + nt=1 + dt[1]=cleanup(text) end -end -local function add_special(what,spacing,text) - if spacing~="" then + else + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..text + else nt=nt+1 - dt[nt]=spacing - end - if strip and (what=="@cm@" or what=="@dt@") then + dt[nt]=text + end else - nt=nt+1 - dt[nt]=linenumbers and { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - cf=currentfilename, - cl=currentline, - } or { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - } + nt=1 + dt[1]=text end + end +end +local function add_special(what,spacing,text) + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + if strip and (what=="@cm@" or what=="@dt@") then + else + nt=nt+1 + dt[nt]=linenumbers and { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + cf=currentfilename, + cl=currentline, + } or { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + } + end end local function set_message(txt) - errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") + errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") end local function attribute_value_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute value %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute value %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end local function attribute_specification_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute specification %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute specification %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end do - local badentity="&" - xml.placeholders={ - unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, - unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, - unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, - } - local function fromhex(s) - local n=tonumber(s,16) - if n then - return utfchar(n) - else - return formatters["h:%s"](s),true + local badentity="&" + xml.placeholders={ + unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, + unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, + unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, + } + local function fromhex(s) + local n=tonumber(s,16) + if n then + return utfchar(n) + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return utfchar(n) + else + return formatters["d:%s"](s),true + end + end + local p_rest=(1-P(";"))^0 + local p_many=P(1)^0 + local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) + xml.parsedentitylpeg=parsedentity + local predefined_unified={ + [38]="&", + [42]=""", + [47]="'", + [74]="<", + [76]=">", + } + local predefined_simplified={ + [38]="&",amp="&", + [42]='"',quot='"', + [47]="'",apos="'", + [74]="<",lt="<", + [76]=">",gt=">", + } + local nofprivates=0xF0000 + local privates_u={ + [ [[&]] ]="&", + [ [["]] ]=""", + [ [[']] ]="'", + [ [[<]] ]="<", + [ [[>]] ]=">", + } + local privates_p={ + } + local privates_s={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[&]] ]="&U+26;", + [ [[']] ]="&U+27;", + [ [[<]] ]="&U+3C;", + [ [[>]] ]="&U+3E;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_x={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[']] ]="&U+27;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_n={ + } + local escaped=utf.remapper(privates_u,"dynamic") + local unprivatized=utf.remapper(privates_p,"dynamic") + local unspecialized=utf.remapper(privates_s,"dynamic") + local despecialized=utf.remapper(privates_x,"dynamic") + xml.unprivatized=unprivatized + xml.unspecialized=unspecialized + xml.despecialized=despecialized + xml.escaped=escaped + local function unescaped(s) + local p=privates_n[s] + if not p then + nofprivates=nofprivates+1 + p=utfchar(nofprivates) + privates_n[s]=p + s="&"..s..";" + privates_u[p]=s + privates_p[p]=s + privates_s[p]=s + end + return p + end + xml.privatetoken=unescaped + xml.privatecodes=privates_n + xml.specialcodes=privates_s + function xml.addspecialcode(key,value) + privates_s[key]=value or "&"..s..";" + end + handle_hex_entity=function(str) + local h=hcache[str] + if not h then + local n=tonumber(str,16) + h=unify_predefined and predefined_unified[n] + if h then + if trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + elseif utfize then + h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" + if not n then + report_xml("utfize, ignoring hex entity &#x%s;",str) + elseif trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + else + if trace_entities then + report_xml("found entity &#x%s;",str) end + h="&#x"..str..";" + end + hcache[str]=h end - local function fromdec(s) - local n=tonumber(s) - if n then - return utfchar(n) - else - return formatters["d:%s"](s),true - end - end - local p_rest=(1-P(";"))^0 - local p_many=P(1)^0 - local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) - xml.parsedentitylpeg=parsedentity - local predefined_unified={ - [38]="&", - [42]=""", - [47]="'", - [74]="<", - [76]=">", - } - local predefined_simplified={ - [38]="&",amp="&", - [42]='"',quot='"', - [47]="'",apos="'", - [74]="<",lt="<", - [76]=">",gt=">", - } - local nofprivates=0xF0000 - local privates_u={ - [ [[&]] ]="&", - [ [["]] ]=""", - [ [[']] ]="'", - [ [[<]] ]="<", - [ [[>]] ]=">", - } - local privates_p={ - } - local privates_s={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[&]] ]="&U+26;", - [ [[']] ]="&U+27;", - [ [[<]] ]="&U+3C;", - [ [[>]] ]="&U+3E;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_x={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[']] ]="&U+27;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_n={ - } - local escaped=utf.remapper(privates_u,"dynamic") - local unprivatized=utf.remapper(privates_p,"dynamic") - local unspecialized=utf.remapper(privates_s,"dynamic") - local despecialized=utf.remapper(privates_x,"dynamic") - xml.unprivatized=unprivatized - xml.unspecialized=unspecialized - xml.despecialized=despecialized - xml.escaped=escaped - local function unescaped(s) - local p=privates_n[s] - if not p then - nofprivates=nofprivates+1 - p=utfchar(nofprivates) - privates_n[s]=p - s="&"..s..";" - privates_u[p]=s - privates_p[p]=s - privates_s[p]=s - end - return p - end - xml.privatetoken=unescaped - xml.privatecodes=privates_n - xml.specialcodes=privates_s - function xml.addspecialcode(key,value) - privates_s[key]=value or "&"..s..";" - end - handle_hex_entity=function(str) - local h=hcache[str] - if not h then - local n=tonumber(str,16) - h=unify_predefined and predefined_unified[n] - if h then - if trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - elseif utfize then - h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" - if not n then - report_xml("utfize, ignoring hex entity &#x%s;",str) - elseif trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - else - if trace_entities then - report_xml("found entity &#x%s;",str) - end - h="&#x"..str..";" - end - hcache[str]=h - end - return h - end - handle_dec_entity=function(str) - local d=dcache[str] - if not d then - local n=tonumber(str) - d=unify_predefined and predefined_unified[n] - if d then - if trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - elseif utfize then - d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" - if not n then - report_xml("utfize, ignoring dec entity &#%s;",str) - elseif trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - else - if trace_entities then - report_xml("found entity &#%s;",str) - end - d="&#"..str..";" - end - dcache[str]=d + return h + end + handle_dec_entity=function(str) + local d=dcache[str] + if not d then + local n=tonumber(str) + d=unify_predefined and predefined_unified[n] + if d then + if trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + elseif utfize then + d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" + if not n then + report_xml("utfize, ignoring dec entity &#%s;",str) + elseif trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + else + if trace_entities then + report_xml("found entity &#%s;",str) end - return d + d="&#"..str..";" + end + dcache[str]=d end - handle_any_entity_dtd=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end - end - return a + return d + end + handle_any_entity_dtd=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end - end - return a + a=entities[str] end - end - handle_any_entity_text=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(grammar_parsed_text_two,a) or a - if type(a)=="number" then - return "" - else - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - end - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) end - return a + a=a(str) or "" + end + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) end - return a - end - end - local p_rest=(1-P(";"))^1 - local spec={ - [0x23]="\\Ux{23}", - [0x24]="\\Ux{24}", - [0x25]="\\Ux{25}", - [0x5C]="\\Ux{5C}", - [0x7B]="\\Ux{7B}", - [0x7C]="\\Ux{7C}", - [0x7D]="\\Ux{7D}", - [0x7E]="\\Ux{7E}", - } - local hash=table.setmetatableindex(spec,function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] - else - return formatters["u:%s"](s),true + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end - end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] + end + return a + end + end + handle_any_entity_text=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - return formatters["d:%s"](s),true + a=entities[str] end - end - local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - local hash=table.setmetatableindex(function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) + end + a=a(str) or "" + end + a=lpegmatch(grammar_parsed_text_two,a) or a + if type(a)=="number" then + return "" + else + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end + end + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - return formatters["u:%s"](s),true + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) + end + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end + end + return a + end + end + local p_rest=(1-P(";"))^1 + local spec={ + [0x23]="\\Ux{23}", + [0x24]="\\Ux{24}", + [0x25]="\\Ux{25}", + [0x5C]="\\Ux{5C}", + [0x7B]="\\Ux{7B}", + [0x7C]="\\Ux{7C}", + [0x7D]="\\Ux{7D}", + [0x7E]="\\Ux{7E}", + } + local hash=table.setmetatableindex(spec,function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] - else - return formatters["d:%s"](s),true - end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true end - local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - xml.reparsedentitylpeg=reparsedentity - xml.unescapedentitylpeg=unescapedentity + end + local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + local hash=table.setmetatableindex(function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true + end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true + end + end + local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + xml.reparsedentitylpeg=reparsedentity + xml.unescapedentitylpeg=unescapedentity end local escaped=xml.escaped local unescaped=xml.unescaped local placeholders=xml.placeholders local function handle_end_entity(str) - report_xml("error in entity, %a found without ending %a",str,";") - return str + report_xml("error in entity, %a found without ending %a",str,";") + return str end local function handle_crap_error(chr) - report_xml("error in parsing, unexpected %a found ",chr) - add_text(chr) - return chr + report_xml("error in parsing, unexpected %a found ",chr) + add_text(chr) + return chr end local function handlenewline() - currentline=currentline+1 + currentline=currentline+1 end local spacetab=S(' \t') local space=S(' \r\n\t') @@ -12849,141 +16338,141 @@ local space_nl=spacetab+newline local spacing_nl=Cs((space_nl)^0) local anything_nl=newline+P(1) local function weirdentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","weird",k,v) - end - parameters[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","weird",k,v) + end + parameters[k]=v end local function normalentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","normal",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","normal",k,v) + end + entities[k]=v end local function systementity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","system",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","system",k,v) + end + entities[k]=v end local function publicentity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","public",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","public",k,v) + end + entities[k]=v end local function entityfile(pattern,k,v,n) - if n then - local okay,data - if resolvers then - okay,data=resolvers.loadbinfile(n) - else - data=io.loaddata(n) - okay=data and data~="" - end - if okay then - if trace_entities then - report_xml("loading public entities %a as %a from %a",k,v,n) - end - lpegmatch(pattern,data) - return - end + if n then + local okay,data + if resolvers then + okay,data=resolvers.loadbinfile(n) + else + data=io.loaddata(n) + okay=data and data~="" end - report_xml("ignoring public entities %a as %a from %a",k,v,n) + if okay then + if trace_entities then + report_xml("loading public entities %a as %a from %a",k,v,n) + end + lpegmatch(pattern,data) + return + end + end + report_xml("ignoring public entities %a as %a from %a",k,v,n) end local function install(spacenewline,spacing,anything) - local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 - local hexentitycontent=R("AF","af","09")^1 - local decentitycontent=R("09")^1 - local parsedentity=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_dtd) - local parsedentity_text=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_text) - local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local text_unparsed=Cs((anything-open)^1) - local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 - local somespace=(spacenewline)^1 - local optionalspace=(spacenewline)^0 - local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) - local endofattributes=slash*close+close - local whatever=space*name*optionalspace*equal - local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error - local attributevalue=value+wrongvalue - local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute - local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 - local parsedtext=text_parsed - local unparsedtext=text_unparsed/add_text - local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } - local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty - local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin - local endelement=(spacing*open*slash*name*optionalspace*close)/add_end - local begincomment=open*P("!--") - local endcomment=P("--")*close - local begininstruction=open*P("?") - local endinstruction=P("?")*close - local begincdata=open*P("![CDATA[") - local endcdata=P("]]")*close - local someinstruction=C((anything-endinstruction)^0) - local somecomment=C((anything-endcomment )^0) - local somecdata=C((anything-endcdata )^0) - local begindoctype=open*P("!DOCTYPE") - local enddoctype=close - local beginset=P("[") - local endset=P("]") - local wrdtypename=C((anything-somespace-P(";"))^1) - local doctypename=C((anything-somespace-close)^0) - local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close - local basiccomment=begincomment*((anything-endcomment)^0)*endcomment - local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity - local normalentitytype=(doctypename*somespace*value)/normalentity - local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity - local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity - local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close - local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) - entityfile(entitydoctype,...) - end - local function weirdresolve(s) - lpegmatch(entitydoctype,parameters[s]) - end - local function normalresolve(s) - lpegmatch(entitydoctype,entities[s]) - end - local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") - entitydoctype=entitydoctype+entityresolve - local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset - local definitiondoctype=doctypename*somespace*doctypeset - local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset - local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset - local simpledoctype=(anything-close)^1 - local somedoctype=C((somespace*( + local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 + local hexentitycontent=R("AF","af","09")^1 + local decentitycontent=R("09")^1 + local parsedentity=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_dtd) + local parsedentity_text=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_text) + local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local text_unparsed=Cs((anything-open)^1) + local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 + local somespace=(spacenewline)^1 + local optionalspace=(spacenewline)^0 + local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) + local endofattributes=slash*close+close + local whatever=space*name*optionalspace*equal + local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error + local attributevalue=value+wrongvalue + local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute + local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 + local parsedtext=text_parsed + local unparsedtext=text_unparsed/add_text + local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } + local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty + local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin + local endelement=(spacing*open*slash*name*optionalspace*close)/add_end + local begincomment=open*P("!--") + local endcomment=P("--")*close + local begininstruction=open*P("?") + local endinstruction=P("?")*close + local begincdata=open*P("![CDATA[") + local endcdata=P("]]")*close + local someinstruction=C((anything-endinstruction)^0) + local somecomment=C((anything-endcomment )^0) + local somecdata=C((anything-endcdata )^0) + local begindoctype=open*P("!DOCTYPE") + local enddoctype=close + local beginset=P("[") + local endset=P("]") + local wrdtypename=C((anything-somespace-P(";"))^1) + local doctypename=C((anything-somespace-close)^0) + local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close + local basiccomment=begincomment*((anything-endcomment)^0)*endcomment + local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity + local normalentitytype=(doctypename*somespace*value)/normalentity + local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity + local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity + local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close + local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) + entityfile(entitydoctype,...) + end + local function weirdresolve(s) + lpegmatch(entitydoctype,parameters[s]) + end + local function normalresolve(s) + lpegmatch(entitydoctype,entities[s]) + end + local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") + entitydoctype=entitydoctype+entityresolve + local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset + local definitiondoctype=doctypename*somespace*doctypeset + local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset + local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset + local simpledoctype=(anything-close)^1 + local somedoctype=C((somespace*( publicentityfile+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 - local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end - local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand - local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error - local trailer=space^0*(text_unparsed/set_message)^0 - local grammar_parsed_text_one=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, - } - local grammar_parsed_text_two=P { "followup", - followup=V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, - } - local grammar_unparsed_text=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, - } - return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text + 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 + local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end + local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand + local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error + local trailer=space^0*(text_unparsed/set_message)^0 + local grammar_parsed_text_one=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, + } + local grammar_parsed_text_two=P { "followup", + followup=V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, + } + local grammar_unparsed_text=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, + } + return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text end grammar_parsed_text_one_nop, grammar_parsed_text_two_nop, @@ -12992,576 +16481,576 @@ grammar_parsed_text_one_yes, grammar_parsed_text_two_yes, grammar_unparsed_text_yes=install(space_nl,spacing_nl,anything_nl) local function _xmlconvert_(data,settings,detail) - settings=settings or {} - preparexmlstate(settings) - if settings.linenumbers then - grammar_parsed_text_one=grammar_parsed_text_one_yes - grammar_parsed_text_two=grammar_parsed_text_two_yes - grammar_unparsed_text=grammar_unparsed_text_yes - else - grammar_parsed_text_one=grammar_parsed_text_one_nop - grammar_parsed_text_two=grammar_parsed_text_two_nop - grammar_unparsed_text=grammar_unparsed_text_nop - end - local preprocessor=settings.preprocessor - if data and data~="" and type(preprocessor)=="function" then - data=preprocessor(data,settings) or data + settings=settings or {} + preparexmlstate(settings) + if settings.linenumbers then + grammar_parsed_text_one=grammar_parsed_text_one_yes + grammar_parsed_text_two=grammar_parsed_text_two_yes + grammar_unparsed_text=grammar_unparsed_text_yes + else + grammar_parsed_text_one=grammar_parsed_text_one_nop + grammar_parsed_text_two=grammar_parsed_text_two_nop + grammar_unparsed_text=grammar_unparsed_text_nop + end + local preprocessor=settings.preprocessor + if data and data~="" and type(preprocessor)=="function" then + data=preprocessor(data,settings) or data + end + if settings.parent_root then + mt=getmetatable(settings.parent_root) + else + initialize_mt(top) + end + level=level+1 + stack[level]=top + top.dt={} + dt=top.dt + nt=0 + if not data or data=="" then + errorstr="empty xml file" + elseif data==true then + errorstr=detail or "problematic xml file" + elseif utfize or resolve then + local m=lpegmatch(grammar_parsed_text_one,data) + if m then + m=lpegmatch(grammar_parsed_text_two,data,m) end - if settings.parent_root then - mt=getmetatable(settings.parent_root) - else - initialize_mt(top) - end - level=level+1 - stack[level]=top - top.dt={} - dt=top.dt - nt=0 - if not data or data=="" then - errorstr="empty xml file" - elseif data==true then - errorstr=detail or "problematic xml file" - elseif utfize or resolve then - local m=lpegmatch(grammar_parsed_text_one,data) - if m then - m=lpegmatch(grammar_parsed_text_two,data,m) - end - if m then - else - errorstr="invalid xml file - parsed text" - end - elseif type(data)=="string" then - if lpegmatch(grammar_unparsed_text,data) then - errorstr="" - else - errorstr="invalid xml file - unparsed text" - end + if m then else - errorstr="invalid xml file - no text at all" - end - local result - if errorstr and errorstr~="" then - result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } - setmetatable(result,mt) - setmetatable(result.dt[1],mt) - setmetatable(stack,mt) - local errorhandler=settings.error_handler - if errorhandler==false then + errorstr="invalid xml file - parsed text" + end + elseif type(data)=="string" then + if lpegmatch(grammar_unparsed_text,data) then + errorstr="" + else + errorstr="invalid xml file - unparsed text" + end + else + errorstr="invalid xml file - no text at all" + end + local result + if errorstr and errorstr~="" then + result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } + setmetatable(result,mt) + setmetatable(result.dt[1],mt) + setmetatable(stack,mt) + local errorhandler=settings.error_handler + if errorhandler==false then + else + errorhandler=errorhandler or xml.errorhandler + if errorhandler then + local currentresource=settings.currentresource + if currentresource and currentresource~="" then + xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) else - errorhandler=errorhandler or xml.errorhandler - if errorhandler then - local currentresource=settings.currentresource - if currentresource and currentresource~="" then - xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) - else - xml.errorhandler(formatters["load error: %s"](errorstr)) - end - end - end - else - result=stack[1] - end - if not settings.no_root then - result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } - setmetatable(result,mt) - local rdt=result.dt - for k=1,#rdt do - local v=rdt[k] - if type(v)=="table" and not v.special then - result.ri=k - v.__p__=result - break - end + xml.errorhandler(formatters["load error: %s"](errorstr)) end + end end - if errorstr and errorstr~="" then - result.error=true - else - errorstr=nil - end - result.statistics={ - errormessage=errorstr, - entities={ - decimals=dcache, - hexadecimals=hcache, - names=acache, - intermediates=parameters, - } + else + result=stack[1] + end + if not settings.no_root then + result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } + setmetatable(result,mt) + local rdt=result.dt + for k=1,#rdt do + local v=rdt[k] + if type(v)=="table" and not v.special then + result.ri=k + v.__p__=result + break + end + end + end + if errorstr and errorstr~="" then + result.error=true + else + errorstr=nil + end + result.statistics={ + errormessage=errorstr, + entities={ + decimals=dcache, + hexadecimals=hcache, + names=acache, + intermediates=parameters, } - preparexmlstate() - return result + } + preparexmlstate() + return result end local function xmlconvert(data,settings) - local ok,result=pcall(function() return _xmlconvert_(data,settings) end) - if ok then - return result - elseif type(result)=="string" then - return _xmlconvert_(true,settings,result) - else - return _xmlconvert_(true,settings) - end + local ok,result=pcall(function() return _xmlconvert_(data,settings) end) + if ok then + return result + elseif type(result)=="string" then + return _xmlconvert_(true,settings,result) + else + return _xmlconvert_(true,settings) + end end xml.convert=xmlconvert function xml.inheritedconvert(data,xmldata) - local settings=xmldata.settings - if settings then - settings.parent_root=xmldata - end - local xc=xmlconvert(data,settings) - return xc + local settings=xmldata.settings + if settings then + settings.parent_root=xmldata + end + local xc=xmlconvert(data,settings) + return xc end function xml.is_valid(root) - return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er + return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er end function xml.package(tag,attributes,data) - local ns,tg=match(tag,"^(.-):?([^:]+)$") - local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } - setmetatable(t,mt) - return t + local ns,tg=match(tag,"^(.-):?([^:]+)$") + local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } + setmetatable(t,mt) + return t end function xml.is_valid(root) - return root and not root.error + return root and not root.error end xml.errorhandler=report_xml function xml.load(filename,settings) - local data="" - if type(filename)=="string" then - local f=io.open(filename,'r') - if f then - data=f:read("*all") - f:close() - end - elseif filename then - data=filename:read("*all") - end - if settings then - settings.currentresource=filename - local result=xmlconvert(data,settings) - settings.currentresource=nil - return result - else - return xmlconvert(data,{ currentresource=filename }) - end + local data="" + if type(filename)=="string" then + local f=io.open(filename,'r') + if f then + data=f:read("*all") + f:close() + end + elseif filename then + data=filename:read("*all") + end + if settings then + settings.currentresource=filename + local result=xmlconvert(data,settings) + settings.currentresource=nil + return result + else + return xmlconvert(data,{ currentresource=filename }) + end end local no_root={ no_root=true } function xml.toxml(data) - if type(data)=="string" then - local root={ xmlconvert(data,no_root) } - return (#root>1 and root) or root[1] - else - return data - end + if type(data)=="string" then + local root={ xmlconvert(data,no_root) } + return (#root>1 and root) or root[1] + else + return data + end end local function copy(old,p) - if old then - local new={} - for k,v in next,old do - local t=type(v)=="table" - if k=="at" then - local t={} - for k,v in next,v do - t[k]=v - end - new[k]=t - elseif k=="dt" then - v.__p__=nil - v=copy(v,new) - new[k]=v - v.__p__=p - else - new[k]=v - end - end - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + local t=type(v)=="table" + if k=="at" then + local t={} + for k,v in next,v do + t[k]=v + end + new[k]=t + elseif k=="dt" then + v.__p__=nil + v=copy(v,new) + new[k]=v + v.__p__=p + else + new[k]=v + end end + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end + return new + else + return {} + end end xml.copy=copy function xml.checkbom(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then - return - end - end - insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) - insert(dt,2,"\n" ) + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then + return + end end + insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) + insert(dt,2,"\n" ) + end end local f_attribute=formatters['%s=%q'] local function verbose_element(e,handlers,escape) - local handle=handlers.handle - local serialize=handlers.serialize - local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn - local ats=eat and next(eat) and {} - if ats then - local n=0 - for k in next,eat do - n=n+1 - ats[n]=k - end - if n==1 then - local k=ats[1] - ats=f_attribute(k,escaped(eat[k])) - else - sort(ats) - for i=1,n do - local k=ats[i] - ats[i]=f_attribute(k,escaped(eat[k])) - end - ats=concat(ats," ") - end - end - if ern and trace_entities and ern~=ens then - ens=ern + local handle=handlers.handle + local serialize=handlers.serialize + local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn + local ats=eat and next(eat) and {} + if ats then + local n=0 + for k in next,eat do + n=n+1 + ats[n]=k end - local n=edt and #edt - if ens~="" then - if n and n>0 then - if ats then - handle("<",ens,":",etg," ",ats,">") - else - handle("<",ens,":",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",ens,":",etg,">") + if n==1 then + local k=ats[1] + ats=f_attribute(k,escaped(eat[k])) + else + sort(ats) + for i=1,n do + local k=ats[i] + ats[i]=f_attribute(k,escaped(eat[k])) + end + ats=concat(ats," ") + end + end + if ern and trace_entities and ern~=ens then + ens=ern + end + local n=edt and #edt + if ens~="" then + if n and n>0 then + if ats then + handle("<",ens,":",etg," ",ats,">") + else + handle("<",ens,":",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",ens,":",etg," ",ats,"/>") - else - handle("<",ens,":",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",ens,":",etg,">") else - if n and n>0 then - if ats then - handle("<",etg," ",ats,">") - else - handle("<",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",etg,">") + if ats then + handle("<",ens,":",etg," ",ats,"/>") + else + handle("<",ens,":",etg,"/>") + end + end + else + if n and n>0 then + if ats then + handle("<",etg," ",ats,">") + else + handle("<",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",etg," ",ats,"/>") - else - handle("<",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",etg,">") + else + if ats then + handle("<",etg," ",ats,"/>") + else + handle("<",etg,"/>") + end end + end end local function verbose_pi(e,handlers) - handlers.handle("<?",e.dt[1],"?>") + handlers.handle("<?",e.dt[1],"?>") end local function verbose_comment(e,handlers) - handlers.handle("<!--",e.dt[1],"-->") + handlers.handle("<!--",e.dt[1],"-->") end local function verbose_cdata(e,handlers) - handlers.handle("<![CDATA[",e.dt[1],"]]>") + handlers.handle("<![CDATA[",e.dt[1],"]]>") end local function verbose_doctype(e,handlers) - handlers.handle("<!DOCTYPE",e.dt[1],">") + handlers.handle("<!DOCTYPE",e.dt[1],">") end local function verbose_root(e,handlers) - handlers.serialize(e.dt,handlers) + handlers.serialize(e.dt,handlers) end local function verbose_text(e,handlers) - handlers.handle(escaped(e)) + handlers.handle(escaped(e)) end local function verbose_document(e,handlers) - local serialize=handlers.serialize - local functions=handlers.functions - for i=1,#e do - local ei=e[i] - if type(ei)=="string" then - functions["@tx@"](ei,handlers) - else - serialize(ei,handlers) - end + local serialize=handlers.serialize + local functions=handlers.functions + for i=1,#e do + local ei=e[i] + if type(ei)=="string" then + functions["@tx@"](ei,handlers) + else + serialize(ei,handlers) end + end end local function serialize(e,handlers,...) - 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 + 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 end local function xserialize(e,handlers) - if e then - local functions=handlers.functions - local etg=e.tg - if etg then - (functions[etg] or functions["@el@"])(e,handlers) - else - functions["@dc@"](e,handlers) - end + if e then + local functions=handlers.functions + local etg=e.tg + if etg then + (functions[etg] or functions["@el@"])(e,handlers) + else + functions["@dc@"](e,handlers) end + end end local handlers={} local function newhandlers(settings) - local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) - if settings then - for k,v in next,settings do - if type(v)=="table" then - local tk=t[k] if not tk then tk={} t[k]=tk end - for kk,vv in next,v do - tk[kk]=vv - end - else - t[k]=v - end - end - if settings.name then - handlers[settings.name]=t - end + local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) + if settings then + for k,v in next,settings do + if type(v)=="table" then + local tk=t[k] if not tk then tk={} t[k]=tk end + for kk,vv in next,v do + tk[kk]=vv + end + else + t[k]=v + end end - utilities.storage.mark(t) - return t + if settings.name then + handlers[settings.name]=t + end + end + utilities.storage.mark(t) + return t end local nofunction=function() end function xml.sethandlersfunction(handler,name,fnc) - handler.functions[name]=fnc or nofunction + handler.functions[name]=fnc or nofunction end function xml.gethandlersfunction(handler,name) - return handler.functions[name] + return handler.functions[name] end function xml.gethandlers(name) - return handlers[name] + return handlers[name] end newhandlers { - name="verbose", - initialize=false, - finalize=false, - serialize=xserialize, - handle=print, - functions={ - ["@dc@"]=verbose_document, - ["@dt@"]=verbose_doctype, - ["@rt@"]=verbose_root, - ["@el@"]=verbose_element, - ["@pi@"]=verbose_pi, - ["@cm@"]=verbose_comment, - ["@cd@"]=verbose_cdata, - ["@tx@"]=verbose_text, - } + name="verbose", + initialize=false, + finalize=false, + serialize=xserialize, + handle=print, + functions={ + ["@dc@"]=verbose_document, + ["@dt@"]=verbose_doctype, + ["@rt@"]=verbose_root, + ["@el@"]=verbose_element, + ["@pi@"]=verbose_pi, + ["@cm@"]=verbose_comment, + ["@cd@"]=verbose_cdata, + ["@tx@"]=verbose_text, + } } local result local xmlfilehandler=newhandlers { - name="file", - initialize=function(name) - result=io.open(name,"wb") - return result - end, - finalize=function() - result:close() - return true - end, - handle=function(...) - result:write(...) - end, + name="file", + initialize=function(name) + result=io.open(name,"wb") + return result + end, + finalize=function() + result:close() + return true + end, + handle=function(...) + result:write(...) + end, } function xml.save(root,name) - serialize(root,xmlfilehandler,name) + serialize(root,xmlfilehandler,name) end local result,r,threshold={},0,512 local xmlstringhandler=newhandlers { - name="string", - initialize=function() - r=0 - return result - end, - finalize=function() - local done=concat(result,"",1,r) - r=0 - if r>threshold then - result={} - end - return done - end, - handle=function(...) - for i=1,select("#",...) do - r=r+1 - result[r]=select(i,...) - end - end, + name="string", + initialize=function() + r=0 + return result + end, + finalize=function() + local done=concat(result,"",1,r) + r=0 + if r>threshold then + result={} + end + return done + end, + handle=function(...) + for i=1,select("#",...) do + r=r+1 + result[r]=select(i,...) + end + end, } local function xmltostring(root) - if not root then - return "" - elseif type(root)=="string" then - return root - else - return serialize(root,xmlstringhandler) or "" - end + if not root then + return "" + elseif type(root)=="string" then + return root + else + return serialize(root,xmlstringhandler) or "" + end end local function __tostring(root) - return (root and xmltostring(root)) or "" + return (root and xmltostring(root)) or "" end initialize_mt=function(root) - mt={ __tostring=__tostring,__index=root } + mt={ __tostring=__tostring,__index=root } end xml.defaulthandlers=handlers xml.newhandlers=newhandlers xml.serialize=serialize xml.tostring=xmltostring local function xmlstring(e,handle) - if not handle or (e.special and e.tg~="@rt@") then - elseif e.tg then - local edt=e.dt - if edt then - for i=1,#edt do - xmlstring(edt[i],handle) - end - end - else - handle(e) + if not handle or (e.special and e.tg~="@rt@") then + elseif e.tg then + local edt=e.dt + if edt then + for i=1,#edt do + xmlstring(edt[i],handle) + end end + else + handle(e) + end end xml.string=xmlstring function xml.settings(e) - while e do - local s=e.settings - if s then - return s - else - e=e.__p__ - end + while e do + local s=e.settings + if s then + return s + else + e=e.__p__ end - return nil + end + return nil end function xml.root(e) - local r=e - while e do - e=e.__p__ - if e then - r=e - end + local r=e + while e do + e=e.__p__ + if e then + r=e end - return r + end + return r end function xml.parent(root) - return root.__p__ + return root.__p__ end function xml.body(root) - return root.ri and root.dt[root.ri] or root + return root.ri and root.dt[root.ri] or root end function xml.name(root) - if not root then - return "" - end - local ns=root.ns - local tg=root.tg - if ns=="" then - return tg - else - return ns..":"..tg - end + if not root then + return "" + end + local ns=root.ns + local tg=root.tg + if ns=="" then + return tg + else + return ns..":"..tg + end end function xml.erase(dt,k) - if dt then - if k then - dt[k]="" - else for k=1,#dt do - dt[1]={ "" } - end end - end + if dt then + if k then + dt[k]="" + else for k=1,#dt do + dt[1]={ "" } + end end + end end function xml.assign(dt,k,root) - if dt and k then - dt[k]=type(root)=="table" and xml.body(root) or root - return dt[k] - else - return xml.body(root) - end + if dt and k then + dt[k]=type(root)=="table" and xml.body(root) or root + return dt[k] + else + return xml.body(root) + end end function xml.tocdata(e,wrapper) - local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" - if wrapper then - whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) - end - local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } - setmetatable(t,getmetatable(e)) - e.dt={ t } + local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" + if wrapper then + whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) + end + local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } + setmetatable(t,getmetatable(e)) + e.dt={ t } end function xml.makestandalone(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" then - local txt=v.dt[1] - if find(txt,"xml.*version=") then - v.dt[1]=txt.." standalone='yes'" - break - end - end + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" then + local txt=v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1]=txt.." standalone='yes'" + break end + end end - return root + end + return root end function xml.kind(e) - local dt=e and e.dt - if dt then - local n=#dt - if n==1 then - local d=dt[1] - if d.special then - local tg=d.tg - if tg=="@cd@" then - return "cdata" - elseif tg=="@cm" then - return "comment" - elseif tg=="@pi@" then - return "instruction" - elseif tg=="@dt@" then - return "declaration" - end - elseif type(d)=="string" then - return "text" - end - return "element" - elseif n>0 then - return "mixed" - end + local dt=e and e.dt + if dt then + local n=#dt + if n==1 then + local d=dt[1] + if d.special then + local tg=d.tg + if tg=="@cd@" then + return "cdata" + elseif tg=="@cm" then + return "comment" + elseif tg=="@pi@" then + return "instruction" + elseif tg=="@dt@" then + return "declaration" + end + elseif type(d)=="string" then + return "text" + end + return "element" + elseif n>0 then + return "mixed" end - return "empty" + end + return "empty" end @@ -13571,14 +17060,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true --- original size: 53301, stripped down to: 32477 +-- original size: 55145, stripped down to: 30992 if not modules then modules={} end modules ['lxml-lpt']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local concat,remove,insert=table.concat,table.remove,table.insert local type,next,tonumber,tostring,setmetatable,load,select=type,next,tonumber,tostring,setmetatable,load,select @@ -13591,21 +17080,21 @@ local trace_lparse=false local trace_lprofile=false local report_lpath=logs.reporter("xml","lpath") if trackers then - trackers.register("xml.path",function(v) - trace_lpath=v - end) - trackers.register("xml.parse",function(v) - trace_lparse=v - end) - trackers.register("xml.profile",function(v) - trace_lpath=v - trace_lparse=v - trace_lprofile=v - end) + trackers.register("xml.path",function(v) + trace_lpath=v + end) + trackers.register("xml.parse",function(v) + trace_lparse=v + end) + trackers.register("xml.profile",function(v) + trace_lpath=v + trace_lparse=v + trace_lprofile=v + end) end local xml=xml -local lpathcalls=0 function xml.lpathcalls () return lpathcalls end -local lpathcached=0 function xml.lpathcached() return lpathcached end +local lpathcalls=0 function xml.lpathcalls () return lpathcalls end +local lpathcached=0 function xml.lpathcached() return lpathcached end xml.functions=xml.functions or {} local functions=xml.functions xml.expressions=xml.expressions or {} @@ -13619,216 +17108,271 @@ local xmlpatterns=lpegpatterns.xml finalizers.xml=finalizers.xml or {} finalizers.tex=finalizers.tex or {} local function fallback (t,name) - local fn=finalizers[name] - if fn then - t[name]=fn - else - report_lpath("unknown sub finalizer %a",name) - fn=function() end - end - return fn + local fn=finalizers[name] + if fn then + t[name]=fn + else + report_lpath("unknown sub finalizer %a",name) + fn=function() end + end + return fn end setmetatableindex(finalizers.xml,fallback) setmetatableindex(finalizers.tex,fallback) xml.defaultprotocol="xml" local apply_axis={} apply_axis['root']=function(list) - local collected={} - for l=1,#list do - local ll=list[l] - local rt=ll - while ll do - ll=ll.__p__ - if ll then - rt=ll - end - end - collected[l]=rt + local collected={} + for l=1,#list do + local ll=list[l] + local rt=ll + while ll do + ll=ll.__p__ + if ll then + rt=ll + end end - return collected + collected[l]=rt + end + return collected end apply_axis['self']=function(list) - return list + return list end apply_axis['child']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local dt=ll.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - end - end - ll.en=en + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local dt=ll.dt + if dt then + local n=#dt + if n==0 then + ll.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + ll.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + end end + ll.en=en + end end - return collected + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + else + list.en=0 + end + else + local en=0 + for k=1,n do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant']=function(list) - local collected,c={},0 - for l=1,#list do - c=collect(list[l],collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + c=collect(list[l],collected,c) + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - if ll.special~=true then - c=c+1 - collected[c]=ll - end - c=collect(ll,collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + if ll.special~=true then + c=c+1 + collected[c]=ll + end + c=collect(ll,collected,c) + end + return collected end apply_axis['ancestor']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + while ll do + ll=ll.__p__ + if ll then + c=c+1 + collected[c]=ll + end end - return collected + end + return collected end apply_axis['ancestor-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + c=c+1 + collected[c]=ll + while ll do + ll=ll.__p__ + if ll then c=c+1 collected[c]=ll - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + end end - return collected + end + return collected end apply_axis['parent']=function(list) - local collected,c={},0 - for l=1,#list do - local pl=list[l].__p__ - if pl then - c=c+1 - collected[c]=pl - end + local collected={} + local c=0 + for l=1,#list do + local pl=list[l].__p__ + if pl then + c=c+1 + collected[c]=pl end - return collected + end + return collected end apply_axis['attribute']=function(list) - return {} + return {} end apply_axis['namespace']=function(list) - return {} + return {} end apply_axis['following']=function(list) - return {} + return {} end apply_axis['preceding']=function(list) - return {} + return {} end apply_axis['following-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni+1,#d do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni+1,#d do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['preceding-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=1,ll.ni-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=1,ll.ni-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['reverse-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni-1,1,-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni-1,1,-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['auto-descendant-or-self']=apply_axis['descendant-or-self'] apply_axis['auto-descendant']=apply_axis['descendant'] @@ -13836,130 +17380,147 @@ apply_axis['auto-child']=apply_axis['child'] apply_axis['auto-self']=apply_axis['self'] apply_axis['initial-child']=apply_axis['child'] local function apply_nodes(list,directive,nodes) - local maxn=#nodes - if maxn==3 then - local nns,ntg=nodes[2],nodes[3] - if not nns and not ntg then + local maxn=#nodes + if maxn==3 then + local nns=nodes[2] + local ntg=nodes[3] + if not nns and not ntg then + if directive then + return list + else + return {} + end + else + local collected={} + local c=0 + local m=0 + local p=nil + if not nns then + for l=1,#list do + local ll=list[l] + local ltg=ll.tg + if ltg then if directive then - return list - else - return {} + if ntg==ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif ntg~=ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - else - local collected,c,m,p={},0,0,nil - if not nns then - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - if directive then - if ntg==ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif ntg~=ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - elseif not ntg then - for l=1,#list do - local ll=list[l] - local lns=ll.rn or ll.ns - if lns then - if directive then - if lns==nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif lns~=nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - else - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=ltg==ntg and lns==nns - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end + end + end + elseif not ntg then + for l=1,#list do + local ll=list[l] + local lns=ll.rn or ll.ns + if lns then + if directive then + if lns==nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif lns~=nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - return collected + end end - else - local collected,c,m,p={},0,0,nil + else for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=false - for n=1,maxn,3 do - local nns,ntg=nodes[n+1],nodes[n+2] - ok=(not ntg or ltg==ntg) and (not nns or lns==nns) - if ok then - break - end - end - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=ltg==ntg and lns==nns + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end + end end - return collected + end + return collected end -end -local quit_expression=false -local function apply_expression(list,expression,order) - local collected,c={},0 - quit_expression=false + else + local collected={} + local c=0 + local m=0 + local p=nil for l=1,#list do - local ll=list[l] - if expression(list,ll,l,order) then + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=false + for n=1,maxn,3 do + local nns=nodes[n+1] + local ntg=nodes[n+2] + ok=(not ntg or ltg==ntg) and (not nns or lns==nns) + if ok then + break + end + end + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end c=c+1 collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - if quit_expression then - break - end + end end return collected + end end -local function apply_selector(list,specification) - if xml.applyselector then - apply_selector=xml.applyselector - return apply_selector(list,specification) - else - return list +local quit_expression=false +local function apply_expression(list,expression,order) + local collected={} + local c=0 + quit_expression=false + for l=1,#list do + local ll=list[l] + if expression(list,ll,l,order) then + c=c+1 + collected[c]=ll + end + if quit_expression then + break end + end + return collected +end +local function apply_selector(list,specification) + if xml.applyselector then + apply_selector=xml.applyselector + return apply_selector(list,specification) + else + return list + end end local P,V,C,Cs,Cc,Ct,R,S,Cg,Cb=lpeg.P,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.R,lpeg.S,lpeg.Cg,lpeg.Cb local spaces=S(" \n\r\t\f")^0 @@ -13970,24 +17531,24 @@ local lp_doequal=P("=")/"==" local lp_or=P("|")/" or " local lp_and=P("&")/" and " local builtin={ - text="(ll.dt[1] or '')", - content="ll.dt", - name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", - tag="ll.tg", - position="l", - firstindex="1", - firstelement="1", - first="1", - lastindex="(#ll.__p__.dt or 1)", - lastelement="(ll.__p__.en or 1)", - last="#list", - rootposition="order", - order="order", - element="(ll.ei or 1)", - index="(ll.ni or 1)", - match="(ll.mi or 1)", - namespace="ll.ns", - ns="ll.ns", + text="(ll.dt[1] or '')", + content="ll.dt", + name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", + tag="ll.tg", + position="l", + firstindex="1", + firstelement="1", + first="1", + lastindex="(#ll.__p__.dt or 1)", + lastelement="(ll.__p__.en or 1)", + last="#list", + rootposition="order", + order="order", + element="(ll.ei or 1)", + index="(ll.ni or 1)", + match="(ll.mi or 1)", + namespace="ll.ns", + ns="ll.ns", } local lp_builtin=lpeg.utfchartabletopattern(builtin)/builtin*((spaces*P("(")*spaces*P(")"))/"") local lp_attribute=(P("@")+P("attribute::"))/""*Cc("(ll.at and ll.at['")*((R("az","AZ")+S("-_:"))^1)*Cc("'])") @@ -13997,11 +17558,11 @@ local lp_fastpos=lp_fastpos_n+lp_fastpos_p local lp_reserved=C("and")+C("or")+C("not")+C("div")+C("mod")+C("true")+C("false") local lp_lua_function=Cs((R("az","AZ","__")^1*(P(".")*R("az","AZ","__")^1)^1)*("("))/"%0" local lp_function=C(R("az","AZ","__")^1)*P("(")/function(t) - if expressions[t] then - return "expr."..t.."(" - else - return "expr.error(" - end + if expressions[t] then + return "expr."..t.."(" + else + return "expr.error(" + end end local lparent=P("(") local rparent=P(")") @@ -14014,24 +17575,24 @@ local lp_string=Cc("'")*R("az","AZ","--","__")^1*Cc("'") local lp_content=(P("'")*(1-P("'"))^0*P("'")+P('"')*(1-P('"'))^0*P('"')) local cleaner local lp_special=(C(P("name")+P("text")+P("tag")+P("count")+P("child")))*value/function(t,s) - if expressions[t] then - s=s and s~="" and lpegmatch(cleaner,s) - if s and s~="" then - return "expr."..t.."(ll,"..s..")" - else - return "expr."..t.."(ll)" - end + if expressions[t] then + s=s and s~="" and lpegmatch(cleaner,s) + if s and s~="" then + return "expr."..t.."(ll,"..s..")" else - return "expr.error("..t..")" + return "expr."..t.."(ll)" end + else + return "expr.error("..t..")" + end end local content=lp_builtin+lp_attribute+lp_special+lp_noequal+lp_doequal+lp_or+lp_and+lp_reserved+lp_lua_function+lp_function+lp_content+ - lp_child+lp_any + lp_child+lp_any local converter=Cs ( - lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 + lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 ) cleaner=Cs (( - lp_reserved+lp_number+lp_string+1 )^1 ) + lp_reserved+lp_number+lp_string+1 )^1 ) local template_e=[[ local expr = xml.expressions return function(list,ll,l,order) @@ -14047,75 +17608,75 @@ local template_f_y=[[ local template_f_n=[[ return xml.finalizers['%s']['%s'] ]] -local register_last_match={ kind="axis",axis="last-match" } -local register_self={ kind="axis",axis="self" } -local register_parent={ kind="axis",axis="parent" } -local register_descendant={ kind="axis",axis="descendant" } -local register_child={ kind="axis",axis="child" } +local register_last_match={ kind="axis",axis="last-match" } +local register_self={ kind="axis",axis="self" } +local register_parent={ kind="axis",axis="parent" } +local register_descendant={ kind="axis",axis="descendant" } +local register_child={ kind="axis",axis="child" } local register_descendant_or_self={ kind="axis",axis="descendant-or-self" } -local register_root={ kind="axis",axis="root" } -local register_ancestor={ kind="axis",axis="ancestor" } -local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } -local register_attribute={ kind="axis",axis="attribute" } -local register_namespace={ kind="axis",axis="namespace" } -local register_following={ kind="axis",axis="following" } +local register_root={ kind="axis",axis="root" } +local register_ancestor={ kind="axis",axis="ancestor" } +local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } +local register_attribute={ kind="axis",axis="attribute" } +local register_namespace={ kind="axis",axis="namespace" } +local register_following={ kind="axis",axis="following" } local register_following_sibling={ kind="axis",axis="following-sibling" } -local register_preceding={ kind="axis",axis="preceding" } +local register_preceding={ kind="axis",axis="preceding" } local register_preceding_sibling={ kind="axis",axis="preceding-sibling" } -local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } +local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } local register_auto_descendant_or_self={ kind="axis",axis="auto-descendant-or-self" } -local register_auto_descendant={ kind="axis",axis="auto-descendant" } -local register_auto_self={ kind="axis",axis="auto-self" } -local register_auto_child={ kind="axis",axis="auto-child" } -local register_initial_child={ kind="axis",axis="initial-child" } +local register_auto_descendant={ kind="axis",axis="auto-descendant" } +local register_auto_self={ kind="axis",axis="auto-self" } +local register_auto_child={ kind="axis",axis="auto-child" } +local register_initial_child={ kind="axis",axis="initial-child" } local register_all_nodes={ kind="nodes",nodetest=true,nodes={ true,false,false } } local skip={} local function errorrunner_e(str,cnv) - if not skip[str] then - report_lpath("error in expression: %s => %s",str,cnv) - skip[str]=cnv or str - end - return false + if not skip[str] then + report_lpath("error in expression: %s => %s",str,cnv) + skip[str]=cnv or str + end + return false end local function errorrunner_f(str,arg) - report_lpath("error in finalizer: %s(%s)",str,arg or "") - return false + report_lpath("error in finalizer: %s(%s)",str,arg or "") + return false end local function register_nodes(nodetest,nodes) - return { kind="nodes",nodetest=nodetest,nodes=nodes } + return { kind="nodes",nodetest=nodetest,nodes=nodes } end local function register_selector(specification) - return { kind="selector",specification=specification } + return { kind="selector",specification=specification } end local function register_expression(expression) - local converted=lpegmatch(converter,expression) - local runner=load(format(template_e,converted)) - runner=(runner and runner()) or function() errorrunner_e(expression,converted) end - return { kind="expression",expression=expression,converted=converted,evaluator=runner } + local converted=lpegmatch(converter,expression) + local runner=load(format(template_e,converted)) + runner=(runner and runner()) or function() errorrunner_e(expression,converted) end + return { kind="expression",expression=expression,converted=converted,evaluator=runner } end local function register_finalizer(protocol,name,arguments) - local runner - if arguments and arguments~="" then - runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) - else - runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) - end - runner=(runner and runner()) or function() errorrunner_f(name,arguments) end - return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } + local runner + if arguments and arguments~="" then + runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) + else + runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) + end + runner=(runner and runner()) or function() errorrunner_f(name,arguments) end + return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } end local expression=P { "ex", - ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", - sq="'"*(1-S("'"))^0*"'", - dq='"'*(1-S('"'))^0*'"', + ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", + sq="'"*(1-S("'"))^0*"'", + dq='"'*(1-S('"'))^0*'"', } local arguments=P { "ar", - ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", - nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, - sq=P("'")*(1-P("'"))^0*P("'"), - dq=P('"')*(1-P('"'))^0*P('"'), + ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", + nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, + sq=P("'")*(1-P("'"))^0*P("'"), + dq=P('"')*(1-P('"'))^0*P('"'), } local function register_error(str) - return { kind="error",error=format("unparsed: %s",str) } + return { kind="error",error=format("unparsed: %s",str) } end local special_1=P("*")*Cc(register_auto_descendant)*Cc(register_all_nodes) local special_2=P("/")*Cc(register_auto_self) @@ -14123,367 +17684,368 @@ local special_3=P("")*Cc(register_auto_self) local no_nextcolon=P(-1)+#(1-P(":")) local no_nextlparent=P(-1)+#(1-P("(")) local pathparser=Ct { "patterns", - patterns=spaces*V("protocol")*spaces*( - (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) - ), - protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), - step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, - axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), - special=special_1+special_2+special_3, - initial=(P("/")*spaces*Cc(register_initial_child))^-1, - error=(P(1)^1)/register_error, - shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), - shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, - s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), - s_descendant=P("**")*Cc(register_descendant), - s_child=P("*")*no_nextcolon*Cc(register_child), - s_parent=P("..")*Cc(register_parent), - s_self=P("." )*Cc(register_self), - s_root=P("^^")*Cc(register_root), - s_ancestor=P("^")*Cc(register_ancestor), - s_lastmatch=P("=")*Cc(register_last_match), - descendant=P("descendant::")*Cc(register_descendant), - child=P("child::")*Cc(register_child), - parent=P("parent::")*Cc(register_parent), - self=P("self::")*Cc(register_self), - root=P('root::')*Cc(register_root), - ancestor=P('ancestor::')*Cc(register_ancestor), - descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), - ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), - following=P('following::')*Cc(register_following), - following_sibling=P('following-sibling::')*Cc(register_following_sibling), - preceding=P('preceding::')*Cc(register_preceding), - preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), - reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), - last_match=P('last-match::')*Cc(register_last_match), - selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, - nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, - expressions=expression/register_expression, - letters=R("az")^1, - name=(1-S("/[]()|:*!"))^1, - negate=P("!")*Cc(false), - nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), - nodetest=V("negate")+Cc(true), - nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), - wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, - nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, - finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, + patterns=spaces*V("protocol")*spaces*( + (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) + ), + protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), + step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, + axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), + special=special_1+special_2+special_3, + initial=(P("/")*spaces*Cc(register_initial_child))^-1, + error=(P(1)^1)/register_error, + shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), + shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, + s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), + s_descendant=P("**")*Cc(register_descendant), + s_child=P("*")*no_nextcolon*Cc(register_child), + s_parent=P("..")*Cc(register_parent), + s_self=P("." )*Cc(register_self), + s_root=P("^^")*Cc(register_root), + s_ancestor=P("^")*Cc(register_ancestor), + s_lastmatch=P("=")*Cc(register_last_match), + descendant=P("descendant::")*Cc(register_descendant), + child=P("child::")*Cc(register_child), + parent=P("parent::")*Cc(register_parent), + self=P("self::")*Cc(register_self), + root=P('root::')*Cc(register_root), + ancestor=P('ancestor::')*Cc(register_ancestor), + descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), + ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), + following=P('following::')*Cc(register_following), + following_sibling=P('following-sibling::')*Cc(register_following_sibling), + preceding=P('preceding::')*Cc(register_preceding), + preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), + reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), + last_match=P('last-match::')*Cc(register_last_match), + selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, + nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, + expressions=expression/register_expression, + letters=R("az")^1, + name=(1-S("/[]()|:*!"))^1, + negate=P("!")*Cc(false), + nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), + nodetest=V("negate")+Cc(true), + nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), + wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, + nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, + finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, } xmlpatterns.pathparser=pathparser local cache={} local function nodesettostring(set,nodetest) - local t={} - for i=1,#set,3 do - local directive,ns,tg=set[i],set[i+1],set[i+2] - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - t[#t+1]=(directive and tg) or format("not(%s)",tg) - end - if nodetest==false then - return format("not(%s)",concat(t,"|")) - else - return concat(t,"|") - end + local t={} + for i=1,#set,3 do + local directive,ns,tg=set[i],set[i+1],set[i+2] + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) + t[#t+1]=(directive and tg) or format("not(%s)",tg) + end + if nodetest==false then + return format("not(%s)",concat(t,"|")) + else + return concat(t,"|") + end end local function tagstostring(list) - if #list==0 then - return "no elements" - else - local t={} - for i=1,#list do - local li=list[i] - local ns,tg=li.ns,li.tg - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - end - return concat(t," ") + if #list==0 then + return "no elements" + else + local t={} + for i=1,#list do + local li=list[i] + local ns=li.ns + local tg=li.tg + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) end + return concat(t," ") + end end xml.nodesettostring=nodesettostring local lpath local function lshow(parsed) - if type(parsed)=="string" then - parsed=lpath(parsed) - end - report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, - table.serialize(parsed,false)) + if type(parsed)=="string" then + parsed=lpath(parsed) + end + report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, + table.serialize(parsed,false)) end xml.lshow=lshow local function add_comment(p,str) - local pc=p.comment - if not pc then - p.comment={ str } - else - pc[#pc+1]=str - end + local pc=p.comment + if not pc then + p.comment={ str } + else + pc[#pc+1]=str + end end lpath=function (pattern) - lpathcalls=lpathcalls+1 - if type(pattern)=="table" then - return pattern - else - local parsed=cache[pattern] - if parsed then - lpathcached=lpathcached+1 + lpathcalls=lpathcalls+1 + if type(pattern)=="table" then + return pattern + else + local parsed=cache[pattern] + if parsed then + lpathcached=lpathcached+1 + else + parsed=lpegmatch(pathparser,pattern) + if parsed then + parsed.pattern=pattern + local np=#parsed + if np==0 then + parsed={ pattern=pattern,register_self,state="parsing error" } + report_lpath("parsing error in pattern: %s",pattern) + lshow(parsed) else - parsed=lpegmatch(pathparser,pattern) - if parsed then - parsed.pattern=pattern - local np=#parsed - if np==0 then - parsed={ pattern=pattern,register_self,state="parsing error" } - report_lpath("parsing error in pattern: %s",pattern) - lshow(parsed) - else - local pi=parsed[1] - if pi.axis=="auto-child" then - if false then - add_comment(parsed,"auto-child replaced by auto-descendant-or-self") - parsed[1]=register_auto_descendant_or_self - else - add_comment(parsed,"auto-child replaced by auto-descendant") - parsed[1]=register_auto_descendant - end - elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then - add_comment(parsed,"initial-child removed") - remove(parsed,1) - end - local np=#parsed - if np>1 then - local pnp=parsed[np] - if pnp.kind=="nodes" and pnp.nodetest==true then - local nodes=pnp.nodes - if nodes[1]==true and nodes[2]==false and nodes[3]==false then - add_comment(parsed,"redundant final wildcard filter removed") - remove(parsed,np) - end - end - end - end + local pi=parsed[1] + if pi.axis=="auto-child" then + if false then + add_comment(parsed,"auto-child replaced by auto-descendant-or-self") + parsed[1]=register_auto_descendant_or_self else - parsed={ pattern=pattern } + add_comment(parsed,"auto-child replaced by auto-descendant") + parsed[1]=register_auto_descendant end - cache[pattern]=parsed - if trace_lparse and not trace_lprofile then - lshow(parsed) + elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then + add_comment(parsed,"initial-child removed") + remove(parsed,1) + end + local np=#parsed + if np>1 then + local pnp=parsed[np] + if pnp.kind=="nodes" and pnp.nodetest==true then + local nodes=pnp.nodes + if nodes[1]==true and nodes[2]==false and nodes[3]==false then + add_comment(parsed,"redundant final wildcard filter removed") + remove(parsed,np) + end end + end end - return parsed + else + parsed={ pattern=pattern } + end + cache[pattern]=parsed + if trace_lparse and not trace_lprofile then + lshow(parsed) + end end + return parsed + end end xml.lpath=lpath do - local profiled={} - xml.profiled=profiled - local lastmatch=nil - local keepmatch=nil - if directives then - directives.register("xml.path.keeplastmatch",function(v) - keepmatch=v - lastmatch=nil - end) - end - apply_axis["last-match"]=function() - return lastmatch or {} - end - local function profiled_apply(list,parsed,nofparsed,order) - local p=profiled[parsed.pattern] - if p then - p.tested=p.tested+1 - else - p={ tested=1,matched=0,finalized=0 } - profiled[parsed.pattern]=p - end - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - p.matched=p.matched+1 - p.finalized=p.finalized+1 - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - p.finalized=p.finalized+1 - return collected - end - return nil - end - end - if collected then - p.matched=p.matched+1 - end - return collected - end - local function traced_apply(list,parsed,nofparsed,order) - if trace_lparse then - lshow(parsed) - end - report_lpath("collecting: %s",parsed.pattern) - report_lpath("root tags : %s",tagstostring(list)) - report_lpath("order : %s",order or "unset") - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") - return collected - end - return nil - end - end + local profiled={} + xml.profiled=profiled + local lastmatch=nil + local keepmatch=nil + if directives then + directives.register("xml.path.keeplastmatch",function(v) + keepmatch=v + lastmatch=nil + end) + end + apply_axis["last-match"]=function() + return lastmatch or {} + end + local function profiled_apply(list,parsed,nofparsed,order) + local p=profiled[parsed.pattern] + if p then + p.tested=p.tested+1 + else + p={ tested=1,matched=0,finalized=0 } + profiled[parsed.pattern]=p + end + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + p.matched=p.matched+1 + p.finalized=p.finalized+1 return collected - end - local function normal_apply(list,parsed,nofparsed,order) - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - local axis=pi.axis - if axis~="self" then - collected=apply_axis[axis](collected) - end - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - return pi.finalizer(collected) - end - if not collected or #collected==0 then - local pf=i<nofparsed and parsed[nofparsed].finalizer - if pf then - return pf(collected) - end - return nil - end + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + p.finalized=p.finalized+1 + return collected end - return collected + return nil + end end - local apply=normal_apply - if trackers then - trackers.register("xml.path,xml.parse,xml.profile",function() - if trace_lprofile then - apply=profiled_apply - elseif trace_lpath then - apply=traced_apply - else - apply=normal_apply - end - end) + if collected then + p.matched=p.matched+1 end - function xml.applylpath(list,pattern) - if not list then - lastmatch=nil - return - end - local parsed=cache[pattern] - if parsed then - lpathcalls=lpathcalls+1 - lpathcached=lpathcached+1 - elseif type(pattern)=="table" then - lpathcalls=lpathcalls+1 - parsed=pattern - else - parsed=lpath(pattern) or pattern - end - if not parsed then - lastmatch=nil - return - end - local nofparsed=#parsed - if nofparsed==0 then - lastmatch=nil - return - end - local collected=apply({ list },parsed,nofparsed,list.mi) - lastmatch=keepmatch and collected or nil + return collected + end + local function traced_apply(list,parsed,nofparsed,order) + if trace_lparse then + lshow(parsed) + end + report_lpath("collecting: %s",parsed.pattern) + report_lpath("root tags : %s",tagstostring(list)) + report_lpath("order : %s",order or "unset") + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") return collected + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") + return collected + end + return nil + end end - function xml.lastmatch() - return lastmatch - end - local stack={} - function xml.pushmatch() - insert(stack,lastmatch) - end - function xml.popmatch() - lastmatch=remove(stack) + return collected + end + local function normal_apply(list,parsed,nofparsed,order) + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + local axis=pi.axis + if axis~="self" then + collected=apply_axis[axis](collected) + end + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + return pi.finalizer(collected) + end + if not collected or #collected==0 then + local pf=i<nofparsed and parsed[nofparsed].finalizer + if pf then + return pf(collected) + end + return nil + end end + return collected + end + local apply=normal_apply + if trackers then + trackers.register("xml.path,xml.parse,xml.profile",function() + if trace_lprofile then + apply=profiled_apply + elseif trace_lpath then + apply=traced_apply + else + apply=normal_apply + end + end) + end + function xml.applylpath(list,pattern) + if not list then + lastmatch=nil + return + end + local parsed=cache[pattern] + if parsed then + lpathcalls=lpathcalls+1 + lpathcached=lpathcached+1 + elseif type(pattern)=="table" then + lpathcalls=lpathcalls+1 + parsed=pattern + else + parsed=lpath(pattern) or pattern + end + if not parsed then + lastmatch=nil + return + end + local nofparsed=#parsed + if nofparsed==0 then + lastmatch=nil + return + end + local collected=apply({ list },parsed,nofparsed,list.mi) + lastmatch=keepmatch and collected or nil + return collected + end + function xml.lastmatch() + return lastmatch + end + local stack={} + function xml.pushmatch() + insert(stack,lastmatch) + end + function xml.popmatch() + lastmatch=remove(stack) + end end local applylpath=xml.applylpath function xml.filter(root,pattern) - return applylpath(root,pattern) + return applylpath(root,pattern) end expressions.child=function(e,pattern) - return applylpath(e,pattern) + return applylpath(e,pattern) end expressions.count=function(e,pattern) - local collected=applylpath(e,pattern) - return pattern and (collected and #collected) or 0 + local collected=applylpath(e,pattern) + return pattern and (collected and #collected) or 0 end expressions.oneof=function(s,...) - for i=1,select("#",...) do - if s==select(i,...) then - return true - end + for i=1,select("#",...) do + if s==select(i,...) then + return true end - return false + end + return false end expressions.error=function(str) - xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) - return false + xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) + return false end expressions.undefined=function(s) - return s==nil + return s==nil end expressions.quit=function(s) - if s or s==nil then - quit_expression=true - end - return true + if s or s==nil then + quit_expression=true + end + return true end expressions.print=function(...) - print(...) - return true + print(...) + return true end expressions.find=find expressions.upper=upper @@ -14491,233 +18053,238 @@ expressions.lower=lower expressions.number=tonumber expressions.boolean=toboolean function expressions.contains(str,pattern) - local t=type(str) - if t=="string" then - if find(str,pattern) then - return true - end - elseif t=="table" then - for i=1,#str do - local d=str[i] - if type(d)=="string" and find(d,pattern) then - return true - end - end + local t=type(str) + if t=="string" then + if find(str,pattern) then + return true end - return false + elseif t=="table" then + for i=1,#str do + local d=str[i] + if type(d)=="string" and find(d,pattern) then + return true + end + end + end + return false end function xml.expressions.idstring(str) - return type(str)=="string" and gsub(str,"^#","") or "" + return type(str)=="string" and gsub(str,"^#","") or "" end local function traverse(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local r=e.__p__ - handle(r,r.dt,e.ni) - end + local collected=applylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local r=e.__p__ + handle(r,r.dt,e.ni) end + end end local function selection(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - if handle then - for c=1,#collected do - handle(collected[c]) - end - else - return collected - end + local collected=applylpath(root,pattern) + if collected then + if handle then + for c=1,#collected do + handle(collected[c]) + end + else + return collected end + end end -xml.traverse=traverse +xml.traverse=traverse xml.selection=selection local function dofunction(collected,fnc,...) - if collected then - local f=functions[fnc] - if f then - for c=1,#collected do - f(collected[c],...) - end - else - report_lpath("unknown function %a",fnc) - end + if collected then + local f=functions[fnc] + if f then + for c=1,#collected do + f(collected[c],...) + end + else + report_lpath("unknown function %a",fnc) end + end end finalizers.xml["function"]=dofunction finalizers.tex["function"]=dofunction expressions.text=function(e,n) - local rdt=e.__p__.dt - return rdt and rdt[n] or "" + local rdt=e.__p__.dt + return rdt and rdt[n] or "" end expressions.name=function(e,n) - local found=false - n=tonumber(n) or 0 - if n==0 then - found=type(e)=="table" and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end + local found=false + n=tonumber(n) or 0 + if n==0 then + found=type(e)=="table" and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 end + end end - if found then - local ns,tg=found.rn or found.ns or "",found.tg - if ns~="" then - return ns..":"..tg + else + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break else - return tg + n=n-1 end + end + end + end + if found then + local ns=found.rn or found.ns or "" + local tg=found.tg + if ns~="" then + return ns..":"..tg else - return "" + return tg end + else + return "" + end end expressions.tag=function(e,n) - if not e then - return "" + if not e then + return "" + else + local found=false + n=tonumber(n) or 0 + if n==0 then + found=(type(e)=="table") and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 + end + end + end else - local found=false - n=tonumber(n) or 0 - if n==0 then - found=(type(e)=="table") and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end - end + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break + else + n=n-1 + end end - return (found and found.tg) or "" + end end + return (found and found.tg) or "" + end end local dummy=function() end function xml.elements(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end 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 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end end + end end function xml.collected(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + return collected[c] + end 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 - return collected[c] - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - return collected[c] - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + return collected[c] + end end + end end function xml.inspect(collection,pattern) - pattern=pattern or "." - for e in xml.collected(collection,pattern or ".") do - report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) - end + pattern=pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) + end end local function split(e) - local dt=e.dt - if dt then - for i=1,#dt do - local dti=dt[i] - if type(dti)=="string" then - dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") - dti=gsub(dti,"[\n\r]+","\n\n") - dt[i]=dti - else - split(dti) - end - end + local dt=e.dt + if dt then + for i=1,#dt do + local dti=dt[i] + if type(dti)=="string" then + dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") + dti=gsub(dti,"[\n\r]+","\n\n") + dt[i]=dti + else + split(dti) + end end - return e + end + return e end function xml.finalizers.paragraphs(c) - for i=1,#c do - split(c[i]) - end - return c + for i=1,#c do + split(c[i]) + end + return c end @@ -14727,14 +18294,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-mis"] = package.loaded["lxml-mis"] or true --- original size: 3574, stripped down to: 1863 +-- original size: 3574, stripped down to: 1808 if not modules then modules={} end modules ['lxml-mis']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local xml,lpeg,string=xml,lpeg,string local type=type @@ -14745,26 +18312,26 @@ local P,S,R,C,V,Cc,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.Cc,lpeg.Cs lpegpatterns.xml=lpegpatterns.xml or {} local xmlpatterns=lpegpatterns.xml local function xmlgsub(t,old,new) - local dt=t.dt - if dt then - for k=1,#dt do - local v=dt[k] - if type(v)=="string" then - dt[k]=gsub(v,old,new) - else - xmlgsub(v,old,new) - end - end + local dt=t.dt + if dt then + for k=1,#dt do + local v=dt[k] + if type(v)=="string" then + dt[k]=gsub(v,old,new) + else + xmlgsub(v,old,new) + end end + end end function xml.stripleadingspaces(dk,d,k) - if d and k then - local dkm=d[k-1] - if dkm and type(dkm)=="string" then - local s=match(dkm,"\n(%s+)") - xmlgsub(dk,"\n"..rep(" ",#s),"\n") - end + if d and k then + local dkm=d[k-1] + if dkm and type(dkm)=="string" then + local s=match(dkm,"\n(%s+)") + xmlgsub(dk,"\n"..rep(" ",#s),"\n") end + end end local normal=(1-S("<&>"))^0 local special=P("<")/"<"+P(">")/">"+P("&")/"&" @@ -14776,17 +18343,17 @@ local cleansed=Cs(((P("<")*(1-P(">"))^0*P(">"))/""+1)^0) xmlpatterns.escaped=escaped xmlpatterns.unescaped=unescaped xmlpatterns.cleansed=cleansed -function xml.escaped (str) return lpegmatch(escaped,str) end +function xml.escaped (str) return lpegmatch(escaped,str) end function xml.unescaped(str) return lpegmatch(unescaped,str) end -function xml.cleansed (str) return lpegmatch(cleansed,str) end +function xml.cleansed (str) return lpegmatch(cleansed,str) end function xml.fillin(root,pattern,str,check) - local e=xml.first(root,pattern) - if e then - local n=#e.dt - if not check or n==0 or (n==1 and e.dt[1]=="") then - e.dt={ str } - end + local e=xml.first(root,pattern) + if e then + local n=#e.dt + if not check or n==0 or (n==1 and e.dt[1]=="") then + e.dt={ str } end + end end @@ -14796,17 +18363,17 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true --- original size: 30650, stripped down to: 21793 +-- original size: 30771, stripped down to: 19680 if not modules then modules={} end modules ['lxml-aux']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) -local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) +local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) +local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) local report_xml=logs.reporter("xml") local xml=xml local xmlcopy,xmlname=xml.copy,xml.name @@ -14819,308 +18386,313 @@ local utfbyte=utf.byte local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local striplinepatterns=utilities.strings.striplinepatterns local function report(what,pattern,c,e) - report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) + report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) end local function withelements(e,handle,depth) - if e and handle then - local edt=e.dt - if edt then - depth=depth or 0 - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - handle(e,depth) - withelements(e,handle,depth+1) - end - end + if e and handle then + local edt=e.dt + if edt then + depth=depth or 0 + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + handle(e,depth) + withelements(e,handle,depth+1) end + end end + end end xml.withelements=withelements function xml.withelement(e,n,handle) - if e and n~=0 and handle then - local edt=e.dt - if edt then - if n>0 then - for i=1,#edt do - local ei=edt[i] - if type(ei)=="table" then - if n==1 then - handle(ei) - return - else - n=n-1 - end - end - end - elseif n<0 then - for i=#edt,1,-1 do - local ei=edt[i] - if type(ei)=="table" then - if n==-1 then - handle(ei) - return - else - n=n+1 - end - end - end + if e and n~=0 and handle then + local edt=e.dt + if edt then + if n>0 then + for i=1,#edt do + local ei=edt[i] + if type(ei)=="table" then + if n==1 then + handle(ei) + return + else + n=n-1 end + end end - end -end -function xml.each(root,pattern,handle,reverse) - local collected=xmlapplylpath(root,pattern) - if collected then - if handle then - if reverse then - for c=#collected,1,-1 do - handle(collected[c]) - end + elseif n<0 then + for i=#edt,1,-1 do + local ei=edt[i] + if type(ei)=="table" then + if n==-1 then + handle(ei) + return else - for c=1,#collected do - handle(collected[c]) - end + n=n+1 end + end end - return collected + end end + end end -function xml.processattributes(root,pattern,handle) - local collected=xmlapplylpath(root,pattern) - if collected and handle then +function xml.each(root,pattern,handle,reverse) + local collected=xmlapplylpath(root,pattern) + if collected then + if handle then + if reverse then + for c=#collected,1,-1 do + handle(collected[c]) + end + else for c=1,#collected do - handle(collected[c].at) + handle(collected[c]) end + end end return collected + end +end +function xml.processattributes(root,pattern,handle) + local collected=xmlapplylpath(root,pattern) + if collected and handle then + for c=1,#collected do + handle(collected[c].at) + end + end + return collected end function xml.collect(root,pattern) - return xmlapplylpath(root,pattern) + return xmlapplylpath(root,pattern) end function xml.collecttexts(root,pattern,flatten) - local collected=xmlapplylpath(root,pattern) - if collected and flatten then - local xmltostring=xml.tostring - for c=1,#collected do - collected[c]=xmltostring(collected[c].dt) - end + local collected=xmlapplylpath(root,pattern) + if collected and flatten then + local xmltostring=xml.tostring + for c=1,#collected do + collected[c]=xmltostring(collected[c].dt) end - return collected or {} + end + return collected or {} end function xml.collect_tags(root,pattern,nonamespace) - local collected=xmlapplylpath(root,pattern) - if collected then - local t,n={},0 - for c=1,#collected do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace then - t[n]=tg - elseif ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end - end - return t + local collected=xmlapplylpath(root,pattern) + if collected then + local t={} + local n=0 + for c=1,#collected do + local e=collected[c] + local ns=e.ns + local tg=e.tg + n=n+1 + if nonamespace then + t[n]=tg + elseif ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg + end end + return t + end end local no_root={ no_root=true } local function redo_ni(d) - for k=1,#d do - local dk=d[k] - if type(dk)=="table" then - dk.ni=k - end + for k=1,#d do + local dk=d[k] + if type(dk)=="table" then + dk.ni=k end + end end xml.reindex=redo_ni local function xmltoelement(whatever,root) - if not whatever then - return nil - end - local element - if type(whatever)=="string" then - element=xmlinheritedconvert(whatever,root) - else - element=whatever - end - if element.error then - return whatever - end - if element then - end - return element + if not whatever then + return nil + end + local element + if type(whatever)=="string" then + element=xmlinheritedconvert(whatever,root) + else + element=whatever + end + if element.error then + return whatever + end + if element then + end + return element end xml.toelement=xmltoelement local function copiedelement(element,newparent) - if type(element)=="string" then - return element - else - element=xmlcopy(element).dt - if newparent and type(element)=="table" then - element.__p__=newparent - end - return element + if type(element)=="string" then + return element + else + element=xmlcopy(element).dt + if newparent and type(element)=="table" then + element.__p__=newparent end + return element + end end function xml.delete(root,pattern) - if not pattern or pattern=="" then - local p=root.__p__ + if not pattern or pattern=="" then + local p=root.__p__ + if p then + if trace_manipulations then + report('deleting',"--",c,root) + end + local d=p.dt + remove(d,root.ni) + redo_ni(d) + end + else + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ if p then - if trace_manipulations then - report('deleting',"--",c,root) - end - local d=p.dt - remove(d,root.ni) - redo_ni(d) - end - else - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('deleting',pattern,c,e) - end - local d=p.dt - local ni=e.ni - if ni<=#d then - if false then - p.dt[ni]="" - else - remove(d,ni) - redo_ni(d) - end - else - end - end + if trace_manipulations then + report('deleting',pattern,c,e) + end + local d=p.dt + local ni=e.ni + if ni<=#d then + if false then + p.dt[ni]="" + else + remove(d,ni) + redo_ni(d) end + else + end end + end end + end end function xml.replace(root,pattern,whatever) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('replacing',pattern,c,e) - end - local d=p.dt - local n=e.ni - local t=copiedelement(element,p) - if type(t)=="table" then - d[n]=t[1] - for i=2,#t do - n=n+1 - insert(d,n,t[i]) - end - else - d[n]=t - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ + if p then + if trace_manipulations then + report('replacing',pattern,c,e) + end + local d=p.dt + local n=e.ni + local t=copiedelement(element,p) + if type(t)=="table" then + d[n]=t[1] + for i=2,#t do + n=n+1 + insert(d,n,t[i]) + end + else + d[n]=t end + redo_ni(d) + end end + end end local function wrap(e,wrapper) - local t={ - rn=e.rn, - tg=e.tg, - ns=e.ns, - at=e.at, - dt=e.dt, - __p__=e, - } - setmetatable(t,getmetatable(e)) - e.rn=wrapper.rn or e.rn or "" - e.tg=wrapper.tg or e.tg or "" - e.ns=wrapper.ns or e.ns or "" - e.at=fastcopy(wrapper.at) - e.dt={ t } + local t={ + rn=e.rn, + tg=e.tg, + ns=e.ns, + at=e.at, + dt=e.dt, + __p__=e, + } + setmetatable(t,getmetatable(e)) + e.rn=wrapper.rn or e.rn or "" + e.tg=wrapper.tg or e.tg or "" + e.ns=wrapper.ns or e.ns or "" + e.at=fastcopy(wrapper.at) + e.dt={ t } end function xml.wrap(root,pattern,whatever) - if whatever then - local wrapper=xmltoelement(whatever,root) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if trace_manipulations then - report('wrapping',pattern,c,e) - end - wrap(e,wrapper) - end + if whatever then + local wrapper=xmltoelement(whatever,root) + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if trace_manipulations then + report('wrapping',pattern,c,e) end - else - wrap(root,xmltoelement(pattern)) + wrap(e,wrapper) + end end + else + wrap(root,xmltoelement(pattern)) + end end local function inject_element(root,pattern,whatever,prepend) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function inject_e(e) - local r=e.__p__ - local d,k,rri=r.dt,e.ni,r.ri - local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) - if edt then - local be,af - local cp=copiedelement(element,e) - if prepend then - be,af=cp,edt - else - be,af=edt,cp - end - local bn=#be - for i=1,#af do - bn=bn+1 - be[bn]=af[i] - end - if rri then - r.dt[rri].dt=be - else - d[k].dt=be - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function inject_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + local rri=r.ri + local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) + if edt then + local be,af + local cp=copiedelement(element,e) + if prepend then + be,af=cp,edt + else + be,af=edt,cp + end + local bn=#be + for i=1,#af do + bn=bn+1 + be[bn]=af[i] + end + if rri then + r.dt[rri].dt=be + else + d[k].dt=be + end + redo_ni(d) end - if not collected then - elseif collected.tg then - inject_e(collected) - else - for c=1,#collected do - inject_e(collected[c]) - end + end + if not collected then + elseif collected.tg then + inject_e(collected) + else + for c=1,#collected do + inject_e(collected[c]) end + end end local function insert_element(root,pattern,whatever,before) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function insert_e(e) - local r=e.__p__ - local d,k=r.dt,e.ni - if not before then - k=k+1 - end - insert(d,k,copiedelement(element,r)) - redo_ni(d) - end - if not collected then - elseif collected.tg then - insert_e(collected) - else - for c=1,#collected do - insert_e(collected[c]) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function insert_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + if not before then + k=k+1 + end + insert(d,k,copiedelement(element,r)) + redo_ni(d) + end + if not collected then + elseif collected.tg then + insert_e(collected) + else + for c=1,#collected do + insert_e(collected[c]) end + end end xml.insert_element=insert_element xml.insertafter=insert_element @@ -15128,124 +18700,124 @@ xml.insertbefore=function(r,p,e) insert_element(r,p,e,true) end xml.injectafter=inject_element xml.injectbefore=function(r,p,e) inject_element(r,p,e,true) end local function include(xmldata,pattern,attribute,recursive,loaddata,level) - pattern=pattern or 'include' - loaddata=loaddata or io.loaddata - local collected=xmlapplylpath(xmldata,pattern) - if collected then - if not level then - level=1 - end - for c=1,#collected do - local ek=collected[c] - local name=nil - local ekdt=ek.dt - if ekdt then - local ekat=ek.at - local ekrt=ek.__p__ - if ekrt then - local epdt=ekrt.dt - if not attribute or attribute=="" then - name=(type(ekdt)=="table" and ekdt[1]) or ekdt - end - if not name then - for a in gmatch(attribute or "href","([^|]+)") do - name=ekat[a] - if name then - break - end - end - end - local data=nil - if name and name~="" then - local d,n=loaddata(name) - data=d or "" - name=n or name - if trace_inclusions then - report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") - end - end - if not data or data=="" then - epdt[ek.ni]="" - elseif ekat["parse"]=="text" then - epdt[ek.ni]=xml.escaped(data) - else + pattern=pattern or 'include' + loaddata=loaddata or io.loaddata + local collected=xmlapplylpath(xmldata,pattern) + if collected then + if not level then + level=1 + end + for c=1,#collected do + local ek=collected[c] + local name=nil + local ekdt=ek.dt + if ekdt then + local ekat=ek.at + local ekrt=ek.__p__ + if ekrt then + local epdt=ekrt.dt + if not attribute or attribute=="" then + name=(type(ekdt)=="table" and ekdt[1]) or ekdt + end + if not name then + for a in gmatch(attribute or "href","([^|]+)") do + name=ekat[a] + if name then + break + end + end + end + local data=nil + if name and name~="" then + local d,n=loaddata(name) + data=d or "" + name=n or name + if trace_inclusions then + report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") + end + end + if not data or data=="" then + epdt[ek.ni]="" + elseif ekat["parse"]=="text" then + epdt[ek.ni]=xml.escaped(data) + else local settings=xmldata.settings local savedresource=settings.currentresource settings.currentresource=name - local xi=xmlinheritedconvert(data,xmldata) - if not xi then - epdt[ek.ni]="" - else - if recursive then - include(xi,pattern,attribute,recursive,loaddata,level+1) - end - local child=xml.body(xi) - child.__p__=ekrt - child.__f__=name + local xi=xmlinheritedconvert(data,xmldata) + if not xi then + epdt[ek.ni]="" + else + if recursive then + include(xi,pattern,attribute,recursive,loaddata,level+1) + end + local child=xml.body(xi) + child.__p__=ekrt + child.__f__=name child.cf=name - epdt[ek.ni]=child - local settings=xmldata.settings - local inclusions=settings and settings.inclusions - if inclusions then - inclusions[#inclusions+1]=name - elseif settings then - settings.inclusions={ name } - else - settings={ inclusions={ name } } - xmldata.settings=settings - end - if child.er then - local badinclusions=settings.badinclusions - if badinclusions then - badinclusions[#badinclusions+1]=name - else - settings.badinclusions={ name } - end - end - end -settings.currentresource=savedresource - end + epdt[ek.ni]=child + local settings=xmldata.settings + local inclusions=settings and settings.inclusions + if inclusions then + inclusions[#inclusions+1]=name + elseif settings then + settings.inclusions={ name } + else + settings={ inclusions={ name } } + xmldata.settings=settings + end + if child.er then + local badinclusions=settings.badinclusions + if badinclusions then + badinclusions[#badinclusions+1]=name + else + settings.badinclusions={ name } end + end end +settings.currentresource=savedresource + end end + end end + end end xml.include=include function xml.inclusion(e,default) - while e do - local f=e.__f__ - if f then - return f - else - e=e.__p__ - end + while e do + local f=e.__f__ + if f then + return f + else + e=e.__p__ end - return default + end + return default end local function getinclusions(key,e,sorted) - while e do - local settings=e.settings - if settings then - local inclusions=settings[key] - if inclusions then - inclusions=table.unique(inclusions) - if sorted then - table.sort(inclusions) - end - return inclusions - else - e=e.__p__ - end - else - e=e.__p__ - end + while e do + local settings=e.settings + if settings then + local inclusions=settings[key] + if inclusions then + inclusions=table.unique(inclusions) + if sorted then + table.sort(inclusions) + end + return inclusions + else + e=e.__p__ + end + else + e=e.__p__ end + end end function xml.inclusions(e,sorted) - return getinclusions("inclusions",e,sorted) + return getinclusions("inclusions",e,sorted) end function xml.badinclusions(e,sorted) - return getinclusions("badinclusions",e,sorted) + return getinclusions("badinclusions",e,sorted) end local b_collapser=lpegpatterns.b_collapser local m_collapser=lpegpatterns.m_collapser @@ -15254,194 +18826,194 @@ local b_stripper=lpegpatterns.b_stripper local m_stripper=lpegpatterns.m_stripper local e_stripper=lpegpatterns.e_stripper local function stripelement(e,nolines,anywhere) - local edt=e.dt - if edt then - local n=#edt - if n==0 then - return e - elseif anywhere then - local t={} - local m=0 - for e=1,n do - local str=edt[e] - if type(str)~="string" then - m=m+1 - t[m]=str - elseif str~="" then - if nolines then - str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) - else - str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) - end - if str~="" then - m=m+1 - t[m]=str - end - end - end - e.dt=t + local edt=e.dt + if edt then + local n=#edt + if n==0 then + return e + elseif anywhere then + local t={} + local m=0 + for e=1,n do + local str=edt[e] + if type(str)~="string" then + m=m+1 + t[m]=str + elseif str~="" then + if nolines then + str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) + else + str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) + end + if str~="" then + m=m+1 + t[m]=str + end + end + end + e.dt=t + else + local str=edt[1] + if type(str)=="string" then + if str~="" then + str=lpegmatch(nolines and b_collapser or b_stripper,str) + end + if str=="" then + remove(edt,1) + n=n-1 else - local str=edt[1] - if type(str)=="string" then - if str~="" then - str=lpegmatch(nolines and b_collapser or b_stripper,str) - end - if str=="" then - remove(edt,1) - n=n-1 - else - edt[1]=str - end - end - if n>0 then - str=edt[n] - if type(str)=="string" then - if str=="" then - remove(edt) - else - str=lpegmatch(nolines and e_collapser or e_stripper,str) - if str=="" then - remove(edt) - else - edt[n]=str - end - end - end + edt[1]=str + end + end + if n>0 then + str=edt[n] + if type(str)=="string" then + if str=="" then + remove(edt) + else + str=lpegmatch(nolines and e_collapser or e_stripper,str) + if str=="" then + remove(edt) + else + edt[n]=str end + end end + end end - return e + end + return e end xml.stripelement=stripelement function xml.strip(root,pattern,nolines,anywhere) - local collected=xmlapplylpath(root,pattern) - if collected then - for i=1,#collected do - stripelement(collected[i],nolines,anywhere) - end + local collected=xmlapplylpath(root,pattern) + if collected then + for i=1,#collected do + stripelement(collected[i],nolines,anywhere) end + end end local function renamespace(root,oldspace,newspace) - local ndt=#root.dt - for i=1,ndt or 0 do - local e=root[i] - if type(e)=="table" then - if e.ns==oldspace then - e.ns=newspace - if e.rn then - e.rn=newspace - end - end - local edt=e.dt - if edt then - renamespace(edt,oldspace,newspace) - end + local ndt=#root.dt + for i=1,ndt or 0 do + local e=root[i] + if type(e)=="table" then + if e.ns==oldspace then + e.ns=newspace + if e.rn then + e.rn=newspace end + end + local edt=e.dt + if edt then + renamespace(edt,oldspace,newspace) + end end + end end xml.renamespace=renamespace function xml.remaptag(root,pattern,newtg) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].tg=newtg - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].tg=newtg end + end end function xml.remapnamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].ns=newns - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].ns=newns end + end end function xml.checknamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if (not e.rn or e.rn=="") and e.ns=="" then - e.rn=newns - end - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if (not e.rn or e.rn=="") and e.ns=="" then + e.rn=newns + end end + end end function xml.remapname(root,pattern,newtg,newns,newrn) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - e.tg,e.ns,e.rn=newtg,newns,newrn - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + e.tg,e.ns,e.rn=newtg,newns,newrn end + end end function xml.cdatatotext(e) - local dt=e.dt - if #dt==1 then - local first=dt[1] - if first.tg=="@cd@" then - e.dt=first.dt - end - else + local dt=e.dt + if #dt==1 then + local first=dt[1] + if first.tg=="@cd@" then + e.dt=first.dt end + else + end end function xml.texttocdata(e) - local dt=e.dt - local s=xml.tostring(dt) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(dt) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end function xml.elementtocdata(e) - local dt=e.dt - local s=xml.tostring(e) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(e) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end xml.builtinentities=table.tohash { "amp","quot","apos","lt","gt" } local entities=characters and characters.entities or nil local builtinentities=xml.builtinentities function xml.addentitiesdoctype(root,option) - if not entities then - require("char-ent") - entities=characters.entities - end - if entities and root and root.tg=="@rt@" and root.statistics then - local list={} - local hexify=option=="hexadecimal" - for k,v in table.sortedhash(root.statistics.entities.names) do - if not builtinentities[k] then - local e=entities[k] - if not e then - e=format("[%s]",k) - elseif hexify then - e=format("&#%05X;",utfbyte(k)) - end - list[#list+1]=format(" <!ENTITY %s %q >",k,e) - end - end - local dt=root.dt - local n=dt[1].tg=="@pi@" and 2 or 1 - if #list>0 then - insert(dt,n,{ "\n" }) - insert(dt,n,{ - tg="@dt@", - dt={ format("Something [\n%s\n] ",concat(list)) }, - ns="", - special=true, - }) - insert(dt,n,{ "\n\n" }) - else - end + if not entities then + require("char-ent") + entities=characters.entities + end + if entities and root and root.tg=="@rt@" and root.statistics then + local list={} + local hexify=option=="hexadecimal" + for k,v in table.sortedhash(root.statistics.entities.names) do + if not builtinentities[k] then + local e=entities[k] + if not e then + e=format("[%s]",k) + elseif hexify then + e=format("&#%05X;",utfbyte(k)) + end + list[#list+1]=format(" <!ENTITY %s %q >",k,e) + end end + local dt=root.dt + local n=dt[1].tg=="@pi@" and 2 or 1 + if #list>0 then + insert(dt,n,{ "\n" }) + insert(dt,n,{ + tg="@dt@", + dt={ format("Something [\n%s\n] ",concat(list)) }, + ns="", + special=true, + }) + insert(dt,n,{ "\n\n" }) + else + end + end end xml.all=xml.each xml.insert=xml.insertafter @@ -15451,239 +19023,241 @@ xml.before=xml.insertbefore xml.process=xml.each xml.obsolete=xml.obsolete or {} local obsolete=xml.obsolete -xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip -xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect -xml.delete_element=xml.delete obsolete.delete_element=xml.delete -xml.replace_element=xml.replace obsolete.replace_element=xml.replace -xml.each_element=xml.each obsolete.each_element=xml.each -xml.process_elements=xml.process obsolete.process_elements=xml.process -xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter -xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore -xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter -xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore -xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes -xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts -xml.inject_element=xml.inject obsolete.inject_element=xml.inject -xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag -xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname -xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace +xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip +xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect +xml.delete_element=xml.delete obsolete.delete_element=xml.delete +xml.replace_element=xml.replace obsolete.replace_element=xml.replace +xml.each_element=xml.each obsolete.each_element=xml.each +xml.process_elements=xml.process obsolete.process_elements=xml.process +xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter +xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore +xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter +xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore +xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes +xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts +xml.inject_element=xml.inject obsolete.inject_element=xml.inject +xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag +xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname +xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace function xml.cdata(e) - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" end - return "" + end + return "" end function xml.finalizers.xml.cdata(collected) - if collected then - local e=collected[1] - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end - end + if collected then + local e=collected[1] + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" + end end - return "" + end + return "" end function xml.insertcomment(e,str,n) - insert(e.dt,n or 1,{ - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.insertcdata(e,str,n) - insert(e.dt,n or 1,{ - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.setcomment(e,str,n) - e.dt={ { - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.setcdata(e,str) - e.dt={ { - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.separate(x,pattern) - local collected=xmlapplylpath(x,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local d=e.dt - if d==x then - report_xml("warning: xml.separate changes root") - x=d - end - local t,n={ "\n" },1 - local i,nd=1,#d - while i<=nd do - while i<=nd do - local di=d[i] - if type(di)=="string" then - if di=="\n" or find(di,"^%s+$") then - i=i+1 - else - d[i]=strip(di) - break - end - else - break - end - end - if i>nd then - break - end - t[n+1]="\n" - t[n+2]=d[i] - t[n+3]="\n" - n=n+3 - i=i+1 + local collected=xmlapplylpath(x,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local d=e.dt + if d==x then + report_xml("warning: xml.separate changes root") + x=d + end + local t={ "\n" } + local n=1 + local i=1 + local nd=#d + while i<=nd do + while i<=nd do + local di=d[i] + if type(di)=="string" then + if di=="\n" or find(di,"^%s+$") then + i=i+1 + else + d[i]=strip(di) + break end - t[n+1]="\n" - setmetatable(t,getmetatable(d)) - e.dt=t + else + break + end + end + if i>nd then + break end + t[n+1]="\n" + t[n+2]=d[i] + t[n+3]="\n" + n=n+3 + i=i+1 + end + t[n+1]="\n" + setmetatable(t,getmetatable(d)) + e.dt=t end - return x + end + return x end local helpers=xml.helpers or {} xml.helpers=helpers local function normal(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)=="string" and str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)=="string" and str~="" then + edt[i]=action(str) + end end + end end local function recurse(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)~="string" then - recurse(str,action) - elseif str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)~="string" then + recurse(str,action) + elseif str~="" then + edt[i]=action(str) + end end + end end function helpers.recursetext(collected,action,recursive) - if recursive then - for i=1,#collected do - recurse(collected[i],action) - end - else - for i=1,#collected do - normal(collected[i],action) - end + if recursive then + for i=1,#collected do + recurse(collected[i],action) end + else + for i=1,#collected do + normal(collected[i],action) + end + end end local specials={ - ["@rt@"]="root", - ["@pi@"]="instruction", - ["@cm@"]="comment", - ["@dt@"]="declaration", - ["@cd@"]="cdata", + ["@rt@"]="root", + ["@pi@"]="instruction", + ["@cm@"]="comment", + ["@dt@"]="declaration", + ["@cd@"]="cdata", } local function convert(x,strip,flat) - local ns=x.ns - local tg=x.tg - local at=x.at - local dt=x.dt - local node=flat and { - [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, - } or { - _namespace=ns~="" and ns or nil, - _tag=not x.special and tg or nil, - _type=specials[tg] or "_element", - } - if at then - for k,v in next,at do - node[k]=v - end - end - local n=0 - for i=1,#dt do - local di=dt[i] - if type(di)=="table" then - if flat and di.special then - else - di=convert(di,strip,flat) - if di then - n=n+1 - node[n]=di - end - end - elseif strip then - di=lpegmatch(strip,di) - if di~="" then - n=n+1 - node[n]=di - end - else - n=n+1 - node[n]=di + local ns=x.ns + local tg=x.tg + local at=x.at + local dt=x.dt + local node=flat and { + [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, + } or { + _namespace=ns~="" and ns or nil, + _tag=not x.special and tg or nil, + _type=specials[tg] or "_element", + } + if at then + for k,v in next,at do + node[k]=v + end + end + local n=0 + for i=1,#dt do + local di=dt[i] + if type(di)=="table" then + if flat and di.special then + else + di=convert(di,strip,flat) + if di then + n=n+1 + node[n]=di end + end + elseif strip then + di=lpegmatch(strip,di) + if di~="" then + n=n+1 + node[n]=di + end + else + n=n+1 + node[n]=di end - if next(node) then - return node - end + end + if next(node) then + return node + end end function xml.totable(x,strip,flat) - if type(x)=="table" then - if strip then - strip=striplinepatterns[strip] - end - return convert(x,strip,flat) + if type(x)=="table" then + if strip then + strip=striplinepatterns[strip] end + return convert(x,strip,flat) + end end function xml.rename(e,namespace,name,attributes) - if type(e)~="table" or not e.tg then - return - end - if type(name)=="table" then - attributes=name - name=namespace - namespace="" - elseif type(name)~="string" then - attributes={} - name=namespace - namespace="" - end - if type(attributes)~="table" then - attributes={} - end - e.ns=namespace - e.rn=namespace - e.tg=name - e.at=attributes + if type(e)~="table" or not e.tg then + return + end + if type(name)=="table" then + attributes=name + name=namespace + namespace="" + elseif type(name)~="string" then + attributes={} + name=namespace + namespace="" + end + if type(attributes)~="table" then + attributes={} + end + e.ns=namespace + e.rn=namespace + e.tg=name + e.at=attributes end @@ -15693,14 +19267,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-xml"] = package.loaded["lxml-xml"] or true --- original size: 11096, stripped down to: 8243 +-- original size: 11096, stripped down to: 7702 if not modules then modules={} end modules ['lxml-xml']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tonumber,next=tonumber,next local concat=table.concat @@ -15712,241 +19286,241 @@ local xmltostring=xml.tostring local xmlserialize=xml.serialize local xmlcollected=xml.collected local xmlnewhandlers=xml.newhandlers -local reparsedentity=xml.reparsedentitylpeg +local reparsedentity=xml.reparsedentitylpeg local unescapedentity=xml.unescapedentitylpeg local parsedentity=reparsedentity local function first(collected) - return collected and collected[1] + return collected and collected[1] end local function last(collected) - return collected and collected[#collected] + return collected and collected[#collected] end local function all(collected) - return collected + return collected end local reverse=table.reversed local function attribute(collected,name) - if collected and #collected>0 then - local at=collected[1].at - return at and at[name] - end + if collected and #collected>0 then + local at=collected[1].at + return at and at[name] + end end local function att(id,name) - local at=id.at - return at and at[name] + local at=id.at + return at and at[name] end local function count(collected) - return collected and #collected or 0 + return collected and #collected or 0 end local function position(collected,n) - if not collected then - return 0 - end - local nc=#collected - if nc==0 then - return 0 - end - n=tonumber(n) or 0 - if n<0 then - return collected[nc+n+1] - elseif n>0 then - return collected[n] - else - return collected[1].mi or 0 - end + if not collected then + return 0 + end + local nc=#collected + if nc==0 then + return 0 + end + n=tonumber(n) or 0 + if n<0 then + return collected[nc+n+1] + elseif n>0 then + return collected[n] + else + return collected[1].mi or 0 + end end local function match(collected) - return collected and #collected>0 and collected[1].mi or 0 + return collected and #collected>0 and collected[1].mi or 0 end local function index(collected) - return collected and #collected>0 and collected[1].ni or 0 + return collected and #collected>0 and collected[1].ni or 0 end local function attributes(collected,arguments) - if collected and #collected>0 then - local at=collected[1].at - if arguments then - return at[arguments] - elseif next(at) then - return at - end + if collected and #collected>0 then + local at=collected[1].at + if arguments then + return at[arguments] + elseif next(at) then + return at end + end end local function chainattribute(collected,arguments) - if collected and #collected>0 then - local e=collected[1] - while e do - local at=e.at - if at then - local a=at[arguments] - if a then - return a - end - else - break - end - e=e.__p__ + if collected and #collected>0 then + local e=collected[1] + while e do + local at=e.at + if at then + local a=at[arguments] + if a then + return a end + else + break + end + e=e.__p__ end - return "" + end + return "" end local function raw(collected) - if collected and #collected>0 then - local e=collected[1] or collected - return e and xmltostring(e) or "" - else - return "" - end + if collected and #collected>0 then + local e=collected[1] or collected + return e and xmltostring(e) or "" + else + return "" + end end local xmltexthandler=xmlnewhandlers { - name="string", - initialize=function() - result={} - return result - end, - finalize=function() - return concat(result) - end, - handle=function(...) - result[#result+1]=concat {... } - end, - escape=false, + name="string", + initialize=function() + result={} + return result + end, + finalize=function() + return concat(result) + end, + handle=function(...) + result[#result+1]=concat {... } + end, + escape=false, } local function xmltotext(root) - local dt=root.dt - if not dt then - return "" - end - local nt=#dt - if nt==0 then - return "" - elseif nt==1 and type(dt[1])=="string" then - return dt[1] - else - return xmlserialize(root,xmltexthandler) or "" - end + local dt=root.dt + if not dt then + return "" + end + local nt=#dt + if nt==0 then + return "" + elseif nt==1 and type(dt[1])=="string" then + return dt[1] + else + return xmlserialize(root,xmltexthandler) or "" + end end function xml.serializetotext(root) - return root and xmlserialize(root,xmltexthandler) or "" + return root and xmlserialize(root,xmltexthandler) or "" end local function text(collected) - if collected then - local e=collected[1] or collected - return e and xmltotext(e) or "" - else - return "" - end + if collected then + local e=collected[1] or collected + return e and xmltotext(e) or "" + else + return "" + end end local function texts(collected) - if not collected then - return {} - end - local nc=#collected - if nc==0 then - return {} - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - if e and e.dt then - n=n+1 - t[n]=e.dt - end - end - return t + if not collected then + return {} + end + local nc=#collected + if nc==0 then + return {} + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + if e and e.dt then + n=n+1 + t[n]=e.dt + end + end + return t end local function tag(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - return c and c.tg + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + return c and c.tg end local function name(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - if not c then - elseif c.ns=="" then - return c.tg - else - return c.ns..":"..c.tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + if not c then + elseif c.ns=="" then + return c.tg + else + return c.ns..":"..c.tg + end end local function tags(collected,nonamespace) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace or ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + local ns,tg=e.ns,e.tg + n=n+1 + if nonamespace or ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg end - return t + end + return t end local function empty(collected,spacesonly) - if not collected then - return true - end - local nc=#collected - if nc==0 then - return true - end - for c=1,nc do - local e=collected[c] - if e then - local edt=e.dt - if edt then - local n=#edt - if n==1 then - local edk=edt[1] - local typ=type(edk) - if typ=="table" then - return false - elseif edk~="" then - return false - elseif spacesonly and not find(edk,"%S") then - return false - end - elseif n>1 then - return false - end - end + if not collected then + return true + end + local nc=#collected + if nc==0 then + return true + end + for c=1,nc do + local e=collected[c] + if e then + local edt=e.dt + if edt then + local n=#edt + if n==1 then + local edk=edt[1] + local typ=type(edk) + if typ=="table" then + return false + elseif edk~="" then + return false + elseif spacesonly and not find(edk,"%S") then + return false + end + elseif n>1 then + return false end + end end - return true + end + return true end finalizers.first=first finalizers.last=last @@ -15969,124 +19543,124 @@ finalizers.name=name finalizers.tags=tags finalizers.empty=empty function xml.first(id,pattern) - return first(xmlfilter(id,pattern)) + return first(xmlfilter(id,pattern)) end function xml.last(id,pattern) - return last(xmlfilter(id,pattern)) + return last(xmlfilter(id,pattern)) end function xml.count(id,pattern) - return count(xmlfilter(id,pattern)) + return count(xmlfilter(id,pattern)) end function xml.attribute(id,pattern,a,default) - return attribute(xmlfilter(id,pattern),a,default) + return attribute(xmlfilter(id,pattern),a,default) end function xml.raw(id,pattern) - if pattern then - return raw(xmlfilter(id,pattern)) - else - return raw(id) - end + if pattern then + return raw(xmlfilter(id,pattern)) + else + return raw(id) + end end function xml.text(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - return collected and #collected>0 and xmltotext(collected[1]) or "" - elseif id then - return xmltotext(id) or "" - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + return collected and #collected>0 and xmltotext(collected[1]) or "" + elseif id then + return xmltotext(id) or "" + else + return "" + end end function xml.pure(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - if collected and #collected>0 then - parsedentity=unescapedentity - local s=collected and #collected>0 and xmltotext(collected[1]) or "" - parsedentity=reparsedentity - return s - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + if collected and #collected>0 then + parsedentity=unescapedentity + local s=collected and #collected>0 and xmltotext(collected[1]) or "" + parsedentity=reparsedentity + return s else - parsedentity=unescapedentity - local s=xmltotext(id) or "" - parsedentity=reparsedentity - return s + return "" end + else + parsedentity=unescapedentity + local s=xmltotext(id) or "" + parsedentity=reparsedentity + return s + end end xml.content=text function xml.position(id,pattern,n) - return position(xmlfilter(id,pattern),n) + return position(xmlfilter(id,pattern),n) end function xml.match(id,pattern) - return match(xmlfilter(id,pattern)) + return match(xmlfilter(id,pattern)) end function xml.empty(id,pattern,spacesonly) - return empty(xmlfilter(id,pattern),spacesonly) + return empty(xmlfilter(id,pattern),spacesonly) end xml.all=xml.filter xml.index=xml.position xml.found=xml.filter local function totable(x) - local t={} - for e in xmlcollected(x[1] or x,"/*") do - t[e.tg]=xmltostring(e.dt) or "" - end - return next(t) and t or nil + local t={} + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg]=xmltostring(e.dt) or "" + end + return next(t) and t or nil end xml.table=totable finalizers.table=totable local function textonly(e,t) - if e then - local edt=e.dt - if edt then - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - textonly(e,t) - else - t[#t+1]=e - end - end + if e then + local edt=e.dt + if edt then + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + textonly(e,t) + else + t[#t+1]=e end + end end - return t + end + return t end function xml.textonly(e) - return concat(textonly(e,{})) + return concat(textonly(e,{})) end function finalizers.lowerall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=lower(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[lower(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=lower(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[lower(k)]=v end + e.at=t + end end + end end function finalizers.upperall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=upper(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[upper(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=upper(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[upper(k)]=v end + e.at=t + end end + end end @@ -16096,14 +19670,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-xml"] = package.loaded["trac-xml"] or true --- original size: 6407, stripped down to: 4965 +-- original size: 6407, stripped down to: 4640 if not modules then modules={} end modules ['trac-xml']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local formatters=string.formatters local reporters=logs.reporters @@ -16112,152 +19686,152 @@ local xmlcollected=xml.collected local xmltext=xml.text local xmlfirst=xml.first local function showhelp(specification,...) - local root=xml.convert(specification.helpinfo or "") - if not root then - return - end - local xs=xml.gethandlers("string") - xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) - xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) - local wantedcategories=select("#",...)==0 and true or table.tohash {... } - local nofcategories=xml.count(root,"/application/flags/category") - local report=specification.report - for category in xmlcollected(root,"/application/flags/category") do - local categoryname=category.at.name or "" - if wantedcategories==true or wantedcategories[categoryname] then - if nofcategories>1 then - report("%s options:",categoryname) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for flag in xmlcollected(subcategory,"/flag") do - local name=flag.at.name - local value=flag.at.value - local short=xmltext(xmlfirst(flag,"/short")) - if value then - report("--%-20s %s",formatters["%s=%s"](name,value),short) - else - report("--%-20s %s",name,short) - end - end - report() - end - end - end - for category in xmlcollected(root,"/application/examples/category") do - local title=xmltext(xmlfirst(category,"/title")) - if title and title~="" then - report() - report(title) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for example in xmlcollected(subcategory,"/example") do - local command=xmltext(xmlfirst(example,"/command")) - local comment=xmltext(xmlfirst(example,"/comment")) - report(command) - end - report() - end - end - for comment in xmlcollected(root,"/application/comments/comment") do - local comment=xmltext(comment) + local root=xml.convert(specification.helpinfo or "") + if not root then + return + end + local xs=xml.gethandlers("string") + xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) + xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) + local wantedcategories=select("#",...)==0 and true or table.tohash {... } + local nofcategories=xml.count(root,"/application/flags/category") + local report=specification.report + for category in xmlcollected(root,"/application/flags/category") do + local categoryname=category.at.name or "" + if wantedcategories==true or wantedcategories[categoryname] then + if nofcategories>1 then + report("%s options:",categoryname) report() - report(comment) + end + for subcategory in xmlcollected(category,"/subcategory") do + for flag in xmlcollected(subcategory,"/flag") do + local name=flag.at.name + local value=flag.at.value + local short=xmltext(xmlfirst(flag,"/short")) + if value then + report("--%-20s %s",formatters["%s=%s"](name,value),short) + else + report("--%-20s %s",name,short) + end + end report() + end + end + end + for category in xmlcollected(root,"/application/examples/category") do + local title=xmltext(xmlfirst(category,"/title")) + if title and title~="" then + report() + report(title) + report() + end + for subcategory in xmlcollected(category,"/subcategory") do + for example in xmlcollected(subcategory,"/example") do + local command=xmltext(xmlfirst(example,"/command")) + local comment=xmltext(xmlfirst(example,"/comment")) + report(command) + end + report() end + end + for comment in xmlcollected(root,"/application/comments/comment") do + local comment=xmltext(comment) + report() + report(comment) + report() + end end local reporthelp=reporters.help local exporthelp=reporters.export local function xmlfound(t) - local helpinfo=t.helpinfo - if type(helpinfo)=="table" then - return false + local helpinfo=t.helpinfo + if type(helpinfo)=="table" then + return false + end + if type(helpinfo)~="string" then + helpinfo="Warning: no helpinfo found." + t.helpinfo=helpinfo + return false + end + if string.find(helpinfo,".xml$") then + local ownscript=environment.ownscript + local helpdata=false + if ownscript then + local helpfile=file.join(file.pathpart(ownscript),helpinfo) + helpdata=io.loaddata(helpfile) + if helpdata=="" then + helpdata=false + end end - if type(helpinfo)~="string" then - helpinfo="Warning: no helpinfo found." - t.helpinfo=helpinfo - return false + if not helpdata then + local helpfile=resolvers.findfile(helpinfo,"tex") + helpdata=helpfile and io.loaddata(helpfile) end - if string.find(helpinfo,".xml$") then - local ownscript=environment.ownscript - local helpdata=false - if ownscript then - local helpfile=file.join(file.pathpart(ownscript),helpinfo) - helpdata=io.loaddata(helpfile) - if helpdata=="" then - helpdata=false - end - end - if not helpdata then - local helpfile=resolvers.findfile(helpinfo,"tex") - helpdata=helpfile and io.loaddata(helpfile) - end - if helpdata and helpdata~="" then - helpinfo=helpdata - else - helpinfo=formatters["Warning: help file %a is not found."](helpinfo) - end + if helpdata and helpdata~="" then + helpinfo=helpdata + else + helpinfo=formatters["Warning: help file %a is not found."](helpinfo) end - t.helpinfo=helpinfo - return string.find(t.helpinfo,"^<%?xml") and true or false + end + t.helpinfo=helpinfo + return string.find(t.helpinfo,"^<%?xml") and true or false end function reporters.help(t,...) - if xmlfound(t) then - showhelp(t,...) - else - reporthelp(t,...) - end + if xmlfound(t) then + showhelp(t,...) + else + reporthelp(t,...) + end end function reporters.export(t,methods,filename) - if not xmlfound(t) then - return exporthelp(t) - end - if not methods or methods=="" then - methods=environment.arguments["exporthelp"] - end - if not filename or filename=="" then - filename=environment.files[1] - end - dofile(resolvers.findfile("trac-exp.lua","tex")) - local exporters=logs.exporters - if not exporters or not methods then - return exporthelp(t) - end - if methods=="all" then - methods=table.keys(exporters) - elseif type(methods)=="string" then - methods=utilities.parsers.settings_to_array(methods) - else - return exporthelp(t) - end - if type(filename)~="string" or filename=="" then - filename=false - elseif file.pathpart(filename)=="" then - t.report("export file %a will not be saved on the current path (safeguard)",filename) - return - end - for i=1,#methods do - local method=methods[i] - local exporter=exporters[method] - if exporter then - local result=exporter(t,method) - if result and result~="" then - if filename then - local fullname=file.replacesuffix(filename,method) - t.report("saving export in %a",fullname) - dir.mkdirs(file.pathpart(fullname)) - io.savedata(fullname,result) - else - reporters.lines(t,result) - end - else - t.report("no output from exporter %a",method) - end + if not xmlfound(t) then + return exporthelp(t) + end + if not methods or methods=="" then + methods=environment.arguments["exporthelp"] + end + if not filename or filename=="" then + filename=environment.files[1] + end + dofile(resolvers.findfile("trac-exp.lua","tex")) + local exporters=logs.exporters + if not exporters or not methods then + return exporthelp(t) + end + if methods=="all" then + methods=table.keys(exporters) + elseif type(methods)=="string" then + methods=utilities.parsers.settings_to_array(methods) + else + return exporthelp(t) + end + if type(filename)~="string" or filename=="" then + filename=false + elseif file.pathpart(filename)=="" then + t.report("export file %a will not be saved on the current path (safeguard)",filename) + return + end + for i=1,#methods do + local method=methods[i] + local exporter=exporters[method] + if exporter then + local result=exporter(t,method) + if result and result~="" then + if filename then + local fullname=file.replacesuffix(filename,method) + t.report("saving export in %a",fullname) + dir.mkdirs(file.pathpart(fullname)) + io.savedata(fullname,result) else - t.report("unknown exporter %a",method) + reporters.lines(t,result) end + else + t.report("no output from exporter %a",method) + end + else + t.report("unknown exporter %a",method) end + end end @@ -16267,149 +19841,149 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 11099, stripped down to: 7516 +-- original size: 11099, stripped down to: 7152 if not modules then modules={} end modules ['data-ini']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false texconfig.shell_escape='t' if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then - local default_texmfcnf=kpse.default_texmfcnf() - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") - default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") - environment.default_texmfcnf=default_texmfcnf + local default_texmfcnf=kpse.default_texmfcnf() + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") + default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") + environment.default_texmfcnf=default_texmfcnf end kpse={ original=kpse } setmetatable(kpse,{ - __index=function(kp,name) - report_initialization("fatal error: kpse library is accessed (key: %s)",name) - os.exit() - end + __index=function(kp,name) + report_initialization("fatal error: kpse library is accessed (key: %s)",name) + os.exit() + end } ) do - local osfontdir=osgetenv("OSFONTDIR") - if osfontdir and osfontdir~="" then - elseif osname=="windows" then - ossetenv("OSFONTDIR","c:/windows/fonts//") - elseif osname=="macosx" then - ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") - end + local osfontdir=osgetenv("OSFONTDIR") + if osfontdir and osfontdir~="" then + elseif osname=="windows" then + ossetenv("OSFONTDIR","c:/windows/fonts//") + elseif osname=="macosx" then + ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") + end end do - local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' - if not homedir or homedir=="" then - homedir=char(127) - end - homedir=file.collapsepath(homedir) - ossetenv("HOME",homedir) - ossetenv("USERPROFILE",homedir) - environment.homedir=homedir + local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' + if not homedir or homedir=="" then + homedir=char(127) + end + homedir=file.collapsepath(homedir) + ossetenv("HOME",homedir) + ossetenv("USERPROFILE",homedir) + environment.homedir=homedir end do - local args=environment.originalarguments or arg - if not environment.ownmain then - environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" - end - local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" - local ownpath=environment.ownpath or os.selfdir - ownbin=file.collapsepath(ownbin) - ownpath=file.collapsepath(ownpath) - if not ownpath or ownpath=="" or ownpath=="unset" then - ownpath=args[-1] or arg[-1] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - if not ownpath or ownpath=="" then - ownpath=args[-0] or arg[-0] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - end - local binary=ownbin - if not ownpath or ownpath=="" then - ownpath=ownpath and filedirname(binary) - end - if not ownpath or ownpath=="" then - if os.binsuffix~="" then - binary=file.replacesuffix(binary,os.binsuffix) - end - local path=osgetenv("PATH") - if path then - for p in gmatch(path,"[^"..io.pathseparator.."]+") do - local b=filejoin(p,binary) - if lfs.isfile(b) then - local olddir=lfs.currentdir() - if lfs.chdir(p) then - local pp=lfs.currentdir() - if trace_locating and p~=pp then - report_initialization("following symlink %a to %a",p,pp) - end - ownpath=pp - lfs.chdir(olddir) - else - if trace_locating then - report_initialization("unable to check path %a",p) - end - ownpath=p - end - break - end - end + local args=environment.originalarguments or arg + if not environment.ownmain then + environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" + end + local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" + local ownpath=environment.ownpath or os.selfdir + ownbin=file.collapsepath(ownbin) + ownpath=file.collapsepath(ownpath) + if not ownpath or ownpath=="" or ownpath=="unset" then + ownpath=args[-1] or arg[-1] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + if not ownpath or ownpath=="" then + ownpath=args[-0] or arg[-0] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + end + local binary=ownbin + if not ownpath or ownpath=="" then + ownpath=ownpath and filedirname(binary) + end + if not ownpath or ownpath=="" then + if os.binsuffix~="" then + binary=file.replacesuffix(binary,os.binsuffix) + end + local path=osgetenv("PATH") + if path then + for p in gmatch(path,"[^"..io.pathseparator.."]+") do + local b=filejoin(p,binary) + if lfs.isfile(b) then + local olddir=lfs.currentdir() + if lfs.chdir(p) then + local pp=lfs.currentdir() + if trace_locating and p~=pp then + report_initialization("following symlink %a to %a",p,pp) + end + ownpath=pp + lfs.chdir(olddir) + else + if trace_locating then + report_initialization("unable to check path %a",p) + end + ownpath=p end + break + end end - if not ownpath or ownpath=="" then - ownpath="." - report_initialization("forcing fallback to ownpath %a",ownpath) - elseif trace_locating then - report_initialization("using ownpath %a",ownpath) - end + end end - environment.ownbin=ownbin - environment.ownpath=ownpath + if not ownpath or ownpath=="" then + ownpath="." + report_initialization("forcing fallback to ownpath %a",ownpath) + elseif trace_locating then + report_initialization("using ownpath %a",ownpath) + end + end + environment.ownbin=ownbin + environment.ownpath=ownpath end resolvers.ownpath=environment.ownpath function resolvers.getownpath() - return environment.ownpath + return environment.ownpath end do - local ownpath=environment.ownpath or dir.current() - if ownpath then - ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) - ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) - ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) - else - report_initialization("error: unable to locate ownpath") - os.exit() - end -end -local texos=environment.texos or osgetenv("TEXOS") + local ownpath=environment.ownpath or dir.current() + if ownpath then + ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) + ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) + ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) + else + report_initialization("error: unable to locate ownpath") + os.exit() + end +end +local texos=environment.texos or osgetenv("TEXOS") local texmfos=environment.texmfos or osgetenv('SELFAUTODIR') if not texos or texos=="" then - texos=file.basename(texmfos) + texos=file.basename(texmfos) end ossetenv('TEXMFOS',texmfos) -ossetenv('TEXOS',texos) -ossetenv('SELFAUTOSYSTEM',os.platform) +ossetenv('TEXOS',texos) +ossetenv('SELFAUTOSYSTEM',os.platform) environment.texos=texos environment.texmfos=texmfos local texroot=environment.texroot or osgetenv("TEXROOT") if not texroot or texroot=="" then - texroot=osgetenv('SELFAUTOPARENT') - ossetenv('TEXROOT',texroot) + texroot=osgetenv('SELFAUTOPARENT') + ossetenv('TEXROOT',texroot) end environment.texroot=file.collapsepath(texroot) local prefixes=utilities.storage.allocate() @@ -16418,30 +19992,30 @@ local resolved={} local abstract={} local dynamic={} function resolvers.resetresolve(str) - resolved,abstract={},{} + resolved,abstract={},{} end function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" end - return all + end + return all end local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end end function resolvers.unresolve(str) - return abstract[str] or str + return abstract[str] or str end function resolvers.setdynamic(str) - dynamic[str]=true + dynamic[str]=true end local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) local prefix=C(R("az")^2)*P(":") @@ -16450,65 +20024,65 @@ local notarget=(#S(";,")+P(-1))*Cc("") local p_resolve=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) local p_simple=prefix*P(-1) local function resolve(str) - if type(str)=="table" then - local res={} - for i=1,#str do - res[i]=resolve(str[i]) - end - return res - end - local res=resolved[str] - if res then - return res + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) end - local simple=lpegmatch(p_simple,str) - local action=prefixes[simple] - if action then - local res=action(res) - if not dynamic[simple] then - resolved[simple]=res - abstract[res]=simple - end - return res + return res + end + local res=resolved[str] + if res then + return res + end + local simple=lpegmatch(p_simple,str) + local action=prefixes[simple] + if action then + local res=action(res) + if not dynamic[simple] then + resolved[simple]=res + abstract[res]=simple end - res=lpegmatch(p_resolve,str) - resolved[str]=res - abstract[res]=str return res + end + res=lpegmatch(p_resolve,str) + resolved[str]=res + abstract[res]=str + return res end resolvers.resolve=resolve if type(osuname)=="function" then - for k,v in next,osuname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end end + end end if ostype=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - table.setmetatablenewindex(prefixes,makepattern) - function resolvers.repath(str) - return lpegmatch(pattern,str) + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end else - function resolvers.repath(str) - return str - end + function resolvers.repath(str) + return str + end end @@ -16518,14 +20092,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 18105, stripped down to: 11207 +-- original size: 18105, stripped down to: 10389 if not modules then modules={} end modules ['data-exp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } 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 @@ -16535,21 +20109,21 @@ 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 isdir=lfs.isdir local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers local resolveprefix=resolvers.resolve local function f_both(a,b) - local t,n={},0 - for sb in gmatch(b,"[^,]+") do - for sa in gmatch(a,"[^,]+") do - n=n+1;t[n]=sa..sb - end + local t,n={},0 + for sb in gmatch(b,"[^,]+") do + for sa in gmatch(a,"[^,]+") do + n=n+1;t[n]=sa..sb end - return concat(t,",") + end + return concat(t,",") end local comma=P(",") local nocomma=(1-comma)^1 @@ -16559,7 +20133,7 @@ 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 function f_both (a,b) return lpegmatch(both,b,1,a) end local left=P("{") local right=P("}") local var=P((1-S("{}" ))^0) @@ -16572,141 +20146,141 @@ local l_rest=Cs((left*var*(left/"")*var*(right/"")*var*right+other )^0 ) local stripper_1=lpeg.stripper ("{}@") local replacer_1=lpeg.replacer { { ",}",",@}" },{ "{,","{@," },} local function splitpathexpr(str,newlist,validate) - if trace_expansions then - report_expansions("expanding variable %a",str) - end - local t,ok,done=newlist or {},false,false - local n=#t - str=lpegmatch(replacer_1,str) + if trace_expansions then + report_expansions("expanding variable %a",str) + end + local t,ok,done=newlist or {},false,false + local n=#t + str=lpegmatch(replacer_1,str) + repeat + local old=str repeat - local old=str - repeat - local old=str - str=lpegmatch(l_first,str) - until old==str - repeat - local old=str - str=lpegmatch(l_second,str) - until old==str - repeat - local old=str - str=lpegmatch(l_both,str) - until old==str - repeat - local old=str - str=lpegmatch(l_rest,str) - until old==str - until old==str - str=lpegmatch(stripper_1,str) - if validate then - for s in gmatch(str,"[^,]+") do - s=validate(s) - if s then - n=n+1 - t[n]=s - end - end - else - for s in gmatch(str,"[^,]+") do - n=n+1 - t[n]=s - end + local old=str + str=lpegmatch(l_first,str) + until old==str + repeat + local old=str + str=lpegmatch(l_second,str) + until old==str + repeat + local old=str + str=lpegmatch(l_both,str) + until old==str + repeat + local old=str + str=lpegmatch(l_rest,str) + until old==str + until old==str + str=lpegmatch(stripper_1,str) + if validate then + for s in gmatch(str,"[^,]+") do + s=validate(s) + if s then + n=n+1 + t[n]=s + end end - if trace_expansions then - for k=1,#t do - report_expansions("% 4i: %s",k,t[k]) - end + else + for s in gmatch(str,"[^,]+") do + n=n+1 + t[n]=s end - return t + end + if trace_expansions then + for k=1,#t do + report_expansions("% 4i: %s",k,t[k]) + end + end + return t end local function validate(s) - s=collapsepath(s) - return s~="" and not find(s,"^!*unset/*$") and s + s=collapsepath(s) + return s~="" and not find(s,"^!*unset/*$") and s end resolvers.validatedpath=validate function resolvers.expandedpathfromlist(pathlist) - local newlist={} - for k=1,#pathlist do - splitpathexpr(pathlist[k],newlist,validate) - end - return newlist + local newlist={} + for k=1,#pathlist do + splitpathexpr(pathlist[k],newlist,validate) + end + return newlist end local usedhomedir=nil -local donegation=(P("!")/"" )^0 +local donegation=(P("!")/"" )^0 local doslashes=(P("\\")/"/"+1)^0 local function expandedhome() - if not usedhomedir then - usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent path using current path") - end - usedhomedir="." - end + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") + end + usedhomedir="." end - return usedhomedir + end + return usedhomedir end local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 local cleanup=Cs(donegation*dohome*doslashes) resolvers.cleanpath=function(str) - return str and lpegmatch(cleanup,str) or "" + return str and lpegmatch(cleanup,str) or "" end local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" -local dostring=(expandhome+1 )^0 +local dostring=(expandhome+1 )^0 local stripper=Cs( - lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer + lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer ) function resolvers.checkedvariable(str) - return type(str)=="string" and lpegmatch(stripper,str) or str + return type(str)=="string" and lpegmatch(stripper,str) or str end local cache={} local splitter=lpeg.tsplitat(";") local backslashswapper=lpeg.replacer("\\","/") local function splitconfigurationpath(str) - if str then - local found=cache[str] - if not found then - if str=="" then - found={} - else - local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) - found={} - local noffound=0 - for i=1,#split do - local s=split[i] - if not find(s,"^{*unset}*") then - noffound=noffound+1 - found[noffound]=s - end - end - if trace_expansions then - report_expansions("splitting path specification %a",str) - for k=1,noffound do - report_expansions("% 4i: %s",k,found[k]) - end - end - cache[str]=found - end + if str then + local found=cache[str] + if not found then + if str=="" then + found={} + else + local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) + found={} + local noffound=0 + for i=1,#split do + local s=split[i] + if not find(s,"^{*unset}*") then + noffound=noffound+1 + found[noffound]=s + end end - return found + if trace_expansions then + report_expansions("splitting path specification %a",str) + for k=1,noffound do + report_expansions("% 4i: %s",k,found[k]) + end + end + cache[str]=found + end end + return found + end end resolvers.splitconfigurationpath=splitconfigurationpath function resolvers.splitpath(str) - if type(str)=='table' then - return str - else - return splitconfigurationpath(str) - end + if type(str)=='table' then + return str + else + return splitconfigurationpath(str) + end end function resolvers.joinpath(str) - if type(str)=='table' then - return joinpath(str) - else - return str - end + if type(str)=='table' then + return joinpath(str) + else + return str + end end local attributes,directory=lfs.attributes,lfs.dir local weird=P(".")^1+lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) @@ -16719,201 +20293,201 @@ local fullcache={} local nofsharedscans=0 local addcasecraptoo=true local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant) - local full=path=="" and spec or (spec..path..'/') - local dirlist={} - local nofdirs=0 - local pattern=tolerant and lessweird or weird - local filelist={} - local noffiles=0 - for name in directory(full) do - if not lpegmatch(pattern,name) then - local mode=attributes(full..name,"mode") - if mode=="file" then - n=n+1 - noffiles=noffiles+1 - filelist[noffiles]=name - elseif mode=="directory" then - m=m+1 - nofdirs=nofdirs+1 - if path~="" then - dirlist[nofdirs]=path.."/"..name - else - dirlist[nofdirs]=name - end - end + local full=path=="" and spec or (spec..path..'/') + local dirlist={} + local nofdirs=0 + local pattern=tolerant and lessweird or weird + local filelist={} + local noffiles=0 + for name in directory(full) do + if not lpegmatch(pattern,name) then + local mode=attributes(full..name,"mode") + if mode=="file" then + n=n+1 + noffiles=noffiles+1 + filelist[noffiles]=name + elseif mode=="directory" then + m=m+1 + nofdirs=nofdirs+1 + if path~="" then + dirlist[nofdirs]=path.."/"..name + else + dirlist[nofdirs]=name end + end end - if noffiles>0 then - sort(filelist) - for i=1,noffiles do - local name=filelist[i] - local lower=lower(name) - local paths=files[lower] - if paths then - if onlyone then - else - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - if addcasecraptoo then - local paths=files[name] - if not paths then - files[name]=path - elseif type(paths)=="string" then - files[name]={ paths,path } - else - paths[#paths+1]=path - end - end - end - if type(paths)=="string" then - files[lower]={ paths,path } - else - paths[#paths+1]=path - end - end - else - files[lower]=path - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - end + end + if noffiles>0 then + sort(filelist) + for i=1,noffiles do + local name=filelist[i] + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then + else + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + if addcasecraptoo then + local paths=files[name] + if not paths then + files[name]=path + elseif type(paths)=="string" then + files[name]={ paths,path } + else + paths[#paths+1]=path + end end + end + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end end - end - if nofdirs>0 then - sort(dirlist) - for i=1,nofdirs do - files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) + else + files[lower]=path + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end + end + end + end + if nofdirs>0 then + sort(dirlist) + for i=1,nofdirs do + files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) end - scancache[sub(full,1,-2)]=files - return files,remap,n,m,r + end + scancache[sub(full,1,-2)]=files + return files,remap,n,m,r end function resolvers.scanfiles(path,branch,usecache,onlyonce,tolerant) - local realpath=resolveprefix(path) - if usecache then - local content=fullcache[realpath] - if content then - if trace_locating then - report_expansions("using cached scan of path %a, branch %a",path,branch or path) - end - nofsharedscans=nofsharedscans+1 - return content - end - end - statistics.starttiming(timer) + local realpath=resolveprefix(path) + if usecache then + local content=fullcache[realpath] + if content then + if trace_locating then + report_expansions("using cached scan of path %a, branch %a",path,branch or path) + end + nofsharedscans=nofsharedscans+1 + return content + end + end + statistics.starttiming(timer) + if trace_locating then + report_expansions("scanning path %a, branch %a",path,branch or path) + end + local content + if isdir(realpath) then + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) + content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) + report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end - local content - if isdir(realpath) then - local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) - content={ - metadata={ - path=path, - files=n, - directories=m, - remappings=r, - }, - files=files, - remap=remap, - } - if trace_locating then - report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) - end - else - content={ - metadata={ - path=path, - files=0, - directories=0, - remappings=0, - }, - files={}, - remap={}, - } - if trace_locating then - report_expansions("invalid path %a",realpath) - end - end - if usecache then - scanned[#scanned+1]=realpath - fullcache[realpath]=content + else + content={ + metadata={ + path=path, + files=0, + directories=0, + remappings=0, + }, + files={}, + remap={}, + } + if trace_locating then + report_expansions("invalid path %a",realpath) end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return content + end + if usecache then + scanned[#scanned+1]=realpath + fullcache[realpath]=content + end + nofscans=nofscans+1 + statistics.stoptiming(timer) + return content end function resolvers.simplescanfiles(path,branch,usecache) - return resolvers.scanfiles(path,branch,usecache,true,true) + return resolvers.scanfiles(path,branch,usecache,true,true) end function resolvers.scandata() - table.sort(scanned) - return { - n=nofscans, - shared=nofsharedscans, - time=statistics.elapsedtime(timer), - paths=scanned, - } + table.sort(scanned) + return { + n=nofscans, + shared=nofsharedscans, + time=statistics.elapsedtime(timer), + paths=scanned, + } end function resolvers.get_from_content(content,path,name) - if not content then - return - end - local files=content.files - if not files then - return - end - local remap=content.remap - if not remap then - return - end - if name then - local used=lower(name) - return path,remap[used] or used - else - local name=path - local used=lower(name) - local path=files[used] - if path then - return path,remap[used] or used - end - end + if not content then + return + end + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end end local nothing=function() end function resolvers.filtered_from_content(content,pattern) - if content and type(pattern)=="string" then - local pattern=lower(pattern) - local files=content.files - local remap=content.remap - if files and remap then - local f=sortedkeys(files) - local n=#f - local i=0 - local function iterator() - while i<n do - i=i+1 - local k=f[i] - if find(k,pattern) then - return files[k],remap and remap[k] or k - end - end - end - return iterator + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local f=sortedkeys(files) + local n=#f + local i=0 + local function iterator() + while i<n do + i=i+1 + local k=f[i] + if find(k,pattern) then + return files[k],remap and remap[k] or k + end end + end + return iterator end - return nothing + end + return nothing end @@ -16923,14 +20497,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-env"] = package.loaded["data-env"] or true --- original size: 9360, stripped down to: 6903 +-- original size: 9360, stripped down to: 6312 if not modules then modules={} end modules ['data-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local lower,gsub=string.lower,string.gsub local next=next @@ -16950,255 +20524,255 @@ resolvers.suffixmap=suffixmap resolvers.usertypes=usertypes local luasuffixes=utilities.lua.suffixes local relations=allocate { - core={ - ofm={ - names={ "ofm","omega font metric","omega font metrics" }, - variable='OFMFONTS', - suffixes={ 'ofm','tfm' }, - }, - ovf={ - names={ "ovf","omega virtual font","omega virtual fonts" }, - variable='OVFFONTS', - suffixes={ 'ovf','vf' }, - }, - tfm={ - names={ "tfm","tex font metric","tex font metrics" }, - variable='TFMFONTS', - suffixes={ 'tfm' }, - }, - vf={ - names={ "vf","virtual font","virtual fonts" }, - variable='VFFONTS', - suffixes={ 'vf' }, - }, - otf={ - names={ "otf","opentype","opentype font","opentype fonts"}, - variable='OPENTYPEFONTS', - suffixes={ 'otf' }, - }, - ttf={ - names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, - variable='TTFONTS', - suffixes={ 'ttf','ttc','dfont' }, - }, - afm={ - names={ "afm","adobe font metric","adobe font metrics" }, - variable="AFMFONTS", - suffixes={ "afm" }, - }, - pfb={ - names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, - variable='T1FONTS', - suffixes={ 'pfb','pfa' }, - }, - fea={ - names={ "fea","font feature","font features","font feature file","font feature files" }, - variable='FONTFEATURES', - suffixes={ 'fea' }, - }, - cid={ - names={ "cid","cid map","cid maps","cid file","cid files" }, - variable='FONTCIDMAPS', - suffixes={ 'cid','cidmap' }, - }, - fmt={ - names={ "fmt","format","tex format" }, - variable='TEXFORMATS', - suffixes={ 'fmt' }, - }, - mem={ - names={ 'mem',"metapost format" }, - variable='MPMEMS', - suffixes={ 'mem' }, - }, - mp={ - names={ "mp" }, - variable='MPINPUTS', - suffixes={ 'mp','mpvi','mpiv','mpii' }, - usertype=true, - }, - tex={ - names={ "tex" }, - variable='TEXINPUTS', - suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, - usertype=true, - }, - icc={ - names={ "icc","icc profile","icc profiles" }, - variable='ICCPROFILES', - suffixes={ 'icc' }, - }, - texmfscripts={ - names={ "texmfscript","texmfscripts","script","scripts" }, - variable='TEXMFSCRIPTS', - suffixes={ 'lua','rb','pl','py' }, - }, - lua={ - names={ "lua" }, - variable='LUAINPUTS', - suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, - usertype=true, - }, - lib={ - names={ "lib" }, - variable='CLUAINPUTS', - suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, - }, - bib={ - names={ 'bib' }, - variable='BIBINPUTS', - suffixes={ 'bib' }, - usertype=true, - }, - bst={ - names={ 'bst' }, - variable='BSTINPUTS', - suffixes={ 'bst' }, - usertype=true, - }, - fontconfig={ - names={ 'fontconfig','fontconfig file','fontconfig files' }, - variable='FONTCONFIG_PATH', - }, - pk={ - names={ "pk" }, - variable='PKFONTS', - suffixes={ 'pk' }, - }, + core={ + ofm={ + names={ "ofm","omega font metric","omega font metrics" }, + variable='OFMFONTS', + suffixes={ 'ofm','tfm' }, + }, + ovf={ + names={ "ovf","omega virtual font","omega virtual fonts" }, + variable='OVFFONTS', + suffixes={ 'ovf','vf' }, + }, + tfm={ + names={ "tfm","tex font metric","tex font metrics" }, + variable='TFMFONTS', + suffixes={ 'tfm' }, + }, + vf={ + names={ "vf","virtual font","virtual fonts" }, + variable='VFFONTS', + suffixes={ 'vf' }, + }, + otf={ + names={ "otf","opentype","opentype font","opentype fonts"}, + variable='OPENTYPEFONTS', + suffixes={ 'otf' }, + }, + ttf={ + names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, + variable='TTFONTS', + suffixes={ 'ttf','ttc','dfont' }, + }, + afm={ + names={ "afm","adobe font metric","adobe font metrics" }, + variable="AFMFONTS", + suffixes={ "afm" }, + }, + pfb={ + names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, + variable='T1FONTS', + suffixes={ 'pfb','pfa' }, + }, + fea={ + names={ "fea","font feature","font features","font feature file","font feature files" }, + variable='FONTFEATURES', + suffixes={ 'fea' }, + }, + cid={ + names={ "cid","cid map","cid maps","cid file","cid files" }, + variable='FONTCIDMAPS', + suffixes={ 'cid','cidmap' }, + }, + fmt={ + names={ "fmt","format","tex format" }, + variable='TEXFORMATS', + suffixes={ 'fmt' }, + }, + mem={ + names={ 'mem',"metapost format" }, + variable='MPMEMS', + suffixes={ 'mem' }, + }, + mp={ + names={ "mp" }, + variable='MPINPUTS', + suffixes={ 'mp','mpvi','mpiv','mpii' }, + usertype=true, + }, + tex={ + names={ "tex" }, + variable='TEXINPUTS', + suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, + usertype=true, + }, + icc={ + names={ "icc","icc profile","icc profiles" }, + variable='ICCPROFILES', + suffixes={ 'icc' }, + }, + texmfscripts={ + names={ "texmfscript","texmfscripts","script","scripts" }, + variable='TEXMFSCRIPTS', + suffixes={ 'lua','rb','pl','py' }, + }, + lua={ + names={ "lua" }, + variable='LUAINPUTS', + suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, + usertype=true, }, - obsolete={ - enc={ - names={ "enc","enc files","enc file","encoding files","encoding file" }, - variable='ENCFONTS', - suffixes={ 'enc' }, - }, - map={ - names={ "map","map files","map file" }, - variable='TEXFONTMAPS', - suffixes={ 'map' }, - }, - lig={ - names={ "lig files","lig file","ligature file","ligature files" }, - variable='LIGFONTS', - suffixes={ 'lig' }, - }, - opl={ - names={ "opl" }, - variable='OPLFONTS', - suffixes={ 'opl' }, - }, - ovp={ - names={ "ovp" }, - variable='OVPFONTS', - suffixes={ 'ovp' }, - }, + lib={ + names={ "lib" }, + variable='CLUAINPUTS', + suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, }, - kpse={ - base={ - names={ 'base',"metafont format" }, - variable='MFBASES', - suffixes={ 'base','bas' }, - }, - cmap={ - names={ 'cmap','cmap files','cmap file' }, - variable='CMAPFONTS', - suffixes={ 'cmap' }, - }, - cnf={ - names={ 'cnf' }, - suffixes={ 'cnf' }, - }, - web={ - names={ 'web' }, - suffixes={ 'web','ch' } - }, - cweb={ - names={ 'cweb' }, - suffixes={ 'w','web','ch' }, - }, - gf={ - names={ 'gf' }, - suffixes={ '<resolution>gf' }, - }, - mf={ - names={ 'mf' }, - variable='MFINPUTS', - suffixes={ 'mf' }, - }, - mft={ - names={ 'mft' }, - suffixes={ 'mft' }, - }, - pk={ - names={ 'pk' }, - suffixes={ '<resolution>pk' }, - }, + bib={ + names={ 'bib' }, + variable='BIBINPUTS', + suffixes={ 'bib' }, + usertype=true, }, + bst={ + names={ 'bst' }, + variable='BSTINPUTS', + suffixes={ 'bst' }, + usertype=true, + }, + fontconfig={ + names={ 'fontconfig','fontconfig file','fontconfig files' }, + variable='FONTCONFIG_PATH', + }, + pk={ + names={ "pk" }, + variable='PKFONTS', + suffixes={ 'pk' }, + }, + }, + obsolete={ + enc={ + names={ "enc","enc files","enc file","encoding files","encoding file" }, + variable='ENCFONTS', + suffixes={ 'enc' }, + }, + map={ + names={ "map","map files","map file" }, + variable='TEXFONTMAPS', + suffixes={ 'map' }, + }, + lig={ + names={ "lig files","lig file","ligature file","ligature files" }, + variable='LIGFONTS', + suffixes={ 'lig' }, + }, + opl={ + names={ "opl" }, + variable='OPLFONTS', + suffixes={ 'opl' }, + }, + ovp={ + names={ "ovp" }, + variable='OVPFONTS', + suffixes={ 'ovp' }, + }, + }, + kpse={ + base={ + names={ 'base',"metafont format" }, + variable='MFBASES', + suffixes={ 'base','bas' }, + }, + cmap={ + names={ 'cmap','cmap files','cmap file' }, + variable='CMAPFONTS', + suffixes={ 'cmap' }, + }, + cnf={ + names={ 'cnf' }, + suffixes={ 'cnf' }, + }, + web={ + names={ 'web' }, + suffixes={ 'web','ch' } + }, + cweb={ + names={ 'cweb' }, + suffixes={ 'w','web','ch' }, + }, + gf={ + names={ 'gf' }, + suffixes={ '<resolution>gf' }, + }, + mf={ + names={ 'mf' }, + variable='MFINPUTS', + suffixes={ 'mf' }, + }, + mft={ + names={ 'mft' }, + suffixes={ 'mft' }, + }, + pk={ + names={ 'pk' }, + suffixes={ '<resolution>pk' }, + }, + }, } resolvers.relations=relations function resolvers.updaterelations() - for category,categories in next,relations do - for name,relation in next,categories do - local rn=relation.names - local rv=relation.variable - if rn and rv then - local rs=relation.suffixes - local ru=relation.usertype - for i=1,#rn do - local rni=lower(gsub(rn[i]," ","")) - formats[rni]=rv - if rs then - suffixes[rni]=rs - for i=1,#rs do - local rsi=rs[i] - suffixmap[rsi]=rni - end - end - end - if ru then - usertypes[name]=true - end + for category,categories in next,relations do + for name,relation in next,categories do + local rn=relation.names + local rv=relation.variable + if rn and rv then + local rs=relation.suffixes + local ru=relation.usertype + for i=1,#rn do + local rni=lower(gsub(rn[i]," ","")) + formats[rni]=rv + if rs then + suffixes[rni]=rs + for i=1,#rs do + local rsi=rs[i] + suffixmap[rsi]=rni end + end + end + if ru then + usertypes[name]=true end + end end + end end resolvers.updaterelations() local function simplified(t,k) - return k and rawget(t,lower(gsub(k," ",""))) or nil + return k and rawget(t,lower(gsub(k," ",""))) or nil end setmetatableindex(formats,simplified) setmetatableindex(suffixes,simplified) setmetatableindex(suffixmap,simplified) function resolvers.suffixofformat(str) - local s=suffixes[str] - return s and s[1] or "" + local s=suffixes[str] + return s and s[1] or "" end function resolvers.suffixofformat(str) - return suffixes[str] or {} + return suffixes[str] or {} end for name,format in next,formats do - dangerous[name]=true + dangerous[name]=true end dangerous.tex=nil function resolvers.formatofvariable(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.formatofsuffix(str) - return suffixmap[suffixonly(str)] or 'tex' + return suffixmap[suffixonly(str)] or 'tex' end function resolvers.variableofformat(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.variableofformatorsuffix(str) - local v=formats[str] - if v then - return v - end - v=suffixmap[suffixonly(str)] - if v then - return formats[v] - end - return '' + local v=formats[str] + if v then + return v + end + v=suffixmap[suffixonly(str)] + if v then + return formats[v] + end + return '' end @@ -17208,14 +20782,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 16116, stripped down to: 11459 +-- original size: 16116, stripped down to: 10782 if not modules then modules={} end modules ['data-tmp']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,concat=string.format,string.lower,string.gsub,table.concat local concat=table.concat @@ -17223,19 +20797,19 @@ local mkdirs,isdir,isfile=dir.mkdirs,lfs.isdir,lfs.isfile local addsuffix,is_writable,is_readable=file.addsuffix,file.is_writable,file.is_readable local formatters=string.formatters local next,type=next,type -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers local cleanpath=resolvers.cleanpath -local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) -local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) +local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) +local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile function utilities.lua.compile(luafile,lucfile,cleanup,strip) - if cleanup==nil then cleanup=directive_cleanup end - if strip==nil then strip=directive_strip end - return compile(luafile,lucfile,cleanup,strip) + if cleanup==nil then cleanup=directive_cleanup end + if strip==nil then strip=directive_strip end + return compile(luafile,lucfile,cleanup,strip) end caches=caches or {} local caches=caches @@ -17250,324 +20824,324 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - cachepath=file.collapsepath(cachepath) - local valid=isdir(cachepath) - if valid then - if is_readable(cachepath) then - readables[#readables+1]=cachepath - if not writable and is_writable(cachepath) then - writable=cachepath - end - end - elseif not writable and caches.force then - local cacheparent=file.dirname(cachepath) - if is_writable(cacheparent) and true then - if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then - mkdirs(cachepath) - if isdir(cachepath) and is_writable(cachepath) then - report_caches("path %a created",cachepath) - writable=cachepath - readables[#readables+1]=cachepath - end - end - end - end + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + cachepath=file.collapsepath(cachepath) + local valid=isdir(cachepath) + if valid then + if is_readable(cachepath) then + readables[#readables+1]=cachepath + if not writable and is_writable(cachepath) then + writable=cachepath end - end - end - local texmfcaches=caches.defaults - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - cachepath=resolvers.expansion(cachepath) - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - local valid=isdir(cachepath) - if valid and is_readable(cachepath) then - if not writable and is_writable(cachepath) then - readables[#readables+1]=cachepath - writable=cachepath - break - end - end + end + elseif not writable and caches.force then + local cacheparent=file.dirname(cachepath) + if is_writable(cacheparent) and true then + if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then + mkdirs(cachepath) + if isdir(cachepath) and is_writable(cachepath) then + report_caches("path %a created",cachepath) + writable=cachepath + readables[#readables+1]=cachepath + end end + end end + end end - if not writable then - report_caches("fatal error: there is no valid writable cache path defined") - os.exit() - elseif #readables==0 then - report_caches("fatal error: there is no valid readable cache path defined") - os.exit() - end - writable=dir.expandname(resolvers.cleanpath(writable)) - local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() - if tree then - caches.tree=tree - writable=mkdirs(writable,base,more,tree) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more,tree) - end - else - writable=mkdirs(writable,base,more) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more) + end + local texmfcaches=caches.defaults + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + cachepath=resolvers.expansion(cachepath) + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + local valid=isdir(cachepath) + if valid and is_readable(cachepath) then + if not writable and is_writable(cachepath) then + readables[#readables+1]=cachepath + writable=cachepath + break + end end + end end - if trace_cache then - for i=1,#readables do - report_caches("using readable path %a (order %s)",readables[i],i) - end - report_caches("using writable path %a",writable) + end + if not writable then + report_caches("fatal error: there is no valid writable cache path defined") + os.exit() + elseif #readables==0 then + report_caches("fatal error: there is no valid readable cache path defined") + os.exit() + end + writable=dir.expandname(resolvers.cleanpath(writable)) + local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() + if tree then + caches.tree=tree + writable=mkdirs(writable,base,more,tree) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more,tree) end - identify=function() - return writable,readables + else + writable=mkdirs(writable,base,more) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more) end + end + if trace_cache then + for i=1,#readables do + report_caches("using readable path %a (order %s)",readables[i],i) + end + report_caches("using writable path %a",writable) + end + identify=function() return writable,readables + end + return writable,readables end function caches.usedpaths(separator) - local writable,readables=identify() - if #readables>1 then - local result={} - local done={} - for i=1,#readables do - local readable=readables[i] - if readable==writable then - done[readable]=true - result[#result+1]=formatters["readable+writable: %a"](readable) - elseif usedreadables[i] then - done[readable]=true - result[#result+1]=formatters["readable: %a"](readable) - end - end - if not done[writable] then - result[#result+1]=formatters["writable: %a"](writable) - end - return concat(result,separator or " | ") - else - return writable or "?" + local writable,readables=identify() + if #readables>1 then + local result={} + local done={} + for i=1,#readables do + local readable=readables[i] + if readable==writable then + done[readable]=true + result[#result+1]=formatters["readable+writable: %a"](readable) + elseif usedreadables[i] then + done[readable]=true + result[#result+1]=formatters["readable: %a"](readable) + end end + if not done[writable] then + result[#result+1]=formatters["writable: %a"](writable) + end + return concat(result,separator or " | ") + else + return writable or "?" + end end function caches.configfiles() - return concat(resolvers.configurationfiles(),";") + return concat(resolvers.configurationfiles(),";") end function caches.hashed(tree) - tree=gsub(tree,"[\\/]+$","") - tree=lower(tree) - local hash=md5.hex(tree) - if trace_cache or trace_locating then - report_caches("hashing tree %a, hash %a",tree,hash) - end - return hash + tree=gsub(tree,"[\\/]+$","") + tree=lower(tree) + local hash=md5.hex(tree) + if trace_cache or trace_locating then + report_caches("hashing tree %a, hash %a",tree,hash) + end + return hash end function caches.treehash() - local tree=caches.configfiles() - if not tree or tree=="" then - return false - else - return caches.hashed(tree) - end + local tree=caches.configfiles() + if not tree or tree=="" then + return false + else + return caches.hashed(tree) + end end local r_cache,w_cache={},{} local function getreadablepaths(...) - local tags={... } - local hash=concat(tags,"/") - local done=r_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done={} - for i=1,#readables do - done[i]=file.join(readables[i],...) - end - else - done=readables - end - r_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=r_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done={} + for i=1,#readables do + done[i]=file.join(readables[i],...) + end + else + done=readables end - return done + r_cache[hash]=done + end + return done end local function getwritablepath(...) - local tags={... } - local hash=concat(tags,"/") - local done=w_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done=mkdirs(writable,...) - else - done=writable - end - w_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=w_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done=mkdirs(writable,...) + else + done=writable end - return done + w_cache[hash]=done + end + return done end caches.getreadablepaths=getreadablepaths caches.getwritablepath=getwritablepath function caches.getfirstreadablefile(filename,...) - local fullname,path=caches.setfirstwritablefile(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 - 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 + usedreadables[i]=true + return fullname,path end - return fullname,path + end + return fullname,path end function caches.setfirstwritablefile(filename,...) - local wr=getwritablepath(...) - local fullname=file.join(wr,filename) - return fullname,wr + local wr=getwritablepath(...) + local fullname=file.join(wr,filename) + return fullname,wr end function caches.define(category,subcategory) - return function() - return getwritablepath(category,subcategory) - end + return function() + return getwritablepath(category,subcategory) + end end function caches.setluanames(path,name) - return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) + return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) end function caches.loaddata(readables,name,writable) - if type(readables)=="string" then - readables={ readables } + if type(readables)=="string" then + readables={ readables } + end + for i=1,#readables do + local path=readables[i] + local loader=false + local tmaname,tmcname=caches.setluanames(path,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader and isfile(tmaname) then + local tmacrap,tmcname=caches.setluanames(writable,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + utilities.lua.compile(tmaname,tmcname) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader then + loader=loadfile(tmaname) + end end - for i=1,#readables do - local path=readables[i] - local loader=false - local tmaname,tmcname=caches.setluanames(path,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader and isfile(tmaname) then - local tmacrap,tmcname=caches.setluanames(writable,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - utilities.lua.compile(tmaname,tmcname) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader then - loader=loadfile(tmaname) - end - end - if loader then - loader=loader() - collectgarbage("step") - return loader - end + if loader then + loader=loader() + collectgarbage("step") + return loader end - return false + end + return false end function caches.is_writable(filepath,filename) - local tmaname,tmcname=caches.setluanames(filepath,filename) - return is_writable(tmaname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + return is_writable(tmaname) end local saveoptions={ compact=true } function caches.savedata(filepath,filename,data,raw) - local tmaname,tmcname=caches.setluanames(filepath,filename) - data.cache_uuid=os.uuid() - if caches.direct then - file.savedata(tmaname,table.serialize(data,true,saveoptions)) - else - table.tofile(tmaname,data,true,saveoptions) - end - utilities.lua.compile(tmaname,tmcname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + data.cache_uuid=os.uuid() + if caches.direct then + file.savedata(tmaname,table.serialize(data,true,saveoptions)) + else + table.tofile(tmaname,data,true,saveoptions) + end + utilities.lua.compile(tmaname,tmcname) end local content_state={} function caches.contentstate() - return content_state or {} + return content_state or {} end function caches.loadcontent(cachename,dataname,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) - if blob then - local data=blob() - if data and data.content then - if data.type==dataname then - if data.version==resolvers.cacheversion then - content_state[#content_state+1]=data.uuid - if trace_locating then - report_resolvers("loading %a for %a from %a",dataname,cachename,filename) - end - return data.content - else - report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) - end - else - report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) - end - elseif trace_locating then - report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) + if blob then + local data=blob() + if data and data.content then + if data.type==dataname then + if data.version==resolvers.cacheversion then + content_state[#content_state+1]=data.uuid + if trace_locating then + report_resolvers("loading %a for %a from %a",dataname,cachename,filename) + end + return data.content + else + report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) end + else + report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) + end elseif trace_locating then - report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) end + elseif trace_locating then + report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + end end function caches.collapsecontent(content) - for k,v in next,content do - if type(v)=="table" and #v==1 then - content[k]=v[1] - end + for k,v in next,content do + if type(v)=="table" and #v==1 then + content[k]=v[1] end + end end function caches.savecontent(cachename,dataname,content,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local luaname=addsuffix(filename,luasuffixes.lua) - local lucname=addsuffix(filename,luasuffixes.luc) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local luaname=addsuffix(filename,luasuffixes.lua) + local lucname=addsuffix(filename,luasuffixes.luc) + if trace_locating then + report_resolvers("preparing %a for %a",dataname,cachename) + end + local data={ + type=dataname, + root=cachename, + version=resolvers.cacheversion, + date=os.date("%Y-%m-%d"), + time=os.date("%H:%M:%S"), + content=content, + uuid=os.uuid(), + } + local ok=io.savedata(luaname,table.serialize(data,true)) + if ok then if trace_locating then - report_resolvers("preparing %a for %a",dataname,cachename) - end - local data={ - type=dataname, - root=cachename, - version=resolvers.cacheversion, - date=os.date("%Y-%m-%d"), - time=os.date("%H:%M:%S"), - content=content, - uuid=os.uuid(), - } - local ok=io.savedata(luaname,table.serialize(data,true)) - if ok then - if trace_locating then - report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) - end - if utilities.lua.compile(luaname,lucname) then - if trace_locating then - report_resolvers("%a compiled to %a",dataname,lucname) - end - return true - else - if trace_locating then - report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) - end - os.remove(lucname) - end - elseif trace_locating then - report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) + end + if utilities.lua.compile(luaname,lucname) then + if trace_locating then + report_resolvers("%a compiled to %a",dataname,lucname) + end + return true + else + if trace_locating then + report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) + end + os.remove(lucname) end + elseif trace_locating then + report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + end end @@ -17577,14 +21151,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5310, stripped down to: 3980 +-- original size: 5310, stripped down to: 3784 if not modules then modules={} end modules ['data-met']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,format=string.find,string.format local sequenced=table.sequenced @@ -17598,86 +21172,86 @@ local allocate=utilities.storage.allocate local resolvers=resolvers local registered={} local function splitmethod(filename) - if not filename then - return { scheme="unknown",original=filename } - end - if type(filename)=="table" then - return filename - end - filename=file.collapsepath(filename,".") - if not find(filename,"://",1,true) then - return { scheme="file",path=filename,original=filename,filename=filename } - end - local specification=url.hashed(filename) - if not specification.scheme or specification.scheme=="" then - return { scheme="file",path=filename,original=filename,filename=filename } - else - return specification - end + if not filename then + return { scheme="unknown",original=filename } + end + if type(filename)=="table" then + return filename + end + filename=file.collapsepath(filename,".") + if not find(filename,"://",1,true) then + return { scheme="file",path=filename,original=filename,filename=filename } + end + local specification=url.hashed(filename) + if not specification.scheme or specification.scheme=="" then + return { scheme="file",path=filename,original=filename,filename=filename } + else + return specification + end end resolvers.splitmethod=splitmethod local function methodhandler(what,first,...) - local method=registered[what] - if method then - local how,namespace=method.how,method.namespace - if how=="uri" or how=="url" then - local specification=splitmethod(first) - local scheme=specification.scheme - local resolver=namespace and namespace[scheme] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) - end - return resolver(specification,...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) - end - return resolver(specification,...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") - end - end - elseif how=="tag" then - local resolver=namespace and namespace[first] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,first) - end - return resolver(...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"default") - end - return resolver(...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") - end - end + local method=registered[what] + if method then + local how,namespace=method.how,method.namespace + if how=="uri" or how=="url" then + local specification=splitmethod(first) + local scheme=specification.scheme + local resolver=namespace and namespace[scheme] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) + end + return resolver(specification,...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) + end + return resolver(specification,...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") end - else - report_methods("resolving, invalid method %a") + end + elseif how=="tag" then + local resolver=namespace and namespace[first] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,first) + end + return resolver(...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"default") + end + return resolver(...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") + end + end end + else + report_methods("resolving, invalid method %a") + end end resolvers.methodhandler=methodhandler function resolvers.registermethod(name,namespace,how) - registered[name]={ how=how or "tag",namespace=namespace } - namespace["byscheme"]=function(scheme,filename,...) - if scheme=="file" then - return methodhandler(name,filename,...) - else - return methodhandler(name,addurlscheme(filename,scheme),...) - end + registered[name]={ how=how or "tag",namespace=namespace } + namespace["byscheme"]=function(scheme,filename,...) + if scheme=="file" then + return methodhandler(name,filename,...) + else + return methodhandler(name,addurlscheme(filename,scheme),...) end + end end -local concatinators=allocate { notfound=file.join } -local locators=allocate { notfound=function() end } -local hashers=allocate { notfound=function() end } -local generators=allocate { notfound=function() end } +local concatinators=allocate { notfound=file.join } +local locators=allocate { notfound=function() end } +local hashers=allocate { notfound=function() end } +local generators=allocate { notfound=function() end } resolvers.concatinators=concatinators resolvers.locators=locators resolvers.hashers=hashers @@ -17695,17 +21269,17 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 68263, stripped down to: 47789 +-- original size: 68195, stripped down to: 43680 if not modules then modules={} end modules ['data-res']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,remove,sortedkeys,sortedhash=table.concat,table.insert,table.remove,table.sortedkeys,table.sortedhash +local concat,insert,remove=table.concat,table.insert,table.remove local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -17727,11 +21301,11 @@ local isfile=lfs.isfile local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) -local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) +local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) +local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) local report_resolving=logs.reporter("resolvers","resolving") local resolvers=resolvers local expandedpathfromlist=resolvers.expandedpathfromlist @@ -17752,15 +21326,15 @@ resolvers.luacnfname="texmfcnf.lua" resolvers.luacnffallback="contextcnf.lua" resolvers.luacnfstate="unknown" if environment.default_texmfcnf then - resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf + resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf else - resolvers.luacnfspec=concat ({ - "home:texmf/web2c", - "selfautoparent:/texmf-local/web2c", - "selfautoparent:/texmf-context/web2c", - "selfautoparent:/texmf-dist/web2c", - "selfautoparent:/texmf/web2c", - },";") + resolvers.luacnfspec=concat ({ + "home:texmf/web2c", + "selfautoparent:/texmf-local/web2c", + "selfautoparent:/texmf-context/web2c", + "selfautoparent:/texmf-dist/web2c", + "selfautoparent:/texmf/web2c", + },";") end local unset_variable="unset" local formats=resolvers.formats @@ -17771,24 +21345,24 @@ local suffixmap=resolvers.suffixmap resolvers.defaultsuffixes={ "tex" } local instance=nil function resolvers.setenv(key,value,raw) - if instance then - instance.environment[key]=value - ossetenv(key,raw and value or resolveprefix(value)) - end + if instance then + instance.environment[key]=value + ossetenv(key,raw and value or resolveprefix(value)) + end end local function getenv(key) - local value=rawget(instance.environment,key) - if value and value~="" then - return value - else - local e=osgetenv(key) - return e~=nil and e~="" and checkedvariable(e) or "" - end + local value=rawget(instance.environment,key) + if value and value~="" then + return value + else + local e=osgetenv(key) + return e~=nil and e~="" and checkedvariable(e) or "" + end end resolvers.getenv=getenv resolvers.env=getenv local function resolvevariable(k) - return instance.expansions[k] + return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") local inhibitstripper=P("!")^0*Cs(P(1)^0) @@ -17802,1506 +21376,1506 @@ local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) - return lpegmatch(variableexpander,var) or var + return lpegmatch(variableexpander,var) or var end function resolvers.reset() - if trace_locating then - report_resolving("creating instance") - end - local environment={} - local variables={} - local expansions={} - local order={} - instance={ - environment=environment, - variables=variables, - expansions=expansions, - order=order, - files={}, - setups={}, - found={}, - foundintrees={}, - hashes={}, - hashed={}, - pathlists=false, - specification={}, - lists={}, - data={}, - fakepaths={}, - remember=true, - diskcache=true, - renewcache=false, - renewtree=false, - loaderror=false, - savelists=true, - pattern=nil, - force_suffixes=true, - pathstack={}, - } - setmetatableindex(variables,function(t,k) - local v - for i=1,#order do - v=order[i][k] - if v~=nil then - t[k]=v - return v - end - end - if v==nil then - v="" - end - t[k]=v - return v - end) - setmetatableindex(environment,function(t,k) - local v=osgetenv(k) - if v==nil then - v=variables[k] - end - if v~=nil then - v=checkedvariable(v) or "" - end - v=resolvers.repath(v) - t[k]=v - return v - end) - setmetatableindex(expansions,function(t,k) - local v=environment[k] - if type(v)=="string" then - v=lpegmatch(variableresolver,v) - v=lpegmatch(variablecleaner,v) - end + if trace_locating then + report_resolving("creating instance") + end + local environment={} + local variables={} + local expansions={} + local order={} + instance={ + environment=environment, + variables=variables, + expansions=expansions, + order=order, + files={}, + setups={}, + found={}, + foundintrees={}, + hashes={}, + hashed={}, + pathlists=false, + specification={}, + lists={}, + data={}, + fakepaths={}, + remember=true, + diskcache=true, + renewcache=false, + renewtree=false, + loaderror=false, + savelists=true, + pattern=nil, + force_suffixes=true, + pathstack={}, + } + setmetatableindex(variables,function(t,k) + local v + for i=1,#order do + v=order[i][k] + if v~=nil then t[k]=v return v - end) + end + end + if v==nil then + v="" + end + t[k]=v + return v + end) + setmetatableindex(environment,function(t,k) + local v=osgetenv(k) + if v==nil then + v=variables[k] + end + if v~=nil then + v=checkedvariable(v) or "" + end + v=resolvers.repath(v) + t[k]=v + return v + end) + setmetatableindex(expansions,function(t,k) + local v=environment[k] + if type(v)=="string" then + v=lpegmatch(variableresolver,v) + v=lpegmatch(variablecleaner,v) + end + t[k]=v + return v + end) end function resolvers.initialized() - return instance~=nil + return instance~=nil end local function reset_hashes() - instance.lists={} - instance.pathlists=false - instance.found={} + instance.lists={} + instance.pathlists=false + instance.found={} end local function reset_caches() - instance.lists={} - instance.pathlists=false + instance.lists={} + instance.pathlists=false end local slash=P("/") local pathexpressionpattern=Cs ( - Cc("^")*( - Cc("%")*S(".-")+slash^2*P(-1)/"/.*" + Cc("^")*( + Cc("%")*S(".-")+slash^2*P(-1)/"/.*" +slash^2/"/"+(1-slash)*P(-1)*Cc("/")+P(1) - )^1*Cc("$") + )^1*Cc("$") ) local cache={} local function makepathexpression(str) - if str=="." then - return "^%./$" - else - local c=cache[str] - if not c then - c=lpegmatch(pathexpressionpattern,str) - cache[str]=c - end - return c + if str=="." then + return "^%./$" + else + local c=cache[str] + if not c then + c=lpegmatch(pathexpressionpattern,str) + cache[str]=c end + return c + end end local function reportcriticalvariables(cnfspec) - if trace_locating then - for i=1,#resolvers.criticalvars do - local k=resolvers.criticalvars[i] - local v=resolvers.getenv(k) or "unknown" - report_resolving("variable %a set to %a",k,v) - end - report_resolving() - if cnfspec then - report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) - end - report_resolving() + if trace_locating then + for i=1,#resolvers.criticalvars do + local k=resolvers.criticalvars[i] + local v=resolvers.getenv(k) or "unknown" + report_resolving("variable %a set to %a",k,v) + end + report_resolving() + if cnfspec then + report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) end - reportcriticalvariables=function() end + report_resolving() + end + reportcriticalvariables=function() end end local function identify_configuration_files() - local specification=instance.specification - if #specification==0 then - local cnfspec=getenv("TEXMFCNF") - if cnfspec=="" then - cnfspec=resolvers.luacnfspec - resolvers.luacnfstate="default" - else - resolvers.luacnfstate="environment" - end - reportcriticalvariables(cnfspec) - local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) - local function locatecnf(luacnfname,kind) - for i=1,#cnfpaths do - local filepath=cnfpaths[i] - local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolveprefix(filename) - if trace_locating then - local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") - local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) - report_resolving("looking for %s %a on %s path %a from specification %a", - kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) - end - if isfile(realname) then - specification[#specification+1]=filename - if trace_locating then - report_resolving("found %s configuration file %a",kind,realname) - end - end - end - end - locatecnf(resolvers.luacnfname,"regular") - if #specification==0 then - locatecnf(resolvers.luacnffallback,"fallback") - end + local specification=instance.specification + if #specification==0 then + local cnfspec=getenv("TEXMFCNF") + if cnfspec=="" then + cnfspec=resolvers.luacnfspec + resolvers.luacnfstate="default" + else + resolvers.luacnfstate="environment" + end + reportcriticalvariables(cnfspec) + local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) + local function locatecnf(luacnfname,kind) + for i=1,#cnfpaths do + local filepath=cnfpaths[i] + local filename=collapsepath(filejoin(filepath,luacnfname)) + local realname=resolveprefix(filename) if trace_locating then - report_resolving() + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") + local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) + report_resolving("looking for %s %a on %s path %a from specification %a", + kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) + end + if isfile(realname) then + specification[#specification+1]=filename + if trace_locating then + report_resolving("found %s configuration file %a",kind,realname) + end end - elseif trace_locating then - report_resolving("configuration files already identified") + end + end + locatecnf(resolvers.luacnfname,"regular") + if #specification==0 then + locatecnf(resolvers.luacnffallback,"fallback") + end + if trace_locating then + report_resolving() end + elseif trace_locating then + report_resolving("configuration files already identified") + end end local function load_configuration_files() - local specification=instance.specification - if #specification>0 then - local luacnfname=resolvers.luacnfname - for i=1,#specification do - local filename=specification[i] - local pathname=filedirname(filename) - local filename=filejoin(pathname,luacnfname) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local setups=instance.setups - local data=blob() - local parent=data and data.parent - if parent then - local filename=filejoin(pathname,parent) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local parentdata=blob() - if parentdata then - report_resolving("loading configuration file %a",filename) - data=table.merged(parentdata,data) - end - end - end - data=data and data.content - if data then - if trace_locating then - report_resolving("loading configuration file %a",filename) - report_resolving() - end - local variables=data.variables or {} - local warning=false - for k,v in next,data do - local variant=type(v) - if variant=="table" then - initializesetter(filename,k,v) - elseif variables[k]==nil then - if trace_locating and not warning then - report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolveprefix(filename)) - warning=true - end - variables[k]=v - end - end - setups[pathname]=variables - if resolvers.luacnfstate=="default" then - local cnfspec=variables["TEXMFCNF"] - if cnfspec then - if trace_locating then - report_resolving("reloading configuration due to TEXMF redefinition") - end - resolvers.setenv("TEXMFCNF",cnfspec) - instance.specification={} - identify_configuration_files() - load_configuration_files() - resolvers.luacnfstate="configuration" - break - end - end - else - if trace_locating then - report_resolving("skipping configuration file %a (no content)",filename) - end - setups[pathname]={} - instance.loaderror=true - end - elseif trace_locating then - report_resolving("skipping configuration file %a (no valid format)",filename) + local specification=instance.specification + if #specification>0 then + local luacnfname=resolvers.luacnfname + for i=1,#specification do + local filename=specification[i] + local pathname=filedirname(filename) + local filename=filejoin(pathname,luacnfname) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local setups=instance.setups + local data=blob() + local parent=data and data.parent + if parent then + local filename=filejoin(pathname,parent) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local parentdata=blob() + if parentdata then + report_resolving("loading configuration file %a",filename) + data=table.merged(parentdata,data) end - instance.order[#instance.order+1]=instance.setups[pathname] - if instance.loaderror then - break + end + end + data=data and data.content + if data then + if trace_locating then + report_resolving("loading configuration file %a",filename) + report_resolving() + end + local variables=data.variables or {} + local warning=false + for k,v in next,data do + local variant=type(v) + if variant=="table" then + initializesetter(filename,k,v) + elseif variables[k]==nil then + if trace_locating and not warning then + report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", + k,resolveprefix(filename)) + warning=true + end + variables[k]=v + end + end + setups[pathname]=variables + if resolvers.luacnfstate=="default" then + local cnfspec=variables["TEXMFCNF"] + if cnfspec then + if trace_locating then + report_resolving("reloading configuration due to TEXMF redefinition") + end + resolvers.setenv("TEXMFCNF",cnfspec) + instance.specification={} + identify_configuration_files() + load_configuration_files() + resolvers.luacnfstate="configuration" + break end + end + else + if trace_locating then + report_resolving("skipping configuration file %a (no content)",filename) + end + setups[pathname]={} + instance.loaderror=true end - elseif trace_locating then - report_resolving("warning: no lua configuration files found") + elseif trace_locating then + report_resolving("skipping configuration file %a (no valid format)",filename) + end + instance.order[#instance.order+1]=instance.setups[pathname] + if instance.loaderror then + break + end end + elseif trace_locating then + report_resolving("warning: no lua configuration files found") + end end function resolvers.configurationfiles() - return instance.specification or {} + return instance.specification or {} end local function load_file_databases() - instance.loaderror=false - instance.files={} - if not instance.renewcache then - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - resolvers.hashers.byscheme(hash.type,hash.name) - if instance.loaderror then break end - end + instance.loaderror=false + instance.files={} + if not instance.renewcache then + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + resolvers.hashers.byscheme(hash.type,hash.name) + if instance.loaderror then break end end + end end local function locate_file_databases() - local texmfpaths=resolvers.expandedpathlist("TEXMF") - if #texmfpaths>0 then - for i=1,#texmfpaths do - local path=collapsepath(texmfpaths[i]) - path=gsub(path,"/+$","") - local stripped=lpegmatch(inhibitstripper,path) - if stripped~="" then - local runtime=stripped==path - path=cleanpath(path) - local spec=resolvers.splitmethod(stripped) - if runtime and (spec.noscheme or spec.scheme=="file") then - stripped="tree:///"..stripped - elseif spec.scheme=="cache" or spec.scheme=="file" then - stripped=spec.path - end - if trace_locating then - if runtime then - report_resolving("locating list of %a (runtime) (%s)",path,stripped) - else - report_resolving("locating list of %a (cached)",path) - end - end - methodhandler('locators',stripped) - end + local texmfpaths=resolvers.expandedpathlist("TEXMF") + if #texmfpaths>0 then + for i=1,#texmfpaths do + local path=collapsepath(texmfpaths[i]) + path=gsub(path,"/+$","") + local stripped=lpegmatch(inhibitstripper,path) + if stripped~="" then + local runtime=stripped==path + path=cleanpath(path) + local spec=resolvers.splitmethod(stripped) + if runtime and (spec.noscheme or spec.scheme=="file") then + stripped="tree:///"..stripped + elseif spec.scheme=="cache" or spec.scheme=="file" then + stripped=spec.path end if trace_locating then - report_resolving() + if runtime then + report_resolving("locating list of %a (runtime) (%s)",path,stripped) + else + report_resolving("locating list of %a (cached)",path) + end end - elseif trace_locating then - report_resolving("no texmf paths are defined (using TEXMF)") - end -end -local function generate_file_databases() - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - methodhandler('generators',hash.name) + methodhandler('locators',stripped) + end end if trace_locating then - report_resolving() + report_resolving() end + elseif trace_locating then + report_resolving("no texmf paths are defined (using TEXMF)") + end +end +local function generate_file_databases() + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + methodhandler('generators',hash.name) + end + if trace_locating then + report_resolving() + end end local function save_file_databases() - for i=1,#instance.hashes do - local hash=instance.hashes[i] - local cachename=hash.name - if hash.cache then - local content=instance.files[cachename] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",cachename) - end - caches.savecontent(cachename,"files",content) - elseif trace_locating then - report_resolving("not saving runtime tree %a",cachename) - end + for i=1,#instance.hashes do + local hash=instance.hashes[i] + local cachename=hash.name + if hash.cache then + local content=instance.files[cachename] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",cachename) + end + caches.savecontent(cachename,"files",content) + elseif trace_locating then + report_resolving("not saving runtime tree %a",cachename) end + end end function resolvers.renew(hashname) - if hashname and hashname~="" then - local expanded=resolvers.expansion(hashname) or "" - if expanded~="" then - if trace_locating then - report_resolving("identifying tree %a from %a",expanded,hashname) - end - hashname=expanded - else - if trace_locating then - report_resolving("identifying tree %a",hashname) - end - end - local realpath=resolveprefix(hashname) - if isdir(realpath) then - if trace_locating then - report_resolving("using path %a",realpath) - end - methodhandler('generators',hashname) - local content=instance.files[hashname] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",hashname) - end - caches.savecontent(hashname,"files",content) - else - report_resolving("invalid path %a",realpath) - end + if hashname and hashname~="" then + local expanded=resolvers.expansion(hashname) or "" + if expanded~="" then + if trace_locating then + report_resolving("identifying tree %a from %a",expanded,hashname) + end + hashname=expanded + else + if trace_locating then + report_resolving("identifying tree %a",hashname) + end end + local realpath=resolveprefix(hashname) + if isdir(realpath) then + if trace_locating then + report_resolving("using path %a",realpath) + end + methodhandler('generators',hashname) + local content=instance.files[hashname] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",hashname) + end + caches.savecontent(hashname,"files",content) + else + report_resolving("invalid path %a",realpath) + end + end end local function load_databases() - locate_file_databases() - if instance.diskcache and not instance.renewcache then - load_file_databases() - if instance.loaderror then - generate_file_databases() - save_file_databases() - end - else - generate_file_databases() - if instance.renewcache then - save_file_databases() - end + locate_file_databases() + if instance.diskcache and not instance.renewcache then + load_file_databases() + if instance.loaderror then + generate_file_databases() + save_file_databases() + end + else + generate_file_databases() + if instance.renewcache then + save_file_databases() end + end end function resolvers.appendhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a appended",name) - end - insert(instance.hashes,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a appended",name) end + insert(instance.hashes,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.prependhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a prepended",name) - end - insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a prepended",name) end + insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.extendtexmfvariable(specification) - local t=resolvers.splitpath(getenv("TEXMF")) - insert(t,1,specification) - local newspec=concat(t,",") - if instance.environment["TEXMF"] then - instance.environment["TEXMF"]=newspec - elseif instance.variables["TEXMF"] then - instance.variables["TEXMF"]=newspec - else - end - reset_hashes() + local t=resolvers.splitpath(getenv("TEXMF")) + insert(t,1,specification) + local newspec=concat(t,",") + if instance.environment["TEXMF"] then + instance.environment["TEXMF"]=newspec + elseif instance.variables["TEXMF"] then + instance.variables["TEXMF"]=newspec + else + end + reset_hashes() end function resolvers.splitexpansions() - local ie=instance.expansions - for k,v in next,ie do - local t,tn,h,p={},0,{},splitconfigurationpath(v) - for kk=1,#p do - local vv=p[kk] - if vv~="" and not h[vv] then - tn=tn+1 - t[tn]=vv - h[vv]=true - end - end - if #t>1 then - ie[k]=t - else - ie[k]=t[1] - end + local ie=instance.expansions + for k,v in next,ie do + local t,tn,h,p={},0,{},splitconfigurationpath(v) + for kk=1,#p do + local vv=p[kk] + if vv~="" and not h[vv] then + tn=tn+1 + t[tn]=vv + h[vv]=true + end end + if #t>1 then + ie[k]=t + else + ie[k]=t[1] + end + end end function resolvers.datastate() - return caches.contentstate() + return caches.contentstate() end function resolvers.variable(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.variables[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.variables[name] + return result~=nil and result or "" end function resolvers.expansion(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.expansions[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.expansions[name] + return result~=nil and result or "" end function resolvers.unexpandedpathlist(str) - local pth=resolvers.variable(str) - local lst=resolvers.splitpath(pth) - return expandedpathfromlist(lst) + local pth=resolvers.variable(str) + local lst=resolvers.splitpath(pth) + return expandedpathfromlist(lst) end function resolvers.unexpandedpath(str) - return joinpath(resolvers.unexpandedpathlist(str)) + return joinpath(resolvers.unexpandedpathlist(str)) end function resolvers.pushpath(name) - local pathstack=instance.pathstack - local lastpath=pathstack[#pathstack] - local pluspath=filedirname(name) - if lastpath then - lastpath=collapsepath(filejoin(lastpath,pluspath)) - else - lastpath=collapsepath(pluspath) - end - insert(pathstack,lastpath) - if trace_paths then - report_resolving("pushing path %a",lastpath) - end + local pathstack=instance.pathstack + local lastpath=pathstack[#pathstack] + local pluspath=filedirname(name) + if lastpath then + lastpath=collapsepath(filejoin(lastpath,pluspath)) + else + lastpath=collapsepath(pluspath) + end + insert(pathstack,lastpath) + if trace_paths then + report_resolving("pushing path %a",lastpath) + end end function resolvers.poppath() - local pathstack=instance.pathstack - if trace_paths and #pathstack>0 then - report_resolving("popping path %a",pathstack[#pathstack]) - end - remove(pathstack) + local pathstack=instance.pathstack + if trace_paths and #pathstack>0 then + report_resolving("popping path %a",pathstack[#pathstack]) + end + remove(pathstack) end function resolvers.stackpath() - local pathstack=instance.pathstack - local currentpath=pathstack[#pathstack] - return currentpath~="" and currentpath or nil + local pathstack=instance.pathstack + local currentpath=pathstack[#pathstack] + return currentpath~="" and currentpath or nil end local done={} function resolvers.resetextrapaths() - local ep=instance.extra_paths - if not ep then - done={} - instance.extra_paths={} - elseif #ep>0 then - done={} - reset_caches() - end + local ep=instance.extra_paths + if not ep then + done={} + instance.extra_paths={} + elseif #ep>0 then + done={} + reset_caches() + end end function resolvers.getextrapaths() - return instance.extra_paths or {} + return instance.extra_paths or {} end function resolvers.registerextrapath(paths,subpaths) - if not subpaths or subpaths=="" then - if not paths or path=="" then - return - elseif done[paths] then - return - end - end - local paths=settings_to_array(paths) - local subpaths=settings_to_array(subpaths) - local ep=instance.extra_paths or {} - local oldn=#ep - local newn=oldn - local nofpaths=#paths - local nofsubpaths=#subpaths - if nofpaths>0 then - if nofsubpaths>0 then - for i=1,nofpaths do - local p=paths[i] - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=p.."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end - end - else - for i=1,nofpaths do - local p=paths[i] - if not done[p] then - newn=newn+1 - ep[newn]=cleanpath(p) - done[p]=true - end - end + if not subpaths or subpaths=="" then + if not paths or path=="" then + return + elseif done[paths] then + return + end + end + local paths=settings_to_array(paths) + local subpaths=settings_to_array(subpaths) + local ep=instance.extra_paths or {} + local oldn=#ep + local newn=oldn + local nofpaths=#paths + local nofsubpaths=#subpaths + if nofpaths>0 then + if nofsubpaths>0 then + for i=1,nofpaths do + local p=paths[i] + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=p.."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end end - elseif nofsubpaths>0 then - for i=1,oldn do - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=ep[i].."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end + end + else + for i=1,nofpaths do + local p=paths[i] + if not done[p] then + newn=newn+1 + ep[newn]=cleanpath(p) + done[p]=true end + end end - if newn>0 then - instance.extra_paths=ep - end - if newn~=oldn then - reset_caches() + elseif nofsubpaths>0 then + for i=1,oldn do + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=ep[i].."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end + end end + end + if newn>0 then + instance.extra_paths=ep + end + if newn~=oldn then + reset_caches() + end end function resolvers.pushextrapath(path) - local paths=settings_to_array(path) - if instance.extra_stack then - insert(instance.extra_stack,1,paths) - else - instance.extra_stack={ paths } - end - reset_caches() + local paths=settings_to_array(path) + if instance.extra_stack then + insert(instance.extra_stack,1,paths) + else + instance.extra_stack={ paths } + end + reset_caches() end function resolvers.popextrapath() - if instance.extra_stack then - reset_caches() - return remove(instance.extra_stack,1) - end + if instance.extra_stack then + reset_caches() + return remove(instance.extra_stack,1) + end end local function made_list(instance,list,extra_too) - local done={} - local new={} - local newn=0 - local function add(p) - for k=1,#p do - local v=p[k] - if not done[v] then - done[v]=true - newn=newn+1 - new[newn]=v - end - end + local done={} + local new={} + local newn=0 + local function add(p) + for k=1,#p do + local v=p[k] + if not done[v] then + done[v]=true + newn=newn+1 + new[newn]=v + end end - for k=1,#list do - local v=list[k] - if done[v] then - elseif find(v,"^[%.%/]$") then - done[v]=true - newn=newn+1 - new[newn]=v - else - break - end + end + for k=1,#list do + local v=list[k] + if done[v] then + elseif find(v,"^[%.%/]$") then + done[v]=true + newn=newn+1 + new[newn]=v + else + break + end + end + if extra_too then + local es=instance.extra_stack + if es and #es>0 then + for k=1,#es do + add(es[k]) + end end - if extra_too then - local es=instance.extra_stack - if es and #es>0 then - for k=1,#es do - add(es[k]) - end - end - local ep=instance.extra_paths - if ep and #ep>0 then - add(ep) - end + local ep=instance.extra_paths + if ep and #ep>0 then + add(ep) end - add(list) - return new + end + add(list) + return new end function resolvers.cleanpathlist(str) - local t=resolvers.expandedpathlist(str) - if t then - for i=1,#t do - t[i]=collapsepath(cleanpath(t[i])) - end + local t=resolvers.expandedpathlist(str) + if t then + for i=1,#t do + t[i]=collapsepath(cleanpath(t[i])) end - return t + end + return t end function resolvers.expandpath(str) - return joinpath(resolvers.expandedpathlist(str)) + return joinpath(resolvers.expandedpathlist(str)) end function resolvers.expandedpathlist(str,extra_too) - if not str then - return {} - elseif instance.savelists then - str=lpegmatch(dollarstripper,str) - local lists=instance.lists - local lst=lists[str] - if not lst then - local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) - lst=expandedpathfromlist(l) - lists[str]=lst - end - return lst - else - local lst=resolvers.splitpath(resolvers.expansion(str)) - return made_list(instance,expandedpathfromlist(lst),extra_too) + if not str then + return {} + elseif instance.savelists then + str=lpegmatch(dollarstripper,str) + local lists=instance.lists + local lst=lists[str] + if not lst then + local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) + lst=expandedpathfromlist(l) + lists[str]=lst end + return lst + else + local lst=resolvers.splitpath(resolvers.expansion(str)) + return made_list(instance,expandedpathfromlist(lst),extra_too) + end end function resolvers.expandedpathlistfromvariable(str) - str=lpegmatch(dollarstripper,str) - local tmp=resolvers.variableofformatorsuffix(str) - return resolvers.expandedpathlist(tmp~="" and tmp or str) + str=lpegmatch(dollarstripper,str) + local tmp=resolvers.variableofformatorsuffix(str) + return resolvers.expandedpathlist(tmp~="" and tmp or str) end function resolvers.expandpathfromvariable(str) - return joinpath(resolvers.expandedpathlistfromvariable(str)) + return joinpath(resolvers.expandedpathlistfromvariable(str)) end function resolvers.cleanedpathlist(v) - local t=resolvers.expandedpathlist(v) - for i=1,#t do - t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) - end - return t + local t=resolvers.expandedpathlist(v) + for i=1,#t do + t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) + end + return t end function resolvers.expandbraces(str) - local pth=expandedpathfromlist(resolvers.splitpath(str)) - return joinpath(pth) + local pth=expandedpathfromlist(resolvers.splitpath(str)) + return joinpath(pth) end function resolvers.registerfilehash(name,content,someerror) - if content then - instance.files[name]=content - else - instance.files[name]={} - if somerror==true then - instance.loaderror=someerror - end + if content then + instance.files[name]=content + else + instance.files[name]={} + if somerror==true then + instance.loaderror=someerror end + end end function resolvers.getfilehashes() - return instance and instance.files or {} + return instance and instance.files or {} end function resolvers.gethashes() - return instance and instance.hashes or {} + return instance and instance.hashes or {} end function resolvers.renewcache() - if instance then - instance.renewcache=true - end + if instance then + instance.renewcache=true + end end local function isreadable(name) - local readable=isfile(name) - if trace_detail then - if readable then - report_resolving("file %a is readable",name) - else - report_resolving("file %a is not readable",name) - end + local readable=isfile(name) + if trace_detail then + if readable then + report_resolving("file %a is readable",name) + else + report_resolving("file %a is not readable",name) end - return readable + end + return readable end local function collect_files(names) - local filelist={} - local noffiles=0 - local function check(hash,root,pathname,path,basename,name) - if not pathname or find(path,pathname) then - local variant=hash.type - local search=filejoin(root,path,name) - local result=methodhandler('concatinators',variant,root,path,name) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,basename,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } end - for k=1,#names do - local filename=names[k] + end + for k=1,#names do + local filename=names[k] + if trace_detail then + report_resolving("checking name %a",filename) + end + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false + else + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" + end + local hashes=instance.hashes + for h=1,#hashes do + local hash=hashes[h] + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("checking name %a",filename) + report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) end - local basename=filebasename(filename) - local pathname=filedirname(filename) - if pathname=="" or find(pathname,"^%.") then - pathname=false - else - pathname=gsub(pathname,"%*",".*") - pathname="/"..pathname.."$" - end - local hashes=instance.hashes - for h=1,#hashes do - local hash=hashes[h] - local hashname=hash.name - local content=hashname and instance.files[hashname] - if content then - if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) - end - local path,name=lookup(content,basename) - if path then - local metadata=content.metadata - local realroot=metadata and metadata.path or hashname - if type(path)=="string" then - check(hash,realroot,pathname,path,basename,name) - else - for i=1,#path do - check(hash,realroot,pathname,path[i],basename,name) - end - end - end - elseif trace_locating then - report_resolving("no match in %a (%s)",hashname,basename) + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,basename,name) + else + for i=1,#path do + check(hash,realroot,pathname,path[i],basename,name) end + end end + elseif trace_locating then + report_resolving("no match in %a (%s)",hashname,basename) + end end - return noffiles>0 and filelist or nil + end + return noffiles>0 and filelist or nil end local fit={} function resolvers.registerintrees(filename,format,filetype,usedmethod,foundname) - local foundintrees=instance.foundintrees - if usedmethod=="direct" and filename==foundname and fit[foundname] then - else - local collapsed=collapsepath(foundname,true) - local t={ - filename=filename, - format=format~="" and format or nil, - filetype=filetype~="" and filetype or nil, - usedmethod=usedmethod, - foundname=foundname, - fullname=collapsed, - } - fit[foundname]=t - foundintrees[#foundintrees+1]=t - end + local foundintrees=instance.foundintrees + if usedmethod=="direct" and filename==foundname and fit[foundname] then + else + local collapsed=collapsepath(foundname,true) + local t={ + filename=filename, + format=format~="" and format or nil, + filetype=filetype~="" and filetype or nil, + usedmethod=usedmethod, + foundname=foundname, + fullname=collapsed, + } + fit[foundname]=t + foundintrees[#foundintrees+1]=t + end end function resolvers.foundintrees() - return instance.foundintrees or {} + return instance.foundintrees or {} end function resolvers.foundintree(fullname) - local f=fit[fullname] - return f and f.usedmethod=="database" + local f=fit[fullname] + return f and f.usedmethod=="database" end local function can_be_dir(name) - local fakepaths=instance.fakepaths - if not fakepaths[name] then - if isdir(name) then - fakepaths[name]=1 - else - fakepaths[name]=2 - end + local fakepaths=instance.fakepaths + if not fakepaths[name] then + if isdir(name) then + fakepaths[name]=1 + else + fakepaths[name]=2 end - return fakepaths[name]==1 + end + return fakepaths[name]==1 end local preparetreepattern=Cs((P(".")/"%%."+P("-")/"%%-"+P(1))^0*Cc("$")) local collect_instance_files local function find_analyze(filename,askedformat,allresults) - local filetype='' - local filesuffix=suffixonly(filename) - local wantedfiles={} - wantedfiles[#wantedfiles+1]=filename - if askedformat=="" then - if filesuffix=="" or not suffixmap[filesuffix] then - local defaultsuffixes=resolvers.defaultsuffixes - local formatofsuffix=resolvers.formatofsuffix - for i=1,#defaultsuffixes do - local forcedname=filename..'.'..defaultsuffixes[i] - wantedfiles[#wantedfiles+1]=forcedname - filetype=formatofsuffix(forcedname) - if trace_locating then - report_resolving("forcing filetype %a",filetype) - end - end - else - filetype=resolvers.formatofsuffix(filename) - if trace_locating then - report_resolving("using suffix based filetype %a",filetype) - end + local filetype='' + local filesuffix=suffixonly(filename) + local wantedfiles={} + wantedfiles[#wantedfiles+1]=filename + if askedformat=="" then + if filesuffix=="" or not suffixmap[filesuffix] then + local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix + for i=1,#defaultsuffixes do + local forcedname=filename..'.'..defaultsuffixes[i] + wantedfiles[#wantedfiles+1]=forcedname + filetype=formatofsuffix(forcedname) + if trace_locating then + report_resolving("forcing filetype %a",filetype) end + end else - if filesuffix=="" or not suffixmap[filesuffix] then - local format_suffixes=suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] - end - end - end - filetype=askedformat - if trace_locating then - report_resolving("using given filetype %a",filetype) + filetype=resolvers.formatofsuffix(filename) + if trace_locating then + report_resolving("using suffix based filetype %a",filetype) + end + end + else + if filesuffix=="" or not suffixmap[filesuffix] then + local format_suffixes=suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] end + end end - return filetype,wantedfiles + filetype=askedformat + if trace_locating then + report_resolving("using given filetype %a",filetype) + end + end + return filetype,wantedfiles end local function find_direct(filename,allresults) - if not dangerous[askedformat] and isreadable(filename) then - if trace_detail then - report_resolving("file %a found directly",filename) - end - return "direct",{ filename } + if not dangerous[askedformat] and isreadable(filename) then + if trace_detail then + report_resolving("file %a found directly",filename) end + return "direct",{ filename } + end end local function find_wildcard(filename,allresults) - if find(filename,'*',1,true) then - if trace_locating then - report_resolving("checking wildcard %a",filename) - end - local result=resolvers.findwildcardfiles(filename) - if result then - return "wildcard",result - end - end -end -local function find_qualified(filename,allresults,askedformat,alsostripped) - if not is_qualified_path(filename) then - return - end + if find(filename,'*',1,true) then if trace_locating then - report_resolving("checking qualified name %a",filename) + report_resolving("checking wildcard %a",filename) end - if isreadable(filename) then - if trace_detail then - report_resolving("qualified file %a found",filename) - end - return "qualified",{ filename } + local result=resolvers.findwildcardfiles(filename) + if result then + return "wildcard",result end + end +end +local function find_qualified(filename,allresults,askedformat,alsostripped) + if not is_qualified_path(filename) then + return + end + if trace_locating then + report_resolving("checking qualified name %a",filename) + end + if isreadable(filename) then if trace_detail then - report_resolving("locating qualified file %a",filename) - end - local forcedname,suffix="",suffixonly(filename) - if suffix=="" then - local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - local s=format_suffixes[i] - forcedname=filename.."."..s - if isreadable(forcedname) then - if trace_locating then - report_resolving("no suffix, forcing format filetype %a",s) - end - return "qualified",{ forcedname } - end - end + report_resolving("qualified file %a found",filename) + end + return "qualified",{ filename } + end + if trace_detail then + report_resolving("locating qualified file %a",filename) + end + local forcedname,suffix="",suffixonly(filename) + if suffix=="" then + local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + local s=format_suffixes[i] + forcedname=filename.."."..s + if isreadable(forcedname) then + if trace_locating then + report_resolving("no suffix, forcing format filetype %a",s) + end + return "qualified",{ forcedname } end + end end - if alsostripped and suffix and suffix~="" then - local basename=filebasename(filename) - local pattern=lpegmatch(preparetreepattern,filename) - local savedformat=askedformat - local format=savedformat or "" - if format=="" then - askedformat=resolvers.formatofsuffix(suffix) + end + if alsostripped and suffix and suffix~="" then + local basename=filebasename(filename) + local pattern=lpegmatch(preparetreepattern,filename) + local savedformat=askedformat + local format=savedformat or "" + if format=="" then + askedformat=resolvers.formatofsuffix(suffix) + end + if not format then + askedformat="othertextfiles" + end + if basename~=filename then + local resolved=collect_instance_files(basename,askedformat,allresults) + if #resolved==0 then + local lowered=lower(basename) + if filename~=lowered then + resolved=collect_instance_files(lowered,askedformat,allresults) end - if not format then - askedformat="othertextfiles" + end + resolvers.format=savedformat + if #resolved>0 then + local result={} + for r=1,#resolved do + local rr=resolved[r] + if find(rr,pattern) then + result[#result+1]=rr + end end - if basename~=filename then - local resolved=collect_instance_files(basename,askedformat,allresults) - if #resolved==0 then - local lowered=lower(basename) - if filename~=lowered then - resolved=collect_instance_files(lowered,askedformat,allresults) - end - end - resolvers.format=savedformat - if #resolved>0 then - local result={} - for r=1,#resolved do - local rr=resolved[r] - if find(rr,pattern) then - result[#result+1]=rr - end - end - if #result>0 then - return "qualified",result - end - end + if #result>0 then + return "qualified",result end + end end + end end local function check_subpath(fname) - if isreadable(fname) then - if trace_detail then - report_resolving("found %a by deep scanning",fname) - end - return fname + if isreadable(fname) then + if trace_detail then + report_resolving("found %a by deep scanning",fname) end + return fname + end end local function makepathlist(list,filetype) - local typespec=resolvers.variableofformat(filetype) - local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) - local entry={} - if pathlist and #pathlist>0 then - for k=1,#pathlist do - local path=pathlist[k] - local prescanned=find(path,'^!!') - local resursive=find(path,'//$') - local pathname=lpegmatch(inhibitstripper,path) - local expression=makepathexpression(pathname) - local barename=gsub(pathname,"/+$","") - barename=resolveprefix(barename) - local scheme=url.hasscheme(barename) - local schemename=gsub(barename,"%.%*$",'') - entry[k]={ - path=path, - pathname=pathname, - prescanned=prescanned, - recursive=recursive, - expression=expression, - barename=barename, - scheme=scheme, - schemename=schemename, - } - end - entry.typespec=typespec - list[filetype]=entry - else - list[filetype]=false - end - return entry + local typespec=resolvers.variableofformat(filetype) + local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) + local entry={} + if pathlist and #pathlist>0 then + for k=1,#pathlist do + local path=pathlist[k] + local prescanned=find(path,'^!!') + local resursive=find(path,'//$') + local pathname=lpegmatch(inhibitstripper,path) + local expression=makepathexpression(pathname) + local barename=gsub(pathname,"/+$","") + barename=resolveprefix(barename) + local scheme=url.hasscheme(barename) + local schemename=gsub(barename,"%.%*$",'') + entry[k]={ + path=path, + pathname=pathname, + prescanned=prescanned, + recursive=recursive, + expression=expression, + barename=barename, + scheme=scheme, + schemename=schemename, + } + end + entry.typespec=typespec + list[filetype]=entry + else + list[filetype]=false + end + return entry end local function find_intree(filename,filetype,wantedfiles,allresults) - local pathlists=instance.pathlists - if not pathlists then - pathlists=setmetatableindex({},makepathlist) - instance.pathlists=pathlists - end - local pathlist=pathlists[filetype] - if pathlist then - local method="intree" - local filelist=collect_files(wantedfiles) - local dirlist={} - local result={} - if filelist then - for i=1,#filelist do - dirlist[i]=filedirname(filelist[i][3]).."/" + local pathlists=instance.pathlists + if not pathlists then + pathlists=setmetatableindex({},makepathlist) + instance.pathlists=pathlists + end + local pathlist=pathlists[filetype] + if pathlist then + local method="intree" + local filelist=collect_files(wantedfiles) + local dirlist={} + local result={} + if filelist then + for i=1,#filelist do + dirlist[i]=filedirname(filelist[i][3]).."/" + end + end + if trace_detail then + report_resolving("checking filename %a in tree",filename) + end + for k=1,#pathlist do + local entry=pathlist[k] + local path=entry.path + local pathname=entry.pathname + local done=false + if filelist then + local expression=entry.expression + if trace_detail then + report_resolving("using pattern %a for path %a",expression,pathname) + end + for k=1,#filelist do + local fl=filelist[k] + local f=fl[2] + local d=dirlist[k] + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) + done=true + if allresults then + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) + end + else + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) + end + break end + elseif trace_detail then + report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + end end - if trace_detail then - report_resolving("checking filename %a in tree",filename) - end - for k=1,#pathlist do - local entry=pathlist[k] - local path=entry.path - local pathname=entry.pathname - local done=false - if filelist then - local expression=entry.expression + end + if done then + method="database" + else + method="filesystem" + local scheme=entry.scheme + if not scheme or scheme=="file" then + local pname=entry.schemename + if not find(pname,"*",1,true) then + if can_be_dir(pname) then + if not done and not entry.prescanned then if trace_detail then - report_resolving("using pattern %a for path %a",expression,pathname) - end - for k=1,#filelist do - local fl=filelist[k] - local f=fl[2] - local d=dirlist[k] - if find(d,expression) or find(resolveprefix(d),expression) then - result[#result+1]=resolveprefix(fl[3]) - done=true - if allresults then - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) - end - else - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) - end - break - end - elseif trace_detail then - report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + report_resolving("quick root scan for %a",pname) + end + for k=1,#wantedfiles do + local w=wantedfiles[k] + local fname=check_subpath(filejoin(pname,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end - end - end - if done then - method="database" - else - method="filesystem" - local scheme=entry.scheme - if not scheme or scheme=="file" then - local pname=entry.schemename - if not find(pname,"*",1,true) then - if can_be_dir(pname) then - if not done and not entry.prescanned then - if trace_detail then - report_resolving("quick root scan for %a",pname) - end - for k=1,#wantedfiles do - local w=wantedfiles[k] - local fname=check_subpath(filejoin(pname,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - if not done and entry.recursive then - if trace_detail then - report_resolving("scanning filesystem for %a",pname) - end - local files=resolvers.simplescanfiles(pname,false,true) - for k=1,#wantedfiles do - local w=wantedfiles[k] - local subpath=files[w] - if not subpath or subpath=="" then - elseif type(subpath)=="string" then - local fname=check_subpath(filejoin(pname,subpath,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - else - for i=1,#subpath do - local sp=subpath[i] - if sp=="" then - else - local fname=check_subpath(filejoin(pname,sp,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - end - if done and not allresults then - break - end - end - end - end - end + end + end + if not done and entry.recursive then + if trace_detail then + report_resolving("scanning filesystem for %a",pname) + end + local files=resolvers.simplescanfiles(pname,false,true) + for k=1,#wantedfiles do + local w=wantedfiles[k] + local subpath=files[w] + if not subpath or subpath=="" then + elseif type(subpath)=="string" then + local fname=check_subpath(filejoin(pname,subpath,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end + end else - end - else - for k=1,#wantedfiles do - local pname=entry.barename - local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) - if fname then + for i=1,#subpath do + local sp=subpath[i] + if sp=="" then + else + local fname=check_subpath(filejoin(pname,sp,w)) + if fname then result[#result+1]=fname done=true if not allresults then - break + break end + end end + end + if done and not allresults then + break + end end + end end + end end - if done and not allresults then + else + end + else + for k=1,#wantedfiles do + local pname=entry.barename + local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) + if fname then + result[#result+1]=fname + done=true + if not allresults then break + end end + end end - if #result>0 then - return method,result - end + end + if done and not allresults then + break + end + end + if #result>0 then + return method,result end + end end local function find_onpath(filename,filetype,wantedfiles,allresults) - if trace_detail then - report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) - end - local result={} - for k=1,#wantedfiles do - local fname=wantedfiles[k] - if fname and isreadable(fname) then - filename=fname - result[#result+1]=filejoin('.',fname) - if not allresults then - break - end - end - end - if #result>0 then - return "onpath",result + if trace_detail then + report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) + end + local result={} + for k=1,#wantedfiles do + local fname=wantedfiles[k] + if fname and isreadable(fname) then + filename=fname + result[#result+1]=filejoin('.',fname) + if not allresults then + break + end end + end + if #result>0 then + return "onpath",result + end end local function find_otherwise(filename,filetype,wantedfiles,allresults) - local filelist=collect_files(wantedfiles) - local fl=filelist and filelist[1] - if fl then - return "otherwise",{ resolveprefix(fl[3]) } - end + local filelist=collect_files(wantedfiles) + local fl=filelist and filelist[1] + if fl then + return "otherwise",{ resolveprefix(fl[3]) } + end end collect_instance_files=function(filename,askedformat,allresults) - if not filename or filename=="" then - return {} - end - askedformat=askedformat or "" - filename=collapsepath(filename,".") - filename=gsub(filename,"^%./",getcurrentdir().."/") - if allresults then - local filetype,wantedfiles=find_analyze(filename,askedformat) - local results={ - { find_direct (filename,true) }, - { find_wildcard (filename,true) }, - { find_qualified(filename,true,askedformat) }, - { find_intree (filename,filetype,wantedfiles,true) }, - { find_onpath (filename,filetype,wantedfiles,true) }, - { find_otherwise(filename,filetype,wantedfiles,true) }, - } - local result,status,done={},{},{} - for k,r in next,results do - local method,list=r[1],r[2] - if method and list then - for i=1,#list do - local c=collapsepath(list[i]) - if not done[c] then - result[#result+1]=c - done[c]=true - end - status[#status+1]=formatters["%-10s: %s"](method,c) - end - end - end - if trace_detail then - report_resolving("lookup status: %s",table.serialize(status,filename)) + if not filename or filename=="" then + return {} + end + askedformat=askedformat or "" + filename=collapsepath(filename,".") + filename=gsub(filename,"^%./",getcurrentdir().."/") + if allresults then + local filetype,wantedfiles=find_analyze(filename,askedformat) + local results={ + { find_direct (filename,true) }, + { find_wildcard (filename,true) }, + { find_qualified(filename,true,askedformat) }, + { find_intree (filename,filetype,wantedfiles,true) }, + { find_onpath (filename,filetype,wantedfiles,true) }, + { find_otherwise(filename,filetype,wantedfiles,true) }, + } + local result,status,done={},{},{} + for k,r in next,results do + local method,list=r[1],r[2] + if method and list then + for i=1,#list do + local c=collapsepath(list[i]) + if not done[c] then + result[#result+1]=c + done[c]=true + end + status[#status+1]=formatters["%-10s: %s"](method,c) end - return result,status - else - local method,result,stamp,filetype,wantedfiles - if instance.remember then - if askedformat=="" then - stamp=formatters["%s::%s"](suffixonly(filename),filename) - else - stamp=formatters["%s::%s"](askedformat,filename) - end - result=stamp and instance.found[stamp] - if result then - if trace_locating then - report_resolving("remembered file %a",filename) - end - return result - end + end + end + if trace_detail then + report_resolving("lookup status: %s",table.serialize(status,filename)) + end + return result,status + else + local method,result,stamp,filetype,wantedfiles + if instance.remember then + if askedformat=="" then + stamp=formatters["%s::%s"](suffixonly(filename),filename) + else + stamp=formatters["%s::%s"](askedformat,filename) + end + result=stamp and instance.found[stamp] + if result then + if trace_locating then + report_resolving("remembered file %a",filename) end - method,result=find_direct(filename) + return result + end + end + method,result=find_direct(filename) + if not result then + method,result=find_wildcard(filename) + if not result then + method,result=find_qualified(filename,false,askedformat) if not result then - method,result=find_wildcard(filename) - if not result then - method,result=find_qualified(filename,false,askedformat) - if not result then - filetype,wantedfiles=find_analyze(filename,askedformat) - method,result=find_intree(filename,filetype,wantedfiles) - if not result then - method,result=find_onpath(filename,filetype,wantedfiles) - if resolve_otherwise and not result then - method,result=find_otherwise(filename,filetype,wantedfiles) - end - end - end - end - end - if result and #result>0 then - local foundname=collapsepath(result[1]) - resolvers.registerintrees(filename,askedformat,filetype,method,foundname) - result={ foundname } - else - result={} - end - if stamp then - if trace_locating then - report_resolving("remembering file %a using hash %a",filename,stamp) + filetype,wantedfiles=find_analyze(filename,askedformat) + method,result=find_intree(filename,filetype,wantedfiles) + if not result then + method,result=find_onpath(filename,filetype,wantedfiles) + if resolve_otherwise and not result then + method,result=find_otherwise(filename,filetype,wantedfiles) end - instance.found[stamp]=result + end end - return result + end + end + if result and #result>0 then + local foundname=collapsepath(result[1]) + resolvers.registerintrees(filename,askedformat,filetype,method,foundname) + result={ foundname } + else + result={} end + if stamp then + if trace_locating then + report_resolving("remembering file %a using hash %a",filename,stamp) + end + instance.found[stamp]=result + end + return result + end end local function findfiles(filename,filetype,allresults) - if not filename or filename=="" then - return {} - end - local result,status=collect_instance_files(filename,filetype or "",allresults) - if not result or #result==0 then - local lowered=lower(filename) - if filename~=lowered then - result,status=collect_instance_files(lowered,filetype or "",allresults) - end + if not filename or filename=="" then + return {} + end + local result,status=collect_instance_files(filename,filetype or "",allresults) + if not result or #result==0 then + local lowered=lower(filename) + if filename~=lowered then + result,status=collect_instance_files(lowered,filetype or "",allresults) end - return result or {},status + end + return result or {},status end function resolvers.findfiles(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,true) - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,true) + end end function resolvers.findfile(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,false)[1] or "" - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,false)[1] or "" + end end function resolvers.findpath(filename,filetype) - return filedirname(findfiles(filename,filetype,false)[1] or "") + return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local base=filebasename(filename) - local result={} - local hashes=instance.hashes - local function okay(hash,path,name) - local found=methodhandler('concatinators',hash.type,hash.name,path,name) - if found and found~="" then - result[#result+1]=resolveprefix(found) - return not allresults - end - end - for k=1,#hashes do - local hash=hashes[k] - local content=instance.files[hash.name] - if content then - local path,name=lookup(content,base) - if not path then - elseif type(path)=="string" then - if okay(hash,path,name) then - return result - end - else - for i=1,#path do - if okay(hash,path[i],name) then - return result - end - end - end + local base=filebasename(filename) + local result={} + local hashes=instance.hashes + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end + for k=1,#hashes do + local hash=hashes[k] + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result + end + else + for i=1,#path do + if okay(hash,path[i],name) then + return result + end end + end end - return result + end + return result end function resolvers.findgivenfiles(filename) - return findgivenfiles(filename,true) + return findgivenfiles(filename,true) end function resolvers.findgivenfile(filename) - return findgivenfiles(filename,false)[1] or "" + return findgivenfiles(filename,false)[1] or "" end local makewildcard=Cs( - (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 + (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) - return lpegmatch(makewildcard,pattern) or pattern + return lpegmatch(makewildcard,pattern) or pattern end local function findwildcardfiles(filename,allresults,result) - local result=result or {} - local base=filebasename(filename) - local dirn=filedirname(filename) - local path=lower(lpegmatch(makewildcard,dirn) or dirn) - local name=lower(lpegmatch(makewildcard,base) or base) - local files=instance.files - if find(name,"*",1,true) then - local hashes=instance.hashes - local function okay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end - end + local result=result or {} + local base=filebasename(filename) + local dirn=filedirname(filename) + local path=lower(lpegmatch(makewildcard,dirn) or dirn) + local name=lower(lpegmatch(makewildcard,base) or base) + local files=instance.files + if find(name,"*",1,true) then + local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults end - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - for found,base in filtered(files[hashname],name) do - if type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end - end + end + end + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break end - end - else - local function okayokay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end end + end end - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - local found,base=lookup(content,base) - if not found then - elseif type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end + end + end + else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break end + end end + end end - return result + end + return result end function resolvers.findwildcardfiles(filename,result) - return findwildcardfiles(filename,true,result) + return findwildcardfiles(filename,true,result) end function resolvers.findwildcardfile(filename) - return findwildcardfiles(filename,false)[1] or "" + return findwildcardfiles(filename,false)[1] or "" end function resolvers.automount() end function resolvers.starttiming() - statistics.starttiming(instance) + statistics.starttiming(instance) end function resolvers.stoptiming() - statistics.stoptiming(instance) + statistics.stoptiming(instance) end function resolvers.load(option) - resolvers.starttiming() - identify_configuration_files() - load_configuration_files() - if option~="nofiles" then - load_databases() - resolvers.automount() - end - resolvers.stoptiming() - local files=instance.files - return files and next(files) and true + resolvers.starttiming() + identify_configuration_files() + load_configuration_files() + if option~="nofiles" then + load_databases() + resolvers.automount() + end + resolvers.stoptiming() + local files=instance.files + return files and next(files) and true end function resolvers.loadtime() - return statistics.elapsedtime(instance) + return statistics.elapsedtime(instance) end local function report(str) - if trace_locating then - report_resolving(str) - else - print(str) - end + if trace_locating then + report_resolving(str) + else + print(str) + end end function resolvers.dowithfilesandreport(command,files,...) - if files and #files>0 then - if trace_locating then - report('') - end - if type(files)=="string" then - files={ files } - end - for f=1,#files do - local file=files[f] - local result=command(file,...) - if type(result)=='string' then - report(result) - else - for i=1,#result do - report(result[i]) - end - end + if files and #files>0 then + if trace_locating then + report('') + end + if type(files)=="string" then + files={ files } + end + for f=1,#files do + local file=files[f] + local result=command(file,...) + if type(result)=='string' then + report(result) + else + for i=1,#result do + report(result[i]) end + end end + end end -function resolvers.showpath(str) - return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) +function resolvers.showpath(str) + return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) end function resolvers.registerfile(files,name,path) - if files[name] then - if type(files[name])=='string' then - files[name]={ files[name],path } - else - files[name]=path - end + if files[name] then + if type(files[name])=='string' then + files[name]={ files[name],path } else - files[name]=path + files[name]=path end + else + files[name]=path + end end function resolvers.dowithpath(name,func) - local pathlist=resolvers.expandedpathlist(name) - for i=1,#pathlist do - func("^"..cleanpath(pathlist[i])) - end + local pathlist=resolvers.expandedpathlist(name) + for i=1,#pathlist do + func("^"..cleanpath(pathlist[i])) + end end function resolvers.dowithvariable(name,func) - func(expandedvariable(name)) + func(expandedvariable(name)) end function resolvers.locateformat(name) - local engine=environment.ownmain or "luatex" - local barename=removesuffix(name) - local fullname=addsuffix(barename,"fmt") - local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" - if fmtname=="" then - fmtname=resolvers.findfile(fullname) - fmtname=cleanpath(fmtname) - end - if fmtname~="" then - local barename=removesuffix(fmtname) - local luaname=addsuffix(barename,luasuffixes.lua) - local lucname=addsuffix(barename,luasuffixes.luc) - local luiname=addsuffix(barename,luasuffixes.lui) - if isfile(luiname) then - return barename,luiname - elseif isfile(lucname) then - return barename,lucname - elseif isfile(luaname) then - return barename,luaname - end - end - return nil,nil + local engine=environment.ownmain or "luatex" + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") + local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" + if fmtname=="" then + fmtname=resolvers.findfile(fullname) + fmtname=cleanpath(fmtname) + end + if fmtname~="" then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then + return barename,luiname + elseif isfile(lucname) then + return barename,lucname + elseif isfile(luaname) then + return barename,luaname + end + end + return nil,nil end function resolvers.booleanvariable(str,default) - local b=resolvers.expansion(str) - if b=="" then - return default - else - b=toboolean(b) - return (b==nil and default) or b - end + local b=resolvers.expansion(str) + if b=="" then + return default + else + b=toboolean(b) + return (b==nil and default) or b + end end function resolvers.dowithfilesintree(pattern,handle,before,after) - local hashes=instance.hashes - for i=1,#hashes do - local hash=hashes[i] - local blobtype=hash.type - local blobpath=hash.name - if blobtype and blobpath then - local total=0 - local checked=0 - local done=0 - if before then - before(blobtype,blobpath,pattern) - end - for path,name in filtered(instance.files[blobpath],pattern) do - if type(path)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,path,name) then - done=done+1 - end - else - checked=checked+#path - for i=1,#path do - if handle(blobtype,blobpath,path[i],name) then - done=done+1 - end - end - end - end - if after then - after(blobtype,blobpath,pattern,total,checked,done) + local hashes=instance.hashes + for i=1,#hashes do + local hash=hashes[i] + local blobtype=hash.type + local blobpath=hash.name + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 + if before then + before(blobtype,blobpath,pattern) + end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end + end end + end + if after then + after(blobtype,blobpath,pattern,checked,done) + end end + end end local obsolete=resolvers.obsolete or {} resolvers.obsolete=obsolete -resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile -resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles +resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile +resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles function resolvers.knownvariables(pattern) - if instance then - local environment=instance.environment - local variables=instance.variables - local expansions=instance.expansions - local order=instance.order - local pattern=upper(pattern or "") - local result={} - for i=1,#order do - for key in next,order[i] do - if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then - result[key]={ - environment=rawget(environment,key), - variable=key, - expansion=expansions[key], - resolved=resolveprefix(expansions[key]), - } - end - end + if instance then + local environment=instance.environment + local variables=instance.variables + local expansions=instance.expansions + local order=instance.order + local pattern=upper(pattern or "") + local result={} + for i=1,#order do + for key in next,order[i] do + if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then + result[key]={ + environment=rawget(environment,key), + variable=key, + expansion=expansions[key], + resolved=resolveprefix(expansions[key]), + } end - return result - else - return {} + end end + return result + else + return {} + end end @@ -19311,14 +22885,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 4090, stripped down to: 3059 +-- original size: 4854, stripped down to: 2889 if not modules then modules={} end modules ['data-pre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local prefixes=resolvers.prefixes @@ -19331,64 +22905,64 @@ local dirname=file.dirname local joinpath=file.join local isfile=lfs.isfile prefixes.environment=function(str) - return cleanpath(expansion(str)) + return cleanpath(expansion(str)) end local function relative(str,n) - if not isfile(str) then - local pstr="./"..str + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str if isfile(pstr) then - str=pstr + str=pstr + break else - local p="../" - for i=1,n or 2 do - local pstr=p..str - if isfile(pstr) then - str=pstr - break - else - p=p.."../" - end - end + p=p.."../" end + end end - return cleanpath(str) + end + return cleanpath(str) end local function locate(str) - local fullname=findgivenfile(str) or "" - return cleanpath(fullname~="" and fullname or str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) end prefixes.relative=relative prefixes.locate=locate prefixes.auto=function(str) - local fullname=relative(str) - if not isfile(fullname) then - fullname=locate(str) - end - return fullname + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) + end + return fullname end prefixes.filename=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(basename((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(basename((fullname~="" and fullname) or str)) end prefixes.pathname=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(dirname((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(dirname((fullname~="" and fullname) or str)) end prefixes.selfautoloc=function(str) - local pth=getenv('SELFAUTOLOC') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOLOC') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautoparent=function(str) - local pth=getenv('SELFAUTOPARENT') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOPARENT') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautodir=function(str) - local pth=getenv('SELFAUTODIR') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTODIR') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.home=function(str) - local pth=getenv('HOME') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('HOME') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.env=prefixes.environment prefixes.rel=prefixes.relative @@ -19398,24 +22972,24 @@ prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname local function toppath() - local inputstack=resolvers.inputstack - if not inputstack then - return "." - end - local pathname=dirname(inputstack[#inputstack] or "") - if pathname=="" then - return "." - else - return pathname - end + local inputstack=resolvers.inputstack + if not inputstack then + return "." + end + local pathname=dirname(inputstack[#inputstack] or "") + if pathname=="" then + return "." + else + return pathname + end end local function jobpath() - local path=resolvers.stackpath() - if not path or path=="" then - return "." - else - return path - end + local path=resolvers.stackpath() + if not path or path=="" then + return "." + else + return path + end end resolvers.toppath=toppath resolvers.jobpath=jobpath @@ -19423,8 +22997,6 @@ prefixes.toppath=function(str) return cleanpath(joinpath(toppath(),str)) end prefixes.jobpath=function(str) return cleanpath(joinpath(jobpath(),str)) end resolvers.setdynamic("toppath") resolvers.setdynamic("jobpath") -prefixes.jobfile=prefixes.jobpath -resolvers.setdynamic("jobfile") end -- of closure @@ -19433,14 +23005,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-inp"] = package.loaded["data-inp"] or true --- original size: 910, stripped down to: 823 +-- original size: 910, stripped down to: 818 if not modules then modules={} end modules ['data-inp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19463,14 +23035,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-out"] = package.loaded["data-out"] or true --- original size: 530, stripped down to: 475 +-- original size: 530, stripped down to: 470 if not modules then modules={} end modules ['data-out']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19486,16 +23058,16 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3863, stripped down to: 3310 +-- original size: 3863, stripped down to: 3170 if not modules then modules={} end modules ['data-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -19503,88 +23075,88 @@ local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolve local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local filename=specification.filename - local realname=resolveprefix(filename) - if realname and realname~='' and lfs.isdir(realname) then - if trace_locating then - report_files("file locator %a found as %a",filename,realname) - end - resolvers.appendhash('file',filename,true) - elseif trace_locating then - report_files("file locator %a not found",filename) + local filename=specification.filename + local realname=resolveprefix(filename) + if realname and realname~='' and lfs.isdir(realname) then + if trace_locating then + report_files("file locator %a found as %a",filename,realname) end + resolvers.appendhash('file',filename,true) + elseif trace_locating then + report_files("file locator %a not found",filename) + end end function hashers.file(specification) - local pathname=specification.filename - local content=caches.loadcontent(pathname,'files') - resolvers.registerfilehash(pathname,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local pathname=specification.filename - local content=resolvers.scanfiles(pathname,false,true) - resolvers.registerfilehash(pathname,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) - local filename=specification.filename - local foundname=resolvers.findfile(filename,filetype) - if foundname and foundname~="" then - if trace_locating then - report_files("file finder: %a found",filename) - end - return foundname - else - if trace_locating then - report_files("file finder: %a not found",filename) - end - return finders.notfound() + local filename=specification.filename + local foundname=resolvers.findfile(filename,filetype) + if foundname and foundname~="" then + if trace_locating then + report_files("file finder: %a found",filename) + end + return foundname + else + if trace_locating then + report_files("file finder: %a not found",filename) end + return finders.notfound() + end end function openers.helpers.textopener(tag,filename,f) - return { - reader=function() return f:read () end, - close=function() logs.show_close(filename) return f:close() end, - } + return { + reader=function() return f:read () end, + close=function() logs.show_close(filename) return f:close() end, + } end function openers.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"r") - if f then - if trace_locating then - report_files("file opener: %a opened",filename) - end - return openers.helpers.textopener("file",filename,f) - end - end - if trace_locating then - report_files("file opener: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"r") + if f then + if trace_locating then + report_files("file opener: %a opened",filename) + end + return openers.helpers.textopener("file",filename,f) end - return openers.notfound() + end + if trace_locating then + report_files("file opener: %a not found",filename) + end + return openers.notfound() end function loaders.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"rb") - if f then - logs.show_load(filename) - if trace_locating then - report_files("file loader: %a loaded",filename) - end - local s=f:read("*a") - if checkgarbage then - checkgarbage(#s) - end - f:close() - if s then - return true,s,#s - end - end - end - if trace_locating then - report_files("file loader: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"rb") + if f then + logs.show_load(filename) + if trace_locating then + report_files("file loader: %a loaded",filename) + end + local s=f:read("*a") + if checkgarbage then + checkgarbage(#s) + end + f:close() + if s then + return true,s,#s + end end - return loaders.notfound() + end + if trace_locating then + report_files("file loader: %a not found",filename) + end + return loaders.notfound() end @@ -19594,116 +23166,116 @@ do -- create closure to overcome 200 locals limit package.loaded["data-con"] = package.loaded["data-con"] or true --- original size: 5029, stripped down to: 3607 +-- original size: 5029, stripped down to: 3432 if not modules then modules={} end modules ['data-con']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) -local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) -local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) +local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) containers=containers or {} local containers=containers containers.usecache=true local report_containers=logs.reporter("resolvers","containers") local allocated={} local mt={ - __index=function(t,k) - if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } - t.writable=writable - return writable - elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } - t.readables=readables - return readables - end - end, - __storage__=true + __index=function(t,k) + if k=="writable" then + local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + t.writable=writable + return writable + elseif k=="readables" then + local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + t.readables=readables + return readables + end + end, + __storage__=true } function containers.define(category,subcategory,version,enabled) - if category and subcategory then - local c=allocated[category] - if not c then - c={} - allocated[category]=c - end - local s=c[subcategory] - if not s then - s={ - category=category, - subcategory=subcategory, - storage={}, - enabled=enabled, - version=version or math.pi, - trace=false, - } - setmetatable(s,mt) - c[subcategory]=s - end - return s + if category and subcategory then + local c=allocated[category] + if not c then + c={} + allocated[category]=c + end + local s=c[subcategory] + if not s then + s={ + category=category, + subcategory=subcategory, + storage={}, + enabled=enabled, + version=version or math.pi, + trace=false, + } + setmetatable(s,mt) + c[subcategory]=s end + return s + end end function containers.is_usable(container,name) - return container.enabled and caches and caches.is_writable(container.writable,name) + return container.enabled and caches and caches.is_writable(container.writable,name) end function containers.is_valid(container,name) - if name and name~="" then - local storage=container.storage[name] - return storage and storage.cache_version==container.version - else - return false - end + if name and name~="" then + local storage=container.storage[name] + return storage and storage.cache_version==container.version + else + return false + end end function containers.read(container,name) - local storage=container.storage - local stored=storage[name] - if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name,container.writable) - if stored and stored.cache_version==container.version then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","load",container.subcategory,name) - end - else - stored=nil - end - storage[name]=stored - elseif stored then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) - end + local storage=container.storage + local stored=storage[name] + if not stored and container.enabled and caches and containers.usecache then + stored=caches.loaddata(container.readables,name,container.writable) + if stored and stored.cache_version==container.version then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","load",container.subcategory,name) + end + else + stored=nil end - return stored + storage[name]=stored + elseif stored then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) + end + end + return stored end function containers.write(container,name,data) - if data then - data.cache_version=container.version - if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","save",container.subcategory,name) - end - data.unique,data.shared=unique,shared - end - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","store",container.subcategory,name) - end - container.storage[name]=data + if data then + data.cache_version=container.version + if container.enabled and caches then + local unique,shared=data.unique,data.shared + data.unique,data.shared=nil,nil + caches.savedata(container.writable,name,data) + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","save",container.subcategory,name) + end + data.unique,data.shared=unique,shared end - return data + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","store",container.subcategory,name) + end + container.storage[name]=data + end + return data end function containers.content(container,name) - return container.storage[name] + return container.storage[name] end function containers.cleanname(name) - return (gsub(lower(name),"[^%w\128-\255]+","-")) + return (gsub(lower(name),"[^%w\128-\255]+","-")) end @@ -19713,97 +23285,101 @@ do -- create closure to overcome 200 locals limit package.loaded["data-use"] = package.loaded["data-use"] or true --- original size: 4272, stripped down to: 3289 +-- original size: 4434, stripped down to: 3180 if not modules then modules={} end modules ['data-use']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,find=string.format,string.lower,string.gsub,string.find -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_mounts=logs.reporter("resolvers","mounts") local resolvers=resolvers resolvers.automounted=resolvers.automounted or {} function resolvers.automount(usecache) - local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) - if (not mountpaths or #mountpaths==0) and usecache then - mountpaths=caches.getreadablepaths("mount") - end - if mountpaths and #mountpaths>0 then - resolvers.starttiming() - for k=1,#mountpaths do - local root=mountpaths[k] - local f=io.open(root.."/url.tmi") - if f then - for line in f:lines() do - if line then - if find(line,"^[%%#%-]") then - elseif find(line,"^zip://") then - if trace_locating then - report_mounts("mounting %a",line) - end - table.insert(resolvers.automounted,line) - resolvers.usezipfile(line) - end - end - end - f:close() + local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) + if (not mountpaths or #mountpaths==0) and usecache then + mountpaths=caches.getreadablepaths("mount") + end + if mountpaths and #mountpaths>0 then + resolvers.starttiming() + for k=1,#mountpaths do + local root=mountpaths[k] + local f=io.open(root.."/url.tmi") + if f then + for line in f:lines() do + if line then + if find(line,"^[%%#%-]") then + elseif find(line,"^zip://") then + if trace_locating then + report_mounts("mounting %a",line) + end + table.insert(resolvers.automounted,line) + resolvers.usezipfile(line) end + end end - resolvers.stoptiming() + f:close() + end end + resolvers.stoptiming() + end 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,kind,banner) - local enginebanner=status.banner - if formatbanner and enginebanner and sourcefile then - local luvname=file.replacesuffix(texname,"luv") - local luvdata={ - enginebanner=enginebanner, - formatbanner=formatbanner, - sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), - sourcefile=sourcefile, - luaversion=LUAVERSION, - } - io.savedata(luvname,table.serialize(luvdata,true)) - lua.registerfinalizer(function() - logs.report("format banner","%s",banner) - logs.newline() - end) - end + local enginebanner=status.banner + if formatbanner and enginebanner and sourcefile then + local luvname=file.replacesuffix(texname,"luv") + local luvdata={ + enginebanner=enginebanner, + formatbanner=formatbanner, + sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), + sourcefile=sourcefile, + luaversion=LUAVERSION, + } + io.savedata(luvname,table.serialize(luvdata,true)) + lua.registerfinalizer(function() + if jit then + logs.report("format banner","%s lua: %s jit",banner,LUAVERSION) + else + logs.report("format banner","%s lua: %s",banner,LUAVERSION) + end + logs.newline() + end) + end end function statistics.checkfmtstatus(texname) - local enginebanner=status.banner - if enginebanner and texname then - local luvname=file.replacesuffix(texname,"luv") - if lfs.isfile(luvname) then - local luv=dofile(luvname) - if luv and luv.sourcefile then - local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") - local luvbanner=luv.enginebanner or "?" - if luvbanner~=enginebanner then - return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) - end - local luvhash=luv.sourcehash or "?" - if luvhash~=sourcehash then - return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) - end - local luvluaversion=luv.luaversion or 0 - if luvluaversion~=LUAVERSION then - return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) - end - else - return "invalid status file" - end - else - return "missing status file" - end + local enginebanner=status.banner + if enginebanner and texname then + local luvname=file.replacesuffix(texname,"luv") + if lfs.isfile(luvname) then + local luv=dofile(luvname) + if luv and luv.sourcefile then + local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") + local luvbanner=luv.enginebanner or "?" + if luvbanner~=enginebanner then + return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) + end + local luvhash=luv.sourcehash or "?" + if luvhash~=sourcehash then + return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) + end + local luvluaversion=luv.luaversion or 0 + if luvluaversion~=LUAVERSION then + return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) + end + else + return "invalid status file" + end + else + return "missing status file" end - return true + end + return true end @@ -19813,233 +23389,233 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8716, stripped down to: 6795 +-- original size: 8700, stripped down to: 6313 if not modules then modules={} end modules ['data-zip']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,find,match=string.format,string.find,string.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_zip=logs.reporter("resolvers","zip") local resolvers=resolvers zip=zip or {} local zip=zip -zip.archives=zip.archives or {} -local archives=zip.archives -zip.registeredfiles=zip.registeredfiles or {} -local registeredfiles=zip.registeredfiles +local archives=zip.archives or {} +zip.archives=archives +local registeredfiles=zip.registeredfiles or {} +zip.registeredfiles=registeredfiles local function validzip(str) - if not find(str,"^zip://") then - return "zip:///"..str - else - return str - end + if not find(str,"^zip://") then + return "zip:///"..str + else + return str + end end function zip.openarchive(name) - if not name or name=="" then - return nil - else - local arch=archives[name] - if not arch then - local full=resolvers.findfile(name) or "" - arch=full~="" and zip.open(full) or false - archives[name]=arch - end - return arch + if not name or name=="" then + return nil + else + local arch=archives[name] + if not arch then + local full=resolvers.findfile(name) or "" + arch=full~="" and zip.open(full) or false + archives[name]=arch end + return arch + end end function zip.closearchive(name) - if not name or (name=="" and archives[name]) then - zip.close(archives[name]) - archives[name]=nil - end + if not name or (name=="" and archives[name]) then + zip.close(archives[name]) + archives[name]=nil + end end function resolvers.locators.zip(specification) - local archive=specification.filename - local zipfile=archive and archive~="" and zip.openarchive(archive) - if trace_locating then - if zipfile then - report_zip("locator: archive %a found",archive) - else - report_zip("locator: archive %a not found",archive) - end + local archive=specification.filename + local zipfile=archive and archive~="" and zip.openarchive(archive) + if trace_locating then + if zipfile then + report_zip("locator: archive %a found",archive) + else + report_zip("locator: archive %a not found",archive) end + end end function resolvers.hashers.zip(specification) - local archive=specification.filename - if trace_locating then - report_zip("loading file %a",archive) - end - resolvers.usezipfile(specification.original) + local archive=specification.filename + if trace_locating then + report_zip("loading file %a",archive) + end + resolvers.usezipfile(specification.original) end function resolvers.concatinators.zip(zipfile,path,name) - if not path or path=="" then - return format('%s?name=%s',zipfile,name) - else - return format('%s?name=%s/%s',zipfile,path,name) - end + if not path or path=="" then + return format('%s?name=%s',zipfile,name) + else + return format('%s?name=%s/%s',zipfile,path,name) + end end function resolvers.finders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("finder: archive %a found",archive) - end - local dfile=zfile:open(queryname) - if dfile then - dfile=zfile:close() - if trace_locating then - report_zip("finder: file %a found",queryname) - end - return specification.original - elseif trace_locating then - report_zip("finder: file %a not found",queryname) - end - elseif trace_locating then - report_zip("finder: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("finder: archive %a found",archive) end + local dfile=zfile:open(queryname) + if dfile then + dfile:close() + if trace_locating then + report_zip("finder: file %a found",queryname) + end + return specification.original + elseif trace_locating then + report_zip("finder: file %a not found",queryname) + end + elseif trace_locating then + report_zip("finder: unknown archive %a",archive) + end end - if trace_locating then - report_zip("finder: %a not found",original) - end - return resolvers.finders.notfound() + end + if trace_locating then + report_zip("finder: %a not found",original) + end + return resolvers.finders.notfound() end function resolvers.openers.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("opener; archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - if trace_locating then - report_zip("opener: file %a found",queryname) - end - return resolvers.openers.helpers.textopener('zip',original,dfile) - elseif trace_locating then - report_zip("opener: file %a not found",queryname) - end - elseif trace_locating then - report_zip("opener: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("opener; archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + if trace_locating then + report_zip("opener: file %a found",queryname) + end + return resolvers.openers.helpers.textopener('zip',original,dfile) + elseif trace_locating then + report_zip("opener: file %a not found",queryname) + end + elseif trace_locating then + report_zip("opener: unknown archive %a",archive) + end end - if trace_locating then - report_zip("opener: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("opener: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.loaders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("loader: archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - logs.show_load(original) - if trace_locating then - report_zip("loader; file %a loaded",original) - end - local s=dfile:read("*all") - dfile:close() - return true,s,#s - elseif trace_locating then - report_zip("loader: file %a not found",queryname) - end - elseif trace_locating then - report_zip("loader; unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("loader: archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + logs.show_load(original) + if trace_locating then + report_zip("loader; file %a loaded",original) + end + local s=dfile:read("*all") + dfile:close() + return true,s,#s + elseif trace_locating then + report_zip("loader: file %a not found",queryname) + end + elseif trace_locating then + report_zip("loader; unknown archive %a",archive) + end end - if trace_locating then - report_zip("loader: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("loader: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.usezipfile(archive) - local specification=resolvers.splitmethod(archive) - local archive=specification.filename - if archive and not registeredfiles[archive] then - local z=zip.openarchive(archive) - if z then - local tree=url.query(specification.query).tree or "" - if trace_locating then - report_zip("registering: archive %a",archive) - end - resolvers.starttiming() - resolvers.prependhash('zip',archive) - resolvers.extendtexmfvariable(archive) - registeredfiles[archive]=z - resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) - resolvers.stoptiming() - elseif trace_locating then - report_zip("registering: unknown archive %a",archive) - end + local specification=resolvers.splitmethod(archive) + local archive=specification.filename + if archive and not registeredfiles[archive] then + local z=zip.openarchive(archive) + if z then + local tree=url.query(specification.query).tree or "" + if trace_locating then + report_zip("registering: archive %a",archive) + end + resolvers.starttiming() + resolvers.prependhash('zip',archive) + resolvers.extendtexmfvariable(archive) + registeredfiles[archive]=z + resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) + resolvers.stoptiming() elseif trace_locating then - report_zip("registering: archive %a not found",archive) + report_zip("registering: unknown archive %a",archive) end + elseif trace_locating then + report_zip("registering: archive %a not found",archive) + end end function resolvers.registerzipfile(z,tree) - local names={} - local files={} - local remap={} - local n=0 - local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) - local register=resolvers.registerfile - if trace_locating then - report_zip("registering: using filter %a",filter) - end - for i in z:files() do - local filename=i.filename - local path,name=match(filename,filter) - if not path then - n=n+1 - register(names,filename,"") - local usedname=lower(filename) - files[usedname]="" - if usedname~=filename then - remap[usedname]=filename - end - elseif name and name~="" then - n=n+1 - register(names,name,path) - local usedname=lower(name) - files[usedname]=path - if usedname~=name then - remap[usedname]=name - end - else - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile + if trace_locating then + report_zip("registering: using filter %a",filter) + end + for i in z:files() do + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename + end + elseif name and name~="" then + n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end - report_zip("registering: %s files registered",n) - return { - files=files, - remap=remap, - } + end + report_zip("registering: %s files registered",n) + return { + files=files, + remap=remap, + } end @@ -20049,20 +23625,20 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 8479, stripped down to: 5580 +-- original size: 8478, stripped down to: 5223 if not modules then modules={} end modules ['data-tre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,gsub,lower=string.find,string.gsub,string.lower -local basename,dirname,joinname=file.basename,file.dirname,file .join +local basename,dirname,joinname=file.basename,file.dirname,file .join local globdir,isdir,isfile=dir.glob,lfs.isdir,lfs.isfile local P,lpegmatch=lpeg.P,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -20071,165 +23647,167 @@ local lookup=resolvers.get_from_content local collectors={} local found={} function resolvers.finders.tree(specification) - local spec=specification.filename - local okay=found[spec] - if okay==nil then - if spec~="" then - local path=dirname(spec) - local name=basename(spec) - if path=="" then - path="." - end - local names=collectors[path] - if not names then - local pattern=find(path,"/%*+$") and path or (path.."/*") - names=globdir(pattern) - collectors[path]=names - end - local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for i=1,#names do - local fullname=names[i] - if find(fullname,pattern) then - found[spec]=fullname - return fullname - end - end - local pattern=lower(pattern) - for i=1,#names do - local fullname=lower(names[i]) - if find(fullname,pattern) then - if isfile(fullname) then - found[spec]=fullname - return fullname - else - break - end - end - end + local spec=specification.filename + local okay=found[spec] + if okay==nil then + if spec~="" then + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names + end + local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname + end + end + local pattern=lower(pattern) + for i=1,#names do + local fullname=lower(names[i]) + if find(fullname,pattern) then + if isfile(fullname) then + found[spec]=fullname + return fullname + else + break + end end - okay=notfound() - found[spec]=okay + end end - return okay + okay=notfound() + found[spec]=okay + end + return okay end function resolvers.locators.tree(specification) - local name=specification.filename - local realname=resolveprefix(name) - if realname and realname~='' and isdir(realname) then - if trace_locating then - report_trees("locator %a found",realname) - end - resolvers.appendhash('tree',name,false) - elseif trace_locating then - report_trees("locator %a not found",name) + local name=specification.filename + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then + if trace_locating then + report_trees("locator %a found",realname) end + resolvers.appendhash('tree',name,false) + elseif trace_locating then + report_trees("locator %a not found",name) + end end function resolvers.hashers.tree(specification) - local name=specification.filename - report_trees("analyzing %a",name) - resolvers.methodhandler("hashers",name) - resolvers.generators.file(specification) + local name=specification.filename + if trace_locating then + report_trees("analyzing %a",name) + end + resolvers.methodhandler("hashers",name) + resolvers.generators.file(specification) end local collectors={} local splitter=lpeg.splitat("/**/") local stripper=lpeg.replacer { [P("/")*P("*")^1*P(-1)]="" } table.setmetatableindex(collectors,function(t,k) - local rootname=lpegmatch(stripper,k) - local dataname=joinname(rootname,"dirlist") - local content=caches.loadcontent(dataname,"files",dataname) - if not content then - content=resolvers.scanfiles(rootname,nil,nil,false,true) - caches.savecontent(dataname,"files",content,dataname) - end - t[k]=content - return content + local rootname=lpegmatch(stripper,k) + local dataname=joinname(rootname,"dirlist") + local content=caches.loadcontent(dataname,"files",dataname) + if not content then + content=resolvers.scanfiles(rootname,nil,nil,false,true) + caches.savecontent(dataname,"files",content,dataname) + end + t[k]=content + return content end) local function checked(root,p,n) - if p then - if type(p)=="table" then - for i=1,#p do - local fullname=joinname(root,p[i],n) - if isfile(fullname) then - return fullname - end - end - else - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end + if p then + if type(p)=="table" then + for i=1,#p do + local fullname=joinname(root,p[i],n) + if isfile(fullname) then + return fullname end + end + else + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - return notfound() + end + return notfound() end local function resolve(specification) - local filename=specification.filename - if filename~="" then - local root,rest=lpegmatch(splitter,filename) - if root and rest then - local path,name=dirname(rest),basename(rest) - if name~=rest then - local content=collectors[root] - local p,n=lookup(content,name) - if not p then - return notfound() - end - local pattern=".*/"..path.."$" - local istable=type(p)=="table" - if istable then - for i=1,#p do - local pi=p[i] - if pi==path or find(pi,pattern) then - local fullname=joinname(root,pi,n) - if isfile(fullname) then - return fullname - end - end - end - elseif p==path or find(p,pattern) then - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end - end - local queries=specification.queries - if queries and queries.option=="fileonly" then - return checked(root,p,n) - else - return notfound() - end + local filename=specification.filename + if filename~="" then + local root,rest=lpegmatch(splitter,filename) + if root and rest then + local path,name=dirname(rest),basename(rest) + if name~=rest then + local content=collectors[root] + local p,n=lookup(content,name) + if not p then + return notfound() + end + local pattern=".*/"..path.."$" + local istable=type(p)=="table" + if istable then + for i=1,#p do + local pi=p[i] + if pi==path or find(pi,pattern) then + local fullname=joinname(root,pi,n) + if isfile(fullname) then + return fullname + end end + end + elseif p==path or find(p,pattern) then + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - local path,name=dirname(filename),basename(filename) - local root=lpegmatch(stripper,path) - local content=collectors[path] - local p,n=lookup(content,name) - if p then - return checked(root,p,n) + local queries=specification.queries + if queries and queries.option=="fileonly" then + return checked(root,p,n) + else + return notfound() end + end end - return notfound() + local path,name=dirname(filename),basename(filename) + local root=lpegmatch(stripper,path) + local content=collectors[path] + local p,n=lookup(content,name) + if p then + return checked(root,p,n) + end + end + return notfound() end -resolvers.finders .dirlist=resolve -resolvers.locators .dirlist=resolvers.locators .tree -resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.finders .dirlist=resolve +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree resolvers.generators.dirlist=resolvers.generators.file -resolvers.openers .dirlist=resolvers.openers .file -resolvers.loaders .dirlist=resolvers.loaders .file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file function resolvers.finders.dirfile(specification) - local queries=specification.queries - if queries then - queries.option="fileonly" - else - specification.queries={ option="fileonly" } - end - return resolve(specification) -end -resolvers.locators .dirfile=resolvers.locators .dirlist -resolvers.hashers .dirfile=resolvers.hashers .dirlist + local queries=specification.queries + if queries then + queries.option="fileonly" + else + specification.queries={ option="fileonly" } + end + return resolve(specification) +end +resolvers.locators .dirfile=resolvers.locators .dirlist +resolvers.hashers .dirfile=resolvers.hashers .dirlist resolvers.generators.dirfile=resolvers.generators.dirlist -resolvers.openers .dirfile=resolvers.openers .dirlist -resolvers.loaders .dirfile=resolvers.loaders .dirlist +resolvers.openers .dirfile=resolvers.openers .dirlist +resolvers.loaders .dirfile=resolvers.loaders .dirlist end -- of closure @@ -20238,19 +23816,19 @@ do -- create closure to overcome 200 locals limit package.loaded["data-sch"] = package.loaded["data-sch"] or true --- original size: 6753, stripped down to: 5511 +-- original size: 6753, stripped down to: 5268 if not modules then modules={} end modules ['data-sch']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local load,tonumber=load,tonumber local gsub,concat,format=string.gsub,table.concat,string.format local finders,openers,loaders=resolvers.finders,resolvers.openers,resolvers.loaders -local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) +local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) local report_schemes=logs.reporter("resolvers","schemes") local http=require("socket.http") local ltn12=require("ltn12") @@ -20263,27 +23841,27 @@ schemes.cleaners=cleaners local threshold=24*60*60 directives.register("schemes.threshold",function(v) threshold=tonumber(v) or threshold end) function cleaners.none(specification) - return specification.original + return specification.original end function cleaners.strip(specification) - local path,name=file.splitbase(specification.original) - if path=="" then - return (gsub(name,"[^%a%d%.]+","-")) - else - return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) - end + local path,name=file.splitbase(specification.original) + if path=="" then + return (gsub(name,"[^%a%d%.]+","-")) + else + return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) + end end function cleaners.md5(specification) - return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) + return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) end local cleaner=cleaners.strip directives.register("schemes.cleanmethod",function(v) cleaner=cleaners[v] or cleaners.strip end) function resolvers.schemes.cleanname(specification) - local hash=cleaner(specification) - if trace_schemes then - report_schemes("hashing %a to %a",specification.original,hash) - end - return hash + local hash=cleaner(specification) + if trace_schemes then + report_schemes("hashing %a to %a",specification.original,hash) + end + return hash end local cached={} local loaded={} @@ -20291,139 +23869,139 @@ local reused={} local thresholds={} local handlers={} local runner=sandbox.registerrunner { - name="curl resolver", - method="execute", - program="curl", - template="--silent --insecure --create-dirs --output %cachename% %original%", - checkers={ - cachename="cache", - original="url", - } + name="curl resolver", + method="execute", + program="curl", + template="--silent --insecure --create-dirs --output %cachename% %original%", + checkers={ + cachename="cache", + original="url", + } } local function fetch(specification) - local original=specification.original - local scheme=specification.scheme - local cleanname=schemes.cleanname(specification) - local cachename=caches.setfirstwritablefile(cleanname,"schemes") - if not cached[original] then - statistics.starttiming(schemes) - if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then - cached[original]=cachename - local handler=handlers[scheme] - if handler then - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") - end - logs.flush() - handler(specification,cachename) - else - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") - end - logs.flush() - runner { - original=original, - cachename=cachename, - } - end - end - if io.exists(cachename) then - cached[original]=cachename - if trace_schemes then - report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) - end - else - cached[original]="" - if trace_schemes then - report_schemes("using missing %a, protocol %a",original,scheme) - end + local original=specification.original + local scheme=specification.scheme + local cleanname=schemes.cleanname(specification) + local cachename=caches.setfirstwritablefile(cleanname,"schemes") + if not cached[original] then + statistics.starttiming(schemes) + if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then + cached[original]=cachename + local handler=handlers[scheme] + if handler then + if trace_schemes then + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") end - loaded[scheme]=loaded[scheme]+1 - statistics.stoptiming(schemes) - else + logs.flush() + handler(specification,cachename) + else if trace_schemes then - report_schemes("reusing %a, protocol %a",original,scheme) + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") end - reused[scheme]=reused[scheme]+1 + logs.flush() + runner { + original=original, + cachename=cachename, + } + end + end + if io.exists(cachename) then + cached[original]=cachename + if trace_schemes then + report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) + end + else + cached[original]="" + if trace_schemes then + report_schemes("using missing %a, protocol %a",original,scheme) + end end - return cached[original] + loaded[scheme]=loaded[scheme]+1 + statistics.stoptiming(schemes) + else + if trace_schemes then + report_schemes("reusing %a, protocol %a",original,scheme) + end + reused[scheme]=reused[scheme]+1 + end + return cached[original] end local function finder(specification,filetype) - return resolvers.methodhandler("finders",fetch(specification),filetype) + return resolvers.methodhandler("finders",fetch(specification),filetype) end local opener=openers.file local loader=loaders.file local function install(scheme,handler,newthreshold) - handlers [scheme]=handler - loaded [scheme]=0 - reused [scheme]=0 - finders [scheme]=finder - openers [scheme]=opener - loaders [scheme]=loader - thresholds[scheme]=newthreshold or threshold + handlers [scheme]=handler + loaded [scheme]=0 + reused [scheme]=0 + finders [scheme]=finder + openers [scheme]=opener + loaders [scheme]=loader + thresholds[scheme]=newthreshold or threshold end schemes.install=install local function http_handler(specification,cachename) - local tempname=cachename..".tmp" - local f=io.open(tempname,"wb") - local status,message=http.request { - url=specification.original, - sink=ltn12.sink.file(f) - } - if not status then - os.remove(tempname) - else - os.remove(cachename) - os.rename(tempname,cachename) - end - return cachename + local tempname=cachename..".tmp" + local f=io.open(tempname,"wb") + local status,message=http.request { + url=specification.original, + sink=ltn12.sink.file(f) + } + if not status then + os.remove(tempname) + else + os.remove(cachename) + os.rename(tempname,cachename) + end + return cachename end install('http',http_handler) install('https') install('ftp') statistics.register("scheme handling time",function() - local l,r,nl,nr={},{},0,0 - for k,v in table.sortedhash(loaded) do - if v>0 then - nl=nl+1 - l[nl]=k..":"..v - end - end - for k,v in table.sortedhash(reused) do - if v>0 then - nr=nr+1 - r[nr]=k..":"..v - end - end - local n=nl+nr - if n>0 then - l=nl>0 and concat(l) or "none" - r=nr>0 and concat(r) or "none" - return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", - statistics.elapsedtime(schemes),n,threshold,l,r) - else - return nil - end + local l,r,nl,nr={},{},0,0 + for k,v in table.sortedhash(loaded) do + if v>0 then + nl=nl+1 + l[nl]=k..":"..v + end + end + for k,v in table.sortedhash(reused) do + if v>0 then + nr=nr+1 + r[nr]=k..":"..v + end + end + local n=nl+nr + if n>0 then + l=nl>0 and concat(l) or "none" + r=nr>0 and concat(r) or "none" + return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", + statistics.elapsedtime(schemes),n,threshold,l,r) + else + return nil + end end) local httprequest=http.request local toquery=url.toquery local function fetchstring(url,data) - local q=data and toquery(data) - if q then - url=url.."?"..q - end - local reply=httprequest(url) - return reply + local q=data and toquery(data) + if q then + url=url.."?"..q + end + local reply=httprequest(url) + return reply end schemes.fetchstring=fetchstring function schemes.fetchtable(url,data) - local reply=fetchstring(url,data) - if reply then - local s=load("return "..reply) - if s then - return s() - end + local reply=fetchstring(url,data) + if reply then + local s=load("return "..reply) + if s then + return s() end + end end @@ -20433,14 +24011,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4207, stripped down to: 3137 +-- original size: 4207, stripped down to: 3041 if not modules then modules={} end modules ['data-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local package,lpeg=package,lpeg local gsub=string.gsub @@ -20459,20 +24037,20 @@ helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) helpers.sequence={ - "already loaded", - "preload table", - "lua variable format", - "lib variable format", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", + "already loaded", + "preload table", + "lua variable format", + "lib variable format", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolveprefix(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local registerpath=helpers.registerpath @@ -20480,56 +24058,56 @@ local lualibfile=helpers.lualibfile local luaformatpaths local libformatpaths local function getluaformatpaths() - if not luaformatpaths then - luaformatpaths={} - for i=1,#luaformats do - registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) - end + if not luaformatpaths then + luaformatpaths={} + for i=1,#luaformats do + registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) end - return luaformatpaths + end + return luaformatpaths end local function getlibformatpaths() - if not libformatpaths then - libformatpaths={} - for i=1,#libformats do - registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) - end + if not libformatpaths then + libformatpaths={} + for i=1,#libformats do + registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) end - return libformatpaths + end + return libformatpaths end local function loadedbyformat(name,rawname,suffixes,islib,what) - local trace=helpers.trace - local report=helpers.report - for i=1,#suffixes do - local format=suffixes[i] - local resolved=resolvers.findfile(name,format) or "" - if trace then - report("%s format, identifying %a using format %a",what,name,format) - end - if resolved~="" then - if trace then - report("%s format, %a found on %a",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + local report=helpers.report + for i=1,#suffixes do + local format=suffixes[i] + local resolved=resolvers.findfile(name,format) or "" + if trace then + report("%s format, identifying %a using format %a",what,name,format) + end + if resolved~="" then + if trace then + report("%s format, %a found on %a",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + end end helpers.loadedbyformat=loadedbyformat methods["lua variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") + if helpers.trace then + helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") end methods["lib variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") + if helpers.trace then + helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") end resolvers.loadlualib=require @@ -20540,64 +24118,64 @@ do -- create closure to overcome 200 locals limit package.loaded["data-aux"] = package.loaded["data-aux"] or true --- original size: 2438, stripped down to: 2003 +-- original size: 2452, stripped down to: 1877 if not modules then modules={} end modules ['data-aux']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find=string.find local type,next=type,next -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +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="context/lua" - newname=file.addsuffix(newname,"lua") - local oldscript=resolvers.cleanpath(oldname) + local scriptpath="context/lua" + newname=file.addsuffix(newname,"lua") + local oldscript=resolvers.cleanpath(oldname) + if trace_locating then + report_scripts("to be replaced old script %a",oldscript) + end + local newscripts=resolvers.findfiles(newname) or {} + if #newscripts==0 then if trace_locating then - report_scripts("to be replaced old script %a",oldscript) + report_scripts("unable to locate new script") end - local newscripts=resolvers.findfiles(newname) or {} - if #newscripts==0 then + else + for i=1,#newscripts do + local newscript=resolvers.cleanpath(newscripts[i]) + if trace_locating then + report_scripts("checking new script %a",newscript) + end + if oldscript==newscript then if trace_locating then - report_scripts("unable to locate new script") + report_scripts("old and new script are the same") end - else - for i=1,#newscripts do - local newscript=resolvers.cleanpath(newscripts[i]) - if trace_locating then - report_scripts("checking new script %a",newscript) - end - if oldscript==newscript then - if trace_locating then - report_scripts("old and new script are the same") - end - elseif not find(newscript,scriptpath,1,true) then - if trace_locating then - report_scripts("new script should come from %a",scriptpath) - end - elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then - if trace_locating then - report_scripts("invalid new script name") - end - else - local newdata=io.loaddata(newscript) - if newdata then - if trace_locating then - report_scripts("old script content replaced by new content") - end - io.savedata(oldscript,newdata) - break - elseif trace_locating then - report_scripts("unable to load new script") - end - end + elseif not find(newscript,scriptpath,1,true) then + if trace_locating then + report_scripts("new script should come from %a",scriptpath) end + elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then + if trace_locating then + report_scripts("invalid new script name") + end + else + local newdata=io.loaddata(newscript) + if newdata then + if trace_locating then + report_scripts("old script content replaced by new content: %s",oldscript) + end + io.savedata(oldscript,newdata) + break + elseif trace_locating then + report_scripts("unable to load new script") + end + end end + end end @@ -20607,53 +24185,53 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2601, stripped down to: 1627 +-- original size: 2601, stripped down to: 1549 if not modules then modules={} end modules ['data-tmf']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local report_tds=logs.reporter("resolvers","tds") function resolvers.load_tree(tree,resolve) - if type(tree)=="string" and tree~="" then - local getenv,setenv=resolvers.getenv,resolvers.setenv - local texos="texmf-"..os.platform - local oldroot=environment.texroot - local newroot=file.collapsepath(tree) - local newtree=file.join(newroot,texos) - local newpath=file.join(newtree,"bin") - if not lfs.isdir(newtree) then - report_tds("no %a under tree %a",texos,tree) - os.exit() - end - if not lfs.isdir(newpath) then - report_tds("no '%s/bin' under tree %a",texos,tree) - os.exit() - end - local texmfos=newtree - environment.texroot=newroot - environment.texos=texos - environment.texmfos=texmfos - if resolve then - resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) - end - setenv('SELFAUTOPARENT',newroot) - setenv('SELFAUTODIR',newtree) - setenv('SELFAUTOLOC',newpath) - setenv('TEXROOT',newroot) - setenv('TEXOS',texos) - setenv('TEXMFOS',texmfos) - setenv('TEXMFCNF',resolvers.luacnfspec,true) - setenv('PATH',newpath..io.pathseparator..getenv('PATH')) - report_tds("changing from root %a to %a",oldroot,newroot) - report_tds("prepending %a to PATH",newpath) - report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) - report_tds() - end + if type(tree)=="string" and tree~="" then + local getenv,setenv=resolvers.getenv,resolvers.setenv + local texos="texmf-"..os.platform + local oldroot=environment.texroot + local newroot=file.collapsepath(tree) + local newtree=file.join(newroot,texos) + local newpath=file.join(newtree,"bin") + if not lfs.isdir(newtree) then + report_tds("no %a under tree %a",texos,tree) + os.exit() + end + if not lfs.isdir(newpath) then + report_tds("no '%s/bin' under tree %a",texos,tree) + os.exit() + end + local texmfos=newtree + environment.texroot=newroot + environment.texos=texos + environment.texmfos=texmfos + if resolve then + resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) + end + setenv('SELFAUTOPARENT',newroot) + setenv('SELFAUTODIR',newtree) + setenv('SELFAUTOLOC',newpath) + setenv('TEXROOT',newroot) + setenv('TEXOS',texos) + setenv('TEXMFOS',texmfos) + setenv('TEXMFCNF',resolvers.luacnfspec,true) + setenv('PATH',newpath..io.pathseparator..getenv('PATH')) + report_tds("changing from root %a to %a",oldroot,newroot) + report_tds("prepending %a to PATH",newpath) + report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) + report_tds() + end end @@ -20663,14 +24241,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 1823, stripped down to: 1591 +-- original size: 1823, stripped down to: 1542 if not modules then modules={} end modules ['data-lst']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local concat,sortedhash=table.concat,table.sortedhash @@ -20681,37 +24259,37 @@ local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local report_resolved=logs.reporter("system","resolved") local function tabstr(str) - if type(str)=='table' then - return concat(str," | ") - else - return str - end + if type(str)=='table' then + return concat(str," | ") + else + return str + end end function listers.variables(pattern) - local result=resolvers.knownvariables(pattern) - for key,value in sortedhash(result) do - report_lists(key) - report_lists(" env: %s",tabstr(value.environment or "unset")) - report_lists(" var: %s",tabstr(value.variable or "unset")) - report_lists(" exp: %s",tabstr(value.expansion or "unset")) - report_lists(" res: %s",tabstr(value.resolved or "unset")) - end + local result=resolvers.knownvariables(pattern) + for key,value in sortedhash(result) do + report_lists(key) + report_lists(" env: %s",tabstr(value.environment or "unset")) + report_lists(" var: %s",tabstr(value.variable or "unset")) + report_lists(" exp: %s",tabstr(value.expansion or "unset")) + report_lists(" res: %s",tabstr(value.resolved or "unset")) + end end function listers.configurations() - local configurations=resolvers.configurationfiles() - for i=1,#configurations do - report_resolved("file : %s",resolveprefix(configurations[i])) - end - report_resolved("") - local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) - for i=1,#list do - local li=resolveprefix(list[i]) - if lfs.isdir(li) then - report_resolved("path - %s",li) - else - report_resolved("path + %s",li) - end + local configurations=resolvers.configurationfiles() + for i=1,#configurations do + report_resolved("file : %s",resolveprefix(configurations[i])) + end + report_resolved("") + local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) + for i=1,#list do + local li=resolveprefix(list[i]) + if lfs.isdir(li) then + report_resolved("path - %s",li) + else + report_resolved("path + %s",li) end + end end @@ -20721,14 +24299,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lib"] = package.loaded["util-lib"] or true --- original size: 14943, stripped down to: 8305 +-- original size: 16094, stripped down to: 8443 if not modules then modules={} end modules ['util-lib']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local type=type local next=next @@ -20748,256 +24326,291 @@ local qualifiedpath=file.is_qualified_path local isfile=lfs.isfile local done=false local function locate(required,version,trace,report,action) - if type(required)~="string" then - report("provide a proper library name") - return - end - if trace then - report("requiring library %a with version %a",required,version or "any") - end - local found_library=nil - local required_full=gsub(required,"%.","/") - local required_path=pathpart(required_full) - local required_base=nameonly(required_full) - if qualifiedpath(required) then - if isfile(addsuffix(required,os.libsuffix)) then - if trace then - report("qualified name %a found",required) - end - found_library=required - else - if trace then - report("qualified name %a not found",required) - end - end + if type(required)~="string" then + report("provide a proper library name") + return + end + if trace then + report("requiring library %a with version %a",required,version or "any") + end + local found_library=nil + local required_full=gsub(required,"%.","/") + local required_path=pathpart(required_full) + local required_base=nameonly(required_full) + if qualifiedpath(required) then + if isfile(addsuffix(required,os.libsuffix)) then + if trace then + report("qualified name %a found",required) + end + found_library=required else - local required_name=required_base.."."..os.libsuffix - local version=type(version)=="string" and version~="" and version or false - local engine="luatex" - if trace and not done then - local list=expandpaths("lib") - for i=1,#list do - report("tds path %i: %s",i,list[i]) - end + if trace then + report("qualified name %a not found",required) + end + end + else + local required_name=required_base.."."..os.libsuffix + local version=type(version)=="string" and version~="" and version or false + local engine="luatex" + if trace and not done then + local list=expandpaths("lib") + for i=1,#list do + report("tds path %i: %s",i,list[i]) + end + end + local function found(locate,asked_library,how,...) + if trace then + report("checking %s: %a",how,asked_library) + end + return locate(asked_library,...) + end + local function check(locate,...) + local found=nil + if version then + local asked_library=joinfile(required_path,version,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function found(locate,asked_library,how,...) - if trace then - report("checking %s: %a",how,asked_library) - end - return locate(asked_library,...) - end - local function check(locate,...) - local found=nil - if version then - local asked_library=joinfile(required_path,version,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - if not found or found=="" then - local asked_library=joinfile(required_path,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - return found and found~="" and found or false + found=locate(asked_library,...) + end + if not found or found=="" then + local asked_library=joinfile(required_path,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function attempt(checkpattern) - if trace then - report("checking tds lib paths strictly") - end - local found=findfile and check(findfile,"lib") - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - if trace then - report("checking tds lib paths with wildcard") - end - local asked_library=joinfile(required_path,".*",required_name) - if trace then - report("checking %s: %a","latest version",asked_library) - end - local list=findfiles(asked_library,"lib",true) - if list and #list>0 then - sort(list) - local found=list[#list] - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - end - if trace then - report("checking lib paths") - end - package.extralibpath(environment.ownpath) - local paths=package.libpaths() - local pattern="/[^/]+%."..os.libsuffix.."$" - for i=1,#paths do - required_path=gsub(paths[i],pattern,"") - local found=check(lfs.isfound) - if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then - return found - end - end - return false + found=locate(asked_library,...) + end + return found and found~="" and found or false + end + local function attempt(checkpattern) + if trace then + report("checking tds lib paths strictly") + end + local found=findfile and check(findfile,"lib") + if found and (not checkpattern or find(found,checkpattern)) then + return found + end + if trace then + report("checking tds lib paths with wildcard") + end + local asked_library=joinfile(required_path,".*",required_name) + if trace then + report("checking %s: %a","latest version",asked_library) + end + local list=findfiles(asked_library,"lib",true) + if list and #list>0 then + sort(list) + local found=list[#list] + if found and (not checkpattern or find(found,checkpattern)) then + return found end - if engine then - if trace then - report("attemp 1, engine %a",engine) - end - found_library=attempt("/"..engine.."/") - if not found_library then - if trace then - report("attemp 2, no engine",asked_library) - end - found_library=attempt() - end - else - found_library=attempt() + end + if trace then + report("checking lib paths") + end + package.extralibpath(environment.ownpath) + local paths=package.libpaths() + local pattern="/[^/]+%."..os.libsuffix.."$" + for i=1,#paths do + required_path=gsub(paths[i],pattern,"") + local found=check(lfs.isfound) + if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then + return found end + end + return false end - if not found_library then + if engine then + if trace then + report("attemp 1, engine %a",engine) + end + found_library=attempt("/"..engine.."/") + if not found_library then if trace then - report("not found: %a",required) + report("attemp 2, no engine",asked_library) end - library=false + found_library=attempt() + end else - if trace then - report("found: %a",found_library) - end - local result,message=action(found_library,required_base) - if result then - library=result - else - library=false - report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") - end + found_library=attempt() end + end + if not found_library then if trace then - if not library then - report("unknown library: %a",required) - else - report("stored library: %a",required) - end + report("not found: %a",required) end - return library + library=false + else + if trace then + report("found: %a",found_library) + end + local result,message=action(found_library,required_base) + if result then + library=result + else + library=false + report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") + end + end + if trace then + if not library then + report("unknown library: %a",required) + else + report("stored library: %a",required) + end + end + return library or nil end do - local report_swiglib=logs.reporter("swiglib") - local trace_swiglib=false - local savedrequire=require - local loadedlibs={} - local loadlib=package.loadlib - local pushdir=dir.push - local popdir=dir.pop - trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) - function requireswiglib(required,version) - local library=loadedlibs[library] - if library==nil then - local trace_swiglib=trace_swiglib or package.helpers.trace - library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) - pushdir(pathpart(name)) - local opener="luaopen_"..base - if trace_swiglib then - report_swiglib("opening: %a with %a",name,opener) - end - local library,message=loadlib(name,opener) - local libtype=type(library) - if libtype=="function" then - library=library() - else - 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 - popdir() - return library - end) - loadedlibs[required]=library or false + local report_swiglib=logs.reporter("swiglib") + local trace_swiglib=false + local savedrequire=require + local loadedlibs={} + local loadlib=package.loadlib + local pushdir=dir.push + local popdir=dir.pop + trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) + function requireswiglib(required,version) + local library=loadedlibs[library] + if library==nil then + local trace_swiglib=trace_swiglib or package.helpers.trace + library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) + pushdir(pathpart(name)) + local opener="luaopen_"..base + if trace_swiglib then + report_swiglib("opening: %a with %a",name,opener) + end + local library,message=loadlib(name,opener) + local libtype=type(library) + if libtype=="function" then + library=library() + else + 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 + popdir() return library + end) + loadedlibs[required]=library or false end - function require(name,version) - if find(name,"^swiglib%.") then - return requireswiglib(name,version) - else - return savedrequire(name) - end + return library + end + function require(name,version) + if find(name,"^swiglib%.") then + return requireswiglib(name,version) + else + return savedrequire(name) + end + end + local swiglibs={} + local initializer="core" + function swiglib(name,version) + local library=swiglibs[name] + if not library then + statistics.starttiming(swiglibs) + if trace_swiglib then + report_swiglib("loading %a",name) + end + 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 - local swiglibs={} - local initializer="core" - function swiglib(name,version) - local library=swiglibs[name] - if not library then - statistics.starttiming(swiglibs) - if trace_swiglib then - report_swiglib("loading %a",name) - end - 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 - return library + return library + end + statistics.register("used swiglibs",function() + if next(swiglibs) then + return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) end - statistics.register("used swiglibs",function() - if next(swiglibs) then - return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) - end - end) + end) end if FFISUPPORTED and ffi and ffi.load then - local report_ffilib=logs.reporter("ffilib") - local trace_ffilib=false - local savedffiload=ffi.load - trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) - local loaded={} - local function locateindeed(name) - name=removesuffix(name) - local l=loaded[name] - if l==nil then - local message,library=pcall(savedffiload,name) - if type(message)=="userdata" then - l=message - elseif type(library)=="userdata" then - l=library - else - l=false - end - loaded[name]=l - elseif trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l + local report_ffilib=logs.reporter("ffilib") + local trace_ffilib=false + local savedffiload=ffi.load + trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) + local loaded={} + local function locateindeed(name) + name=removesuffix(name) + local l=loaded[name] + if l==nil then + local state,library=pcall(savedffiload,name) + if type(library)=="userdata" then + l=library + elseif type(state)=="userdata" then + l=state + else + l=false + end + loaded[name]=l + elseif trace_ffilib then + report_ffilib("reusing already loaded %a",name) end - function ffilib(name,version) - name=removesuffix(name) - local l=loaded[name] - if l~=nil then - if trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l - elseif version=="system" then - return locateindeed(name) - else - return locate(name,version,trace_ffilib,report_ffilib,locateindeed) + return l + end + local function getlist(required) + local list=directives.value("system.librarynames" ) + if type(list)=="table" then + list=list[required] + if type(list)=="table" then + if trace then + report("using lookup list for library %a: % | t",required,list) end + return list + end end - function ffi.load(name) - local library=ffilib(name) + return { required } + end + function ffilib(name,version) + name=removesuffix(name) + local l=loaded[name] + if l~=nil then + if trace_ffilib then + report_ffilib("reusing already loaded %a",name) + end + return l + end + local list=getlist(name) + if version=="system" then + for i=1,#list do + local library=locateindeed(list[i]) if type(library)=="userdata" then - return library + return library end - if trace_ffilib then - report_ffilib("trying to load %a using normal loader",name) + end + else + for i=1,#list do + local library=locate(list[i],version,trace_ffilib,report_ffilib,locateindeed) + if type(library)=="userdata" then + return library end - return savedffiload(name) + end end + end + function ffi.load(name) + local list=getlist(name) + for i=1,#list do + local library=ffilib(list[i]) + if type(library)=="userdata" then + return library + end + end + if trace_ffilib then + report_ffilib("trying to load %a using normal loader",name) + end + for i=1,#list do + local state,library=pcall(savedffiload,list[i]) + if type(library)=="userdata" then + return library + elseif type(state)=="userdata" then + return library + end + end + end end @@ -21007,13 +24620,13 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-sta"] = package.loaded["luat-sta"] or true --- original size: 5703, stripped down to: 2507 +-- original size: 5703, stripped down to: 2321 if not modules then modules={} end modules ['luat-sta']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gmatch,match=string.gmatch,string.match local type=type @@ -21026,81 +24639,81 @@ local hash=states.hash states.tag=states.tag or "" states.filename=states.filename or "" function states.save(filename,tag) - tag=tag or states.tag - filename=file.addsuffix(filename or states.filename,'lus') - io.savedata(filename, - "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) - ) + tag=tag or states.tag + filename=file.addsuffix(filename or states.filename,'lus') + io.savedata(filename, + "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) + ) end function states.load(filename,tag) - states.filename=filename - states.tag=tag or "whatever" - states.filename=file.addsuffix(states.filename,'lus') - data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} + states.filename=filename + states.tag=tag or "whatever" + states.filename=file.addsuffix(states.filename,'lus') + data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} end local function set_by_tag(tag,key,value,default,persistent) - local d,h=data[tag],hash[tag] - if d then - if type(d)=="table" then - local dkey,hkey=key,key - local pre,post=match(key,"(.+)%.([^%.]+)$") - if pre and post then - for k in gmatch(pre,"[^%.]+") do - local dk=d[k] - if not dk then - dk={} - d[k]=dk - elseif type(dk)=="string" then - break - end - d=dk - end - dkey,hkey=post,key - end - if value==nil then - value=default - elseif value==false then - elseif persistent then - value=value or d[dkey] or default - else - value=value or default - end - d[dkey],h[hkey]=value,value - elseif type(d)=="string" then - data[tag],hash[tag]=value,value + local d,h=data[tag],hash[tag] + if d then + if type(d)=="table" then + local dkey,hkey=key,key + local pre,post=match(key,"(.+)%.([^%.]+)$") + if pre and post then + for k in gmatch(pre,"[^%.]+") do + local dk=d[k] + if not dk then + dk={} + d[k]=dk + elseif type(dk)=="string" then + break + end + d=dk end + dkey,hkey=post,key + end + if value==nil then + value=default + elseif value==false then + elseif persistent then + value=value or d[dkey] or default + else + value=value or default + end + d[dkey],h[hkey]=value,value + elseif type(d)=="string" then + data[tag],hash[tag]=value,value end + end end local function get_by_tag(tag,key,default) - local h=hash[tag] - if h and h[key] then - return h[key] - else - local d=data[tag] - if d then - for k in gmatch(key,"[^%.]+") do - local dk=d[k] - if dk~=nil then - d=dk - else - return default - end - end - if d==false then - return false - else - return d or default - end + local h=hash[tag] + if h and h[key] then + return h[key] + else + local d=data[tag] + if d then + for k in gmatch(key,"[^%.]+") do + local dk=d[k] + if dk~=nil then + d=dk + else + return default end + end + if d==false then + return false + else + return d or default + end end + end end states.set_by_tag=set_by_tag states.get_by_tag=get_by_tag function states.set(key,value,default,persistent) - set_by_tag(states.tag,key,value,default,persistent) + set_by_tag(states.tag,key,value,default,persistent) end function states.get(key,default) - return get_by_tag(states.tag,key,default) + return get_by_tag(states.tag,key,default) end @@ -21110,14 +24723,14 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-fmt"] = package.loaded["luat-fmt"] or true --- original size: 9268, stripped down to: 7401 +-- original size: 9418, stripped down to: 7087 if not modules then modules={} end modules ['luat-fmt']={ - version=1.001, - comment="companion to mtxrun", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to mtxrun", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format=string.format local concat=table.concat @@ -21125,229 +24738,232 @@ local quoted=string.quoted local luasuffixes=utilities.lua.suffixes local report_format=logs.reporter("resolvers","formats") local function primaryflags() - local arguments=environment.arguments - local flags={} - if arguments.silent then - flags[#flags+1]="--interaction=batchmode" - end - if arguments.jit then - flags[#flags+1]="--jiton" - end - return concat(flags," ") + local arguments=environment.arguments + local flags={} + if arguments.silent then + flags[#flags+1]="--interaction=batchmode" + end + return concat(flags," ") end local function secondaryflags() - local arguments=environment.arguments - local trackers=arguments.trackers - local directives=arguments.directives - local flags={} - if trackers and trackers~="" then - flags[#flags+1]="--c:trackers="..quoted(trackers) - end - if directives and directives~="" then - flags[#flags+1]="--c:directives="..quoted(directives) - end - if arguments.silent then - flags[#flags+1]="--c:silent" - end - if arguments.errors then - flags[#flags+1]="--c:errors" - end - if arguments.jit then - flags[#flags+1]="--c:jiton" - end - if arguments.ansi then - flags[#flags+1]="--c:ansi" - end - return concat(flags," ") + local arguments=environment.arguments + local trackers=arguments.trackers + local directives=arguments.directives + local flags={} + if trackers and trackers~="" then + flags[#flags+1]="--c:trackers="..quoted(trackers) + end + if directives and directives~="" then + flags[#flags+1]="--c:directives="..quoted(directives) + end + if arguments.silent then + flags[#flags+1]="--c:silent" + end + if arguments.errors then + flags[#flags+1]="--c:errors" + end + if arguments.jit then + flags[#flags+1]="--c:jiton" + end + if arguments.ansi then + flags[#flags+1]="--c:ansi" + end + if arguments.strip then + flags[#flags+1]="--c:strip" + end + if arguments.lmtx then + flags[#flags+1]="--c:lmtx" + end + return concat(flags," ") end local template=[[--ini %primaryflags% --lua=%luafile% %texfile% %secondaryflags% %dump% %redirect%]] local checkers={ - primaryflags="string", - secondaryflags="string", - luafile="readable", - texfile="readable", - redirect="string", - dump="string", + primaryflags="string", + secondaryflags="string", + luafile="readable", + texfile="readable", + redirect="string", + dump="string", } local runners={ - luatex=sandbox.registerrunner { - name="make luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="make luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="make luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="make luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.make_format(name,arguments) - local engine=environment.ownmain or "luatex" - local silent=environment.arguments.silent - local errors=environment.arguments.errors - local olddir=dir.current() - local path=caches.getwritablepath("formats",engine) or "" - if path~="" then - lfs.chdir(path) - end - report_format("using format path %a",dir.current()) - local texsourcename=file.addsuffix(name,"mkiv") - local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - if fulltexsourcename=="" then - texsourcename=file.addsuffix(name,"tex") - fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - end - if fulltexsourcename=="" then - report_format("no tex source file with name %a (mkiv or tex)",name) - lfs.chdir(olddir) - return - else - report_format("using tex source file %a",fulltexsourcename) - end - local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) - local specificationname=file.replacesuffix(fulltexsourcename,"lus") - local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - if fullspecificationname=="" then - specificationname=file.join(texsourcepath,"context.lus") - fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - end - if fullspecificationname=="" then - report_format("unknown stub specification %a",specificationname) - lfs.chdir(olddir) - return - end - local specificationpath=file.dirname(fullspecificationname) - local usedluastub=nil - local usedlualibs=dofile(fullspecificationname) - if type(usedlualibs)=="string" then - usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) - elseif type(usedlualibs)=="table" then - report_format("using stub specification %a",fullspecificationname) - local texbasename=file.basename(name) - local luastubname=file.addsuffix(texbasename,luasuffixes.lua) - local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) - report_format("creating initialization file %a",luastubname) - utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) - if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then - report_format("using compiled initialization file %a",lucstubname) - usedluastub=lucstubname - else - report_format("using uncompiled initialization file %a",luastubname) - usedluastub=luastubname - end - else - report_format("invalid stub specification %a",fullspecificationname) - lfs.chdir(olddir) - return - end - local specification={ - primaryflags=primaryflags(), - secondaryflags=secondaryflags(), - luafile=quoted(usedluastub), - texfile=quoted(fulltexsourcename), - dump=os.platform=="unix" and "\\\\dump" or "\\dump", - } - local runner=runners[engine] - if not runner then - report_format("format %a cannot be generated, no runner available for engine %a",name,engine) - elseif silent then - statistics.starttiming() - specification.redirect="> temp.log" - local result=runner(specification) - local runtime=statistics.stoptiming() - if result~=0 then - print(format("%s silent make > fatal error when making format %q",engine,name)) - else - print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) - end - os.remove("temp.log") - else - runner(specification) - end - local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" - local mp=dir.glob(pattern) - if mp then - for i=1,#mp do - local name=mp[i] - report_format("removing related mplib format %a",file.basename(name)) - os.remove(name) - end - end + local engine=environment.ownmain or "luatex" + local silent=environment.arguments.silent + local errors=environment.arguments.errors + local olddir=dir.current() + local path=caches.getwritablepath("formats",engine) or "" + if path~="" then + lfs.chdir(path) + end + report_format("using format path %a",dir.current()) + local texsourcename=file.addsuffix(name,"mkiv") + local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + if fulltexsourcename=="" then + texsourcename=file.addsuffix(name,"tex") + fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + end + if fulltexsourcename=="" then + report_format("no tex source file with name %a (mkiv or tex)",name) + lfs.chdir(olddir) + return + else + report_format("using tex source file %a",fulltexsourcename) + end + local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) + local specificationname=file.replacesuffix(fulltexsourcename,"lus") + local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + if fullspecificationname=="" then + specificationname=file.join(texsourcepath,"context.lus") + fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + end + if fullspecificationname=="" then + report_format("unknown stub specification %a",specificationname) + lfs.chdir(olddir) + return + end + local specificationpath=file.dirname(fullspecificationname) + local usedluastub=nil + local usedlualibs=dofile(fullspecificationname) + if type(usedlualibs)=="string" then + usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) + elseif type(usedlualibs)=="table" then + report_format("using stub specification %a",fullspecificationname) + local texbasename=file.basename(name) + local luastubname=file.addsuffix(texbasename,luasuffixes.lua) + local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) + report_format("creating initialization file %a",luastubname) + utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) + if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then + report_format("using compiled initialization file %a",lucstubname) + usedluastub=lucstubname + else + report_format("using uncompiled initialization file %a",luastubname) + usedluastub=luastubname + end + else + report_format("invalid stub specification %a",fullspecificationname) lfs.chdir(olddir) + return + end + local specification={ + primaryflags=primaryflags(), + secondaryflags=secondaryflags(), + luafile=quoted(usedluastub), + texfile=quoted(fulltexsourcename), + dump=os.platform=="unix" and "\\\\dump" or "\\dump", + } + local runner=runners[engine] + if not runner then + report_format("format %a cannot be generated, no runner available for engine %a",name,engine) + elseif silent then + statistics.starttiming() + specification.redirect="> temp.log" + local result=runner(specification) + local runtime=statistics.stoptiming() + if result~=0 then + print(format("%s silent make > fatal error when making format %q",engine,name)) + else + print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) + end + os.remove("temp.log") + else + runner(specification) + end + local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" + local mp=dir.glob(pattern) + if mp then + for i=1,#mp do + local name=mp[i] + report_format("removing related mplib format %a",file.basename(name)) + os.remove(name) + end + end + lfs.chdir(olddir) end local template=[[%flags% --fmt=%fmtfile% --lua=%luafile% %texfile% %more%]] local checkers={ - flags="string", - more="string", - fmtfile="readable", - luafile="readable", - texfile="readable", + flags="string", + more="string", + fmtfile="readable", + luafile="readable", + texfile="readable", } local runners={ - luatex=sandbox.registerrunner { - name="run luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="run luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="run luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="run luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.run_format(name,data,more) - if name and name~="" then - local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) - if fmtname=="" then - fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" - end - fmtname=resolvers.cleanpath(fmtname) - if fmtname=="" then - report_format("no format with name %a",name) + if name and name~="" then + local engine=environment.ownmain or "luatex" + local barename=file.removesuffix(name) + local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) + if fmtname=="" then + fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" + end + fmtname=resolvers.cleanpath(fmtname) + if fmtname=="" then + report_format("no format with name %a",name) + else + local barename=file.removesuffix(name) + local luaname=file.addsuffix(barename,"luc") + if not lfs.isfile(luaname) then + luaname=file.addsuffix(barename,"lua") + end + if not lfs.isfile(luaname) then + report_format("using format name %a",fmtname) + report_format("no luc/lua file with name %a",barename) + else + local runner=runners[engine] + if not runner then + report_format("format %a cannot be run, no runner available for engine %a",name,engine) else - local barename=file.removesuffix(name) - local luaname=file.addsuffix(barename,"luc") - if not lfs.isfile(luaname) then - luaname=file.addsuffix(barename,"lua") - end - if not lfs.isfile(luaname) then - report_format("using format name %a",fmtname) - report_format("no luc/lua file with name %a",barename) - else - local runner=runners[engine] - if not runner then - report_format("format %a cannot be run, no runner available for engine %a",name,engine) - else - runner { - flags=primaryflags(), - fmtfile=quoted(barename), - luafile=quoted(luaname), - texfile=quoted(data), - more=more, - } - end - end + runner { + flags=primaryflags(), + fmtfile=quoted(barename), + luafile=quoted(luaname), + texfile=quoted(data), + more=more, + } end + end end + end end end -- of closure --- used libraries : l-lua.lua l-macro.lua l-sandbox.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-fil.lua util-sac.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-tpl.lua util-sbx.lua util-mrg.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 +-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.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-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.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 : 877962 --- stripped bytes : 317771 +-- original bytes : 994864 +-- stripped bytes : 395007 -- end library merge @@ -21370,6 +24986,7 @@ local owntree = environment and environment.ownpath or ownpath local ownlibs = { -- order can be made better + 'l-bit32.lua', 'l-lua.lua', 'l-macro.lua', 'l-sandbox.lua', @@ -21385,6 +25002,7 @@ local ownlibs = { -- order can be made better 'l-file.lua', 'l-gzip.lua', 'l-md5.lua', + 'l-sha.lua', 'l-url.lua', 'l-dir.lua', 'l-boolean.lua', @@ -21399,6 +25017,19 @@ local ownlibs = { -- order can be made better 'util-prs.lua', 'util-fmt.lua', + 'util-soc-imp-reset.lua', + 'util-soc-imp-socket.lua', + 'util-soc-imp-copas.lua', + 'util-soc-imp-ltn12.lua', + -- 'util-soc-imp-mbox.lua', + 'util-soc-imp-mime.lua', + 'util-soc-imp-url.lua', + 'util-soc-imp-headers.lua', + 'util-soc-imp-tp.lua', + 'util-soc-imp-http.lua', + 'util-soc-imp-ftp.lua', + 'util-soc-imp-smtp.lua', + 'trac-set.lua', 'trac-log.lua', 'trac-inf.lua', -- was before trac-set @@ -21601,9 +25232,7 @@ local helpinfo = [[ <flag name="locate"><short>locate given filename in database (default) or system (<ref name="first"/> <ref name="all"/> <ref name="detail"/>)</short></flag> </subcategory> <subcategory> - <flag name="autotree"><short>use texmf tree cf. env texmfstart_tree or texmfstarttree</short></flag> <flag name="tree" value="pathtotree"><short>use given texmf tree (default file: setuptex.tmf)</short></flag> - <flag name="environment" value="name"><short>use given (tmf) environment file</short></flag> <flag name="path" value="runpath"><short>go to given path before execution</short></flag> <flag name="ifchanged" value="filename"><short>only execute when given file has changed (md checksum)</short></flag> <flag name="iftouched" value="old,new"><short>only execute when given file has changed (time stamp)</short></flag> @@ -21623,7 +25252,7 @@ local helpinfo = [[ </subcategory> <subcategory> <flag name="edit"><short>launch editor with found file</short></flag> - <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>)</short></flag> + <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>,<ref name="list"/>)</short></flag> </subcategory> <subcategory> <flag name="timedrun"><short>run a script and time its run</short></flag> @@ -22022,9 +25651,9 @@ function resolvers.launch(str) end function runners.launch_file(filename) - trackers.enable("resolvers.locating") local allresults = environment.arguments["all"] - local pattern = environment.arguments["pattern"] + local pattern = environment.arguments["pattern"] + local listonly = environment.arguments["list"] if not pattern or pattern == "" then pattern = filename end @@ -22039,14 +25668,32 @@ function runners.launch_file(filename) t = resolvers.findfiles("*/" .. pattern .. "*",nil,allresults) end if t and #t > 0 then - if allresults then - for _, v in pairs(t) do - report("launching %s", v) - resolvers.launch(v) + for i=1,#t do + local name = t[i] + if listonly then + report("% 3i: %-30s %s",i,file.basename(name),file.dirname(name)) + else + report("launching: %s",name) + resolvers.launch(name) + if not allresults then + break + end + end + end + if listonly then + io.write("\n") + io.write("\n[select number]\n\n>> ") + local answer = tonumber(io.read()) + if answer then + io.write("\n") + local name = t[answer] + if name then + report("launching: %s",name) + resolvers.launch(name) + else + report("invalid number") + end end - else - report("launching %s", t[1]) - resolvers.launch(t[1]) end else report("no match for %s", pattern) @@ -22166,12 +25813,9 @@ function runners.execute_ctx_script(filename,...) dofile(fullname) local savename = environment.arguments['save'] if savename then - local save_list = runners.save_list - if save_list and next(save_list) then - if type(savename) ~= "string" then savename = file.basename(fullname) end - savename = file.replacesuffix(savename,"cfg") - runners.save_script_session(savename,save_list) - end + if type(savename) ~= "string" then savename = file.basename(fullname) end + savename = file.replacesuffix(savename,"cfg") + runners.save_script_session(savename,save_list) end return true end @@ -22188,22 +25832,22 @@ function runners.execute_ctx_script(filename,...) local scriptbase = match(scriptname,".*mtx%-([^%-]-)%.lua") if scriptbase then local data = io.loaddata(scriptname) -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 + 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 @@ -22243,7 +25887,7 @@ function runners.timedrun(filename) -- just for me end function runners.timed(action) - statistics.timed(action) + statistics.timed(action,true) end function runners.associate(filename) diff --git a/scripts/context/stubs/setup/setuptex b/scripts/context/stubs/setup/setuptex index 9808140e4..fb65788b6 100644 --- a/scripts/context/stubs/setup/setuptex +++ b/scripts/context/stubs/setup/setuptex @@ -24,9 +24,23 @@ cpu=`uname -m` case "$system" in # linux Linux) + if command -v ldd >/dev/null && ldd --version 2>&1 | grep -E '^musl' >/dev/null + then + libc=musl + else + libc=glibc + fi case "$cpu" in - i*86) platform="linux" ;; - x86_64|ia64) platform="linux-64" ;; + i*86) + case "$libc" in + glibc) platform="linux" ;; + musl) platform="linuxmusl" ;; + esac ;; + x86_64|ia64) + case "$libc" in + glibc) platform="linux-64" ;; + musl) platform="linuxmusl-64" ;; + esac ;; # a little bit of cheating with ppc64 (won't work on Gentoo) ppc|ppc64) platform="linux-ppc" ;; diff --git a/scripts/context/stubs/setup/setuptex.csh b/scripts/context/stubs/setup/setuptex.csh index c1160675f..62ca03569 100644 --- a/scripts/context/stubs/setup/setuptex.csh +++ b/scripts/context/stubs/setup/setuptex.csh @@ -82,6 +82,19 @@ switch ( $system ) set platform="unknown" endsw breaksw + # OpenBSD + case OpenBSD: + switch ( $cpu ) + case i*86: + set platform="openbsd" + breaksw + case amd64: + set platform="openbsd-amd64" + breaksw + default: + set platform="unknown" + endsw + breaksw # cygwin case CYGWIN: switch ( $cpu ) diff --git a/scripts/context/stubs/unix/metatex b/scripts/context/stubs/unix/metatex deleted file mode 100644 index f0c6b65d4..000000000 --- a/scripts/context/stubs/unix/metatex +++ /dev/null @@ -1,2 +0,0 @@ -#!/bin/sh -mtxrun --script metatex "$@" diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 0f4767d91..569a7f2e1 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -1,16 +1,5 @@ #!/usr/bin/env texlua --- for k, v in next, _G.string do --- local tv = type(v) --- if tv == "table" then --- for kk, vv in next, v do --- print(k,kk,vv) --- end --- else --- print(tv,k,v) --- end --- end - if not modules then modules = { } end modules ['mtxrun'] = { version = 1.001, comment = "runner, lua replacement for texmfstart.rb", @@ -20,25 +9,43 @@ if not modules then modules = { } end modules ['mtxrun'] = { } -- one can make a stub: + +-- mtxrun : -- -- #!/bin/sh -- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@" +-- mtxrun.cmd : +-- +-- @luatex --luaonly %~d0%~p0mtxrun.lua %* + -- filename : mtxrun.lua -- comment : companion to context.tex -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files --- This script is based on texmfstart.rb but does not use kpsewhich to --- locate files. Although kpse is a library it never came to opening up --- its interface to other programs (esp scripting languages) and so we --- do it ourselves. The lua variant evolved out of an experimental ruby --- one. Interesting is that using a scripting language instead of c does --- not have a speed penalty. Actually the lua variant is more efficient, --- especially when multiple calls to kpsewhich are involved. The lua +-- This script is based on texmfstart.rb but does not use kpsewhich to locate files. +-- Although kpse is a library it never came to opening up its interface to other +-- programs (esp scripting languages) and so we do it ourselves. The lua variant +-- evolved out of an experimental ruby one. Interesting is that using a scripting +-- language instead of c does not have a speed penalty. Actually the lua variant is +-- more efficient, especially when multiple calls to kpsewhich are involved. The lua -- library also gives way more control. +-- When libraries used here are updates you can run +-- +-- mtxrun --selfmerge +-- +-- to update the embedded code. After that you might need to run +-- +-- mtxrun --selfupdate +-- +-- to copy the new script (from scripts/context/lua) to location where +-- binaries are expected. If you want to remove the embedded code you can run +-- +-- mtxxun --selfclean + -- to be done / considered -- -- support for --exec or make it default @@ -54,16 +61,147 @@ if not modules then modules = { } end modules ['mtxrun'] = { do -- create closure to overcome 200 locals limit +package.loaded["l-bit32"] = package.loaded["l-bit32"] or true + +-- original size: 3607, stripped down to: 3009 + +if not modules then modules={} end modules ['l-bit32']={ + version=1.001, + license="the same as regular Lua", + source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto", + comment="drop-in for bit32, adapted a bit by Hans Hagen", +} +if bit32 then +elseif utf8 then + load ([[ +local select = select -- instead of: arg = { ... } +bit32 = { + bnot = function (a) + return ~a & 0xFFFFFFFF + end, + band = function (x, y, z, ...) + if not z then + return ((x or -1) & (y or -1)) & 0xFFFFFFFF + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bor = function (x, y, z, ...) + if not z then + return ((x or 0) | (y or 0)) & 0xFFFFFFFF + else + local res = x | y | z + for i=1,select("#",...) do + res = res | select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bxor = function (x, y, z, ...) + if not z then + return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF + else + local res = x ~ y ~ z + for i=1,select("#",...) do + res = res ~ select(i,...) + end + return res & 0xFFFFFFFF + end + end, + btest = function (x, y, z, ...) + if not z then + return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0 + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return (res & 0xFFFFFFFF) ~= 0 + end + end, + lshift = function (a, b) + return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF + end, + rshift = function (a, b) + return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF + end, + arshift = function (a, b) + a = a & 0xFFFFFFFF + if b <= 0 or (a & 0x80000000) == 0 then + return (a >> b) & 0xFFFFFFFF + else + return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF + end + end, + lrotate = function (a ,b) + b = b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + rrotate = function (a, b) + b = -b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + extract = function (a, f, w) + return (a >> f) & ~(-1 << (w or 1)) + end, + replace = function (a, v, f, w) + local mask = ~(-1 << (w or 1)) + return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF + end, +} + ]] ) () +elseif bit then + load ([[ +local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift +bit32 = { + arshift = bit.arshift, + band = band, + bnot = bnot, + bor = bit.bor, + bxor = bit.bxor, + btest = function(...) + return band(...) ~= 0 + end, + extract = function(a,f,w) + return band(rshift(a,f),2^(w or 1)-1) + end, + lrotate = bit.rol, + lshift = lshift, + replace = function(a,v,f,w) + local mask = 2^(w or 1)-1 + return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f) + end, + rrotate = bit.ror, + rshift = rshift, +} + ]] ) () +else + xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end) +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + package.loaded["l-lua"] = package.loaded["l-lua"] or true --- original size: 6230, stripped down to: 3662 +-- original size: 6281, stripped down to: 2863 if not modules then modules={} end modules ['l-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,tonumber=next,type,tonumber LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$") @@ -71,122 +209,111 @@ LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5 LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1 LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10 if LUAVERSION<5.2 and jit then - MINORVERSION=2 - LUAVERSION=5.2 + MINORVERSION=2 + LUAVERSION=5.2 end -_LUAVERSION=LUAVERSION if not lpeg then - lpeg=require("lpeg") + lpeg=require("lpeg") end if loadstring then - local loadnormal=load - function load(first,...) - if type(first)=="string" then - return loadstring(first,...) - else - return loadnormal(first,...) - end + local loadnormal=load + function load(first,...) + if type(first)=="string" then + return loadstring(first,...) + else + return loadnormal(first,...) end + end else - loadstring=load + loadstring=load end if not ipairs then - local function iterate(a,i) - i=i+1 - local v=a[i] - if v~=nil then - return i,v - end - end - function ipairs(a) - return iterate,a,0 + local function iterate(a,i) + i=i+1 + local v=a[i] + if v~=nil then + return i,v end + end + function ipairs(a) + return iterate,a,0 + end end if not pairs then - function pairs(t) - return next,t - end + function pairs(t) + return next,t + end end if not table.unpack then - table.unpack=_G.unpack + table.unpack=_G.unpack elseif not unpack then - _G.unpack=table.unpack + _G.unpack=table.unpack end if not package.loaders then - package.loaders=package.searchers + package.loaders=package.searchers end local print,select,tostring=print,select,tostring local inspectors={} function setinspector(kind,inspector) - inspectors[kind]=inspector + inspectors[kind]=inspector end function inspect(...) - for s=1,select("#",...) do - local value=select(s,...) - if value==nil then - print("nil") - else - local done=false - local kind=type(value) - local inspector=inspectors[kind] - if inspector then - done=inspector(value) - if done then - break - end - end - for kind,inspector in next,inspectors do - done=inspector(value) - if done then - break - end - end - if not done then - print(tostring(value)) - end + for s=1,select("#",...) do + local value=select(s,...) + if value==nil then + print("nil") + else + local done=false + local kind=type(value) + local inspector=inspectors[kind] + if inspector then + done=inspector(value) + if done then + break + end + end + for kind,inspector in next,inspectors do + done=inspector(value) + if done then + break end + end + if not done then + print(tostring(value)) + end end + end end local dummy=function() end function optionalrequire(...) - local ok,result=xpcall(require,dummy,...) - if ok then - return result - end + local ok,result=xpcall(require,dummy,...) + if ok then + return result + end end if lua then - lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" + lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" end local flush=io.flush if flush then - local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end - local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end - local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end - local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end + local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end + local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end + local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end + local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end end FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load if not FFISUPPORTED then - local okay;okay,ffi=pcall(require,"ffi") - FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load + local okay;okay,ffi=pcall(require,"ffi") + FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load end if not FFISUPPORTED then - ffi=nil + ffi=nil elseif not ffi.number then - ffi.number=tonumber + ffi.number=tonumber end -if not bit32 then - bit32=require("l-bit32") +if LUAVERSION>5.3 then + collectgarbage("generational") end -local loaded=package.loaded -if not loaded["socket"] then loaded["socket"]=loaded["socket.core"] end -if not loaded["mime"] then loaded["mime"]=loaded["mime.core"] end -if not socket.mime then socket.mime=package.loaded["mime"] end -if not loaded["socket.mime"] then loaded["socket.mime"]=socket.mime end -if not loaded["socket.http"] then loaded["socket.http"]=socket.http end -if not loaded["socket.ftp"] then loaded["socket.ftp"]=socket.ftp end -if not loaded["socket.smtp"] then loaded["socket.smtp"]=socket.smtp end -if not loaded["socket.tp"] then loaded["socket.tp"]=socket.tp end -if not loaded["socket.url"] then loaded["socket.url"]=socket.url end end -- of closure @@ -195,25 +322,27 @@ do -- create closure to overcome 200 locals limit package.loaded["l-macro"] = package.loaded["l-macro"] or true --- original size: 8260, stripped down to: 5213 +-- original size: 10131, stripped down to: 5991 if not modules then modules={} end modules ['l-macros']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg local lpegmatch=lpeg.match local concat=table.concat -local format,sub=string.format,string.sub +local format,sub,match=string.format,string.sub,string.match local next,load,type=next,load,type local newline=S("\n\r")^1 local continue=P("\\")*newline +local whitespace=S(" \t\n\r") local spaces=S(" \t")+continue -local name=R("az","AZ","__","09")^1 -local body=((1+continue/"")-newline)^1 +local nametoken=R("az","AZ","__","09") +local name=nametoken^1 +local body=((continue/""+1)-newline)^1 local lparent=P("(") local rparent=P(")") local noparent=1-(lparent+rparent) @@ -230,172 +359,214 @@ local definitions={} local resolve local subparser local report_lua=function(...) - if logs and logs.reporter then - report_lua=logs.reporter("system","lua") - report_lua(...) - else - print(format(...)) - end -end -resolve=C(C(name)*arguments^-1)/function(raw,s,a) - local d=definitions[s] - if d then - if a then - local n=#a - local p=patterns[s][n] - if p then - local d=d[n] - for i=1,n do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return lpegmatch(p,d,1,a) or d - else - return raw - end - else - return d[0] or raw - end - elseif a then - for i=1,#a do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return s.."("..concat(a,",")..")" - else - return raw - end -end -subparser=Cs((resolve+P(1))^1) -local enddefine=P("#enddefine")/"" -local beginregister=(C(name)*spaces^0*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) - local n=0 + if logs and logs.reporter then + report_lua=logs.reporter("system","lua") + report_lua(...) + else + print(format(...)) + end +end +local safeguard=P("local")*whitespace^1*name*(whitespace+P("=")) +resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a) + local d=definitions[s] + if d then if a then - n=#a - local pattern=P(false) + local n=#a + local p=patterns[s][n] + if p then + local d=d[n] for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p + a[i]=lpegmatch(subparser,a[i]) or a[i] end - p[n]=pattern + return lpegmatch(p,d,1,a) or d + else + return raw + end + else + return d[0] or raw end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d + elseif a then + for i=1,#a do + a[i]=lpegmatch(subparser,a[i]) or a[i] end - d[n]=lpegmatch(subparser,v) or v - return "" + return s.."("..concat(a,",")..")" + else + return raw + end end -local register=(C(name)*spaces^0*(arguments+Cc(false))*spaces^0*C(body))/function(k,a,v) - local n=0 - if a then - n=#a - local pattern=P(false) - for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p - end - p[n]=pattern - end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d - end - d[n]=lpegmatch(subparser,v) or v - return "" +subparser=Cs((resolve+P(1))^1) +local enddefine=P("#enddefine")/"" +local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" +end +local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" end local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a) - local n=0 - if a then - n=#a - local p=patterns[k] - if p then - p[n]=false - end - end - local d=definitions[k] - if d then - d[n]=false + local n=0 + if a then + n=#a + local p=patterns[k] + if p then + p[n]=false end - return "" + end + local d=definitions[k] + if d then + d[n]=false + end + return "" end local begindefine=(P("begindefine")*spaces^0/"")*beginregister -local define=(P("define" )*spaces^0/"")*register -local undefine=(P("undefine" )*spaces^0/"")*unregister +local define=(P("define" )*spaces^0/"")*register +local undefine=(P("undefine" )*spaces^0/"")*unregister local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 ) function macros.reset() - definitions={} - patterns={} + definitions={} + patterns={} +end +function macros.showdefinitions() + for name,list in table.sortedhash(definitions) do + local arguments=list.a + if arguments then + arguments="("..concat(arguments,",")..")" + else + arguments="" + end + print("macro: "..name..arguments) + for i=0,#list do + local l=list[i] + if l then + print(" "..l) + end + end + end end function macros.resolvestring(str) - return lpegmatch(parser,str) or str + return lpegmatch(parser,str) or str end function macros.resolving() - return next(patterns) -end -local function loaded(name,trace,detail) - local f=io.open(name,"rb") - if not f then - return false,format("file '%s' not found",name) - end - local c=f:read("*a") - if not c then - return false,format("file '%s' is invalid",name) - end + return next(patterns) +end +local function reload(path,name,data) + local only=match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only + local f=io.open(name,"wb") + f:write(data) f:close() - local n=lpegmatch(parser,c) - if trace then - if #n~=#c then - report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) - if detail then - report_lua() - report_lua(n) - report_lua() - end - elseif detail then - report_lua("no macros expanded in '%s'",name) - end + local f=loadfile(name) + os.remove(name) + return f + end +end +local function reload(path,name,data) + if path and path~="" then + local only=string.match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only.."-macro.lua" + local f=io.open(name,"wb") + if f then + f:write(data) + f:close() + local l=loadfile(name) + os.remove(name) + return l + end end - if #name>30 then - n="--[["..sub(name,-30).."]] "..n - else - n="--[["..name.."]] "..n + end + return load(data,name) +end +local function loaded(name,trace,detail) + local f=io.open(name,"rb") + if not f then + return false,format("file '%s' not found",name) + end + local c=f:read("*a") + if not c then + return false,format("file '%s' is invalid",name) + end + f:close() + local n=lpegmatch(parser,c) + if trace then + if #n~=#c then + report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) + if detail then + report_lua() + report_lua(n) + report_lua() + end + elseif detail then + report_lua("no macros expanded in '%s'",name) end - return load(n) + end + return reload(lfs and lfs.currentdir(),name,n) end macros.loaded=loaded function required(name,trace) - local filename=file.addsuffix(name,"lua") - local fullname=resolvers and resolvers.find_file(filename) or filename - if not fullname or fullname=="" then - return false - end - local codeblob=package.loaded[fullname] - if codeblob then - return codeblob - end - local code,message=loaded(fullname,macros,trace,trace) - if type(code)=="function" then - code=code() - else - report_lua("error when loading '%s'",fullname) - return false,message - end - if code==nil then - code=false - end - package.loaded[fullname]=code - return code + local filename=file.addsuffix(name,"lua") + local fullname=resolvers and resolvers.find_file(filename) or filename + if not fullname or fullname=="" then + return false + end + local codeblob=package.loaded[fullname] + if codeblob then + return codeblob + end + local code,message=loaded(fullname,macros,trace,trace) + if type(code)=="function" then + code=code() + else + report_lua("error when loading '%s'",fullname) + return false,message + end + if code==nil then + code=false + end + package.loaded[fullname]=code + return code end macros.required=required @@ -406,14 +577,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true --- original size: 9678, stripped down to: 6688 +-- original size: 9747, stripped down to: 6313 if not modules then modules={} end modules ['l-sandbox']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local global=_G local next=next @@ -439,231 +610,234 @@ local trace=false local logger=false local blocked={} local function report(...) - tprint("sandbox ! "..format(...)) + tprint("sandbox ! "..format(...)) end sandbox.report=report function sandbox.setreporter(r) - report=r - sandbox.report=r + report=r + sandbox.report=r end function sandbox.settrace(v) - trace=v + trace=v end function sandbox.setlogger(l) - logger=type(l)=="function" and l or false + logger=type(l)=="function" and l or false end local function register(func,overload,comment) - if type(func)=="function" then - if type(overload)=="string" then - comment=overload - overload=nil - end - local function f(...) - if sandboxed then - local overload=overloads[f] - if overload then - if logger then - local result={ overload(func,...) } - logger { - comment=comments[f] or tostring(f), - arguments={... }, - result=result[1] and true or false, - } - return unpack(result) - else - return overload(func,...) - end - else - end - else - return func(...) - end - end - if comment then - comments[f]=comment - if trace then - report("registering function: %s",comment) - end + if type(func)=="function" then + if type(overload)=="string" then + comment=overload + overload=nil + end + local function f(...) + if sandboxed then + local overload=overloads[f] + if overload then + if logger then + local result={ overload(func,...) } + logger { + comment=comments[f] or tostring(f), + arguments={... }, + result=result[1] and true or false, + } + return unpack(result) + else + return overload(func,...) + end + else end - overloads[f]=overload or false - originals[f]=func - return f + else + return func(...) + end end + if comment then + comments[f]=comment + if trace then + report("registering function: %s",comment) + end + end + overloads[f]=overload or false + originals[f]=func + return f + end end local function redefine(func,comment) - if type(func)=="function" then - skiploads[func]=comment or comments[func] or "unknown" - if overloads[func]==false then - overloads[func]=nil - end + if type(func)=="function" then + skiploads[func]=comment or comments[func] or "unknown" + if overloads[func]==false then + overloads[func]=nil end + end end sandbox.register=register sandbox.redefine=redefine function sandbox.original(func) - return originals and originals[func] or func + return originals and originals[func] or func end function sandbox.overload(func,overload,comment) - comment=comment or comments[func] or "?" - if type(func)~="function" then - if trace then - report("overloading unknown function: %s",comment) - end - elseif type(overload)~="function" then - if trace then - report("overloading function with bad overload: %s",comment) - end - elseif overloads[func]==nil then - if trace then - report("function is not registered: %s",comment) - end - elseif skiploads[func] then - if trace then - report("function is not skipped: %s",comment) - end - else - if trace then - report("overloading function: %s",comment) - end - overloads[func]=overload + comment=comment or comments[func] or "?" + if type(func)~="function" then + if trace then + report("overloading unknown function: %s",comment) + end + elseif type(overload)~="function" then + if trace then + report("overloading function with bad overload: %s",comment) + end + elseif overloads[func]==nil then + if trace then + report("function is not registered: %s",comment) + end + elseif skiploads[func] then + if trace then + report("function is not skipped: %s",comment) end - return func + else + if trace then + report("overloading function: %s",comment) + end + overloads[func]=overload + end + return func end local function whatever(specification,what,target) - if type(specification)~="table" then - report("%s needs a specification",what) - elseif type(specification.category)~="string" or type(specification.action)~="function" then - report("%s needs a category and action",what) - elseif not sandboxed then - target[#target+1]=specification - elseif trace then - report("already enabled, discarding %s",what) - end + if type(specification)~="table" then + report("%s needs a specification",what) + elseif type(specification.category)~="string" or type(specification.action)~="function" then + report("%s needs a category and action",what) + elseif not sandboxed then + target[#target+1]=specification + elseif trace then + report("already enabled, discarding %s",what) + end end function sandbox.initializer(specification) - whatever(specification,"initializer",initializers) + whatever(specification,"initializer",initializers) end function sandbox.finalizer(specification) - whatever(specification,"finalizer",finalizers) + whatever(specification,"finalizer",finalizers) end function require(name) - local n=gsub(name,"^.*[\\/]","") - local n=gsub(n,"[%.].*$","") - local b=blocked[n] - if b==false then - return nil - elseif b then - if trace then - report("using blocked: %s",n) - end - return b - else - if trace then - report("requiring: %s",name) - end - return requiem(name) + local n=gsub(name,"^.*[\\/]","") + local n=gsub(n,"[%.].*$","") + local b=blocked[n] + if b==false then + return nil + elseif b then + if trace then + report("using blocked: %s",n) end -end -function blockrequire(name,lib) + return b + else if trace then - report("preventing reload of: %s",name) + report("requiring: %s",name) end - blocked[name]=lib or _G[name] or false + return requiem(name) + end +end +function blockrequire(name,lib) + if trace then + report("preventing reload of: %s",name) + end + blocked[name]=lib or _G[name] or false end function sandbox.enable() - if not sandboxed then - for i=1,#initializers do - initializers[i].action() - end - for i=1,#finalizers do - finalizers[i].action() - end - local nnot=0 - local nyes=0 - local cnot={} - local cyes={} - local skip={} - for k,v in next,overloads do - local c=comments[k] - if v then - if c then - cyes[#cyes+1]=c - else - nyes=nyes+1 - end - else - if c then - cnot[#cnot+1]=c - else - nnot=nnot+1 - end - end - end - for k,v in next,skiploads do - skip[#skip+1]=v - end - if #cyes>0 then - sort(cyes) - report("overloaded known: %s",concat(cyes," | ")) - end - if nyes>0 then - report("overloaded unknown: %s",nyes) - end - if #cnot>0 then - sort(cnot) - report("not overloaded known: %s",concat(cnot," | ")) - end - if nnot>0 then - report("not overloaded unknown: %s",nnot) + if not sandboxed then + debug={ + traceback=debug.traceback, + } + for i=1,#initializers do + initializers[i].action() + end + for i=1,#finalizers do + finalizers[i].action() + end + local nnot=0 + local nyes=0 + local cnot={} + local cyes={} + local skip={} + for k,v in next,overloads do + local c=comments[k] + if v then + if c then + cyes[#cyes+1]=c + else + nyes=nyes+1 end - if #skip>0 then - sort(skip) - report("not overloaded redefined: %s",concat(skip," | ")) + else + if c then + cnot[#cnot+1]=c + else + nnot=nnot+1 end - initializers=nil - finalizers=nil - originals=nil - sandboxed=true + end + end + for k,v in next,skiploads do + skip[#skip+1]=v + end + if #cyes>0 then + sort(cyes) + report("overloaded known: %s",concat(cyes," | ")) + end + if nyes>0 then + report("overloaded unknown: %s",nyes) end + if #cnot>0 then + sort(cnot) + report("not overloaded known: %s",concat(cnot," | ")) + end + if nnot>0 then + report("not overloaded unknown: %s",nnot) + end + if #skip>0 then + sort(skip) + report("not overloaded redefined: %s",concat(skip," | ")) + end + initializers=nil + finalizers=nil + originals=nil + sandboxed=true + end end blockrequire("lfs",lfs) blockrequire("io",io) blockrequire("os",os) blockrequire("ffi",ffi) local function supported(library) - local l=_G[library] - return l + local l=_G[library] + return l end loadfile=register(loadfile,"loadfile") if supported("io") then - io.open=register(io.open,"io.open") - io.popen=register(io.popen,"io.popen") - io.lines=register(io.lines,"io.lines") - io.output=register(io.output,"io.output") - io.input=register(io.input,"io.input") + io.open=register(io.open,"io.open") + io.popen=register(io.popen,"io.popen") + io.lines=register(io.lines,"io.lines") + io.output=register(io.output,"io.output") + io.input=register(io.input,"io.input") end if supported("os") then - os.execute=register(os.execute,"os.execute") - os.spawn=register(os.spawn,"os.spawn") - os.exec=register(os.exec,"os.exec") - os.rename=register(os.rename,"os.rename") - os.remove=register(os.remove,"os.remove") + os.execute=register(os.execute,"os.execute") + os.spawn=register(os.spawn,"os.spawn") + os.exec=register(os.exec,"os.exec") + os.rename=register(os.rename,"os.rename") + os.remove=register(os.remove,"os.remove") end if supported("lfs") then - lfs.chdir=register(lfs.chdir,"lfs.chdir") - lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") - lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") - lfs.isfile=register(lfs.isfile,"lfs.isfile") - lfs.isdir=register(lfs.isdir,"lfs.isdir") - lfs.attributes=register(lfs.attributes,"lfs.attributes") - lfs.dir=register(lfs.dir,"lfs.dir") - lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") - lfs.touch=register(lfs.touch,"lfs.touch") - lfs.link=register(lfs.link,"lfs.link") - lfs.setmode=register(lfs.setmode,"lfs.setmode") - lfs.readlink=register(lfs.readlink,"lfs.readlink") - lfs.shortname=register(lfs.shortname,"lfs.shortname") - lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") + lfs.chdir=register(lfs.chdir,"lfs.chdir") + lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") + lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") + lfs.isfile=register(lfs.isfile,"lfs.isfile") + lfs.isdir=register(lfs.isdir,"lfs.isdir") + lfs.attributes=register(lfs.attributes,"lfs.attributes") + lfs.dir=register(lfs.dir,"lfs.dir") + lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") + lfs.touch=register(lfs.touch,"lfs.touch") + lfs.link=register(lfs.link,"lfs.link") + lfs.setmode=register(lfs.setmode,"lfs.setmode") + lfs.readlink=register(lfs.readlink,"lfs.readlink") + lfs.shortname=register(lfs.shortname,"lfs.shortname") + lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") end @@ -673,14 +847,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-package"] = package.loaded["l-package"] or true --- original size: 11562, stripped down to: 8625 +-- original size: 11605, stripped down to: 8299 if not modules then modules={} end modules ['l-package']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local gsub,format,find=string.gsub,string.format,string.find @@ -688,40 +862,40 @@ local insert,remove=table.insert,table.remove local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match local package=package local searchers=package.searchers or package.loaders -local filejoin=file and file.join or function(path,name) return path.."/"..name end -local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end -local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end +local filejoin=file and file.join or function(path,name) return path.."/"..name end +local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end +local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end local function cleanpath(path) - return path + return path end local pattern=Cs((((1-S("\\/"))^0*(S("\\/")^1/"/"))^0*(P(".")^1/"/"+P(1))^1)*-1) local function lualibfile(name) - return lpegmatch(pattern,name) or name + return lpegmatch(pattern,name) or name end local offset=luarocks and 1 or 0 local helpers=package.helpers or { - cleanpath=cleanpath, - lualibfile=lualibfile, - trace=false, - report=function(...) print(format(...)) end, - builtin={ - ["preload table"]=searchers[1+offset], - ["path specification"]=searchers[2+offset], - ["cpath specification"]=searchers[3+offset], - ["all in one fallback"]=searchers[4+offset], - }, - methods={}, - sequence={ - "already loaded", - "preload table", - "qualified path", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", - } + cleanpath=cleanpath, + lualibfile=lualibfile, + trace=false, + report=function(...) print(format(...)) end, + builtin={ + ["preload table"]=searchers[1+offset], + ["path specification"]=searchers[2+offset], + ["cpath specification"]=searchers[3+offset], + ["all in one fallback"]=searchers[4+offset], + }, + methods={}, + sequence={ + "already loaded", + "preload table", + "qualified path", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", + } } package.helpers=helpers local methods=helpers.methods @@ -737,253 +911,256 @@ local nofextralib=-1 local nofpathlua=-1 local nofpathlib=-1 local function listpaths(what,paths) - local nofpaths=#paths - if nofpaths>0 then - for i=1,nofpaths do - helpers.report("using %s path %i: %s",what,i,paths[i]) - end - else - helpers.report("no %s paths defined",what) + local nofpaths=#paths + if nofpaths>0 then + for i=1,nofpaths do + helpers.report("using %s path %i: %s",what,i,paths[i]) end - return nofpaths + else + helpers.report("no %s paths defined",what) + end + return nofpaths end local function getextraluapaths() - if helpers.trace and #extraluapaths~=nofextralua then - nofextralua=listpaths("extra lua",extraluapaths) - end - return extraluapaths + if helpers.trace and #extraluapaths~=nofextralua then + nofextralua=listpaths("extra lua",extraluapaths) + end + return extraluapaths end local function getextralibpaths() - if helpers.trace and #extralibpaths~=nofextralib then - nofextralib=listpaths("extra lib",extralibpaths) - end - return extralibpaths + if helpers.trace and #extralibpaths~=nofextralib then + nofextralib=listpaths("extra lib",extralibpaths) + end + return extralibpaths end local function getluapaths() - local luapath=package.path or "" - if oldluapath~=luapath then - luapaths=file.splitpath(luapath,";") - oldluapath=luapath - nofpathlua=-1 - end - if helpers.trace and #luapaths~=nofpathlua then - nofpathlua=listpaths("builtin lua",luapaths) - end - return luapaths + local luapath=package.path or "" + if oldluapath~=luapath then + luapaths=file.splitpath(luapath,";") + oldluapath=luapath + nofpathlua=-1 + end + if helpers.trace and #luapaths~=nofpathlua then + nofpathlua=listpaths("builtin lua",luapaths) + end + return luapaths end local function getlibpaths() - local libpath=package.cpath or "" - if oldlibpath~=libpath then - libpaths=file.splitpath(libpath,";") - oldlibpath=libpath - nofpathlib=-1 - end - if helpers.trace and #libpaths~=nofpathlib then - nofpathlib=listpaths("builtin lib",libpaths) - end - return libpaths + local libpath=package.cpath or "" + if oldlibpath~=libpath then + libpaths=file.splitpath(libpath,";") + oldlibpath=libpath + nofpathlib=-1 + end + if helpers.trace and #libpaths~=nofpathlib then + nofpathlib=listpaths("builtin lib",libpaths) + end + return libpaths end package.luapaths=getluapaths package.libpaths=getlibpaths package.extraluapaths=getextraluapaths package.extralibpaths=getextralibpaths local hashes={ - lua={}, - lib={}, + lua={}, + lib={}, } local function registerpath(tag,what,target,...) - local pathlist={... } - local cleanpath=helpers.cleanpath - local trace=helpers.trace - local report=helpers.report - local hash=hashes[what] - local function add(path) - local path=cleanpath(path) - if not hash[path] then - target[#target+1]=path - hash[path]=true - if trace then - report("registered %s path %s: %s",tag,#target,path) - end - else - if trace then - report("duplicate %s path: %s",tag,path) - end - end + local pathlist={... } + local cleanpath=helpers.cleanpath + local trace=helpers.trace + local report=helpers.report + local hash=hashes[what] + local function add(path) + local path=cleanpath(path) + if not hash[path] then + target[#target+1]=path + hash[path]=true + if trace then + report("registered %s path %s: %s",tag,#target,path) + end + else + if trace then + report("duplicate %s path: %s",tag,path) + end end - for p=1,#pathlist do - local path=pathlist[p] - if type(path)=="table" then - for i=1,#path do - add(path[i]) - end - else - add(path) - end + end + for p=1,#pathlist do + local path=pathlist[p] + if type(path)=="table" then + for i=1,#path do + add(path[i]) + end + else + add(path) end + end end local function pushpath(tag,what,target,path) - local path=helpers.cleanpath(path) - insert(target,1,path) - if helpers.trace then - helpers.report("pushing %s path in front: %s",tag,path) - end + local path=helpers.cleanpath(path) + insert(target,1,path) + if helpers.trace then + helpers.report("pushing %s path in front: %s",tag,path) + end end local function poppath(tag,what,target) - local path=remove(target,1) - if helpers.trace then - if path then - helpers.report("popping %s path from front: %s",tag,path) - else - helpers.report("no %s path to pop",tag) - end + local path=remove(target,1) + if helpers.trace then + if path then + helpers.report("popping %s path from front: %s",tag,path) + else + helpers.report("no %s path to pop",tag) end + end end helpers.registerpath=registerpath function package.extraluapath(...) - registerpath("extra lua","lua",extraluapaths,...) + registerpath("extra lua","lua",extraluapaths,...) end function package.pushluapath(path) - pushpath("extra lua","lua",extraluapaths,path) + pushpath("extra lua","lua",extraluapaths,path) end function package.popluapath() - poppath("extra lua","lua",extraluapaths) + poppath("extra lua","lua",extraluapaths) end function package.extralibpath(...) - registerpath("extra lib","lib",extralibpaths,...) + registerpath("extra lib","lib",extralibpaths,...) end function package.pushlibpath(path) - pushpath("extra lib","lib",extralibpaths,path) + pushpath("extra lib","lib",extralibpaths,path) end function package.poplibpath() - poppath("extra lib","lua",extralibpaths) + poppath("extra lib","lua",extralibpaths) end local function loadedaslib(resolved,rawname) - local base=gsub(rawname,"%.","_") - local init="luaopen_"..gsub(base,"%.","_") - if helpers.trace then - helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) - end - return package.loadlib(resolved,init) + local base=gsub(rawname,"%.","_") + local init="luaopen_"..gsub(base,"%.","_") + if helpers.trace then + helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) + end + return package.loadlib(resolved,init) end helpers.loadedaslib=loadedaslib local function loadedbypath(name,rawname,paths,islib,what) - local trace=helpers.trace - for p=1,#paths do - local path=paths[p] - local resolved=filejoin(path,name) - if trace then - helpers.report("%s path, identifying '%s' on '%s'",what,name,path) - end - if isreadable(resolved) then - if trace then - helpers.report("%s path, '%s' found on '%s'",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + for p=1,#paths do + local path=paths[p] + local resolved=filejoin(path,name) + if trace then + helpers.report("%s path, identifying '%s' on '%s'",what,name,path) + end + if isreadable(resolved) then + if trace then + helpers.report("%s path, '%s' found on '%s'",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + 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 + 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] + return package.loaded[name] end methods["preload table"]=function(name) - return builtin["preload table"](name) + return builtin["preload table"](name) end methods["qualified path"]=function(name) - return loadedbyname(addsuffix(lualibfile(name),"lua"),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") + return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib") end methods["path specification"]=function(name) - getluapaths() - return builtin["path specification"](name) + getluapaths() + return builtin["path specification"](name) end methods["cpath specification"]=function(name) - getlibpaths() - return builtin["cpath specification"](name) + getlibpaths() + return builtin["cpath specification"](name) end methods["all in one fallback"]=function(name) - return builtin["all in one fallback"](name) + return builtin["all in one fallback"](name) end methods["not loaded"]=function(name) - if helpers.trace then - helpers.report("unable to locate '%s'",name or "?") - end - return nil + if helpers.trace then + helpers.report("unable to locate '%s'",name or "?") + end + return nil end local level=0 local used={} helpers.traceused=false function helpers.loaded(name) - local sequence=helpers.sequence - level=level+1 - for i=1,#sequence do - local method=sequence[i] - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) - end - local result,rest=methods[method](name) - if type(result)=="function" then - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) - end - if helpers.traceused then - used[#used+1]={ level=level,name=name } - end - level=level-1 - return result,rest - end + local sequence=helpers.sequence + level=level+1 + for i=1,#sequence do + local method=sequence[i] + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) end - level=level-1 - return nil + local result,rest=methods[method](name) + if type(result)=="function" then + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) + end + if helpers.traceused then + used[#used+1]={ level=level,name=name } + end + level=level-1 + return result,rest + end + end + level=level-1 + return nil end function helpers.showused() - local n=#used - if n>0 then - helpers.report("%s libraries loaded:",n) - helpers.report() - for i=1,n do - local u=used[i] - helpers.report("%i %a",u.level,u.name) - end - helpers.report() - end + local n=#used + if n>0 then + helpers.report("%s libraries loaded:",n) + helpers.report() + for i=1,n do + local u=used[i] + helpers.report("%i %a",u.level,u.name) + end + helpers.report() + end end function helpers.unload(name) - if helpers.trace then - if package.loaded[name] then - helpers.report("unloading, name '%s', %s",name,"done") - else - helpers.report("unloading, name '%s', %s",name,"not loaded") - end + if helpers.trace then + if package.loaded[name] then + helpers.report("unloading, name '%s', %s",name,"done") + else + helpers.report("unloading, name '%s', %s",name,"not loaded") end - package.loaded[name]=nil + end + package.loaded[name]=nil end table.insert(searchers,1,helpers.loaded) +if context then + package.path="" +end end -- of closure @@ -992,14 +1169,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true --- original size: 38582, stripped down to: 20518 +-- original size: 38434, stripped down to: 19310 if not modules then modules={} end modules ['l-lpeg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } lpeg=require("lpeg") local lpeg=lpeg @@ -1010,7 +1187,7 @@ 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 if setinspector then - setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) + setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns @@ -1033,7 +1210,7 @@ local underscore=P("_") local hexdigit=digit+lowercase+uppercase local hexdigits=hexdigit^1 local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") -local newline=P("\r")*(P("\n")+P(true))+P("\n") +local newline=P("\r")*(P("\n")+P(true))+P("\n") local escaped=P("\\")*anything local squote=P("'") local dquote=P('"') @@ -1042,9 +1219,9 @@ 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_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") @@ -1076,7 +1253,7 @@ patterns.utf8character=utf8character patterns.validutf8=validutf8char patterns.validutf8char=validutf8char local eol=S("\n\r") -local spacer=S(" \t\f\v") +local spacer=S(" \t\f\v") local whitespace=eol+spacer local nonspacer=1-spacer local nonwhitespace=1-whitespace @@ -1085,15 +1262,15 @@ 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)) local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0) local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0) -local e_collapser=Cs((whitespace^1*P(-1)/""+nonwhitespace^1+whitespace^1/" ")^0) +local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0) local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0) local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0) -local e_stripper=Cs((spacer^1*P(-1)/""+nonspacer^1+spacer^1/" ")^0) +local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0) local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0) patterns.stripper=stripper patterns.fullstripper=fullstripper @@ -1150,7 +1327,7 @@ patterns.cpfloat=sign^-1*patterns.cpunsigned patterns.number=patterns.float+patterns.integer patterns.cnumber=patterns.cfloat+patterns.integer patterns.cpnumber=patterns.cpfloat+patterns.integer -patterns.oct=zero*octdigits +patterns.oct=zero*octdigits patterns.octal=patterns.oct patterns.HEX=zero*P("X")*(digit+uppercase)^1 patterns.hex=zero*P("x")*(digit+lowercase)^1 @@ -1160,76 +1337,84 @@ patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)* 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/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) -local function anywhere(pattern) - return P { P(pattern)+1*V(1) } +patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0)) +function anywhere(pattern) + return (1-P(pattern))^0*P(pattern) end lpeg.anywhere=anywhere function lpeg.instringchecker(p) - p=anywhere(p) - return function(str) - return lpegmatch(p,str) and true or false - end + p=anywhere(p) + return function(str) + return lpegmatch(p,str) and true or false + end end function lpeg.splitter(pattern,action) + if action then return (((1-P(pattern))^1)/action+1)^0 + else + return (Cs((1-P(pattern))^1)+1)^0 + end end function lpeg.tsplitter(pattern,action) + if action then return Ct((((1-P(pattern))^1)/action+1)^0) + else + return Ct((Cs((1-P(pattern))^1)+1)^0) + end end local splitters_s,splitters_m,splitters_t={},{},{} local function splitat(separator,single) - local splitter=(single and splitters_s[separator]) or splitters_m[separator] - if not splitter then - separator=P(separator) - local other=C((1-separator)^0) - if single then - local any=anything - splitter=other*(separator*C(any^0)+"") - splitters_s[separator]=splitter - else - splitter=other*(separator*other)^0 - splitters_m[separator]=splitter - end + local splitter=(single and splitters_s[separator]) or splitters_m[separator] + if not splitter then + separator=P(separator) + local other=C((1-separator)^0) + if single then + local any=anything + splitter=other*(separator*C(any^0)+"") + splitters_s[separator]=splitter + else + splitter=other*(separator*other)^0 + splitters_m[separator]=splitter end - return splitter + end + return splitter end local function tsplitat(separator) - local splitter=splitters_t[separator] - if not splitter then - splitter=Ct(splitat(separator)) - splitters_t[separator]=splitter - end - return splitter + local splitter=splitters_t[separator] + if not splitter then + splitter=Ct(splitat(separator)) + splitters_t[separator]=splitter + end + return splitter end lpeg.splitat=splitat lpeg.tsplitat=tsplitat function string.splitup(str,separator) - if not separator then - separator="," - end - return lpegmatch(splitters_m[separator] or splitat(separator),str) + if not separator then + separator="," + end + return lpegmatch(splitters_m[separator] or splitat(separator),str) end local cache={} function lpeg.split(separator,str) + local c=cache[separator] + if not c then + c=tsplitat(separator) + cache[separator]=c + end + return lpegmatch(c,str) +end +function string.split(str,separator) + if separator then local c=cache[separator] if not c then - c=tsplitat(separator) - cache[separator]=c + c=tsplitat(separator) + cache[separator]=c end return lpegmatch(c,str) -end -function string.split(str,separator) - if separator then - local c=cache[separator] - if not c then - c=tsplitat(separator) - cache[separator]=c - end - return lpegmatch(c,str) - else - return { str } - end + else + return { str } + end end local spacing=patterns.spacer^0*newline local empty=spacing*Cc("") @@ -1239,505 +1424,463 @@ patterns.textline=content local linesplitter=tsplitat(newline) patterns.linesplitter=linesplitter function string.splitlines(str) - return lpegmatch(linesplitter,str) + return lpegmatch(linesplitter,str) end local cache={} function lpeg.checkedsplit(separator,str) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) end function string.checkedsplit(str,separator) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) -end -local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end -local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) +end +local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end +local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4 patterns.utf8byte=utf8byte local cache={} function lpeg.stripper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs(((S(str)^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs(((str^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs(((S(str)^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs(((str^1)/""+1)^0) + end end local cache={} function lpeg.keeper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs((((1-S(str))^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs((((1-str)^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs((((1-S(str))^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs((((1-str)^1)/""+1)^0) + end end function lpeg.frontstripper(str) - return (P(str)+P(true))*Cs(anything^0) + return (P(str)+P(true))*Cs(anything^0) end function lpeg.endstripper(str) - return Cs((1-P(str)*endofstring)^0) + return Cs((1-P(str)*endofstring)^0) end function lpeg.replacer(one,two,makefunction,isutf) - local pattern - local u=isutf and utf8char or 1 - if type(one)=="table" then - local no=#one - local p=P(false) - if no==0 then - for k,v in next,one do - p=p+P(k)/v - end - pattern=Cs((p+u)^0) - elseif no==1 then - local o=one[1] - one,two=P(o[1]),o[2] - pattern=Cs((one/two+u)^0) - else - for i=1,no do - local o=one[i] - p=p+P(o[1])/o[2] - end - pattern=Cs((p+u)^0) - end - else - pattern=Cs((P(one)/(two or "")+u)^0) + local pattern + local u=isutf and utf8char or 1 + if type(one)=="table" then + local no=#one + local p=P(false) + if no==0 then + for k,v in next,one do + p=p+P(k)/v + end + pattern=Cs((p+u)^0) + elseif no==1 then + local o=one[1] + one,two=P(o[1]),o[2] + pattern=Cs((one/two+u)^0) + else + for i=1,no do + local o=one[i] + p=p+P(o[1])/o[2] + end + pattern=Cs((p+u)^0) end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=Cs((P(one)/(two or "")+u)^0) + end + if makefunction then + return function(str) + return lpegmatch(pattern,str) end + else + return pattern + end end function lpeg.finder(lst,makefunction,isutf) - local pattern - if type(lst)=="table" then - pattern=P(false) - if #lst==0 then - for k,v in next,lst do - pattern=pattern+P(k) - end - else - for i=1,#lst do - pattern=pattern+P(lst[i]) - end - end - else - pattern=P(lst) - end - if isutf then - pattern=((utf8char or 1)-pattern)^0*pattern + local pattern + if type(lst)=="table" then + pattern=P(false) + if #lst==0 then + for k,v in next,lst do + pattern=pattern+P(k) + end else - pattern=(1-pattern)^0*pattern + for i=1,#lst do + pattern=pattern+P(lst[i]) + end end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=P(lst) + end + 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) end + else + return pattern + end end local splitters_f,splitters_s={},{} function lpeg.firstofsplit(separator) - local splitter=splitters_f[separator] - if not splitter then - local pattern=P(separator) - splitter=C((1-pattern)^0) - splitters_f[separator]=splitter - end - return splitter + local splitter=splitters_f[separator] + if not splitter then + local pattern=P(separator) + splitter=C((1-pattern)^0) + splitters_f[separator]=splitter + end + return splitter end function lpeg.secondofsplit(separator) - local splitter=splitters_s[separator] - if not splitter then - local pattern=P(separator) - splitter=(1-pattern)^0*pattern*C(anything^0) - splitters_s[separator]=splitter - end - return splitter + local splitter=splitters_s[separator] + if not splitter then + 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 + 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 + 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 } + left,right=P(left),P(right) + return P { left*((1-left-right)+V(1))^0*right } end function lpeg.counter(pattern,action) - local n=0 - local pattern=(P(pattern)/function() n=n+1 end+anything)^0 - if action then - return function(str) n=0;lpegmatch(pattern,str);action(n) end - else - return function(str) n=0;lpegmatch(pattern,str);return n end - end -end -utf=utf or (unicode and unicode.utf8) or {} -local utfcharacters=utf and utf.characters or string.utfcharacters -local utfgmatch=utf and utf.gmatch -local utfchar=utf and utf.char -lpeg.UP=lpeg.P -if utfcharacters then - function lpeg.US(str) - local p=P(false) - for uc in utfcharacters(str) do - p=p+P(uc) - end - return p - end -elseif utfgmatch then - function lpeg.US(str) - local p=P(false) - for uc in utfgmatch(str,".") do - p=p+P(uc) - end - return p - end -else - function lpeg.US(str) - local p=P(false) - local f=function(uc) - p=p+P(uc) - end - lpegmatch((utf8char/f)^0,str) - return p - end -end -local range=utf8byte*utf8byte+Cc(false) -function lpeg.UR(str,more) - local first,last - if type(str)=="number" then - first=str - last=more or first - else - first,last=lpegmatch(range,str) - if not last then - return P(str) - end - end - if first==last then - return P(str) - elseif utfchar and (last-first<8) then - local p=P(false) - for i=first,last do - p=p+P(utfchar(i)) - end - return p - else - local f=function(b) - return b>=first and b<=last - end - return utf8byte/f - end + local n=0 + local pattern=(P(pattern)/function() n=n+1 end+anything)^0 + if action then + return function(str) n=0;lpegmatch(pattern,str);action(n) end + else + return function(str) n=0;lpegmatch(pattern,str);return n end + end end function lpeg.is_lpeg(p) - return p and lpegtype(p)=="pattern" + return p and lpegtype(p)=="pattern" end function lpeg.oneof(list,...) - if type(list)~="table" then - list={ list,... } - end - local p=P(list[1]) - for l=2,#list do - p=p+P(list[l]) - end - return p + if type(list)~="table" then + list={ list,... } + end + local p=P(list[1]) + for l=2,#list do + p=p+P(list[l]) + end + return p end local sort=table.sort local function copyindexed(old) - local new={} - for i=1,#old do - new[i]=old - end - return new + local new={} + for i=1,#old do + new[i]=old + end + return new end local function sortedkeys(tab) - local keys,s={},0 - for key,_ in next,tab do - s=s+1 - keys[s]=key - end - sort(keys) - return keys + local keys,s={},0 + for key,_ in next,tab do + s=s+1 + keys[s]=key + end + sort(keys) + return keys end function lpeg.append(list,pp,delayed,checked) - local p=pp - if #list>0 then - local keys=copyindexed(list) - sort(keys) - for i=#keys,1,-1 do - local k=keys[i] - if p then - p=P(k)+p - else - p=P(k) - end - end - elseif delayed then - local keys=sortedkeys(list) + local p=pp + if #list>0 then + local keys=copyindexed(list) + sort(keys) + for i=#keys,1,-1 do + local k=keys[i] + if p then + p=P(k)+p + else + p=P(k) + end + end + elseif delayed then + local keys=sortedkeys(list) + if p then + for i=1,#keys,1 do + local k=keys[i] + local v=list[k] + p=P(k)/list+p + end + else + for i=1,#keys do + local k=keys[i] + local v=list[k] if p then - for i=1,#keys,1 do - local k=keys[i] - local v=list[k] - p=P(k)/list+p - end + p=P(k)+p else - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)+p - else - p=P(k) - end - end - if p then - p=p/list - end + p=P(k) end - elseif checked then - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - if k==v then - p=P(k)+p - else - p=P(k)/v+p - end - else - if k==v then - p=P(k) - else - p=P(k)/v - end - end + end + if p then + p=p/list + end + end + elseif checked then + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + if k==v then + p=P(k)+p + else + p=P(k)/v+p end - else - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)/v+p - else - p=P(k)/v - end + else + if k==v then + p=P(k) + else + p=P(k)/v end + end end - return p + else + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + p=P(k)/v+p + else + p=P(k)/v + end + end + end + return p end local p_false=P(false) local p_true=P(true) local lower=utf and utf.lower or string.lower local upper=utf and utf.upper or string.upper function lpeg.setutfcasers(l,u) - lower=l or lower - upper=u or upper + lower=l or lower + upper=u or upper end local function make1(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+P(k)*p_true - elseif v==false then - else - p=p+P(k)*make1(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+P(k)*p_true + elseif v==false then + else + p=p+P(k)*make1(v,v[""]) + end end - return p + end + if rest then + p=p+p_true + end + return p end local function make2(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+(P(lower(k))+P(upper(k)))*p_true - elseif v==false then - else - p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+(P(lower(k))+P(upper(k)))*p_true + elseif v==false then + else + p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) + end end - return p -end -function lpeg.utfchartabletopattern(list,insensitive) - local tree={} - local n=#list - if n==0 then - for s in next,list do - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + end + if rest then + p=p+p_true + end + return p +end +local function utfchartabletopattern(list,insensitive) + local tree={} + local n=#list + if n==0 then + for s in next,list do + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end - else - for i=1,n do - local s=list[i] - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end + end + else + for i=1,n do + local s=list[i] + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end end - return (insensitive and make2 or make1)(tree) + end + return (insensitive and make2 or make1)(tree) +end +lpeg.utfchartabletopattern=utfchartabletopattern +function lpeg.utfreplacer(list,insensitive) + local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0) + return function(str) + return lpegmatch(pattern,str) or str + end end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) - local m=n%step - local d=floor(n/step) - if d>0 then - local v=V(tostring(step)) - local s=result.start - for i=1,d do - if s then - s=v*s - else - s=v - end - end - result.start=s - end - if step>1 and result.start then - local v=V(tostring(step/2)) - result[tostring(step)]=v*v - end - if step>0 then - return nextstep(m,step/2,result) - else - return result + local m=n%step + local d=floor(n/step) + if d>0 then + local v=V(tostring(step)) + local s=result.start + for i=1,d do + if s then + s=v*s + else + s=v + end end + result.start=s + end + if step>1 and result.start then + local v=V(tostring(step/2)) + result[tostring(step)]=v*v + end + if step>0 then + return nextstep(m,step/2,result) + else + return result + end end function lpeg.times(pattern,n) - return P(nextstep(n,2^16,{ "start",["1"]=pattern })) -end -local trailingzeros=zero^0*-digit -local case_1=period*trailingzeros/"" -local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"") -local number=digits*(case_1+case_2) -local stripper=Cs((number+1)^0) -lpeg.patterns.stripzeros=stripper + return P(nextstep(n,2^16,{ "start",["1"]=pattern })) +end +do + local trailingzeros=zero^0*-digit + local stripper=Cs(( + digits*( + period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"") + )+1 + )^0) + lpeg.patterns.stripzeros=stripper + local nonzero=digit-zero + local trailingzeros=zero^1*endofstring + local stripper=Cs((1-period)^0*( + period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring + )) + lpeg.patterns.stripzero=stripper +end local byte_to_HEX={} local byte_to_hex={} local byte_to_dec={} local hex_to_byte={} for i=0,255 do - local H=format("%02X",i) - local h=format("%02x",i) - local d=format("%03i",i) - local c=char(i) - byte_to_HEX[c]=H - byte_to_hex[c]=h - byte_to_dec[c]=d - hex_to_byte[h]=c - hex_to_byte[H]=c + local H=format("%02X",i) + local h=format("%02x",i) + local d=format("%03i",i) + local c=char(i) + byte_to_HEX[c]=H + byte_to_hex[c]=h + byte_to_dec[c]=d + hex_to_byte[h]=c + hex_to_byte[H]=c end local hextobyte=P(2)/hex_to_byte local bytetoHEX=P(1)/byte_to_HEX @@ -1756,32 +1899,47 @@ patterns.bytestoHEX=bytestoHEX patterns.bytestohex=bytestohex patterns.bytestodec=bytestodec function string.toHEX(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestoHEX,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestoHEX,s) + end end function string.tohex(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestohex,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestohex,s) + end end function string.todec(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestodec,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestodec,s) + end end function string.tobytes(s) - if not s or s=="" then - return s - else - return lpegmatch(hextobytes,s) - end + if not s or s=="" then + return s + else + return lpegmatch(hextobytes,s) + end +end +local patterns={} +local function containsws(what) + local p=patterns[what] + if not p then + local p1=P(what)*(whitespace+endofstring)*Cc(true) + local p2=whitespace*P(p1) + p=P(p1)+P(1-p2)^0*p2+Cc(false) + patterns[what]=p + end + return p +end +lpeg.containsws=containsws +function string.containsws(str,what) + return lpegmatch(patterns[what] or containsws(what),str) end @@ -1791,14 +1949,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-function"] = package.loaded["l-function"] or true --- original size: 361, stripped down to: 322 +-- original size: 361, stripped down to: 317 if not modules then modules={} end modules ['l-functions']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } functions=functions or {} function functions.dummy() end @@ -1810,14 +1968,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-string"] = package.loaded["l-string"] or true --- original size: 6461, stripped down to: 3341 +-- original size: 6461, stripped down to: 3255 if not modules then modules={} end modules ['l-string']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local string=string local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower @@ -1825,25 +1983,25 @@ local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote function string.unquoted(str) - return lpegmatch(unquoted,str) or str + return lpegmatch(unquoted,str) or str end function string.quoted(str) - return format("%q",str) + return format("%q",str) end function string.count(str,pattern) - local n=0 - for _ in gmatch(str,pattern) do - n=n+1 - end - return n + local n=0 + for _ in gmatch(str,pattern) do + n=n+1 + end + return n end function string.limit(str,n,sentinel) - if #str>n then - sentinel=sentinel or "..." - return sub(str,1,(n-#sentinel))..sentinel - else - return str - end + if #str>n then + sentinel=sentinel or "..." + return sub(str,1,(n-#sentinel))..sentinel + else + return str + end end local stripper=patterns.stripper local fullstripper=patterns.fullstripper @@ -1851,81 +2009,81 @@ local collapser=patterns.collapser local nospacer=patterns.nospacer local longtostring=patterns.longtostring function string.strip(str) - return str and lpegmatch(stripper,str) or "" + return str and lpegmatch(stripper,str) or "" end function string.fullstrip(str) - return str and lpegmatch(fullstripper,str) or "" + return str and lpegmatch(fullstripper,str) or "" end function string.collapsespaces(str) - return str and lpegmatch(collapser,str) or "" + return str and lpegmatch(collapser,str) or "" end function string.nospaces(str) - return str and lpegmatch(nospacer,str) or "" + return str and lpegmatch(nospacer,str) or "" end function string.longtostring(str) - return str and lpegmatch(longtostring,str) or "" + return str and lpegmatch(longtostring,str) or "" end local pattern=P(" ")^0*P(-1) function string.is_empty(str) - if not str or str=="" then - return true - else - return lpegmatch(pattern,str) and true or false - end + if not str or str=="" then + return true + else + return lpegmatch(pattern,str) and true or false + end end local anything=patterns.anything local allescapes=Cc("%")*S(".-+%?()[]*") -local someescapes=Cc("%")*S(".-+%()[]") -local matchescapes=Cc(".")*S("*?") +local someescapes=Cc("%")*S(".-+%()[]") +local matchescapes=Cc(".")*S("*?") local pattern_a=Cs ((allescapes+anything )^0 ) local pattern_b=Cs ((someescapes+matchescapes+anything )^0 ) local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") ) function string.escapedpattern(str,simple) - return lpegmatch(simple and pattern_b or pattern_a,str) + return lpegmatch(simple and pattern_b or pattern_a,str) end function string.topattern(str,lowercase,strict) - if str=="" or type(str)~="string" then - return ".*" - elseif strict then - str=lpegmatch(pattern_c,str) - else - str=lpegmatch(pattern_b,str) - end - if lowercase then - return lower(str) - else - return str - end + if str=="" or type(str)~="string" then + return ".*" + elseif strict then + str=lpegmatch(pattern_c,str) + else + str=lpegmatch(pattern_b,str) + end + if lowercase then + return lower(str) + else + return str + end end function string.valid(str,default) - return (type(str)=="string" and str~="" and str) or default or nil + return (type(str)=="string" and str~="" and str) or default or nil end string.itself=function(s) return s end local pattern_c=Ct(C(1)^0) local pattern_b=Ct((C(1)/byte)^0) function string.totable(str,bytes) - return lpegmatch(bytes and pattern_b or pattern_c,str) + return lpegmatch(bytes and pattern_b or pattern_c,str) end local replacer=lpeg.replacer("@","%%") function string.tformat(fmt,...) - return format(lpegmatch(replacer,fmt),...) + return format(lpegmatch(replacer,fmt),...) end string.quote=string.quoted string.unquote=string.unquoted if not string.bytetable then - local limit=5000 - function string.bytetable(str) - local n=#str - if n>limit then - local t={ byte(str,1,limit) } - for i=limit+1,n do - t[i]=byte(str,i) - end - return t - else - return { byte(str,1,n) } - end + local limit=5000 + function string.bytetable(str) + local n=#str + if n>limit then + local t={ byte(str,1,limit) } + for i=limit+1,n do + t[i]=byte(str,i) + end + return t + else + return { byte(str,1,n) } end + end end @@ -1935,166 +2093,172 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 40197, stripped down to: 23561 +-- original size: 41298, stripped down to: 21498 if not modules then modules={} end modules ['l-table']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select local table,string=table,string -local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove +local concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable -local getinfo=debug.getinfo local lpegmatch,patterns=lpeg.match,lpeg.patterns local floor=math.floor local stripper=patterns.stripper function table.getn(t) - return t and #t + return t and #t end function table.strip(tab) - local lst,l={},0 - for i=1,#tab do - local s=lpegmatch(stripper,tab[i]) or "" - if s=="" then - else - l=l+1 - lst[l]=s - end + local lst={} + local l=0 + for i=1,#tab do + local s=lpegmatch(stripper,tab[i]) or "" + if s=="" then + else + l=l+1 + lst[l]=s end - return lst + end + return lst end function table.keys(t) - if t then - local keys,k={},0 - for key in next,t do - k=k+1 - keys[k]=key - end - return keys - else - return {} + if t then + local keys={} + local k=0 + for key in next,t do + k=k+1 + keys[k]=key end + return keys + else + return {} + end end local function compare(a,b) - local ta=type(a) - if ta=="number" then - local tb=type(b) - if ta==tb then - return a<b - elseif tb=="string" then - return tostring(a)<b - end - elseif ta=="string" then - local tb=type(b) - if ta==tb then - return a<b - else - return a<tostring(b) - end + local ta=type(a) + if ta=="number" then + local tb=type(b) + if ta==tb then + return a<b + elseif tb=="string" then + return tostring(a)<b end - return tostring(a)<tostring(b) + elseif ta=="string" then + local tb=type(b) + if ta==tb then + return a<b + else + return a<tostring(b) + end + end + return tostring(a)<tostring(b) end local function sortedkeys(tab) - if tab then - local srt,category,s={},0,0 - for key in next,tab do - s=s+1 - srt[s]=key - if category==3 then - elseif category==1 then - if type(key)~="string" then - category=3 - end - elseif category==2 then - if type(key)~="number" then - category=3 - end - else - local tkey=type(key) - if tkey=="string" then - category=1 - elseif tkey=="number" then - category=2 - else - category=3 - end - end - end - if s<2 then - elseif category==3 then - sort(srt,compare) + if tab then + local srt={} + local category=0 + local s=0 + for key in next,tab do + s=s+1 + srt[s]=key + if category==3 then + elseif category==1 then + if type(key)~="string" then + category=3 + end + elseif category==2 then + if type(key)~="number" then + category=3 + end + else + local tkey=type(key) + if tkey=="string" then + category=1 + elseif tkey=="number" then + category=2 else - sort(srt) + category=3 end - return srt + end + end + if s<2 then + elseif category==3 then + sort(srt,compare) else - return {} + sort(srt) end + return srt + else + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="string" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="number" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + return srt + else + return {} + end end local function sortedhashkeys(tab,cmp) - if tab then - local srt,s={},0 - for key in next,tab do - if key then - s=s+1 - srt[s]=key - end - end - if s>1 then - sort(srt,cmp) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if key then + s=s+1 + srt[s]=key + end + end + if s>1 then + sort(srt,cmp) end + return srt + else + return {} + end end function table.allkeys(t) - local keys={} - for k,v in next,t do - for k in next,v do - keys[k]=true - end + local keys={} + for k,v in next,t do + for k in next,v do + keys[k]=true end - return sortedkeys(keys) + end + return sortedkeys(keys) end table.sortedkeys=sortedkeys table.sortedhashonly=sortedhashonly @@ -2102,907 +2266,944 @@ table.sortedindexonly=sortedindexonly table.sortedhashkeys=sortedhashkeys local function nothing() end local function sortedhash(t,cmp) - if t then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local m=#s - if m==1 then - return next,t - elseif m>0 then - local n=0 - return function() - if n<m then - n=n+1 - local k=s[n] - return k,t[k] - end - end + if t then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local m=#s + if m==1 then + return next,t + elseif m>0 then + local n=0 + return function() + if n<m then + n=n+1 + local k=s[n] + return k,t[k] end + end end - return nothing + end + return nothing end table.sortedhash=sortedhash table.sortedpairs=sortedhash function table.append(t,list) - local n=#t - for i=1,#list do - n=n+1 - t[n]=list[i] - end - return t + local n=#t + for i=1,#list do + n=n+1 + t[n]=list[i] + end + return t end function table.prepend(t,list) - local nl=#list - local nt=nl+#t - for i=#t,1,-1 do - t[nt]=t[i] - nt=nt-1 - end - for i=1,#list do - t[i]=list[i] - end - return t + local nl=#list + local nt=nl+#t + for i=#t,1,-1 do + t[nt]=t[i] + nt=nt-1 + end + for i=1,#list do + t[i]=list[i] + end + return t end function table.merge(t,...) - t=t or {} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + if not t then + t={} + end + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.merged(...) - local t={} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + local t={} + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.imerge(t,...) - local nt=#t - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - nt=nt+1 - t[nt]=nst[j] - end + local nt=#t + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + nt=nt+1 + t[nt]=nst[j] end - return t + end + return t end function table.imerged(...) - local tmp,ntmp={},0 - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - ntmp=ntmp+1 - tmp[ntmp]=nst[j] - end + local tmp={} + local ntmp=0 + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + ntmp=ntmp+1 + tmp[ntmp]=nst[j] end - return tmp + end + return tmp end local function fastcopy(old,metatabletoo) - if old then - local new={} - for k,v in next,old do - if type(v)=="table" then - new[k]=fastcopy(v,metatabletoo) - else - new[k]=v - end - end - if metatabletoo then - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + if type(v)=="table" then + new[k]=fastcopy(v,metatabletoo) + else + new[k]=v + end + end + if metatabletoo then + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end end + return new + else + return {} + end end local function copy(t,tables) - tables=tables or {} - local tcopy={} - if not tables[t] then - tables[t]=tcopy - end - for i,v in next,t do - if type(i)=="table" then - if tables[i] then - i=tables[i] - else - i=copy(i,tables) - end - end - if type(v)~="table" then - tcopy[i]=v - elseif tables[v] then - tcopy[i]=tables[v] - else - tcopy[i]=copy(v,tables) - end + if not tables then + tables={} + end + local tcopy={} + if not tables[t] then + tables[t]=tcopy + end + for i,v in next,t do + if type(i)=="table" then + if tables[i] then + i=tables[i] + else + i=copy(i,tables) + end end - local mt=getmetatable(t) - if mt then - setmetatable(tcopy,mt) + if type(v)~="table" then + tcopy[i]=v + elseif tables[v] then + tcopy[i]=tables[v] + else + tcopy[i]=copy(v,tables) end - return tcopy + end + local mt=getmetatable(t) + if mt then + setmetatable(tcopy,mt) + end + return tcopy end table.fastcopy=fastcopy table.copy=copy function table.derive(parent) - local child={} - if parent then - setmetatable(child,{ __index=parent }) - end - return child + local child={} + if parent then + setmetatable(child,{ __index=parent }) + end + return child end function table.tohash(t,value) - local h={} - if t then - if value==nil then value=true end - for _,v in next,t do - h[v]=value - end + local h={} + if t then + if value==nil then value=true end + for _,v in next,t do + h[v]=value end - return h + end + return h end function table.fromhash(t) - local hsh,h={},0 - for k,v in next,t do - if v then - h=h+1 - hsh[h]=k - end + local hsh={} + local h=0 + for k,v in next,t do + if v then + h=h+1 + hsh[h]=k end - return hsh + end + return hsh end local noquotes,hexify,handle,compact,inline,functions,metacheck 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', + '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 is_simple_table(t,hexify) - local nt=#t - if nt>0 then - local n=0 - for _,v in next,t do - n=n+1 - if type(v)=="table" then - return nil - end + local nt=#t + if nt>0 then + local n=0 + for _,v in next,t do + n=n+1 + if type(v)=="table" then + return nil + end + end + local haszero=rawget(t,0) + if n==nt then + local tt={} + for i=1,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i]=format("0x%X",v) + else + tt[i]=v + end + elseif tv=="string" then + tt[i]=format("%q",v) + elseif tv=="boolean" then + tt[i]=v and "true" or "false" + else + return nil end - local haszero=rawget(t,0) - if n==nt then - local tt={} - for i=1,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i]=format("0x%X",v) - else - tt[i]=v - end - elseif tv=="string" then - tt[i]=format("%q",v) - elseif tv=="boolean" then - tt[i]=v and "true" or "false" - else - return nil - end - end - return tt - elseif haszero and (n==nt+1) then - local tt={} - for i=0,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i+1]=format("0x%X",v) - else - tt[i+1]=v - end - elseif tv=="string" then - tt[i+1]=format("%q",v) - elseif tv=="boolean" then - tt[i+1]=v and "true" or "false" - else - return nil - end - end - tt[1]="[0] = "..tt[1] - return tt + end + return tt + elseif haszero and (n==nt+1) then + local tt={} + for i=0,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i+1]=format("0x%X",v) + else + tt[i+1]=v + end + elseif tv=="string" then + tt[i+1]=format("%q",v) + elseif tv=="boolean" then + tt[i+1]=v and "true" or "false" + else + return nil end + end + tt[1]="[0] = "..tt[1] + return tt end - return nil + end + return nil end table.is_simple_table=is_simple_table local propername=patterns.propername local function dummy() end local function do_serialize(root,name,depth,level,indexed) - if level>0 then - depth=depth.." " - if indexed then - handle(format("%s{",depth)) + if level>0 then + depth=depth.." " + if indexed then + handle(format("%s{",depth)) + else + local tn=type(name) + if tn=="number" then + if hexify then + handle(format("%s[0x%X]={",depth,name)) else - local tn=type(name) - if tn=="number" then - if hexify then - handle(format("%s[0x%X]={",depth,name)) - else - handle(format("%s[%s]={",depth,name)) - end - elseif tn=="string" then - if noquotes and not reserved[name] and lpegmatch(propername,name) then - handle(format("%s%s={",depth,name)) - else - handle(format("%s[%q]={",depth,name)) - end - elseif tn=="boolean" then - handle(format("%s[%s]={",depth,name and "true" or "false")) - else - handle(format("%s{",depth)) - end + handle(format("%s[%s]={",depth,name)) end + elseif tn=="string" then + if noquotes and not reserved[name] and lpegmatch(propername,name) then + handle(format("%s%s={",depth,name)) + else + handle(format("%s[%q]={",depth,name)) + end + elseif tn=="boolean" then + handle(format("%s[%s]={",depth,name and "true" or "false")) + else + handle(format("%s{",depth)) + end end - if root and next(root)~=nil then - local first,last=nil,0 - if compact then - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end - end - if last>0 then - first=1 - end + end + if root and next(root)~=nil then + local first=nil + local last=0 + if compact then + last=#root + for k=1,last do + if rawget(root,k)==nil then + last=k-1 + break 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 compact and first and tk=="number" and k>=first and k<=last then - if tv=="number" then - if hexify then - handle(format("%s 0x%X,",depth,v)) - else - handle(format("%s %s,",depth,v)) - end - elseif tv=="string" then - handle(format("%s %q,",depth,v)) - elseif tv=="table" then - if next(v)==nil then - handle(format("%s {},",depth)) - elseif inline then - local st=is_simple_table(v,hexify) - if st then - handle(format("%s { %s },",depth,concat(st,", "))) - else - do_serialize(v,k,depth,level+1,true) - end - else - do_serialize(v,k,depth,level+1,true) - end - 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))) - else - handle(format('%s "function",',depth)) - end - else - handle(format("%s %q,",depth,tostring(v))) - end - elseif k=="__p__" then - if false then - handle(format("%s __p__=nil,",depth)) - end - elseif tv=="number" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=0x%X,",depth,k,v)) - else - handle(format("%s [%s]=%s,",depth,k,v)) - end - elseif tk=="boolean" then - if hexify then - handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) - else - handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) - end - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - if hexify then - handle(format("%s %s=0x%X,",depth,k,v)) - else - handle(format("%s %s=%s,",depth,k,v)) - end - else - if hexify then - handle(format("%s [%q]=0x%X,",depth,k,v)) - else - handle(format("%s [%q]=%s,",depth,k,v)) - end - end - elseif tv=="string" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,v)) - else - handle(format("%s [%s]=%q,",depth,k,v)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) - elseif tk~="string" then - 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 - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={},",depth,k)) - else - handle(format("%s [%s]={},",depth,k)) - end - elseif tk=="boolean" then - handle(format("%s [%s]={},",depth,k and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={},",depth,k)) - else - handle(format("%s [%q]={},",depth,k)) - end - elseif inline then - local st=is_simple_table(v,hexify) - if st then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) - end - elseif tk=="boolean" then - handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) - end - else - do_serialize(v,k,depth,level+1) - end - else - do_serialize(v,k,depth,level+1) - end - elseif tv=="boolean" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) - else - 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),v and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,v and "true" or "false")) - else - handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) - end - elseif tv=="function" then - if functions then - local f=getinfo(v).what=="C" and dump(dummy) or dump(v) - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=load(%q),",depth,k,f)) - else - handle(format("%s [%s]=load(%q),",depth,k,f)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=load(%q),",depth,k,f)) - else - handle(format("%s [%q]=load(%q),",depth,k,f)) - end - end + end + if last>0 then + first=1 + end + 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 compact and first and tk=="number" and k>=first and k<=last then + if tv=="number" then + if hexify then + handle(format("%s 0x%X,",depth,v)) + else + handle(format("%s %s,",depth,v)) + end + elseif tv=="string" then + handle(format("%s %q,",depth,v)) + elseif tv=="table" then + if next(v)==nil then + handle(format("%s {},",depth)) + elseif inline then + local st=is_simple_table(v,hexify) + if st then + handle(format("%s { %s },",depth,concat(st,", "))) else - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) - else - handle(format("%s [%s]=%q,",depth,k,tostring(v))) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%q,",depth,k,tostring(v))) - else - handle(format("%s [%q]=%q,",depth,k,tostring(v))) - end + do_serialize(v,k,depth,level+1,true) end + else + do_serialize(v,k,depth,level+1,true) + end + 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))) + else + handle(format('%s "function",',depth)) + end + else + handle(format("%s %q,",depth,tostring(v))) end - end - if level>0 then - handle(format("%s},",depth)) - end -end -local function serialize(_handle,root,name,specification) - local tname=type(name) - if type(specification)=="table" then - noquotes=specification.noquotes - hexify=specification.hexify - handle=_handle or specification.handle or print - functions=specification.functions - compact=specification.compact - inline=specification.inline and compact - metacheck=specification.metacheck - if functions==nil then - functions=true - end - if compact==nil then - compact=true - end - if inline==nil then - inline=compact - end - if metacheck==nil then - metacheck=true + elseif k=="__p__" then + if false then + handle(format("%s __p__=nil,",depth)) end - else - noquotes=false - hexify=false - handle=_handle or print - compact=true - inline=true - functions=true - metacheck=true - end - if tname=="string" then - if name=="return" then - handle("return {") + elseif tv=="number" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=0x%X,",depth,k,v)) + else + handle(format("%s [%s]=%s,",depth,k,v)) + end + elseif tk=="boolean" then + if hexify then + handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + else + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) + end + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + if hexify then + handle(format("%s %s=0x%X,",depth,k,v)) + else + handle(format("%s %s=%s,",depth,k,v)) + end + else + if hexify then + handle(format("%s [%q]=0x%X,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end + end + elseif tv=="string" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,v)) + else + handle(format("%s [%s]=%q,",depth,k,v)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) else - handle(name.."={") + handle(format("%s [%q]=%q,",depth,k,v)) end - elseif tname=="number" then - if hexify then - handle(format("[0x%X]={",name)) + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={},",depth,k)) + else + handle(format("%s [%s]={},",depth,k)) + end + elseif tk=="boolean" then + handle(format("%s [%s]={},",depth,k and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={},",depth,k)) + else + handle(format("%s [%q]={},",depth,k)) + end + elseif inline then + local st=is_simple_table(v,hexify) + if st then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) + end + elseif tk=="boolean" then + handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) + end + else + do_serialize(v,k,depth,level+1) + end else - handle("["..name.."]={") + do_serialize(v,k,depth,level+1) end - elseif tname=="boolean" then - if name then - handle("return {") + elseif tv=="boolean" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) + else + 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),v and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else - handle("{") + handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) end - else - handle("t={") - end - if root then - if metacheck and getmetatable(root) then - local dummy=root._w_h_a_t_e_v_e_r_ - root._w_h_a_t_e_v_e_r_=nil + elseif tv=="function" then + if functions then + local getinfo=debug and debug.getinfo + if getinfo then + local f=getinfo(v).what=="C" and dump(dummy) or dump(v) + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=load(%q),",depth,k,f)) + else + handle(format("%s [%s]=load(%q),",depth,k,f)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=load(%q),",depth,k,f)) + else + handle(format("%s [%q]=load(%q),",depth,k,f)) + end + end end - if next(root)~=nil then - do_serialize(root,name,"",0) + else + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) + else + handle(format("%s [%s]=%q,",depth,k,tostring(v))) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,tostring(v))) + else + handle(format("%s [%q]=%q,",depth,k,tostring(v))) end + end end - handle("}") + end + if level>0 then + handle(format("%s},",depth)) + end end -function table.serialize(root,name,specification) - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s +local function serialize(_handle,root,name,specification) + local tname=type(name) + if type(specification)=="table" then + noquotes=specification.noquotes + hexify=specification.hexify + handle=_handle or specification.handle or print + functions=specification.functions + compact=specification.compact + inline=specification.inline and compact + metacheck=specification.metacheck + if functions==nil then + functions=true + end + if compact==nil then + compact=true + end + if inline==nil then + inline=compact + end + if metacheck==nil then + metacheck=true + end + else + noquotes=false + hexify=false + handle=_handle or print + compact=true + inline=true + functions=true + metacheck=true + end + if tname=="string" then + if name=="return" then + handle("return {") + else + handle(name.."={") + end + elseif tname=="number" then + if hexify then + handle(format("[0x%X]={",name)) + else + handle("["..name.."]={") + end + elseif tname=="boolean" then + if name then + handle("return {") + else + handle("{") + end + else + handle("t={") + end + if root then + if metacheck and 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)~=nil then + do_serialize(root,name,"",0) end - serialize(flush,root,name,specification) - return concat(t,"\n") + end + handle("}") +end +function table.serialize(root,name,specification) + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + end + serialize(flush,root,name,specification) + return concat(t,"\n") end table.tohandle=serialize local maxtab=2*1024 function table.tofile(filename,root,name,specification) - local f=io.open(filename,'w') - if f then - if maxtab>1 then - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s - if n>maxtab then - f:write(concat(t,"\n"),"\n") - t,n={},0 - end - end - serialize(flush,root,name,specification) - f:write(concat(t,"\n"),"\n") - else - local function flush(s) - f:write(s,"\n") - end - serialize(flush,root,name,specification) + local f=io.open(filename,'w') + if f then + if maxtab>1 then + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + if n>maxtab then + f:write(concat(t,"\n"),"\n") + t={} + n=0 end - f:close() - io.flush() + end + serialize(flush,root,name,specification) + f:write(concat(t,"\n"),"\n") + else + local function flush(s) + f:write(s,"\n") + end + serialize(flush,root,name,specification) end + f:close() + io.flush() + end end local function flattened(t,f,depth) - if f==nil then - f={} - depth=0xFFFF - elseif tonumber(f) then - depth=f - f={} - elseif not depth then - depth=0xFFFF - end - for k,v in next,t do - if type(k)~="number" then - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end - end + if f==nil then + f={} + depth=0xFFFF + elseif tonumber(f) then + depth=f + f={} + elseif not depth then + depth=0xFFFF + end + for k,v in next,t do + if type(k)~="number" then + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v + end end - for k=1,#t do - local v=t[k] - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end + end + for k=1,#t do + local v=t[k] + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v end - return f + end + return f end table.flattened=flattened local function collapsed(t,f,h) - if f==nil then - f={} - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsed(v,f,h) - elseif not h[v] then - f[#f+1]=v - h[v]=true - end + if f==nil then + f={} + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsed(v,f,h) + elseif not h[v] then + f[#f+1]=v + h[v]=true end - return f + end + return f end local function collapsedhash(t,h) - if h==nil then - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsedhash(v,h) - else - h[v]=true - end + if h==nil then + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsedhash(v,h) + else + h[v]=true end - return h + end + return h end -table.collapsed=collapsed +table.collapsed=collapsed table.collapsedhash=collapsedhash local function unnest(t,f) - if not f then - f={} - end - for i=1,#t do - local v=t[i] - if type(v)=="table" then - if type(v[1])=="table" then - unnest(v,f) - else - f[#f+1]=v - end - else - f[#f+1]=v - end + if not f then + f={} + end + for i=1,#t do + local v=t[i] + if type(v)=="table" then + if type(v[1])=="table" then + unnest(v,f) + else + f[#f+1]=v + end + else + f[#f+1]=v end - return f + end + return f end function table.unnest(t) - return unnest(t) + return unnest(t) end local function are_equal(a,b,n,m) - if a==b then - return true - elseif a and b and #a==#b then - n=n or 1 - m=m or #a - for i=n,m do - local ai,bi=a[i],b[i] - if ai==bi then - elseif type(ai)=="table" and type(bi)=="table" then - if not are_equal(ai,bi) then - return false - end - else - return false - end + if a==b then + return true + elseif a and b and #a==#b then + if not n then + n=1 + end + if not m then + m=#a + end + for i=n,m do + local ai,bi=a[i],b[i] + if ai==bi then + elseif type(ai)=="table" and type(bi)=="table" then + if not are_equal(ai,bi) then + return false end - return true - else + else return false + end end + return true + else + return false + end end local function identical(a,b) - if a~=b then - for ka,va in next,a do - local vb=b[ka] - if va==vb then - elseif type(va)=="table" and type(vb)=="table" then - if not identical(va,vb) then - return false - end - else - return false - end - end + if a~=b then + for ka,va in next,a do + local vb=b[ka] + if va==vb then + elseif type(va)=="table" and type(vb)=="table" then + if not identical(va,vb) then + return false + end + else + return false + end end - return true + end + return true end table.identical=identical table.are_equal=are_equal local function sparse(old,nest,keeptables) - local new={} - for k,v in next,old do - if not (v=="" or v==false) then - if nest and type(v)=="table" then - v=sparse(v,nest) - if keeptables or next(v)~=nil then - new[k]=v - end - else - new[k]=v - end - end + local new={} + for k,v in next,old do + if not (v=="" or v==false) then + if nest and type(v)=="table" then + v=sparse(v,nest) + if keeptables or next(v)~=nil then + new[k]=v + end + else + new[k]=v + end end - return new + end + return new end table.sparse=sparse function table.compact(t) - return sparse(t,true,true) + return sparse(t,true,true) end function table.contains(t,v) - if t then - for i=1,#t do - if t[i]==v then - return i - end - end + if t then + for i=1,#t do + if t[i]==v then + return i + end end - return false + end + return false end function table.count(t) - local n=0 - for k,v in next,t do - n=n+1 - end - return n + local n=0 + for k,v in next,t do + n=n+1 + end + return n end function table.swapped(t,s) - local n={} - if s then - for k,v in next,s do - n[k]=v - end + local n={} + if s then + for k,v in next,s do + n[k]=v end - for k,v in next,t do - n[v]=k - end - return n + end + for k,v in next,t do + n[v]=k + end + return n end function table.hashed(t) - for i=1,#t do - t[t[i]]=i - end - return t + for i=1,#t do + t[t[i]]=i + end + return t end function table.mirrored(t) - local n={} - for k,v in next,t do - n[v]=k - n[k]=v - end - return n + local n={} + for k,v in next,t do + n[v]=k + n[k]=v + end + return n end function table.reversed(t) - if t then - local tt,tn={},#t - if tn>0 then - local ttn=0 - for i=tn,1,-1 do - ttn=ttn+1 - tt[ttn]=t[i] - end - end - return tt + if t then + local tt={} + local tn=#t + if tn>0 then + local ttn=0 + for i=tn,1,-1 do + ttn=ttn+1 + tt[ttn]=t[i] + end end + return tt + end end function table.reverse(t) - if t then - local n=#t - for i=1,floor(n/2) do - local j=n-i+1 - t[i],t[j]=t[j],t[i] - end - return t + if t then + local n=#t + local m=n+1 + for i=1,floor(n/2) do + local j=m-i + t[i],t[j]=t[j],t[i] end + return t + end end -function table.sequenced(t,sep,simple) - if not t then - return "" +local function sequenced(t,sep,simple) + if not t then + return "" + elseif type(t)=="string" then + return t + end + local n=#t + local s={} + if n>0 then + for i=1,n do + local v=t[i] + if type(v)=="table" then + s[i]="{"..sequenced(v,sep,simple).."}" + else + s[i]=tostring(t[i]) + end end - local n=#t - local s={} - if n>0 then - for i=1,n do - s[i]=tostring(t[i]) + else + n=0 + for k,v in sortedhash(t) do + if simple then + if v==true then + n=n+1 + s[n]=k + elseif v and v~="" then + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) + end end - else - n=0 - for k,v in sortedhash(t) do - if simple then - if v==true then - n=n+1 - s[n]=k - elseif v and v~="" then - n=n+1 - s[n]=k.."="..tostring(v) - end - else - n=n+1 - s[n]=k.."="..tostring(v) - end + else + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) end + end end - return concat(s,sep or " | ") + end + return concat(s,sep or " | ") end +table.sequenced=sequenced function table.print(t,...) - if type(t)~="table" then - print(tostring(t)) - else - serialize(print,t,...) - end + if type(t)~="table" then + print(tostring(t)) + else + serialize(print,t,...) + end end if setinspector then - setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) + setinspector("table",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) } + return { unpack(t,i,j) } end function table.is_empty(t) - return not t or next(t)==nil + return not t or next(t)==nil end function table.has_one_entry(t) - return t and next(t,next(t))==nil + return t and next(t,next(t))==nil end function table.loweredkeys(t) - local l={} - for k,v in next,t do - l[lower(k)]=v - end - return l + local l={} + for k,v in next,t do + l[lower(k)]=v + end + return l end function table.unique(old) - local hash={} - local new={} - local n=0 - for i=1,#old do - local oi=old[i] - if not hash[oi] then - n=n+1 - new[n]=oi - hash[oi]=true - end - end - return new + local hash={} + local new={} + local n=0 + for i=1,#old do + local oi=old[i] + if not hash[oi] then + n=n+1 + new[n]=oi + hash[oi]=true + end + end + return new end function table.sorted(t,...) - sort(t,...) - return 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 {} + if t then + local values={} + local keys={} + local 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 function table.filtered(t,pattern,sort,cmp) - if t and type(pattern)=="string" then - if sort then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local n=0 - local m=#s - local function kv(s) - while n<m do - n=n+1 - local k=s[n] - if find(k,pattern) then - return k,t[k] - end - end - end - return kv,s - else - local n=next(t) - local function iterator() - while n~=nil do - local k=n - n=next(t,k) - if find(k,pattern) then - return k,t[k] - end - end - end - return iterator,t + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end end - else - return nothing + end + return kv,s + else + local n=next(t) + local function iterator() + while n~=nil do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t end + else + return nothing + end end if not table.move then - function table.move(a1,f,e,t,a2) - if a2 and a1~=a2 then - for i=f,e do - a2[t]=a1[i] - t=t+1 - end - return a2 - else - t=t+e-f - for i=e,f,-1 do - a1[t]=a1[i] - t=t-1 - end - return a1 - end + function table.move(a1,f,e,t,a2) + if a2 and a1~=a2 then + for i=f,e do + a2[t]=a1[i] + t=t+1 + end + return a2 + else + t=t+e-f + for i=e,f,-1 do + a1[t]=a1[i] + t=t-1 + end + return a1 end + end end @@ -3012,14 +3213,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-io"] = package.loaded["l-io"] or true --- original size: 11823, stripped down to: 6945 +-- original size: 11823, stripped down to: 6325 if not modules then modules={} end modules ['l-io']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local io=io local open,flush,write,read=io.open,io.flush,io.write,io.read @@ -3027,334 +3228,334 @@ local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local type=type if string.find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator="\\",";" + io.fileseparator,io.pathseparator="\\",";" else - io.fileseparator,io.pathseparator="/",":" + io.fileseparator,io.pathseparator="/",":" end local large=0x01000000 local medium=0x00100000 local small=0x00020000 local function readall(f) - local size=f:seek("end") - if size>0 then - f:seek("set",0) - return f:read(size) - else - return "" - end + local size=f:seek("end") + if size>0 then + f:seek("set",0) + return f:read(size) + else + return "" + end end io.readall=readall function io.loaddata(filename,textmode) - local f=open(filename,(textmode and 'r') or 'rb') - if f then - local size=f:seek("end") - local data=nil - if size>0 then - f:seek("set",0) - data=f:read(size) - end - f:close() - return data + local f=open(filename,(textmode and 'r') or 'rb') + if f then + local size=f:seek("end") + local data=nil + if size>0 then + f:seek("set",0) + data=f:read(size) end + f:close() + return data + end end function io.copydata(source,target,action) - local f=open(source,"rb") - if f then - local g=open(target,"wb") - if g then - local size=f:seek("end") - if size>0 then - f:seek("set",0) - local data=f:read(size) - if action then - data=action(data) - end - if data then - g:write(data) - end - end - g:close() + local f=open(source,"rb") + if f then + local g=open(target,"wb") + if g then + local size=f:seek("end") + if size>0 then + f:seek("set",0) + local data=f:read(size) + if action then + data=action(data) end - f:close() - flush() + if data then + g:write(data) + end + end + g:close() end + f:close() + flush() + end end function io.savedata(filename,data,joiner) - local f=open(filename,"wb") - if f then - if type(data)=="table" then - f:write(concat(data,joiner or "")) - elseif type(data)=="function" then - data(f) - else - f:write(data or "") - end - f:close() - flush() - return true + local f=open(filename,"wb") + if f then + if type(data)=="table" then + f:write(concat(data,joiner or "")) + elseif type(data)=="function" then + data(f) else - return false + f:write(data or "") end + f:close() + flush() + return true + else + return false + end end if fio and fio.readline then - local readline=fio.readline - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=readline(f) - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + local readline=fio.readline + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=readline(f) + if line then + lines[i]=line else - local line=readline(f) - f:close() - if line and #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=readline(f) + f:close() + if line and #line>0 then + return line + end end + end else - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=f:read("*lines") - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=f:read("*lines") + if line then + lines[i]=line else - local line=f:read("*line") or "" - f:close() - if #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=f:read("*line") or "" + f:close() + if #line>0 then + return line + end end + end end function io.loadchunk(filename,n) - local f=open(filename,'rb') - if f then - local data=f:read(n or 1024) - f:close() - if #data>0 then - return data - end + local f=open(filename,'rb') + if f then + local data=f:read(n or 1024) + f:close() + if #data>0 then + return data end + end end function io.exists(filename) - local f=open(filename) - if f==nil then - return false - else - f:close() - return true - end + local f=open(filename) + if f==nil then + return false + else + f:close() + return true + end end function io.size(filename) - local f=open(filename) - if f==nil then - return 0 - else - local s=f:seek("end") - f:close() - return s - end + local f=open(filename) + if f==nil then + return 0 + else + local s=f:seek("end") + f:close() + return s + end end local function noflines(f) - if type(f)=="string" then - local f=open(filename) - if f then - local n=f and noflines(f) or 0 - f:close() - return n - else - return 0 - end + if type(f)=="string" then + local f=open(filename) + if f then + local n=f and noflines(f) or 0 + f:close() + return n else - local n=0 - for _ in f:lines() do - n=n+1 - end - f:seek('set',0) - return n + return 0 + end + else + local n=0 + for _ in f:lines() do + n=n+1 end + f:seek('set',0) + return n + end end io.noflines=noflines local nextchar={ - [ 4]=function(f) - return f:read(1,1,1,1) - end, - [ 2]=function(f) - return f:read(1,1) - end, - [ 1]=function(f) - return f:read(1) - end, - [-2]=function(f) - local a,b=f:read(1,1) - return b,a - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - return d,c,b,a - end + [ 4]=function(f) + return f:read(1,1,1,1) + end, + [ 2]=function(f) + return f:read(1,1) + end, + [ 1]=function(f) + return f:read(1) + end, + [-2]=function(f) + local a,b=f:read(1,1) + return b,a + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + return d,c,b,a + end } function io.characters(f,n) - if f then - return nextchar[n or 1],f - end + if f then + return nextchar[n or 1],f + end end local nextbyte={ - [4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(a),byte(b),byte(c),byte(d) - end - end, - [3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(a),byte(b),byte(c) - end - end, - [2]=function(f) - local a,b=f:read(1,1) - if b then - return byte(a),byte(b) - end - end, - [1]=function (f) - local a=f:read(1) - if a then - return byte(a) - end - end, - [-2]=function (f) - local a,b=f:read(1,1) - if b then - return byte(b),byte(a) - end - end, - [-3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(c),byte(b),byte(a) - end - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(d),byte(c),byte(b),byte(a) - end + [4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(a),byte(b),byte(c),byte(d) + end + end, + [3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(a),byte(b),byte(c) + end + end, + [2]=function(f) + local a,b=f:read(1,1) + if b then + return byte(a),byte(b) + end + end, + [1]=function (f) + local a=f:read(1) + if a then + return byte(a) + end + end, + [-2]=function (f) + local a,b=f:read(1,1) + if b then + return byte(b),byte(a) + end + end, + [-3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(c),byte(b),byte(a) + end + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(d),byte(c),byte(b),byte(a) end + end } function io.bytes(f,n) - if f then - return nextbyte[n or 1],f - else - return nil,nil - end + if f then + return nextbyte[n or 1],f + else + return nil,nil + end end function io.ask(question,default,options) - while true do - write(question) - if options then - write(format(" [%s]",concat(options,"|"))) - end - if default then - write(format(" [%s]",default)) - end - write(format(" ")) - flush() - local answer=read() - answer=gsub(answer,"^%s*(.*)%s*$","%1") - if answer=="" and default then - return default - elseif not options then - return answer - else - for k=1,#options do - if options[k]==answer then - return answer - end - end - local pattern="^"..answer - for k=1,#options do - local v=options[k] - if find(v,pattern) then - return v - end - end + while true do + write(question) + if options then + write(format(" [%s]",concat(options,"|"))) + end + if default then + write(format(" [%s]",default)) + end + write(format(" ")) + flush() + local answer=read() + answer=gsub(answer,"^%s*(.*)%s*$","%1") + if answer=="" and default then + return default + elseif not options then + return answer + else + for k=1,#options do + if options[k]==answer then + return answer end + end + local pattern="^"..answer + for k=1,#options do + local v=options[k] + if find(v,pattern) then + return v + end + end end + end end local function readnumber(f,n,m) - if m then - f:seek("set",n) - n=m - end - if n==1 then - return byte(f:read(1)) - elseif n==2 then - local a,b=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==3 then - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==4 then - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==8 then - local a,b=readnumber(f,4),readnumber(f,4) - return 0x100*a+b - elseif n==12 then - local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) - return 0x10000*a+0x100*b+c - elseif n==-2 then - local b,a=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==-3 then - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==-4 then - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==-8 then - local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) - return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h - else - return 0 - end + if m then + f:seek("set",n) + n=m + end + if n==1 then + return byte(f:read(1)) + elseif n==2 then + local a,b=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==3 then + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==4 then + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==8 then + local a,b=readnumber(f,4),readnumber(f,4) + return 0x100*a+b + elseif n==12 then + local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) + return 0x10000*a+0x100*b+c + elseif n==-2 then + local b,a=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==-3 then + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==-4 then + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==-8 then + local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) + return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h + else + return 0 + end end io.readnumber=readnumber function io.readstring(f,n,m) - if m then - f:seek("set",n) - n=m - end - local str=gsub(f:read(n),"\000","") - return str + if m then + f:seek("set",n) + n=m + end + local str=gsub(f:read(n),"\000","") + return str end @@ -3364,14 +3565,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-number"] = package.loaded["l-number"] or true --- original size: 5645, stripped down to: 2253 +-- original size: 5720, stripped down to: 2176 if not modules then modules={} end modules ['l-number']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tostring,tonumber=tostring,tonumber local format,floor,match,rep=string.format,math.floor,string.match,string.rep @@ -3381,99 +3582,107 @@ local floor=math.floor number=number or {} local number=number if bit32 then - local bextract=bit32.extract - local t={ - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - } - function number.tobitstring(b,m) - local n=32 - for i=0,31 do - local v=bextract(b,i) - local k=32-i - if v==1 then - n=k - t[k]="1" - else - t[k]="0" - end - end - if m then - m=33-m*8 - if m<1 then - m=1 - end - return concat(t,"",m) - elseif n<8 then - return concat(t) - elseif n<16 then - return concat(t,"",9) - elseif n<24 then - return concat(t,"",17) - else - return concat(t,"",25) - end + local bextract=bit32.extract + local t={ + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + } + function number.tobitstring(b,m,w) + if not w then + w=32 + end + local n=w + for i=0,w-1 do + local v=bextract(b,i) + local k=w-i + if v==1 then + n=k + t[k]="1" + else + t[k]="0" + end + end + if w then + return concat(t,"",1,w) + elseif m then + m=33-m*8 + if m<1 then + m=1 + end + return concat(t,"",1,m) + elseif n<8 then + return concat(t) + elseif n<16 then + return concat(t,"",9) + elseif n<24 then + return concat(t,"",17) + else + return concat(t,"",25) end + end else - function number.tobitstring(n,m) - if n>0 then - local t={} - while n>0 do - insert(t,1,n%2>0 and 1 or 0) - n=floor(n/2) - end - local nn=8-#t%8 - if nn>0 and nn<8 then - for i=1,nn do - insert(t,1,0) - end - end - if m then - m=m*8-#t - if m>0 then - insert(t,1,rep("0",m)) - end - end - return concat(t) - elseif m then - rep("00000000",m) - else - return "00000000" + function number.tobitstring(n,m) + if n>0 then + local t={} + while n>0 do + insert(t,1,n%2>0 and 1 or 0) + n=floor(n/2) + end + local nn=8-#t%8 + if nn>0 and nn<8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m=m*8-#t + if m>0 then + insert(t,1,rep("0",m)) end + end + return concat(t) + elseif m then + rep("00000000",m) + else + return "00000000" end + end end function number.valid(str,default) - return tonumber(str) or default or nil + return tonumber(str) or default or nil end function number.toevenhex(n) - local s=format("%X",n) - if #s%2==0 then - return s - else - return "0"..s - end + local s=format("%X",n) + if #s%2==0 then + return s + else + return "0"..s + end end function number.bytetodecimal(b) - local d=floor(b*100/255+0.5) - if d>100 then - return 100 - elseif d<-100 then - return -100 - else - return d - end + local d=floor(b*100/255+0.5) + if d>100 then + return 100 + elseif d<-100 then + return -100 + else + return d + end end function number.decimaltobyte(d) - local b=floor(d*255/100+0.5) - if b>255 then - return 255 - elseif b<-255 then - return -255 - else - return b - end + local b=floor(d*255/100+0.5) + if b>255 then + return 255 + elseif b<-255 then + return -255 + else + return b + end +end +function number.idiv(i,d) + return floor(i/d) end @@ -3483,14 +3692,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-set"] = package.loaded["l-set"] or true --- original size: 1923, stripped down to: 1133 +-- original size: 1923, stripped down to: 1044 if not modules then modules={} end modules ['l-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } set=set or {} local nums={} @@ -3499,54 +3708,54 @@ local concat=table.concat local next,type=next,type set.create=table.tohash function set.tonumber(t) - if next(t) then - local s="" - for k,v in next,t do - if v then - s=s.." "..k - end - end - local n=nums[s] - if not n then - n=#tabs+1 - tabs[n]=t - nums[s]=n - end - return n - else - return 0 + if next(t) then + local s="" + for k,v in next,t do + if v then + s=s.." "..k + end end + local n=nums[s] + if not n then + n=#tabs+1 + tabs[n]=t + nums[s]=n + end + return n + else + return 0 + end end function set.totable(n) - if n==0 then - return {} - else - return tabs[n] or {} - end + if n==0 then + return {} + else + return tabs[n] or {} + end end function set.tolist(n) - if n==0 or not tabs[n] then - return "" - else - local t,n={},0 - for k,v in next,tabs[n] do - if v then - n=n+1 - t[n]=k - end - end - return concat(t," ") + if n==0 or not tabs[n] then + return "" + else + local t,n={},0 + for k,v in next,tabs[n] do + if v then + n=n+1 + t[n]=k + end end + return concat(t," ") + end end function set.contains(n,s) - if type(n)=="table" then - return n[s] - elseif n==0 then - return false - else - local t=tabs[n] - return t and t[s] - end + if type(n)=="table" then + return n[s] + elseif n==0 then + return false + else + local t=tabs[n] + return t and t[s] + end end @@ -3556,14 +3765,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-os"] = package.loaded["l-os"] or true --- original size: 16268, stripped down to: 9246 +-- original size: 19347, stripped down to: 10258 if not modules then modules={} end modules ['l-os']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local os=os local date,time=os.date,os.time @@ -3571,357 +3780,434 @@ local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string local concat=table.concat local random,ceil,randomseed=math.random,math.ceil,math.randomseed local rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring=rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring -math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) -randomseed(math.initialseed) -if not os.__getenv__ then - os.__getenv__=os.getenv - os.__setenv__=os.setenv - if os.env then - local osgetenv=os.getenv - local ossetenv=os.setenv - local osenv=os.env local _=osenv.PATH - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - if type(v)=="table" then - v=concat(v,";") - end - ossetenv(K,v) - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v - end +do + local selfdir=os.selfdir + if selfdir=="" then + selfdir=nil + end + if not selfdir then + if arg then + for i=1,#arg do + local a=arg[i] + if find(a,"^%-%-[c:]*texmfbinpath=") then + selfdir=gsub(a,"^.-=","") + break end - else - local ossetenv=os.setenv - local osgetenv=os.getenv - local osenv={} - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v + end + end + if not selfdir then + selfdir=os.selfbin or "luatex" + if find(selfdir,"[/\\]") then + selfdir=gsub(selfdir,"[/\\][^/\\]*$","") + elseif os.getenv then + local path=os.getenv("PATH") + local name=gsub(selfdir,"^.*[/\\][^/\\]","") + local patt="[^:]+" + if os.type=="windows" then + patt="[^;]+" + name=name..".exe" + end + local isfile + if lfs then + local attributes=lfs.attributes + isfile=function(name) + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil + end + else + local open=io.open + isfile=function(name) + local f=open(name) + if f then + f:close() + return true end + end end - local function __index(t,k) - return os.getenv(k) - end - local function __newindex(t,k,v) - os.setenv(k,v) + for p in gmatch(path,patt) do + if isfile(p.."/"..name) then + selfdir=p + break + end end - os.env={} - setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end + os.selfdir=selfdir or "." + end +end +math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) +randomseed(math.initialseed) +if not os.__getenv__ then + os.__getenv__=os.getenv + os.__setenv__=os.setenv + if os.env then + local osgetenv=os.getenv + local ossetenv=os.setenv + local osenv=os.env local _=osenv.PATH + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + if type(v)=="table" then + v=concat(v,";") + end + ossetenv(K,v) + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + else + local ossetenv=os.setenv + local osgetenv=os.getenv + local osenv={} + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + local function __index(t,k) + return os.getenv(k) + end + local function __newindex(t,k,v) + os.setenv(k,v) + end + os.env={} + setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end local execute=os.execute local iopopen=io.popen local function resultof(command) - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - else - return "" - end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + else + return "" + end end os.resultof=resultof function os.pipeto(command) - return iopopen(command,"w") + return iopopen(command,"w") end if not io.fileseparator then - if find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" - else - io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" - end + if find(os.getenv("PATH"),";",1,true) then + io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" + else + io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" + end end os.type=os.type or (io.pathseparator==";" and "windows") or "unix" -os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" +os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" if os.type=="windows" then - os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } + os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } else - os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } + os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } end local launchers={ - windows="start %s", - macosx="open %s", - unix="$BROWSER %s &> /dev/null &", + windows="start %s", + macosx="open %s", + unix="xdg-open %s &> /dev/null &", } function os.launch(str) - execute(format(launchers[os.name] or launchers.unix,str)) + execute(format(launchers[os.name] or launchers.unix,str)) end if not os.times then - function os.times() - return { - utime=os.gettimeofday(), - stime=0, - cutime=0, - cstime=0, - } - end + function os.times() + return { + utime=os.gettimeofday(), + stime=0, + cutime=0, + cstime=0, + } + end end local gettimeofday=os.gettimeofday or os.clock os.gettimeofday=gettimeofday local startuptime=gettimeofday() function os.runtime() - return gettimeofday()-startuptime + return gettimeofday()-startuptime end 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 + local r=resolvers[k] + return r and r(t,k) or nil end }) local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or "" if platform~="" then - os.platform=platform + os.platform=platform elseif os.type=="windows" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or "" - if find(architecture,"AMD64",1,true) then - platform="win64" - else - platform="mswin" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("PROCESSOR_ARCHITECTURE") or "" + local platform="" + if find(architecture,"AMD64",1,true) then + platform="win64" + else + platform="mswin" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="linux" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="linux-64" - elseif find(architecture,"ppc",1,true) then - platform="linux-ppc" - else - platform="linux" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform=os.getenv("MTX_PLATFORM") or "" + local musl=find(os.selfdir or "","linuxmusl") + if platform~="" then + elseif find(architecture,"x86_64",1,true) then + platform=musl and "linuxmusl" or "linux-64" + elseif find(architecture,"ppc",1,true) then + platform="linux-ppc" + else + platform=musl and "linuxmusl" or "linux" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="macosx" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("echo $HOSTTYPE") or "" - if architecture=="" then - platform="osx-intel" - elseif find(architecture,"i386",1,true) then - platform="osx-intel" - elseif find(architecture,"x86_64",1,true) then - platform="osx-64" - else - platform="osx-ppc" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=resultof("echo $HOSTTYPE") or "" + local platform="" + if architecture=="" then + platform="osx-intel" + elseif find(architecture,"i386",1,true) then + platform="osx-intel" + elseif find(architecture,"x86_64",1,true) then + platform="osx-64" + else + platform="osx-ppc" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="sunos" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"sparc",1,true) then - platform="solaris-sparc" - else - platform="solaris-intel" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"sparc",1,true) then + platform="solaris-sparc" + else + platform="solaris-intel" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="freebsd" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"amd64",1,true) then - platform="freebsd-amd64" - else - platform="freebsd" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"amd64",1,true) then + platform="freebsd-amd64" + else + platform="freebsd" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="kfreebsd" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="kfreebsd-amd64" - else - platform="kfreebsd-i386" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform="" + if find(architecture,"x86_64",1,true) then + platform="kfreebsd-amd64" + else + platform="kfreebsd-i386" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end else - function resolvers.platform(t,k) - local platform="linux" - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local platform="linux" + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end end os.newline=name=="windows" and "\013\010" or "\010" function resolvers.bits(t,k) - local bits=find(os.platform,"64",1,true) and 64 or 32 - os.bits=bits - return bits + 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", - random(0xFFFF),random(0xFFFF), - random(0x0FFF), - t[ceil(random(4))] or 8,random(0x0FFF), - random(0xFFFF), - random(0xFFFF),random(0xFFFF),random(0xFFFF) - ) + return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", + random(0xFFFF),random(0xFFFF), + random(0x0FFF), + t[ceil(random(4))] or 8,random(0x0FFF), + random(0xFFFF), + random(0xFFFF),random(0xFFFF),random(0xFFFF) + ) end local d function os.timezone(delta) - d=d or tonumber(tonumber(date("%H")-date("!%H"))) - if delta then - if d>0 then - return format("+%02i:00",d) - else - return format("-%02i:00",-d) - end + d=d or tonumber(tonumber(date("%H")-date("!%H"))) + if delta then + if d>0 then + return format("+%02i:00",d) else - return 1 + return format("-%02i:00",-d) end + else + return 1 + end 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=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=format(timeformat,date(dateformat)) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=format(timeformat,date(dateformat)) + end + return lastdate end local dateformat="%Y-%m-%d %H:%M:%S" local lasttime=nil local lastdate=nil function os.localtime(t,default) - t=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=date(dateformat,t) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=date(dateformat,t) + end + return lastdate end function os.converttime(t,default) - local t=tonumber(t) - if t and t>0 then - return date(dateformat,t) - else - return default or "-" - end + local t=tonumber(t) + if t and t>0 then + return date(dateformat,t) + else + return default or "-" + end end local memory={} local function which(filename) - local fullname=memory[filename] - if fullname==nil then - local suffix=file.suffix(filename) - local suffixes=suffix=="" and os.binsuffixes or { suffix } - for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do - local df=file.join(directory,filename) - for i=1,#suffixes do - local dfs=file.addsuffix(df,suffixes[i]) - if io.exists(dfs) then - fullname=dfs - break - end - end - end - if not fullname then - fullname=false + local fullname=memory[filename] + if fullname==nil then + local suffix=file.suffix(filename) + local suffixes=suffix=="" and os.binsuffixes or { suffix } + for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local df=file.join(directory,filename) + for i=1,#suffixes do + local dfs=file.addsuffix(df,suffixes[i]) + if io.exists(dfs) then + fullname=dfs + break end - memory[filename]=fullname + end end - return fullname + if not fullname then + fullname=false + end + memory[filename]=fullname + end + return fullname end os.which=which os.where=which function os.today() - return date("!*t") + return date("!*t") end function os.now() - return date("!%Y-%m-%d %H:%M:%S") + return date("!%Y-%m-%d %H:%M:%S") end if not os.sleep then - local socket=socket - function os.sleep(n) - if not socket then - socket=require("socket") - end - socket.sleep(n) + local socket=socket + function os.sleep(n) + if not socket then + socket=require("socket") end + socket.sleep(n) + end end local function isleapyear(year) - return (year%4==0) and (year%100~=0 or year%400==0) + return (year%4==0) and (year%100~=0 or year%400==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 + 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 + 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 + 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 +local osexit=os.exit +local exitcode=nil +function os.setexitcode(code) + exitcode=code +end +function os.exit(c) + if exitcode~=nil then + return osexit(exitcode) + end + if c~=nil then + return osexit(c) + end + return osexit() end @@ -3931,19 +4217,19 @@ do -- create closure to overcome 200 locals limit package.loaded["l-file"] = package.loaded["l-file"] or true --- original size: 21616, stripped down to: 10359 +-- original size: 21804, stripped down to: 9980 if not modules then modules={} end modules ['l-file']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } file=file or {} local file=file if not lfs then - lfs=optionalrequire("lfs") + lfs=optionalrequire("lfs") end local insert,concat=table.insert,table.concat local match,find,gmatch=string.match,string.find,string.gmatch @@ -3951,24 +4237,22 @@ local lpegmatch=lpeg.match local getcurrentdir,attributes=lfs.currentdir,lfs.attributes local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct -local tricky=S("/\\")*P(-1) local attributes=lfs.attributes -if sandbox then - sandbox.redefine(lfs.isfile,"lfs.isfile") - sandbox.redefine(lfs.isdir,"lfs.isdir") -end function lfs.isdir(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end + return attributes(name,"mode")=="directory" end function lfs.isfile(name) - return attributes(name,"mode")=="file" + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil end function lfs.isfound(name) - return attributes(name,"mode")=="file" and name or nil + local a=attributes(name,"mode") + return (a=="file" or a=="link") and name or nil +end +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir,"lfs.isdir") + sandbox.redefine(lfs.isfound,"lfs.isfound") end local colon=P(":") local period=P(".") @@ -3982,27 +4266,27 @@ local name=noperiod^1 local suffix=period/""*(1-period-slashes)^1*-1 local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) local function pathpart(name,default) - return name and lpegmatch(pattern,name) or default or "" + return name and lpegmatch(pattern,name) or default or "" end local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1 local function basename(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0 local function nameonly(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1 local function suffixonly(name) - return name and lpegmatch(pattern,name) or "" + return name and lpegmatch(pattern,name) or "" end local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("") local function suffixesonly(name) - if name then - return lpegmatch(pattern,name) - else - return "" - end + if name then + return lpegmatch(pattern,name) + else + return "" + end end file.pathpart=pathpart file.basename=basename @@ -4011,7 +4295,7 @@ file.suffixonly=suffixonly file.suffix=suffixonly file.suffixesonly=suffixesonly file.suffixes=suffixesonly -file.dirname=pathpart +file.dirname=pathpart file.extname=suffixonly local drive=C(R("az","AZ"))*colon local path=C((noslashes^0*slashes)^0) @@ -4027,142 +4311,142 @@ local pattern_b=path*base*suffix local pattern_c=C(drive*path)*C(base*suffix) local pattern_d=path*rest function file.splitname(str,splitdrive) - if not str then - elseif splitdrive then - return lpegmatch(pattern_a,str) - else - return lpegmatch(pattern_b,str) - end + if not str then + elseif splitdrive then + return lpegmatch(pattern_a,str) + else + return lpegmatch(pattern_b,str) + end end function file.splitbase(str) - if str then - return lpegmatch(pattern_d,str) - else - return "",str - end + if str then + return lpegmatch(pattern_d,str) + else + return "",str + end end function file.nametotable(str,splitdrive) - if str then - local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) - if splitdrive then - return { - path=path, - drive=drive, - subpath=subpath, - name=name, - base=base, - suffix=suffix, - } - else - return { - path=path, - name=name, - base=base, - suffix=suffix, - } - end + if str then + local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) + if splitdrive then + return { + path=path, + drive=drive, + subpath=subpath, + name=name, + base=base, + suffix=suffix, + } + else + return { + path=path, + name=name, + base=base, + suffix=suffix, + } end + end end local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1) function file.removesuffix(name) - return name and lpegmatch(pattern,name) + return name and lpegmatch(pattern,name) end local suffix=period/""*(1-period-slashes)^1*-1 local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix) function file.addsuffix(filename,suffix,criterium) - if not filename or not suffix or suffix=="" then - return filename - elseif criterium==true then - return filename.."."..suffix - elseif not criterium then - local n,s=lpegmatch(pattern,filename) - if not s or s=="" then - return filename.."."..suffix - else + if not filename or not suffix or suffix=="" then + return filename + elseif criterium==true then + return filename.."."..suffix + elseif not criterium then + local n,s=lpegmatch(pattern,filename) + if not s or s=="" then + return filename.."."..suffix + else + return filename + end + else + local n,s=lpegmatch(pattern,filename) + if s and s~="" then + local t=type(criterium) + if t=="table" then + for i=1,#criterium do + if s==criterium[i] then return filename + end end - else - local n,s=lpegmatch(pattern,filename) - if s and s~="" then - local t=type(criterium) - if t=="table" then - for i=1,#criterium do - if s==criterium[i] then - return filename - end - end - elseif t=="string" then - if s==criterium then - return filename - end - end + elseif t=="string" then + if s==criterium then + return filename end - return (n or filename).."."..suffix + end end + return (n or filename).."."..suffix + end end local suffix=period*(1-period-slashes)^1*-1 local pattern=Cs((1-suffix)^0) function file.replacesuffix(name,suffix) - if name and suffix and suffix~="" then - return lpegmatch(pattern,name).."."..suffix - else - return name - end + if name and suffix and suffix~="" then + return lpegmatch(pattern,name).."."..suffix + else + return name + end end local reslasher=lpeg.replacer(P("\\"),"/") function file.reslash(str) - return str and lpegmatch(reslasher,str) + return str and lpegmatch(reslasher,str) end function file.is_writable(name) - if not name then - elseif lfs.isdir(name) then - name=name.."/m_t_x_t_e_s_t.tmp" - local f=io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f=io.open(name,"ab") - if f then - f:close() - return true - end - else - local f=io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true - end + if not name then + elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true end - return false + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end + end + return false end local readable=P("r")*Cc(true) function file.is_readable(name) - if name then - local a=attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else - return false - end + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end file.isreadable=file.is_readable file.iswritable=file.is_writable function file.size(name) - if name then - local a=attributes(name) - return a and a.size or 0 - else - return 0 - end + if name then + local a=attributes(name) + return a and a.size or 0 + else + return 0 + end end function file.splitpath(str,separator) - return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) + return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) end function file.joinpath(tab,separator) - return tab and concat(tab,separator or io.pathseparator) + return tab and concat(tab,separator or io.pathseparator) end local someslash=S("\\/") local stripper=Cs(P(fwslash)^0/""*reslasher) @@ -4172,30 +4456,30 @@ local hasroot=fwslash^1 local reslasher=lpeg.replacer(S("\\/"),"/") local deslasher=lpeg.replacer(S("\\/")^1,"/") function file.join(one,two,three,...) - if not two then - return one=="" and one or lpegmatch(reslasher,one) - end - if one=="" then - return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) - end - if lpegmatch(isnetwork,one) then - local one=lpegmatch(reslasher,one) - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return one..two - else - return one.."/"..two - end - elseif lpegmatch(isroot,one) then - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return two - else - return "/"..two - end - else - return lpegmatch(deslasher,concat({ one,two,three,... },"/")) - end + if not two then + return one=="" and one or lpegmatch(reslasher,one) + end + if one=="" then + return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) + end + if lpegmatch(isnetwork,one) then + local one=lpegmatch(reslasher,one) + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return one..two + else + return one.."/"..two + end + elseif lpegmatch(isroot,one) then + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return two + else + return "/"..two + end + else + return lpegmatch(deslasher,concat({ one,two,three,... },"/")) + end end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec @@ -4205,56 +4489,56 @@ 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 - return - end - if anchor==true and not lpegmatch(anchors,str) then - str=getcurrentdir().."/"..str - end - if str=="" or str=="." then - return "." - elseif lpegmatch(untouched,str) then - return lpegmatch(reslasher,str) - end - local starter,oldelements=lpegmatch(splitstarter,str) - local newelements={} - local i=#oldelements - while i>0 do - local element=oldelements[i] - if element=='.' then - elseif element=='..' then - local n=i-1 - while n>0 do - local element=oldelements[n] - if element~='..' and element~='.' then - oldelements[n]='.' - break - else - n=n-1 - end - end - if n<1 then - insert(newelements,1,'..') - end - elseif element~="" then - insert(newelements,1,element) - end - i=i-1 - end - if #newelements==0 then - return starter or "." - elseif starter then - return starter..concat(newelements,'/') - elseif lpegmatch(absolute,str) then - return "/"..concat(newelements,'/') - else - newelements=concat(newelements,'/') - if anchor=="." and find(str,"^%./") then - return "./"..newelements + if not str then + return + end + if anchor==true and not lpegmatch(anchors,str) then + str=getcurrentdir().."/"..str + end + if str=="" or str=="." then + return "." + elseif lpegmatch(untouched,str) then + return lpegmatch(reslasher,str) + end + local starter,oldelements=lpegmatch(splitstarter,str) + local newelements={} + local i=#oldelements + while i>0 do + local element=oldelements[i] + if element=='.' then + elseif element=='..' then + local n=i-1 + while n>0 do + local element=oldelements[n] + if element~='..' and element~='.' then + oldelements[n]='.' + break else - return newelements + n=n-1 end - end + end + if n<1 then + insert(newelements,1,'..') + end + elseif element~="" then + insert(newelements,1,element) + end + i=i-1 + end + if #newelements==0 then + return starter or "." + elseif starter then + return starter..concat(newelements,'/') + elseif lpegmatch(absolute,str) then + return "/"..concat(newelements,'/') + else + newelements=concat(newelements,'/') + if anchor=="." and find(str,"^%./") then + return "./"..newelements + else + return newelements + end + end end local validchars=R("az","09","AZ","--","..") local pattern_a=lpeg.replacer(1-validchars) @@ -4262,26 +4546,26 @@ local pattern_a=Cs((validchars+P(1)/"-")^1) local whatever=P("-")^0/"" local pattern_b=Cs(whatever*(1-whatever*-1)^1) function file.robustname(str,strict) - if str then - str=lpegmatch(pattern_a,str) or str - if strict then - return lpegmatch(pattern_b,str) or str - else - return str - end + if str then + str=lpegmatch(pattern_a,str) or str + if strict then + return lpegmatch(pattern_b,str) or str + else + return str end + end end local loaddata=io.loaddata local savedata=io.savedata file.readdata=loaddata file.savedata=savedata function file.copy(oldname,newname) - if oldname and newname then - local data=loaddata(oldname) - if data and data~="" then - savedata(newname,data) - end + if oldname and newname then + local data=loaddata(oldname) + if data and data~="" then + savedata(newname,data) end + end end local letter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4290,40 +4574,44 @@ local rootbased=fwslash+letter*colon lpeg.patterns.qualified=qualified lpeg.patterns.rootbased=rootbased function file.is_qualified_path(filename) - return filename and lpegmatch(qualified,filename)~=nil + return filename and lpegmatch(qualified,filename)~=nil end function file.is_rootbased_path(filename) - return filename and lpegmatch(rootbased,filename)~=nil + return filename and lpegmatch(rootbased,filename)~=nil end function file.strip(name,dir) - if name then - local b,a=match(name,"^(.-)"..dir.."(.*)$") - return a~="" and a or name - end + if name then + local b,a=match(name,"^(.-)"..dir.."(.*)$") + return a~="" and a or name + end end function lfs.mkdirs(path) - local full="" - for sub in gmatch(path,"(/*[^\\/]+)") do - full=full..sub - lfs.mkdir(full) - end + local full="" + for sub in gmatch(path,"(/*[^\\/]+)") do + full=full..sub + lfs.mkdir(full) + end end function file.withinbase(path) - local l=0 - if not find(path,"^/") then - path="/"..path + local l=0 + if not find(path,"^/") then + path="/"..path + end + for dir in gmatch(path,"/([^/]+)") do + if dir==".." then + l=l-1 + elseif dir~="." then + l=l+1 end - for dir in gmatch(path,"/([^/]+)") do - if dir==".." then - l=l-1 - elseif dir~="." then - l=l+1 - end - if l<0 then - return false - end + if l<0 then + return false end - return true + end + return true +end +local symlinkattributes=lfs.symlinkattributes +function lfs.readlink(name) + return symlinkattributes(name,"target") or nil end @@ -4333,51 +4621,51 @@ do -- create closure to overcome 200 locals limit package.loaded["l-gzip"] = package.loaded["l-gzip"] or true --- original size: 1211, stripped down to: 1002 +-- original size: 1211, stripped down to: 951 if not modules then modules={} end modules ['l-gzip']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not gzip then - return + return end local suffix,suffixes=file.suffix,file.suffixes function gzip.load(filename) - local f=io.open(filename,"rb") - if not f then - elseif suffix(filename)=="gz" then - f:close() - local g=gzip.open(filename,"rb") - if g then - local str=g:read("*all") - g:close() - return str - end - else - local str=f:read("*all") - f:close() - return str - end + local f=io.open(filename,"rb") + if not f then + elseif suffix(filename)=="gz" then + f:close() + local g=gzip.open(filename,"rb") + if g then + local str=g:read("*all") + g:close() + return str + end + else + local str=f:read("*all") + f:close() + return str + end end function gzip.save(filename,data) - if suffix(filename)~="gz" then - filename=filename..".gz" - end - local f=io.open(filename,"wb") - if f then - local s=zlib.compress(data or "",9,nil,15+16) - f:write(s) - f:close() - return #s - end + if suffix(filename)~="gz" then + filename=filename..".gz" + end + local f=io.open(filename,"wb") + if f then + local s=zlib.compress(data or "",9,nil,15+16) + f:write(s) + f:close() + return #s + end end function gzip.suffix(filename) - local suffix,extra=suffixes(filename) - local gzipped=extra=="gz" - return suffix,gzipped + local suffix,extra=suffixes(filename) + local gzipped=extra=="gz" + return suffix,gzipped end @@ -4387,87 +4675,119 @@ do -- create closure to overcome 200 locals limit package.loaded["l-md5"] = package.loaded["l-md5"] or true --- original size: 3309, stripped down to: 2314 +-- original size: 3309, stripped down to: 2218 if not modules then modules={} end modules ['l-md5']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not md5 then - md5=optionalrequire("md5") + md5=optionalrequire("md5") end if not md5 then - md5={ - sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, - sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, - } + md5={ + sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, + sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, + } end local md5,file=md5,file local gsub=string.gsub do - local patterns=lpeg and lpeg.patterns - if patterns then - local bytestoHEX=patterns.bytestoHEX - local bytestohex=patterns.bytestohex - local bytestodec=patterns.bytestodec - local lpegmatch=lpeg.match - local md5sum=md5.sum - if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end - if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end - if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end - md5.sumhexa=md5.hex - md5.sumHEXA=md5.HEX - end + local patterns=lpeg and lpeg.patterns + if patterns then + local bytestoHEX=patterns.bytestoHEX + local bytestohex=patterns.bytestohex + local bytestodec=patterns.bytestodec + local lpegmatch=lpeg.match + local md5sum=md5.sum + if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end + if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end + if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end + md5.sumhexa=md5.hex + md5.sumHEXA=md5.HEX + end end function file.needsupdating(oldname,newname,threshold) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime then - local newtime=lfs.attributes(newname,"modification") - if not newtime then - return true - elseif newtime>=oldtime then - return false - elseif oldtime-newtime<(threshold or 1) then - return false - else - return true - end - else - return false - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime then + local newtime=lfs.attributes(newname,"modification") + if not newtime then + return true + elseif newtime>=oldtime then + return false + elseif oldtime-newtime<(threshold or 1) then + return false + else + return true + end + else + return false + end end file.needs_updating=file.needsupdating function file.syncmtimes(oldname,newname) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime and lfs.isfile(newname) then - lfs.touch(newname,oldtime,oldtime) - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) + end end function file.checksum(name) - if md5 then - local data=io.loaddata(name) - if data then - return md5.HEX(data) - end + if md5 then + local data=io.loaddata(name) + if data then + return md5.HEX(data) end - return nil + end + return nil end function file.loadchecksum(name) - if md5 then - local data=io.loaddata(name..".md5") - return data and (gsub(data,"%s","")) - end - return nil + if md5 then + local data=io.loaddata(name..".md5") + return data and (gsub(data,"%s","")) + end + return nil end function file.savechecksum(name,checksum) - if not checksum then checksum=file.checksum(name) end - if checksum then - io.savedata(name..".md5",checksum) - return checksum - end - return nil + if not checksum then checksum=file.checksum(name) end + if checksum then + io.savedata(name..".md5",checksum) + return checksum + end + return nil +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["l-sha"] = package.loaded["l-sha"] or true + +-- original size: 1085, stripped down to: 969 + +if not modules then modules={} end modules ['l-sha']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +if sha2 then + local lpegmatch=lpeg.match + local lpegpatterns=lpeg.patterns + local bytestohex=lpegpatterns.bytestohex + local bytestoHEX=lpegpatterns.bytestoHEX + local digest256=sha2.digest256 + local digest384=sha2.digest384 + local digest512=sha2.digest512 + sha2.hash256=function(str) return lpegmatch(bytestohex,digest256(str)) end + sha2.hash384=function(str) return lpegmatch(bytestohex,digest384(str)) end + sha2.hash512=function(str) return lpegmatch(bytestohex,digest512(str)) end + sha2.HASH256=function(str) return lpegmatch(bytestoHEX,digest256(str)) end + sha2.HASH384=function(str) return lpegmatch(bytestoHEX,digest384(str)) end + sha2.HASH512=function(str) return lpegmatch(bytestoHEX,digest512(str)) end end @@ -4477,14 +4797,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-url"] = package.loaded["l-url"] or true --- original size: 14755, stripped down to: 7236 +-- original size: 14755, stripped down to: 6981 if not modules then modules={} end modules ['l-url']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local char,format,byte=string.char,string.format,string.byte local concat=table.concat @@ -4497,14 +4817,14 @@ local url=url local unescapes={} local escapes={} setmetatable(unescapes,{ __index=function(t,k) - local v=char(tonumber(k,16)) - t[k]=v - return v + local v=char(tonumber(k,16)) + t[k]=v + return v end }) setmetatable(escapes,{ __index=function(t,k) - local v=format("%%%02X",byte(k)) - t[k]=v - return v + local v=format("%%%02X",byte(k)) + t[k]=v + return v end }) local colon=P(":") local qmark=P("?") @@ -4523,21 +4843,21 @@ local escaped=(plus/" ")+escapedchar local noslash=P("/")/"" local plustospace=P("+")/" " local decoder=Cs(( - plustospace+escapedchar+P("\r\n")/"\n"+P(1) - )^0 ) + plustospace+escapedchar+P("\r\n")/"\n"+P(1) + )^0 ) local encoder=Cs(( - R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar - )^0 ) + R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar + )^0 ) lpegpatterns.urldecoder=decoder lpegpatterns.urlencoder=encoder -function url.decode (str) return str and lpegmatch(decoder,str) or str end -function url.encode (str) return str and lpegmatch(encoder,str) or str end +function url.decode (str) return str and lpegmatch(decoder,str) or str end +function url.encode (str) return str and lpegmatch(encoder,str) or str end function url.unescape(str) return str and lpegmatch(unescaper,str) or str end local schemestr=Cs((escaped+(1-colon-slash-qmark-hash))^2) local authoritystr=Cs((escaped+(1- slash-qmark-hash))^0) -local pathstr=Cs((escaped+(1- qmark-hash))^0) -local querystr=Cs(((1- hash))^0) -local fragmentstr=Cs((escaped+(1- endofstring))^0) +local pathstr=Cs((escaped+(1- qmark-hash))^0) +local querystr=Cs(((1- hash))^0) +local fragmentstr=Cs((escaped+(1- endofstring))^0) local scheme=schemestr*colon+nothing local authority=slash*slash*authoritystr+nothing local path=slash*pathstr+nothing @@ -4555,19 +4875,19 @@ lpegpatterns.urlescaper=escaper lpegpatterns.urlunescaper=unescaper lpegpatterns.urlgetcleaner=getcleaner function url.unescapeget(str) - return lpegmatch(getcleaner,str) + return lpegmatch(getcleaner,str) end local function split(str) - return (type(str)=="string" and lpegmatch(parser,str)) or str + return (type(str)=="string" and lpegmatch(parser,str)) or str end local isscheme=schemestr*colon*slash*slash local function hasscheme(str) - if str then - local scheme=lpegmatch(isscheme,str) - return scheme~="" and scheme or false - else - return false - end + if str then + local scheme=lpegmatch(isscheme,str) + return scheme~="" and scheme or false + else + return false + end end local rootletter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4577,161 +4897,161 @@ local barswapper=replacer("|",":") local backslashswapper=replacer("\\","/") local equal=P("=") local amp=P("&") -local key=Cs(((plustospace+escapedchar+1)-equal )^0) +local key=Cs(((plustospace+escapedchar+1)-equal )^0) local value=Cs(((plustospace+escapedchar+1)-amp-endofstring)^0) local splitquery=Cf (Ct("")*P { "sequence", - sequence=V("pair")*(amp*V("pair"))^0, - pair=Cg(key*equal*value), + sequence=V("pair")*(amp*V("pair"))^0, + pair=Cg(key*equal*value), },rawset) local userpart=(1-atsign-colon)^1 local serverpart=(1-colon)^1 local splitauthority=((Cs(userpart)*colon*Cs(userpart)+Cs(userpart)*Cc(nil))*atsign+Cc(nil)*Cc(nil))*Cs(serverpart)*(colon*(serverpart/tonumber)+Cc(nil)) local function hashed(str) - if not str or str=="" then - return { - scheme="invalid", - original=str, - } - end - local detailed=split(str) - local rawscheme="" - local rawquery="" - local somescheme=false - local somequery=false - if detailed then - rawscheme=detailed[1] - rawquery=detailed[4] - somescheme=rawscheme~="" - somequery=rawquery~="" - end - if not somescheme and not somequery then - return { - scheme="file", - authority="", - path=str, - query="", - fragment="", - original=str, - noscheme=true, - filename=str, - } - end - local authority=detailed[2] - local path=detailed[3] - local filename - local username - local password - local host - local port - if authority~="" then - username,password,host,port=lpegmatch(splitauthority,authority) - end - if authority=="" then - filename=path - elseif path=="" then - filename="" - else - filename=authority.."/"..path - end + if not str or str=="" then return { - scheme=rawscheme, - authority=authority, - path=path, - query=lpegmatch(unescaper,rawquery), - queries=lpegmatch(splitquery,rawquery), - fragment=detailed[5], - original=str, - noscheme=false, - filename=filename, - host=host, - port=port, + scheme="invalid", + original=str, } + end + local detailed=split(str) + local rawscheme="" + local rawquery="" + local somescheme=false + local somequery=false + if detailed then + rawscheme=detailed[1] + rawquery=detailed[4] + somescheme=rawscheme~="" + somequery=rawquery~="" + end + if not somescheme and not somequery then + return { + scheme="file", + authority="", + path=str, + query="", + fragment="", + original=str, + noscheme=true, + filename=str, + } + end + local authority=detailed[2] + local path=detailed[3] + local filename + local username + local password + local host + local port + if authority~="" then + username,password,host,port=lpegmatch(splitauthority,authority) + end + if authority=="" then + filename=path + elseif path=="" then + filename="" + else + filename=authority.."/"..path + end + return { + scheme=rawscheme, + authority=authority, + path=path, + query=lpegmatch(unescaper,rawquery), + queries=lpegmatch(splitquery,rawquery), + fragment=detailed[5], + original=str, + noscheme=false, + filename=filename, + host=host, + port=port, + } end url.split=split url.hasscheme=hasscheme url.hashed=hashed function url.addscheme(str,scheme) - if hasscheme(str) then - return str - elseif not scheme then - return "file:///"..str - else - return scheme..":///"..str - end + if hasscheme(str) then + return str + elseif not scheme then + return "file:///"..str + else + return scheme..":///"..str + end end function url.construct(hash) - local result,r={},0 - local scheme=hash.scheme - local authority=hash.authority - local path=hash.path - local queries=hash.queries - local fragment=hash.fragment - if scheme and scheme~="" then - r=r+1;result[r]=lpegmatch(escaper,scheme) - r=r+1;result[r]="://" - end - if authority and authority~="" then - r=r+1;result[r]=lpegmatch(escaper,authority) - end - if path and path~="" then - r=r+1;result[r]="/" - r=r+1;result[r]=lpegmatch(escaper,path) - end - if queries then - local done=false - for k,v in sortedhash(queries) do - r=r+1;result[r]=done and "&" or "?" - r=r+1;result[r]=lpegmatch(escaper,k) - r=r+1;result[r]="=" - r=r+1;result[r]=lpegmatch(escaper,v) - done=true - end - end - if fragment and fragment~="" then - r=r+1;result[r]="#" - r=r+1;result[r]=lpegmatch(escaper,fragment) - end - return concat(result) + local result,r={},0 + local scheme=hash.scheme + local authority=hash.authority + local path=hash.path + local queries=hash.queries + local fragment=hash.fragment + if scheme and scheme~="" then + r=r+1;result[r]=lpegmatch(escaper,scheme) + r=r+1;result[r]="://" + end + if authority and authority~="" then + r=r+1;result[r]=lpegmatch(escaper,authority) + end + if path and path~="" then + r=r+1;result[r]="/" + r=r+1;result[r]=lpegmatch(escaper,path) + end + if queries then + local done=false + for k,v in sortedhash(queries) do + r=r+1;result[r]=done and "&" or "?" + r=r+1;result[r]=lpegmatch(escaper,k) + r=r+1;result[r]="=" + r=r+1;result[r]=lpegmatch(escaper,v) + done=true + end + end + if fragment and fragment~="" then + r=r+1;result[r]="#" + r=r+1;result[r]=lpegmatch(escaper,fragment) + end + return concat(result) end local pattern=Cs(slash^-1/""*R("az","AZ")*((S(":|")/":")+P(":"))*slash*P(1)^0) function url.filename(filename) - local spec=hashed(filename) - local path=spec.path - return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename + local spec=hashed(filename) + local path=spec.path + return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename end local function escapestring(str) - return lpegmatch(escaper,str) + return lpegmatch(escaper,str) end url.escape=escapestring function url.query(str) - if type(str)=="string" then - return lpegmatch(splitquery,str) or "" - else - return str - end + if type(str)=="string" then + return lpegmatch(splitquery,str) or "" + else + return str + end end function url.toquery(data) - local td=type(data) - if td=="string" then - return #str and escape(data) or nil - elseif td=="table" then - if next(data) then - local t={} - for k,v in next,data do - t[#t+1]=format("%s=%s",k,escapestring(v)) - end - return concat(t,"&") - end - else + local td=type(data) + if td=="string" then + return #str and escape(data) or nil + elseif td=="table" then + if next(data) then + local t={} + for k,v in next,data do + t[#t+1]=format("%s=%s",k,escapestring(v)) + end + return concat(t,"&") end + else + end end local pattern=Cs(noslash^0*(1-noslash*P(-1))^0) function url.barepath(path) - if not path or path=="" then - return "" - else - return lpegmatch(pattern,path) - end + if not path or path=="" then + return "" + else + return lpegmatch(pattern,path) + end end @@ -4741,14 +5061,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 17703, stripped down to: 11691 +-- original size: 18002, stripped down to: 10681 if not modules then modules={} end modules ['l-dir']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,select=type,select local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub @@ -4760,471 +5080,478 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir +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 onwindows then - local tricky=S("/\\")*P(-1) - isdir=function(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end - end - isfile=function(name) - return attributes(name,"mode")=="file" + local tricky=S("/\\")*P(-1) + isdir=function(name) + if lpegmatch(tricky,name) then + return attributes(name,"mode")=="directory" + else + return attributes(name.."/.","mode")=="directory" end - lfs.isdir=isdir - lfs.isfile=isfile + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile else - isdir=function(name) - return attributes(name,"mode")=="directory" - end - isfile=function(name) - return attributes(name,"mode")=="file" - end - lfs.isdir=isdir - lfs.isfile=isfile + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile end function dir.current() - return (gsub(currentdir(),"\\","/")) + return (gsub(currentdir(),"\\","/")) end local function glob_pattern_function(path,patt,recurse,action) - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - action(full) - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end - if dirs then - for i=1,#dirs do - glob_pattern_function(dirs[i],patt,recurse,action) - end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if dirs then + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } + end end + end + end + if dirs then + for i=1,nofdirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end end + end end local function glob_pattern_table(path,patt,recurse,result) - if not result then - result={} - end - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - result[#result+1]=full - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end + if not result then + result={} + end + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + local noffiles=#result + for name,a in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + noffiles=noffiles+1 + result[noffiles]=full + end + elseif recurse and mode=="directory" then if dirs then - for i=1,#dirs do - glob_pattern_table(dirs[i],patt,recurse,result) - end + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } end + end end - return result + end + if dirs then + for i=1,nofdirs do + glob_pattern_table(dirs[i],patt,recurse,result) + end + end + return result end local function globpattern(path,patt,recurse,method) - local kind=type(method) - if patt and sub(patt,1,-3)==path then - patt=false - end - if kind=="function" then - return glob_pattern_function(path,patt,recurse,method) - elseif kind=="table" then - return glob_pattern_table(path,patt,recurse,method) - else - return glob_pattern_table(path,patt,recurse,{}) - end + local kind=type(method) + if patt and sub(patt,1,-3)==path then + patt=false + end + local okay=isdir(path) + if kind=="function" then + return okay and glob_pattern_function(path,patt,recurse,method) or {} + elseif kind=="table" then + return okay and glob_pattern_table(path,patt,recurse,method) or method + else + return okay and glob_pattern_table(path,patt,recurse,{}) or {} + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) - local ok,scanner - result=result or {} - if path=="/" then - ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) - else - ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) - end - if ok and type(scanner)=="function" then - if not find(path,"/$") then - path=path..'/' - end - for name in scanner,first do - if name=="." then - elseif name==".." then - else - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then - result[name]=attr - end - elseif recurse and mode=="directory" then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr - end - end + local ok,scanner + result=result or {} + if path=="/" then + ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) + else + ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) + end + if ok and type(scanner)=="function" then + if not find(path,"/$") then + path=path..'/' + end + for name in scanner,first do + if name=="." then + elseif name==".." then + else + local full=path..name + local attr=attributes(full) + local mode=attr.mode + if mode=='file' then + if find(full,patt) then + result[name]=attr + end + elseif recurse and mode=="directory" then + attr.list=collectpattern(full,patt,recurse) + result[name]=attr end + end end - return result + end + return result end dir.collectpattern=collectpattern local separator,pattern if onwindows then - local slash=S("/\\")/"/" - pattern={ - [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) - } + local slash=S("/\\")/"/" + pattern={ + [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={ - [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), - [2]=C(((1-S("*?/"))^0*P("/"))^0), - [3]=C(P(1)^0) - } + pattern={ + [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) + P("**")/".*"+P("*")/"[^/]*"+P("?")/"[^/]"+P(".")/"%%."+P("+")/"%%+"+P("-")/"%%-"+P(1) )^0 ) local function glob(str,t) - if type(t)=="function" then - if type(str)=="table" then - for s=1,#str do - glob(str[s],t) - end - elseif isfile(str) then - t(str) - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,t) - end - end + if type(t)=="function" then + if type(str)=="table" then + for s=1,#str do + glob(str[s],t) + end + elseif isfile(str) then + t(str) + else + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + globpattern(start,result,recurse,t) + end + end + else + if type(str)=="table" then + local t=t or {} + for s=1,#str do + glob(str[s],t) + end + return t + elseif isfile(str) then + if t then + t[#t+1]=str + return t + else + return { str } + end else - if type(str)=="table" then - local t=t or {} - for s=1,#str do - glob(str[s],t) - end - return t - elseif isfile(str) then - if t then - t[#t+1]=str - return t - else - return { str } - end - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - return globpattern(start,result,recurse,t) - else - return {} - end - end + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + return globpattern(start,result,recurse,t) + else + return {} + end end + end end dir.glob=glob local function globfiles(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if recurse then - globfiles(path.."/"..name,recurse,func,files) - end - elseif mode=="file" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if recurse then + globfiles(path.."/"..name,recurse,func,files) + end + elseif mode=="file" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name end + end end - return files + end + return files end dir.globfiles=globfiles local function globdirs(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - if recurse then - globdirs(path.."/"..name,recurse,func,files) - end - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name + if recurse then + globdirs(path.."/"..name,recurse,func,files) + end end + end end - return files + end + return files end dir.globdirs=globdirs function dir.ls(pattern) - return concat(glob(pattern),"\n") + return concat(glob(pattern),"\n") end local make_indeed=true if onwindows then - function dir.mkdirs(...) - local n=select("#",...) - local str - if n==1 then - str=select(1,...) - if isdir(str) then - return str,true - end + function dir.mkdirs(...) + 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="" - for i=1,n do - local s=select(i,...) - if s=="" then - elseif str=="" then - str=s - else - str=str.."/"..s - end - end + str=str.."/"..s end - local pth="" - local drive=false - local first,middle,last=match(str,"^(//)(//*)(.*)$") - if first then + end + end + local pth="" + local drive=false + local first,middle,last=match(str,"^(//)(//*)(.*)$") + if first then + else + first,last=match(str,"^(//)/*(.-)$") + if first then + middle,last=match(str,"([^/]+)/+(.-)$") + if middle then + pth="//"..middle else - first,last=match(str,"^(//)/*(.-)$") - if first then - middle,last=match(str,"([^/]+)/+(.-)$") - if middle then - pth="//"..middle - else - pth="//"..last - last="" - end - else - first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") - if first then - pth,drive=first..middle,true - else - middle,last=match(str,"^(/*)(.-)$") - if not middle then - last=str - end - end - end + pth="//"..last + last="" end - for s in gmatch(last,"[^/]+") do - if pth=="" then - pth=s - elseif drive then - pth,drive=pth..s,false - else - pth=pth.."/"..s - end - if make_indeed and not isdir(pth) then - mkdir(pth) - end + else + first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") + if first then + pth,drive=first..middle,true + else + middle,last=match(str,"^(/*)(.-)$") + if not middle then + last=str + end end - return pth,(isdir(pth)==true) + end end + for s in gmatch(last,"[^/]+") do + if pth=="" then + pth=s + elseif drive then + pth,drive=pth..s,false + else + pth=pth.."/"..s + end + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end + return pth,(isdir(pth)==true) + end else - function dir.mkdirs(...) - 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 + function dir.mkdirs(...) + 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 - str=gsub(str,"/+","/") - if find(str,"^/") then - pth="/" - for s in gmatch(str,"[^/]+") do - local first=(pth=="/") - if first then - pth=pth..s - else - pth=pth.."/"..s - end - if make_indeed and not first and not isdir(pth) then - mkdir(pth) - end - end + end + end + str=gsub(str,"/+","/") + if find(str,"^/") then + pth="/" + for s in gmatch(str,"[^/]+") do + local first=(pth=="/") + if first then + pth=pth..s else - pth="." - for s in gmatch(str,"[^/]+") do - pth=pth.."/"..s - if make_indeed and not isdir(pth) then - mkdir(pth) - end - end + pth=pth.."/"..s end - return pth,(isdir(pth)==true) + if make_indeed and not first and not isdir(pth) then + mkdir(pth) + end + end + else + pth="." + for s in gmatch(str,"[^/]+") do + pth=pth.."/"..s + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end end + return pth,(isdir(pth)==true) + end end dir.makedirs=dir.mkdirs do - local chdir=sandbox and sandbox.original(chdir) or chdir - if onwindows then - local xcurrentdir=dir.current - function dir.expandname(str) - local first,nothing,last=match(str,"^(//)(//*)(.*)$") - if first then - first=xcurrentdir().."/" - end - if not first then - first,last=match(str,"^(//)/*(.*)$") - end - if not first then - first,last=match(str,"^([a-zA-Z]:)(.*)$") - if first and not find(last,"^/") then - local d=currentdir() - if chdir(first) then - first=xcurrentdir() - end - chdir(d) - end - end - if not first then - first,last=xcurrentdir(),str - end - last=gsub(last,"//","/") - last=gsub(last,"/%./","/") - last=gsub(last,"^/*","") - first=gsub(first,"/*$","") - if last=="" or last=="." then - return first - else - return first.."/"..last - end - end - else - function dir.expandname(str) - if not find(str,"^/") then - str=currentdir().."/"..str - end - str=gsub(str,"//","/") - str=gsub(str,"/%./","/") - str=gsub(str,"(.)/%.$","%1") - return str + local chdir=sandbox and sandbox.original(chdir) or chdir + if onwindows then + local xcurrentdir=dir.current + function dir.expandname(str) + local first,nothing,last=match(str,"^(//)(//*)(.*)$") + if first then + first=xcurrentdir().."/" + end + if not first then + first,last=match(str,"^(//)/*(.*)$") + end + if not first then + first,last=match(str,"^([a-zA-Z]:)(.*)$") + if first and not find(last,"^/") then + local d=currentdir() + if chdir(first) then + first=xcurrentdir() + end + chdir(d) end + end + if not first then + first,last=xcurrentdir(),str + end + last=gsub(last,"//","/") + last=gsub(last,"/%./","/") + last=gsub(last,"^/*","") + first=gsub(first,"/*$","") + if last=="" or last=="." then + return first + else + return first.."/"..last + end end + else + function dir.expandname(str) + if not find(str,"^/") then + str=currentdir().."/"..str + end + str=gsub(str,"//","/") + str=gsub(str,"/%./","/") + str=gsub(str,"(.)/%.$","%1") + return str + end + end end file.expandname=dir.expandname local stack={} function dir.push(newdir) - local curdir=currentdir() - insert(stack,curdir) - if newdir and newdir~="" then - chdir(newdir) - return newdir - else - return curdir - end + local curdir=currentdir() + insert(stack,curdir) + if newdir and newdir~="" then + chdir(newdir) + return newdir + else + return curdir + end end function dir.pop() - local d=remove(stack) - if d then - chdir(d) - end - return d + local d=remove(stack) + if d then + chdir(d) + end + return d end local function found(...) - for i=1,select("#",...) do - local path=select(i,...) - local kind=type(path) - if kind=="string" then - if isdir(path) then - return path - end - elseif kind=="table" then - local path=found(unpack(path)) - if path then - return path - end - end + for i=1,select("#",...) do + local path=select(i,...) + local kind=type(path) + if kind=="string" then + if isdir(path) then + return path + end + elseif kind=="table" then + local path=found(unpack(path)) + if path then + return path + end end + end end dir.found=found @@ -5235,69 +5562,69 @@ do -- create closure to overcome 200 locals limit package.loaded["l-boolean"] = package.loaded["l-boolean"] or true --- original size: 1850, stripped down to: 1568 +-- original size: 1850, stripped down to: 1498 if not modules then modules={} end modules ['l-boolean']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber=type,tonumber boolean=boolean or {} local boolean=boolean function boolean.tonumber(b) - if b then return 1 else return 0 end + if b then return 1 else return 0 end end function toboolean(str,tolerant) - if str==nil then - return false - elseif str==false then - return false - elseif str==true then - return true - elseif str=="true" then - return true - elseif str=="false" then - return false - elseif not tolerant then - return false - elseif str==0 then - return false - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str==nil then + return false + elseif str==false then + return false + elseif str==true then + return true + elseif str=="true" then + return true + elseif str=="false" then + return false + elseif not tolerant then + return false + elseif str==0 then + return false + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end string.toboolean=toboolean function string.booleanstring(str) - if str=="0" then - return false - elseif str=="1" then - return true - elseif str=="" then - return false - elseif str=="false" then - return false - elseif str=="true" then - return true - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str=="0" then + return false + elseif str=="1" then + return true + elseif str=="" then + return false + elseif str=="false" then + return false + elseif str=="true" then + return true + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end function string.is_boolean(str,default,strict) - if type(str)=="string" then - if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then - return true - elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then - return false - end + if type(str)=="string" then + if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then + return true + elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then + return false end - return default + end + return default end @@ -5307,18 +5634,24 @@ do -- create closure to overcome 200 locals limit package.loaded["l-unicode"] = package.loaded["l-unicode"] or true --- original size: 40036, stripped down to: 17837 +-- original size: 41047, stripped down to: 17171 if not modules then modules={} end modules ['l-unicode']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -utf=utf or (unicode and unicode.utf8) or {} -utf.characters=utf.characters or string.utfcharacters -utf.values=utf.values or string.utfvalues +utf=utf or {} +unicode=nil +if not string.utfcharacters then + local gmatch=string.gmatch + function string.characters(str) + return gmatch(str,".[\128-\191]*") + end +end +utf.characters=string.utfcharacters local type=type local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch local concat=table.concat @@ -5329,345 +5662,340 @@ local tabletopattern=lpeg.utfchartabletopattern local bytepairs=string.bytepairs local finder=lpeg.finder 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.utf8character +local p_utf8character=patterns.utf8character +local p_utf8char=patterns.utf8char local p_utf8byte=patterns.utf8byte local p_utfbom=patterns.utfbom local p_newline=patterns.newline local p_whitespace=patterns.whitespace -if not unicode then - unicode={ utf=utf } -end if not utf.char then - utf.char=string.utfcharacter or (utf8 and utf8.char) - if not utf.char then - local char=string.char - if bit32 then - local rshift=bit32.rshift - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+rshift(n,6), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+rshift(n,12), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+rshift(n,18), - 0x80+(rshift(n,12)%0x40), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + utf.char=string.utfcharacter or (utf8 and utf8.char) + if not utf.char then + local char=string.char + if bit32 then + local rshift=bit32.rshift + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+rshift(n,6), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+rshift(n,12), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+rshift(n,18), + 0x80+(rshift(n,12)%0x40), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) else - local floor=math.floor - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+floor(n/0x40), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+floor(n/0x1000), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+floor(n/0x40000), - 0x80+(floor(n/0x1000)%0x40), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + return "" end + end + else + local floor=math.floor + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+floor(n/0x40), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+floor(n/0x1000), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+floor(n/0x40000), + 0x80+(floor(n/0x1000)%0x40), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + else + return "" + end + end end + end end if not utf.byte then - utf.byte=string.utfvalue or (utf8 and utf8.codepoint) - if not utf.byte then - local utf8byte=patterns.utf8byte - function utf.byte(c) - return lpegmatch(utf8byte,c) - end + utf.byte=string.utfvalue or (utf8 and utf8.codepoint) + if not utf.byte then + function utf.byte(c) + return lpegmatch(p_utf8byte,c) end + end end local utfchar,utfbyte=utf.char,utf.byte function utf.filetype(data) - return data and lpegmatch(p_utftype,data) or "unknown" + return data and lpegmatch(p_utftype,data) or "unknown" end local toentities=Cs ( - ( - patterns.utf8one+( - patterns.utf8two+patterns.utf8three+patterns.utf8four - )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end - )^0 + ( + patterns.utf8one+( + patterns.utf8two+patterns.utf8three+patterns.utf8four + )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end + )^0 ) patterns.toentities=toentities function utf.toentities(str) - return lpegmatch(toentities,str) + return lpegmatch(toentities,str) end local one=P(1) local two=C(1)*C(1) local four=C(R(utfchar(0xD8),utfchar(0xFF)))*C(1)*C(1)*C(1) local pattern=P("\254\255")*Cs(( - four/function(a,b,c,d) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(a,b) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 )+P("\255\254")*Cs(( - four/function(b,a,d,c) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(b,a) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 ) + four/function(a,b,c,d) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(a,b) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 )+P("\255\254")*Cs(( + four/function(b,a,d,c) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(b,a) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 ) function string.toutf(s) - return lpegmatch(pattern,s) or s + return lpegmatch(pattern,s) or s end local validatedutf=Cs ( - ( - patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" - )^0 + ( + patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" + )^0 ) patterns.validatedutf=validatedutf function utf.is_valid(str) - return type(str)=="string" and lpegmatch(validatedutf,str) or false + return type(str)=="string" and lpegmatch(validatedutf,str) or false end if not utf.len then - utf.len=string.utflength or (utf8 and utf8.len) - if not utf.len then - local n,f=0,1 - local utfcharcounter=patterns.utfbom^-1*Cmt ( - Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, - function(_,t,d) - n=n+(t-f)/d - f=t - return true - end - )^0 - function utf.len(str) - n,f=0,1 - lpegmatch(utfcharcounter,str or "") - return n - end + utf.len=string.utflength or (utf8 and utf8.len) + if not utf.len then + local n,f=0,1 + local utfcharcounter=patterns.utfbom^-1*Cmt ( + Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, + function(_,t,d) + n=n+(t-f)/d + f=t + return true + end + )^0 + function utf.len(str) + n,f=0,1 + lpegmatch(utfcharcounter,str or "") + return n end + end end utf.length=utf.len if not utf.sub then - local utflength=utf.length - local b,e,n,first,last=0,0,0,0,0 - local function slide_zero(s,p) - n=n+1 - if n>=last then - e=p-1 - else - return p - end + local utflength=utf.length + local b,e,n,first,last=0,0,0,0,0 + local function slide_zero(s,p) + n=n+1 + if n>=last then + e=p-1 + else + return p end - local function slide_one(s,p) - n=n+1 - if n==first then - b=p - end - if n>=last then - e=p-1 - else - return p - end + end + local function slide_one(s,p) + n=n+1 + if n==first then + b=p end - local function slide_two(s,p) - n=n+1 - if n==first then - b=p - else - return true - end + if n>=last then + e=p-1 + else + return p end - local pattern_zero=Cmt(p_utf8char,slide_zero)^0 - local pattern_one=Cmt(p_utf8char,slide_one )^0 - local pattern_two=Cmt(p_utf8char,slide_two )^0 - local pattern_first=C(patterns.utf8character) - function utf.sub(str,start,stop) - if not start then - return str - end - if start==0 then - start=1 - end - if not stop then - if start<0 then - local l=utflength(str) - start=l+start - else - start=start-1 - end - b,n,first=0,0,start - lpegmatch(pattern_two,str) - if n>=first then - return sub(str,b) - else - return "" - end - end - if start<0 or stop<0 then - local l=utf.length(str) - if start<0 then - start=l+start - if start<=0 then - start=1 - else - start=start+1 - end - end - if stop<0 then - stop=l+stop - if stop==0 then - stop=1 - else - stop=stop+1 - end - end + end + local function slide_two(s,p) + n=n+1 + if n==first then + b=p + else + return true + end + end + local pattern_zero=Cmt(p_utf8character,slide_zero)^0 + local pattern_one=Cmt(p_utf8character,slide_one )^0 + local pattern_two=Cmt(p_utf8character,slide_two )^0 + local pattern_first=C(p_utf8character) + function utf.sub(str,start,stop) + if not start then + return str + end + if start==0 then + start=1 + end + if not stop then + if start<0 then + local l=utflength(str) + start=l+start + else + start=start-1 + end + b,n,first=0,0,start + lpegmatch(pattern_two,str) + if n>=first then + return sub(str,b) + else + return "" + end + end + if start<0 or stop<0 then + local l=utf.length(str) + if start<0 then + start=l+start + if start<=0 then + start=1 + else + start=start+1 end - if start==1 and stop==1 then - return lpegmatch(pattern_first,str) or "" - elseif start>stop then - return "" - elseif start>1 then - b,e,n,first,last=0,0,0,start-1,stop - lpegmatch(pattern_one,str) - if n>=first and e==0 then - e=#str - end - return sub(str,b,e) + end + if stop<0 then + stop=l+stop + if stop==0 then + stop=1 else - b,e,n,last=1,0,0,stop - lpegmatch(pattern_zero,str) - if e==0 then - e=#str - end - return sub(str,b,e) + stop=stop+1 end + end end + if start==1 and stop==1 then + return lpegmatch(pattern_first,str) or "" + elseif start>stop then + return "" + elseif start>1 then + b,e,n,first,last=0,0,0,start-1,stop + lpegmatch(pattern_one,str) + if n>=first and e==0 then + e=#str + end + return sub(str,b,e) + else + b,e,n,last=1,0,0,stop + lpegmatch(pattern_zero,str) + if e==0 then + e=#str + end + return sub(str,b,e) + end + end end function utf.remapper(mapping,option,action) - local variant=type(mapping) - if variant=="table" then - action=action or mapping - if option=="dynamic" then - local pattern=false - table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) - return function(str) - if not str or str=="" then - return "" - else - if not pattern then - pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - end - return lpegmatch(pattern,str) - end - end - elseif option=="pattern" then - return Cs((tabletopattern(mapping)/action+p_utf8char)^0) + local variant=type(mapping) + if variant=="table" then + action=action or mapping + if option=="dynamic" then + local pattern=false + table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + if not pattern then + pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + end + return lpegmatch(pattern,str) end - elseif variant=="function" then - if option=="pattern" then - return Cs((p_utf8char/mapping+p_utf8char)^0) + end + elseif option=="pattern" then + return Cs((tabletopattern(mapping)/action+p_utf8character)^0) + else + local pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((p_utf8char/mapping+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + return lpegmatch(pattern,str) end + end,pattern + end + elseif variant=="function" then + if option=="pattern" then + return Cs((p_utf8character/mapping+p_utf8character)^0) else - return function(str) - return str or "" + local pattern=Cs((p_utf8character/mapping+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" + else + return lpegmatch(pattern,str) end + end,pattern end -end -function utf.replacer(t) - local r=replacer(t,false,false,true) + else return function(str) - return lpegmatch(r,str) + return str or "" end + end +end +function utf.replacer(t) + local r=replacer(t,false,false,true) + return function(str) + return lpegmatch(r,str) + end end function utf.subtituter(t) - local f=finder (t) - local r=replacer(t,false,false,true) - return function(str) - local i=lpegmatch(f,str) - if not i then - return str - elseif i>#str then - return str - else - return lpegmatch(r,str) - end + local f=finder (t) + local r=replacer(t,false,false,true) + return function(str) + local i=lpegmatch(f,str) + if not i then + return str + elseif i>#str then + return str + else + return lpegmatch(r,str) end + end end local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline) -local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0) -local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0) -local utfcharsplitter_raw=Ct(C(p_utf8char)^0) +local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8character)^0) +local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8character))^0) +local utfcharsplitter_raw=Ct(C(p_utf8character)^0) patterns.utflinesplitter=utflinesplitter function utf.splitlines(str) - return lpegmatch(utflinesplitter,str or "") + return lpegmatch(utflinesplitter,str or "") end function utf.split(str,ignorewhitespace) - if ignorewhitespace then - return lpegmatch(utfcharsplitter_iws,str or "") - else - return lpegmatch(utfcharsplitter_ows,str or "") - end + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end end function utf.totable(str) - return lpegmatch(utfcharsplitter_raw,str) + return lpegmatch(utfcharsplitter_raw,str) end function utf.magic(f) - local str=f:read(4) or "" - local off=lpegmatch(p_utfoffset,str) - if off<4 then - f:seek('set',off) - end - return lpegmatch(p_utftype,str) + local str=f:read(4) or "" + local off=lpegmatch(p_utfoffset,str) + if off<4 then + f:seek('set',off) + end + return lpegmatch(p_utftype,str) end local utf16_to_utf8_be,utf16_to_utf8_le local utf32_to_utf8_be,utf32_to_utf8_le @@ -5681,36 +6009,36 @@ local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_n local utf_32_le_linesplitter=utf_32_le_getbom*lpeg.tsplitat(patterns.utf_32_le_nl) local more=0 local p_utf16_to_utf8_be=C(1)*C(1)/function(left,right) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf16_to_utf8_le=C(1)*C(1)/function(right,left) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf32_to_utf8_be=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) + return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) end local p_utf32_to_utf8_le=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) + return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) end p_utf16_to_utf8_be=P(true)/function() more=0 end*utf_16_be_getbom*Cs(p_utf16_to_utf8_be^0) p_utf16_to_utf8_le=P(true)/function() more=0 end*utf_16_le_getbom*Cs(p_utf16_to_utf8_le^0) @@ -5721,88 +6049,88 @@ patterns.utf16_to_utf8_le=p_utf16_to_utf8_le patterns.utf32_to_utf8_be=p_utf32_to_utf8_be patterns.utf32_to_utf8_le=p_utf32_to_utf8_le utf16_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_be,s) + else + return s + end end local utf16_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_be,s) end - return t + end + return t end utf16_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_le,s) + else + return s + end end local utf16_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_le,s) end - return t + end + return t end utf32_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_be,s) + else + return s + end end local utf32_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_be,s) end - return t + end + return t end utf32_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_le,s) + else + return s + end end local utf32_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_le,s) end - return t + end + return t end utf.utf16_to_utf8_le_t=utf16_to_utf8_le_t utf.utf16_to_utf8_be_t=utf16_to_utf8_be_t @@ -5813,189 +6141,225 @@ 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(t) - return type(t)=="string" and lpegmatch(utflinesplitter,t) or t + return type(t)=="string" and lpegmatch(utflinesplitter,t) or t end function utf.utf16_to_utf8_t(t,endian) - return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t + return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t end function utf.utf32_to_utf8_t(t,endian) - return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t + return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t end local function little(b) - if b<0x10000 then - return char(b%256,rshift(b,8)) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) - end + if b<0x10000 then + return char(b%256,rshift(b,8)) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) + end end local function big(b) - if b<0x10000 then - return char(rshift(b,8),b%256) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) - end + if b<0x10000 then + return char(rshift(b,8),b%256) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) + end end local l_remap=Cs((p_utf8byte/little+P(1)/"")^0) local b_remap=Cs((p_utf8byte/big+P(1)/"")^0) local function utf8_to_utf16_be(str,nobom) - if nobom then - return lpegmatch(b_remap,str) - else - return char(254,255)..lpegmatch(b_remap,str) - end + if nobom then + return lpegmatch(b_remap,str) + else + return char(254,255)..lpegmatch(b_remap,str) + end end local function utf8_to_utf16_le(str,nobom) - if nobom then - return lpegmatch(l_remap,str) - else - return char(255,254)..lpegmatch(l_remap,str) - end + if nobom then + return lpegmatch(l_remap,str) + else + return char(255,254)..lpegmatch(l_remap,str) + end end utf.utf8_to_utf16_be=utf8_to_utf16_be utf.utf8_to_utf16_le=utf8_to_utf16_le function utf.utf8_to_utf16(str,littleendian,nobom) - if littleendian then - return utf8_to_utf16_le(str,nobom) - else - return utf8_to_utf16_be(str,nobom) - end + if littleendian then + return utf8_to_utf16_le(str,nobom) + else + return 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 + (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 ) function utf.tocodes(str,separator) - return lpegmatch(pattern,str,1,separator or " ") + return lpegmatch(pattern,str,1,separator or " ") end function utf.ustring(s) - return format("U+%05X",type(s)=="number" and s or utfbyte(s)) + return format("U+%05X",type(s)=="number" and s or utfbyte(s)) end function utf.xstring(s) - return format("0x%05X",type(s)=="number" and s or utfbyte(s)) + return format("0x%05X",type(s)=="number" and s or utfbyte(s)) end function utf.toeight(str) - if not str or str=="" then - return nil - end - local utftype=lpegmatch(p_utfstricttype,str) - if utftype=="utf-8" then - return sub(str,4) - elseif utftype=="utf-16-be" then - return utf16_to_utf8_be(str) - elseif utftype=="utf-16-le" then - return utf16_to_utf8_le(str) - else - return str - end -end -local p_nany=p_utf8char/"" -if utfgmatch then - function utf.count(str,what) - if type(what)=="string" then - local n=0 - for _ in utfgmatch(str,what) do - n=n+1 - end - return n - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end -else - local cache={} - function utf.count(str,what) - if type(what)=="string" then - local p=cache[what] - if not p then - p=Cs((P(what)/" "+p_nany)^0) - cache[p]=p - end - return #lpegmatch(p,str) - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end + if not str or str=="" then + return nil + end + local utftype=lpegmatch(p_utfstricttype,str) + if utftype=="utf-8" then + return sub(str,4) + elseif utftype=="utf-16-be" then + return utf16_to_utf8_be(str) + elseif utftype=="utf-16-le" then + return utf16_to_utf8_le(str) + else + return str + end end -if not utf.characters then - function utf.characters(str) - return gmatch(str,".[\128-\191]*") +do + local p_nany=p_utf8character/"" + local cache={} + function utf.count(str,what) + if type(what)=="string" then + local p=cache[what] + if not p then + p=Cs((P(what)/" "+p_nany)^0) + cache[p]=p + end + return #lpegmatch(p,str) + else + return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) end - string.utfcharacters=utf.characters + end end -if not utf.values then - local find=string.find - local dummy=function() - end - function utf.values(str) - local n=#str - if n==0 then - return dummy - elseif n==1 then - return function() return utfbyte(str) end - else - local p=1 - return function() - local b,e=find(str,".[\128-\191]*",p) - if b then - p=e+1 - return utfbyte(sub(str,b,e)) - end - end - end +if not string.utfvalues then + local find=string.find + local dummy=function() + end + function string.utfvalues(str) + local n=#str + if n==0 then + return dummy + elseif n==1 then + return function() return utfbyte(str) end + else + local p=1 + return function() + local b,e=find(str,".[\128-\191]*",p) + if b then + p=e+1 + return utfbyte(sub(str,b,e)) + end + end end - string.utfvalues=utf.values + end end +utf.values=string.utfvalues 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 + 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 if bit32 then - local extract=bit32.extract - local char=string.char - function unicode.toutf32string(n) - if n<=0xFF then - return - char(n).."\000\000\000" - elseif n<=0xFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" - elseif n<=0xFFFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" - else - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) - end - end + local extract=bit32.extract + local char=string.char + function utf.toutf32string(n) + if n<=0xFF then + return + char(n).."\000\000\000" + elseif n<=0xFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" + elseif n<=0xFFFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" + else + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) + end + end end local len=utf.len local rep=rep function string.utfpadd(s,n) - if n and n~=0 then - local l=len(s) - if n>0 then - local d=n-l - if d>0 then - return rep(c or " ",d)..s - end - else - local d=- n-l - if d>0 then - return s..rep(c or " ",d) - end - end + if n and n~=0 then + local l=len(s) + if n>0 then + local d=n-l + if d>0 then + return rep(c or " ",d)..s + end + else + local d=- n-l + if d>0 then + return s..rep(c or " ",d) + end end - return s + end + return s +end +do + local utfcharacters=utf.characters or string.utfcharacters + local utfchar=utf.char or string.utfcharacter + lpeg.UP=P + if utfcharacters then + function lpeg.US(str) + local p=P(false) + for uc in utfcharacters(str) do + p=p+P(uc) + end + return p + end + else + function lpeg.US(str) + local p=P(false) + local f=function(uc) + p=p+P(uc) + end + lpegmatch((p_utf8char/f)^0,str) + return p + end + end + local range=p_utf8byte*p_utf8byte+Cc(false) + function lpeg.UR(str,more) + local first,last + if type(str)=="number" then + first=str + last=more or first + else + first,last=lpegmatch(range,str) + if not last then + return P(str) + end + end + if first==last then + return P(str) + end + if not utfchar then + utfchar=utf.char + end + if utfchar and (last-first<8) then + local p=P(false) + for i=first,last do + p=p+P(utfchar(i)) + end + return p + else + local f=function(b) + return b>=first and b<=last + end + return p_utf8byte/f + end + end end @@ -6005,93 +6369,93 @@ do -- create closure to overcome 200 locals limit package.loaded["l-math"] = package.loaded["l-math"] or true --- original size: 2555, stripped down to: 1900 +-- original size: 2555, stripped down to: 1831 if not modules then modules={} end modules ['l-math']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not math.ceiling then - math.ceiling=math.ceil + math.ceiling=math.ceil end if not math.round then - local floor=math.floor - function math.round(x) return floor(x+0.5) end + local floor=math.floor + function math.round(x) return floor(x+0.5) end end if not math.div then - local floor=math.floor - function math.div(n,m) return floor(n/m) end + local floor=math.floor + function math.div(n,m) return floor(n/m) end end if not math.mod then - function math.mod(n,m) return n%m end + function math.mod(n,m) return n%m end end if not math.sind then - local sin,cos,tan=math.sin,math.cos,math.tan - local pipi=2*math.pi/360 - function math.sind(d) return sin(d*pipi) end - function math.cosd(d) return cos(d*pipi) end - function math.tand(d) return tan(d*pipi) end + local sin,cos,tan=math.sin,math.cos,math.tan + local pipi=2*math.pi/360 + function math.sind(d) return sin(d*pipi) end + function math.cosd(d) return cos(d*pipi) end + function math.tand(d) return tan(d*pipi) end end if not math.odd then - function math.odd (n) return n%2~=0 end - function math.even(n) return n%2==0 end + function math.odd (n) return n%2~=0 end + function math.even(n) return n%2==0 end end if not math.cosh then - local exp=math.exp - function math.cosh(x) - local xx=exp(x) - return (xx+1/xx)/2 - end - function math.sinh(x) - local xx=exp(x) - return (xx-1/xx)/2 - end - function math.tanh(x) - local xx=exp(x) - return (xx-1/xx)/(xx+1/xx) - end + local exp=math.exp + function math.cosh(x) + local xx=exp(x) + return (xx+1/xx)/2 + end + function math.sinh(x) + local xx=exp(x) + return (xx-1/xx)/2 + end + function math.tanh(x) + local xx=exp(x) + return (xx-1/xx)/(xx+1/xx) + end end if not math.pow then - function math.pow(x,y) - return x^y - end + function math.pow(x,y) + return x^y + end end if not math.atan2 then - math.atan2=math.atan + math.atan2=math.atan end if not math.ldexp then - function math.ldexp(x,e) - return x*2.0^e - end + function math.ldexp(x,e) + return x*2.0^e + end end if not math.log10 then - local log=math.log - function math.log10(x) - return log(x,10) - end + local log=math.log + function math.log10(x) + return log(x,10) + end end if not math.type then - function math.type() - return "float" - end + function math.type() + return "float" + end end if not math.tointeger then - math.mininteger=-0x4FFFFFFFFFFF - math.maxinteger=0x4FFFFFFFFFFF - local floor=math.floor - function math.tointeger(n) - local f=floor(n) - return f==n and f or nil - end + math.mininteger=-0x4FFFFFFFFFFF + math.maxinteger=0x4FFFFFFFFFFF + local floor=math.floor + function math.tointeger(n) + local f=floor(n) + return f==n and f or nil + end end if not math.ult then - local floor=math.floor - function math.tointeger(m,n) - return floor(m)<floor(n) - end + local floor=math.floor + function math.tointeger(m,n) + return floor(m)<floor(n) + end end @@ -6101,14 +6465,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 38734, stripped down to: 22142 +-- original size: 43539, stripped down to: 21641 if not modules then modules={} end modules ['util-str']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.strings=utilities.strings or {} @@ -6121,624 +6485,657 @@ 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,utflen=utf.char,utf.byte,utf.len -local loadstripped=nil -local oldfashioned=LUAVERSION<5.2 -if oldfashioned 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 +local 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 if not number then number={} end -local stripper=patterns.stripzeros +local stripzero=patterns.stripzero +local stripzeros=patterns.stripzeros local newline=patterns.newline local endofstring=patterns.endofstring +local anything=patterns.anything local whitespace=patterns.whitespace +local space=patterns.space local spacer=patterns.spacer local spaceortab=patterns.spaceortab +local digit=patterns.digit +local sign=patterns.sign +local period=patterns.period +local ptf=1/65536 +local bpf=(7200/7227)/65536 local function points(n) - n=tonumber(n) - return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*ptf + if n%1==0 then + return format("%ipt",n) + end + return lpegmatch(stripzeros,format("%.5fpt",n)) 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)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*bpf + if n%1==0 then + return format("%ibp",n) + end + return lpegmatch(stripzeros,format("%.5fbp",n)) end number.points=points number.basepoints=basepoints local rubish=spaceortab^0*newline local anyrubish=spaceortab+newline -local anything=patterns.anything local stripped=(spaceortab^1/"")*newline local leading=rubish^0/"" local trailing=(anyrubish^1*endofstring)/"" local redundant=rubish^3/"\n" local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) function strings.collapsecrlf(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local repeaters={} function strings.newrepeater(str,offset) - offset=offset or 0 - local s=repeaters[str] - if not s then - s={} - repeaters[str]=s - end - local t=s[offset] - if t then - return t - end - t={} - setmetatable(t,{ __index=function(t,k) - if not k then - return "" - end - local n=k+offset - local s=n>0 and rep(str,n) or "" - t[k]=s - return s - end }) - s[offset]=t + offset=offset or 0 + local s=repeaters[str] + if not s then + s={} + repeaters[str]=s + end + local t=s[offset] + if t then return t + end + t={} + setmetatable(t,{ __index=function(t,k) + if not k then + return "" + end + local n=k+offset + local s=n>0 and rep(str,n) or "" + t[k]=s + return s + end }) + s[offset]=t + return t end local extra,tab,start=0,0,4,0 local nspaces=strings.newrepeater(" ") string.nspaces=nspaces local pattern=Carg(1)/function(t) - extra,tab,start=0,t or 7,1 - end*Cs(( + extra,tab,start=0,t or 7,1 + end*Cs(( Cp()*patterns.tab/function(position) - local current=(position-start+1)+extra - local spaces=tab-(current-1)%tab - if spaces>0 then - extra=extra+spaces-1 - return nspaces[spaces] - else - return "" - end + local current=(position-start+1)+extra + local spaces=tab-(current-1)%tab + if spaces>0 then + extra=extra+spaces-1 + return nspaces[spaces] + else + return "" + end end+newline*Cp()/function(position) - extra,start=0,position - end+patterns.anything - )^1) + extra,start=0,position + end+anything + )^1) function strings.tabtospace(str,tab) - return lpegmatch(pattern,str,1,tab or 7) + return lpegmatch(pattern,str,1,tab or 7) end function string.utfpadding(s,n) - if not n or n==0 then - return "" - end - local l=utflen(s) - if n>0 then - return nspaces[n-l] - else - return nspaces[-n-l] - end -end -local space=spacer^0 -local nospace=space/"" + if not n or n==0 then + return "" + end + local l=utflen(s) + if n>0 then + return nspaces[n-l] + else + return nspaces[-n-l] + end +end +local optionalspace=spacer^0 +local nospace=optionalspace/"" local endofline=nospace*newline local stripend=(whitespace^1*endofstring)/"" -local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) +local normalline=(nospace*((1-optionalspace*(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 intospace=whitespace^1/" " +local noleading=whitespace^1/"" +local notrailing=noleading*endofstring 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_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^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, - ["collapse"]=patterns.collapser, + ["prune"]=p_prune_normal, + ["prune and collapse"]=p_prune_collapse, + ["prune and no empty"]=p_prune_noempty, + ["prune and to space"]=p_prune_intospace, + ["retain"]=p_retain_normal, + ["retain and collapse"]=p_retain_collapse, + ["retain and no empty"]=p_retain_noempty, + ["collapse"]=patterns.collapser, } setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end }) strings.striplinepatterns=striplinepatterns function strings.striplines(str,how) - return str and lpegmatch(striplinepatterns[how],str) or str + return str and lpegmatch(striplinepatterns[how],str) or str +end +function strings.collapse(str) + return str and lpegmatch(p_prune_intospace,str) or str end strings.striplong=strings.striplines function strings.nice(str) - str=gsub(str,"[:%-+_]+"," ") - return str + str=gsub(str,"[:%-+_]+"," ") + return str end local n=0 local sequenced=table.sequenced function string.autodouble(s,sep) - if s==nil then - return '""' - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ('"'..sequenced(s,sep or ",")..'"') - end - return ('"'..tostring(s)..'"') + if s==nil then + return '""' + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ('"'..sequenced(s,sep or ",")..'"') + end + return ('"'..tostring(s)..'"') end function string.autosingle(s,sep) - if s==nil then - return "''" - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ("'"..sequenced(s,sep or ",").."'") - end - return ("'"..tostring(s).."'") + if s==nil then + return "''" + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ("'"..sequenced(s,sep or ",").."'") + end + return ("'"..tostring(s).."'") end local tracedchars={ [0]= - "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", - "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", - "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", - "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", - "[space]", + "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", + "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", + "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", + "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", + "[space]", } string.tracedchars=tracedchars strings.tracers=tracedchars function string.tracedchar(b) - if type(b)=="number" then - return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") - else - local c=utfbyte(b) - return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") - end + if type(b)=="number" then + return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") + else + local c=utfbyte(b) + return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") + end end function number.signed(i) - if i>0 then - return "+",i - else - return "-",-i - end -end -local digit=patterns.digit -local period=patterns.period -local three=digit*digit*digit + if i>0 then + return "+",i + else + return "-",-i + end +end +local two=digit*digit +local three=two*digit +local prefix=(Carg(1)*three)^1 local splitter=Cs ( - (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2) + (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2) +) +local splitter3=Cs ( + three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit ) patterns.formattednumber=splitter function number.formatted(n,sep1,sep2) - local s=type(s)=="string" and n or format("%0.2f",n) + if sep1==false then + if type(n)=="number" then + n=tostring(n) + end + return lpegmatch(splitter3,n,1,sep2 or ".") + else + if type(n)=="number" then + n=format("%0.2f",n) + end if sep1==true then - return lpegmatch(splitter,s,1,".",",") + return lpegmatch(splitter,n,1,".",",") elseif sep1=="." then - return lpegmatch(splitter,s,1,sep1,sep2 or ",") + return lpegmatch(splitter,n,1,sep1,sep2 or ",") elseif sep1=="," then - return lpegmatch(splitter,s,1,sep1,sep2 or ".") + return lpegmatch(splitter,n,1,sep1,sep2 or ".") else - return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") + return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".") end + end end local p=Cs( - P("-")^0*(P("0")^1/"")^0*(1-P("."))^0*(P(".")*P("0")^1*P(-1)/""+P(".")^0)*P(1-P("0")^1*P(-1))^0 - ) + P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0 + ) function number.compactfloat(n,fmt) - if n==0 then - return "0" - elseif n==1 then - return "1" - end - n=lpegmatch(p,format(fmt or "%0.3f",n)) - if n=="." or n=="" or n=="-" then - return "0" - end - return n + if n==0 then + return "0" + elseif n==1 then + return "1" + end + n=lpegmatch(p,format(fmt or "%0.3f",n)) + if n=="." or n=="" or n=="-" then + return "0" + end + return n end local zero=P("0")^1/"" local plus=P("+")/"" local minus=P("-") -local separator=S(".") -local digit=R("09") +local separator=period 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 exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1)) local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) -local pattern_b=Cs((exponent+P(1))^0) +local pattern_b=Cs((exponent+anything)^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)) + 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 - return tostring(n) + 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 hf={} local hs={} setmetatable(hf,{ __index=function(t,k) - local v="%."..k.."f" - t[k]=v - return v + local v="%."..k.."f" + t[k]=v + return v end } ) setmetatable(hs,{ __index=function(t,k) - local v="%"..k.."s" - t[k]=v - return v + local v="%"..k.."s" + t[k]=v + return v end } ) function number.formattedfloat(n,b,a) - local s=format(hf[a],n) - local l=(b or 0)+(a or 0)+1 - if #s<l then - return format(hs[l],s) - else - return s - end + local s=format(hf[a],n) + local l=(b or 0)+(a or 0)+1 + if #s<l then + return format(hs[l],s) + else + return s + end end local template=[[ %s %s return function(%s) return %s end ]] -local preamble,environment="",{} -if oldfashioned 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 utfpadding=string.utfpadding -local tracedchar=string.tracedchar -local autosingle=string.autosingle -local autodouble=string.autodouble -local sequenced=table.sequenced -local formattednumber=number.formatted -local sparseexponent=number.sparseexponent -local formattedfloat=number.formattedfloat - ]] -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, - utfpadding=string.utfpadding, - tracedchar=string.tracedchar, - autosingle=string.autosingle, - autodouble=string.autodouble, - sequenced=table.sequenced, - formattednumber=number.formatted, - sparseexponent=number.sparseexponent, - formattedfloat=number.formattedfloat, - } -end +local preamble="" +local 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, + utfpadding=string.utfpadding, + tracedchar=string.tracedchar, + autosingle=string.autosingle, + autodouble=string.autodouble, + sequenced=table.sequenced, + formattednumber=number.formatted, + sparseexponent=number.sparseexponent, + formattedfloat=number.formattedfloat, + stripzero=lpeg.patterns.stripzero, + stripzeros=lpeg.patterns.stripzeros, + FORMAT=string.f9, +} local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) - local v=t[k-1]..",a"..k - t[k]=v - return v - end + local v=t[k-1]..",a"..k + t[k]=v + return v + end }) -local prefix_any=C((S("+- .")+R("09"))^0) -local prefix_sub=(C((S("+-")+R("09"))^0)+Cc(0))*P(".")*(C((S("+-")+R("09"))^0)+Cc(0)) +local prefix_any=C((sign+space+period+digit)^0) +local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(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 - return format("format('%%%ss',a%s)",f,n) - else - return format("(a%s or '')",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',a%s)",f,n) + else + return format("(a%s or '')",n) + end end local format_S=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%ss',tostring(a%s))",f,n) - else - return format("tostring(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',tostring(a%s))",f,n) + else + return format("tostring(a%s)",n) + end end local format_right=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - elseif f>0 then - return format("utfpadding(a%s,%i)..a%s",n,f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + elseif f>0 then + return format("utfpadding(a%s,%i)..a%s",n,f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,f) + end end local format_left=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - end - if f<0 then - return format("utfpadding(a%s,%i)..a%s",n,-f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,-f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + end + if f<0 then + return format("utfpadding(a%s,%i)..a%s",n,-f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,-f) + end end local format_q=function() - n=n+1 - return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) + n=n+1 + return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) end local format_Q=function() - n=n+1 - return format("format('%%q',tostring(a%s))",n) + n=n+1 + return format("format('%%q',tostring(a%s))",n) end local format_i=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%si',a%s)",f,n) - else - return format("format('%%i',a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%si',a%s)",f,n) + else + return format("format('%%i',a%s)",n) + end end local format_d=format_i local format_I=function(f) - n=n+1 - return format("format('%%s%%%si',signed(a%s))",f,n) + n=n+1 + return format("format('%%s%%%si',signed(a%s))",f,n) end local format_f=function(f) - n=n+1 - return format("format('%%%sf',a%s)",f,n) + n=n+1 + return format("format('%%%sf',a%s)",f,n) end local format_F=function(f) - n=n+1 - if not f or f=="" then - return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) - else - return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) - end + n=n+1 + if not f or f=="" then + return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) + else + return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) + end end local format_k=function(b,a) - n=n+1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) + n=n+1 + return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) end local format_g=function(f) - n=n+1 - return format("format('%%%sg',a%s)",f,n) + n=n+1 + return format("format('%%%sg',a%s)",f,n) end local format_G=function(f) - n=n+1 - return format("format('%%%sG',a%s)",f,n) + n=n+1 + return format("format('%%%sG',a%s)",f,n) end local format_e=function(f) - n=n+1 - return format("format('%%%se',a%s)",f,n) + n=n+1 + return format("format('%%%se',a%s)",f,n) end local format_E=function(f) - n=n+1 - return format("format('%%%sE',a%s)",f,n) + 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) + 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) + 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) + n=n+1 + return format("format('%%%sx',a%s)",f,n) end local format_X=function(f) - n=n+1 - return format("format('%%%sX',a%s)",f,n) + n=n+1 + return format("format('%%%sX',a%s)",f,n) end local format_o=function(f) - n=n+1 - return format("format('%%%so',a%s)",f,n) + n=n+1 + return format("format('%%%so',a%s)",f,n) end local format_c=function() - n=n+1 - return format("utfchar(a%s)",n) + n=n+1 + return format("utfchar(a%s)",n) end local format_C=function() - n=n+1 - return format("tracedchar(a%s)",n) + n=n+1 + return format("tracedchar(a%s)",n) end local format_r=function(f) - n=n+1 - return format("format('%%%s.0f',a%s)",f,n) + n=n+1 + return format("format('%%%s.0f',a%s)",f,n) end local format_h=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_H=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_u=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_U=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_p=function() - n=n+1 - return format("points(a%s)",n) + n=n+1 + return format("points(a%s)",n) end local format_b=function() - n=n+1 - return format("basepoints(a%s)",n) + n=n+1 + return format("basepoints(a%s)",n) end local format_t=function(f) - n=n+1 - if f and f~="" then - return format("concat(a%s,%q)",n,f) - else - return format("concat(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("concat(a%s,%q)",n,f) + else + return format("concat(a%s)",n) + end end local format_T=function(f) - n=n+1 - if f and f~="" then - return format("sequenced(a%s,%q)",n,f) - else - return format("sequenced(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("sequenced(a%s,%q)",n,f) + else + return format("sequenced(a%s)",n) + end end local format_l=function() - n=n+1 - return format("(a%s and 'true' or 'false')",n) + n=n+1 + return format("(a%s and 'true' or 'false')",n) end local format_L=function() - n=n+1 - return format("(a%s and 'TRUE' or 'FALSE')",n) + n=n+1 + return format("(a%s and 'TRUE' or 'FALSE')",n) end -local format_N=function() - n=n+1 - return format("tostring(tonumber(a%s) or a%s)",n,n) +local format_n=function() + n=n+1 + return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n) +end +local format_N=function(f) + n=n+1 + if not f or f=="" then + f=".9" + end + return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n) end local format_a=function(f) - n=n+1 - if f and f~="" then - return format("autosingle(a%s,%q)",n,f) - else - return format("autosingle(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autosingle(a%s,%q)",n,f) + else + return format("autosingle(a%s)",n) + end end local format_A=function(f) - n=n+1 - if f and f~="" then - return format("autodouble(a%s,%q)",n,f) - else - return format("autodouble(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autodouble(a%s,%q)",n,f) + else + return format("autodouble(a%s)",n) + end end local format_w=function(f) - n=n+1 - f=tonumber(f) - if f then - return format("nspaces[%s+a%s]",f,n) - else - return format("nspaces[a%s]",n) - end + n=n+1 + f=tonumber(f) + if f then + return format("nspaces[%s+a%s]",f,n) + else + return format("nspaces[a%s]",n) + end end local format_W=function(f) - return format("nspaces[%s]",tonumber(f) or 0) + return format("nspaces[%s]",tonumber(f) or 0) end local format_m=function(f) - n=n+1 - if not f or f=="" then - f="," - end + n=n+1 + if not f or f=="" then + f="," + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,".")]],n,f) + end end local format_M=function(f) - n=n+1 - if not f or f=="" then - f="." - end + n=n+1 + if not f or f=="" then + f="." + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,",")]],n,f) + end end local format_z=function(f) - n=n+(tonumber(f) or 1) - return "''" + n=n+(tonumber(f) or 1) + return "''" end local format_rest=function(s) - return format("%q",s) + return format("%q",s) end local format_extension=function(extensions,f,name) - local extension=extensions[name] or "tostring(%s)" - local f=tonumber(f) or 1 - local w=find(extension,"%.%.%.") + local extension=extensions[name] or "tostring(%s)" + local f=tonumber(f) or 1 + local w=find(extension,"%.%.%.") + if w then if f==0 then - if w then - extension=gsub(extension,"%.%.%.","") - end - return extension + extension=gsub(extension,"%.%.%.","") + return extension elseif f==1 then - if w then - extension=gsub(extension,"%.%.%.","%%s") - end - n=n+1 - local a="a"..n - return format(extension,a,a) + extension=gsub(extension,"%.%.%.","%%s") + n=n+1 + local a="a"..n + return format(extension,a,a) elseif f<0 then - local a="a"..(n+f+1) - return format(extension,a,a) + local a="a"..(n+f+1) + return format(extension,a,a) else - if w then - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - end - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + local t={} + for i=1,f do + n=n+1 + t[i]="a"..n + end + return format(extension,unpack(t)) end + else + extension=gsub(extension,"%%s",function() + n=n+1 + return "a"..n + end) + return extension + end end local builder=Cs { "start", - start=( - ( - P("%")/""*( - V("!") + start=( + ( + P("%")/""*( + V("!") +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("N") +V("k") +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") @@ -6750,160 +7147,156 @@ local builder=Cs { "start", +V("z") +V(">") +V("<") - )+V("*") - )*(P(-1)+Carg(1)) - )^0, - ["s"]=(prefix_any*P("s"))/format_s, - ["q"]=(prefix_any*P("q"))/format_q, - ["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, - ["E"]=(prefix_any*P("E"))/format_E, - ["x"]=(prefix_any*P("x"))/format_x, - ["X"]=(prefix_any*P("X"))/format_X, - ["o"]=(prefix_any*P("o"))/format_o, - ["S"]=(prefix_any*P("S"))/format_S, - ["Q"]=(prefix_any*P("Q"))/format_Q, - ["N"]=(prefix_any*P("N"))/format_N, - ["k"]=(prefix_sub*P("k"))/format_k, - ["c"]=(prefix_any*P("c"))/format_c, - ["C"]=(prefix_any*P("C"))/format_C, - ["r"]=(prefix_any*P("r"))/format_r, - ["h"]=(prefix_any*P("h"))/format_h, - ["H"]=(prefix_any*P("H"))/format_H, - ["u"]=(prefix_any*P("u"))/format_u, - ["U"]=(prefix_any*P("U"))/format_U, - ["p"]=(prefix_any*P("p"))/format_p, - ["b"]=(prefix_any*P("b"))/format_b, - ["t"]=(prefix_tab*P("t"))/format_t, - ["T"]=(prefix_tab*P("T"))/format_T, - ["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, - ["<"]=(prefix_any*P("<"))/format_left, - [">"]=(prefix_any*P(">"))/format_right, - ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, - ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, - ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, + )+V("*") + )*(endofstring+Carg(1)) + )^0, + ["s"]=(prefix_any*P("s"))/format_s, + ["q"]=(prefix_any*P("q"))/format_q, + ["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, + ["E"]=(prefix_any*P("E"))/format_E, + ["x"]=(prefix_any*P("x"))/format_x, + ["X"]=(prefix_any*P("X"))/format_X, + ["o"]=(prefix_any*P("o"))/format_o, + ["S"]=(prefix_any*P("S"))/format_S, + ["Q"]=(prefix_any*P("Q"))/format_Q, + ["n"]=(prefix_any*P("n"))/format_n, + ["N"]=(prefix_any*P("N"))/format_N, + ["k"]=(prefix_sub*P("k"))/format_k, + ["c"]=(prefix_any*P("c"))/format_c, + ["C"]=(prefix_any*P("C"))/format_C, + ["r"]=(prefix_any*P("r"))/format_r, + ["h"]=(prefix_any*P("h"))/format_h, + ["H"]=(prefix_any*P("H"))/format_H, + ["u"]=(prefix_any*P("u"))/format_u, + ["U"]=(prefix_any*P("U"))/format_U, + ["p"]=(prefix_any*P("p"))/format_p, + ["b"]=(prefix_any*P("b"))/format_b, + ["t"]=(prefix_tab*P("t"))/format_t, + ["T"]=(prefix_tab*P("T"))/format_T, + ["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_any*P("m"))/format_m, + ["M"]=(prefix_any*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, + ["<"]=(prefix_any*P("<"))/format_left, + [">"]=(prefix_any*P(">"))/format_right, + ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, + ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, + ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } local xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end }) local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end }) local preset={ - ["%02x"]=function(n) return xx[n] end, - ["%02X"]=function(n) return XX[n] end, + ["%02x"]=function(n) return xx[n] end, + ["%02X"]=function(n) return XX[n] end, } -local direct=P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] +local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]] local function make(t,str) - local f=preset[str] - if f then - return f - end - local p=lpegmatch(direct,str) - if p then - f=loadstripped(p)() + local f=preset[str] + if f then + return f + end + local p=lpegmatch(direct,str) + if p then + f=loadstripped(p)() + else + n=0 + 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,t._environment_)() else - n=0 - 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,t._environment_)() - else - f=function() return str end - end + f=function() return str end end - t[str]=f - return f + end + t[str]=f + return f end local function use(t,fmt,...) - return t[fmt](...) + return t[fmt](...) end strings.formatters={} -if oldfashioned 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 +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 local formatters=strings.formatters.new() string.formatters=formatters 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 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 + if type(t)=="table" and t._type_=="formatter" then + t._extensions_[name]=template or "%s" + 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 -patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) -patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) +patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+anything)^0) +patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^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 oldfashioned 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 +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 }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 -local space=patterns.space local cquote=Cc('"') -local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +Cs(cquote*(equote-space)^0*space*equote^0*cquote) function string.optionalquoted(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local pattern=Cs((newline/(os.newline or "\r")+1)^0) function string.replacenewlines(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function strings.newcollector() - local result,r={},0 - return - function(fmt,str,...) - r=r+1 - result[r]=str==nil and fmt or formatters[fmt](str,...) - end, - function(connector) - if result then - local str=concat(result,connector) - result,r={},0 - return str - end - end + local result,r={},0 + return + function(fmt,str,...) + r=r+1 + result[r]=str==nil and fmt or formatters[fmt](str,...) + end, + function(connector) + if result then + local str=concat(result,connector) + result,r={},0 + return str + end + end +end +local f_16_16=formatters["%0.5N"] +function number.to16dot16(n) + return f_16_16(n/65536.0) end @@ -6913,14 +7306,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tab"] = package.loaded["util-tab"] or true --- original size: 27741, stripped down to: 17085 +-- original size: 28772, stripped down to: 16111 if not modules then modules={} end modules ['util-tab']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.tables=utilities.tables or {} @@ -6935,219 +7328,220 @@ local formatters=string.formatters local utftoeight=utf.toeight local splitter=lpeg.tsplitat(".") 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=composed.."."..name - t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) - else - composed=name - if not nofirst then - t[#t+1]=formatters["%s = %s or { }"](composed,composed) - end - end - end + local composed=nil + local t={} + local snippets=lpegmatch(splitter,target) + for i=1,#snippets-(nolast and 1 or 0) do + local name=snippets[i] if composed then - if nolast then - composed=composed.."."..snippets[#snippets] - end - return concat(t,"\n"),composed + composed=composed.."."..name + t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) else - return "",target + composed=name + if not nofirst then + t[#t+1]=formatters["%s = %s or { }"](composed,composed) + end + end + end + if composed then + if nolast then + composed=composed.."."..snippets[#snippets] end + return concat(t,"\n"),composed + else + return "",target + end end function tables.definedtable(...) - local t=_G - for i=1,select("#",...) do - local li=select(i,...) - local tl=t[li] - if not tl then - tl={} - t[li]=tl - end - t=tl - end - return t + local t=_G + for i=1,select("#",...) do + local li=select(i,...) + local tl=t[li] + if not tl then + tl={} + t[li]=tl + end + t=tl + end + return t end function tables.accesstable(target,root) - local t=root or _G - for name in gmatch(target,"([^%.]+)") do - t=t[name] - if not t then - return - end + local t=root or _G + for name in gmatch(target,"([^%.]+)") do + t=t[name] + if not t then + return end - return t + end + return t end function tables.migratetable(target,v,root) - local t=root or _G - local names=lpegmatch(splitter,target) - for i=1,#names-1 do - local name=names[i] - t[name]=t[name] or {} - t=t[name] - if not t then - return - end + local t=root or _G + local names=lpegmatch(splitter,target) + for i=1,#names-1 do + local name=names[i] + t[name]=t[name] or {} + t=t[name] + if not t then + return end - t[names[#names]]=v + end + t[names[#names]]=v end function tables.removevalue(t,value) - if value then - for i=1,#t do - if t[i]==value then - remove(t,i) - end - end + if value then + for i=1,#t do + if t[i]==value then + remove(t,i) + end end + end end function tables.replacevalue(t,oldvalue,newvalue) - if oldvalue and newvalue then - for i=1,#t do - if t[i]==oldvalue then - t[i]=newvalue - end - end + if oldvalue and newvalue then + for i=1,#t do + if t[i]==oldvalue then + t[i]=newvalue + end end + end end function tables.insertbeforevalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i,extra) + return end - insert(t,1,extra) + end + insert(t,1,extra) end function tables.insertaftervalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i+1,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i+1,extra) + return end - insert(t,#t+1,extra) + end + insert(t,#t+1,extra) end local escape=Cs(Cc('"')*((P('"')/'""'+P(1))^0)*Cc('"')) function table.tocsv(t,specification) - if t and #t>0 then - local result={} - local r={} - specification=specification or {} - local fields=specification.fields - if type(fields)~="string" then - fields=sortedkeys(t[1]) - end - local separator=specification.separator or "," - local noffields=#fields - if specification.preamble==true then - for f=1,noffields do - r[f]=lpegmatch(escape,tostring(fields[f])) - end - result[1]=concat(r,separator) - end - for i=1,#t do - local ti=t[i] - for f=1,noffields do - local field=ti[fields[f]] - if type(field)=="string" then - r[f]=lpegmatch(escape,field) - else - r[f]=tostring(field) - end - end - result[i+1]=concat(r,separator) + if t and #t>0 then + local result={} + local r={} + specification=specification or {} + local fields=specification.fields + if type(fields)~="string" then + fields=sortedkeys(t[1]) + end + local separator=specification.separator or "," + local noffields=#fields + if specification.preamble==true then + for f=1,noffields do + r[f]=lpegmatch(escape,tostring(fields[f])) + end + result[1]=concat(r,separator) + end + for i=1,#t do + local ti=t[i] + for f=1,noffields do + local field=ti[fields[f]] + if type(field)=="string" then + r[f]=lpegmatch(escape,field) + else + r[f]=tostring(field) end - return concat(result,"\n") - else - return "" + end + result[i+1]=concat(r,separator) end + return concat(result,"\n") + else + return "" + end end local nspaces=utilities.strings.newrepeater(" ") local function toxml(t,d,result,step) - local r=#result - for k,v in sortedpairs(t) do - local s=nspaces[d] - local tk=type(k) - local tv=type(v) - if tv=="table" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</entry>"](s,k) - else - r=r+1 result[r]=formatters["%s<%s>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</%s>"](s,k) - end - elseif tv=="string" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) - end - elseif tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) - end + local r=#result + for k,v in sortedpairs(t) do + local s=nspaces[d] + local tk=type(k) + local tv=type(v) + if tv=="table" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</entry>"](s,k) + else + r=r+1 result[r]=formatters["%s<%s>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</%s>"](s,k) + end + elseif tv=="string" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) + end + elseif tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) end + end end function table.toxml(t,specification) - specification=specification or {} - local name=specification.name - local noroot=name==false - local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } - local indent=specification.indent or 0 - local spaces=specification.spaces or 1 - if noroot then - toxml(t,indent,result,spaces) - else - toxml({ [name or "data"]=t },indent,result,spaces) - end - return concat(result,"\n") + specification=specification or {} + local name=specification.name + local noroot=name==false + local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } + local indent=specification.indent or 0 + local spaces=specification.spaces or 1 + if noroot then + toxml(t,indent,result,spaces) + else + toxml({ [name or "data"]=t },indent,result,spaces) + end + return concat(result,"\n") end function tables.encapsulate(core,capsule,protect) - if type(capsule)~="table" then - protect=true - capsule={} - end + if type(capsule)~="table" then + protect=true + capsule={} + end + for key,value in next,core do + if capsule[key] then + print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) + os.exit() + else + capsule[key]=value + end + end + if protect then for key,value in next,core do + core[key]=nil + end + setmetatable(core,{ + __index=capsule, + __newindex=function(t,key,value) if capsule[key] then - print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) - os.exit() + print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) + os.exit() else - capsule[key]=value + rawset(t,key,value) end - end - if protect then - for key,value in next,core do - core[key]=nil - end - setmetatable(core,{ - __index=capsule, - __newindex=function(t,key,value) - if capsule[key] then - print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) - os.exit() - else - rawset(t,key,value) - end - end - } ) - end + end + } ) + end end local f_hashed_string=formatters["[%q]=%q,"] local f_hashed_number=formatters["[%q]=%s,"] @@ -7161,157 +7555,157 @@ 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 + 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 - for k,v in next,t do - 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 + end + for k,v in next,t do + 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 - m=m+1 - if outer then - r[m]="}" - else - r[m]="}," + 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 - return r + end end - return concat(fastserialize(t,true)) + m=m+1 + if outer then + r[m]="}" + else + r[m]="}," + end + return r + end + return concat(fastserialize(t,true)) end function table.deserialize(str) - if not str or str=="" then - return - end - local code=load(str) - if not code then - return - end - code=code() - if not code then - return - end - return code + if not str or str=="" then + return + end + local code=load(str) + if not code then + return + end + code=code() + if not code then + return + end + return code end 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() - if type(t)=="table" then - return t - end - end + 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() + if type(t)=="table" then + return t end + end end + end end function table.save(filename,t,n,...) - io.savedata(filename,table.serialize(t,n==nil and true or n,...)) + io.savedata(filename,table.serialize(t,n==nil and true or n,...)) end 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 - local ti=t[i] - local j=0 - for k,v in next,ti do - j=j+1 - l[j]=f_key_value(k,v) - end - r[i]=f_add_table(l) - end - return f_return_table(r) + local r={} + local l={} + for i=1,#t do + local ti=t[i] + local j=0 + for k,v in next,ti do + j=j+1 + l[j]=f_key_value(k,v) + end + r[i]=f_add_table(l) + end + 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] - m=m+1 r[m]=" {" - for k,v in next,ti do - m=m+1 r[m]=f_key_value(k,v) - end - m=m+1 r[m]="},\n" - end - m=m+1 - r[m]="}" - return concat(r) + local r={ "return {\n" } + local m=1 + for i=1,#t do + local ti=t[i] + m=m+1 r[m]=" {" + for k,v in next,ti do + m=m+1 r[m]=f_key_value(k,v) + end + m=m+1 r[m]="},\n" + end + m=m+1 + r[m]="}" + return concat(r) end function table.drop(t,slow) - if #t==0 then - return "return { }" - elseif slow==true then - return slowdrop(t) - else - return fastdrop(t) - end + if #t==0 then + return "return { }" + elseif slow==true then + return slowdrop(t) + else + return fastdrop(t) + end end local selfmapper={ __index=function(t,k) t[k]=k return k end } -function table.twowaymapper(t) - if not t then - t={} - else - local zero=rawget(t,0) - for i=zero and 0 or 1,#t do - local ti=t[i] - if ti then - local i=tostring(i) - t[i]=ti - t[ti]=i - end - end +function table.twowaymapper(t) + if not t then + t={} + else + local zero=rawget(t,0) + for i=zero and 0 or 1,#t do + local ti=t[i] + if ti then + local i=tostring(i) + t[i]=ti + t[ti]=i + end end - setmetatable(t,selfmapper) - return t + end + setmetatable(t,selfmapper) + return t end local f_start_key_idx=formatters["%w{"] local f_start_key_num=formatters["%w[%s]={"] @@ -7349,187 +7743,223 @@ local spaces=utilities.strings.newrepeater(" ") local original_serialize=table.serialize local is_simple_table=table.is_simple_table local function serialize(root,name,specification) - if type(specification)=="table" then - return original_serialize(root,name,specification) - end - local t - local n=1 - local unknown=false - 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) + if type(specification)=="table" then + return original_serialize(root,name,specification) + end + local t + local n=1 + local unknown=false + 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)~=nil then + local first=nil + local last=0 + last=#root + for k=1,last do + if rawget(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<=last and k>=first 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 next(v)==nil then + n=n+1 t[n]=f_val_not(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)~=nil then - local first=nil - local last=0 - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end + local st=is_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 - if last>0 then - first=1 + elseif tv=="boolean" then + n=n+1 t[n]=f_val_boo(depth,v) + elseif unknown then + n=n+1 t[n]=f_val_str(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) + end + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_not(depth,k) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_not(depth,k) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_not(depth,k) + elseif unknown then + n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) 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<=last and k>=first 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 next(v)==nil then - n=n+1 t[n]=f_val_not(depth) - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_val_str(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) - end - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - n=n+1 t[n]=f_key_num_value_not(depth,k) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_not(depth,k) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_not(depth,k) - elseif unknown then - n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) - end - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_seq(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) - end - else - if tk=="number" then - n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(v)) - end - end + else + local st=is_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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_seq(depth,tostring(k),st) 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() } + 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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) + end else - t={ f_table_direct() } + if tk=="number" then + n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(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("t") } + t={ f_table_name(name) } 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)~=nil then - local st=is_simple_table(root) - if st then - return t[1]..f_fin_seq(st) - else - do_serialize(root,name,1,0) - end - 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)~=nil then + local st=is_simple_table(root) + if st then + return t[1]..f_fin_seq(st) + else + do_serialize(root,name,1,0) + end end - n=n+1 - t[n]=f_table_finish() - return concat(t,"\n") + end + n=n+1 + t[n]=f_table_finish() + return concat(t,"\n") end table.serialize=serialize if setinspector then - setinspector("table",function(v) - if type(v)=="table" then - print(serialize(v,"table",{ metacheck=false })) - return true - end - end) + setinspector("table",function(v) + if type(v)=="table" then + print(serialize(v,"table",{ metacheck=false })) + return true + end + end) +end +local mt={ + __newindex=function(t,k,v) + local n=t.last+1 + t.last=n + t.list[n]=k + t.hash[k]=v + end, + __index=function(t,k) + return t.hash[k] + end, + __len=function(t) + return t.last + end, +} +function table.orderedhash() + return setmetatable({ list={},hash={},last=0 },mt) +end +function table.ordered(t) + local n=t.last + if n>0 then + local l=t.list + local i=1 + local h=t.hash + local f=function() + if i<=n then + local k=i + local v=h[l[k]] + i=i+1 + return k,v + end + end + return f,1,h[l[1]] + else + return function() end + end end @@ -7539,15 +7969,16 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7787, stripped down to: 5858 +-- original size: 8607, stripped down to: 6727 if not modules then modules={} end modules ['util-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } +local tonumber=tonumber local byte=string.byte local char=string.char utilities=utilities or {} @@ -7555,251 +7986,280 @@ local files={} utilities.files=files local zerobased={} function files.open(filename,zb) - local f=io.open(filename,"rb") - if f then - zerobased[f]=zb or false - end - return f + local f=io.open(filename,"rb") + if f then + zerobased[f]=zb or false + end + return f end function files.close(f) - zerobased[f]=nil - f:close() + zerobased[f]=nil + f:close() end function files.size(f) - local current=f:seek() - local size=f:seek("end") - f:seek("set",current) - return size + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) - if zerobased[f] then - f:seek("set",n) - else - f:seek("set",n-1) - end + if zerobased[f] then + f:seek("set",n) + else + f:seek("set",n-1) + end end function files.getposition(f) - if zerobased[f] then - return f:seek() - else - return f:seek()+1 - end + if zerobased[f] then + return f:seek() + else + return f:seek()+1 + end end function files.look(f,n,chars) - local p=f:seek() - local s=f:read(n) - f:seek("set",p) - if chars then - return s - else - return byte(s,1,#s) - end + local p=f:seek() + local s=f:read(n) + f:seek("set",p) + if chars then + return s + else + return byte(s,1,#s) + end end function files.skip(f,n) - if n==1 then - f:read(n) - else - f:seek("set",f:seek()+n) - end + if n==1 then + f:read(n) + else + f:seek("set",f:seek()+n) + end end function files.readbyte(f) - return byte(f:read(1)) + return byte(f:read(1)) end function files.readbytes(f,n) - return byte(f:read(n),1,n) + return byte(f:read(n),1,n) end function files.readbytetable(f,n) - local s=f:read(n or 1) - return { byte(s,1,#s) } + local s=f:read(n or 1) + return { byte(s,1,#s) } end function files.readchar(f) - return f:read(1) + return f:read(1) end function files.readstring(f,n) - return f:read(n or 1) + return f:read(n or 1) end -function files.readinteger1(f) - local n=byte(f:read(1)) - if n>=0x80 then - return n-0x100 - else - return n - end +function files.readinteger1(f) + local n=byte(f:read(1)) + if n>=0x80 then + return n-0x100 + else + return n + end end -files.readcardinal1=files.readbyte +files.readcardinal1=files.readbyte files.readcardinal=files.readcardinal1 files.readinteger=files.readinteger1 files.readsignedbyte=files.readinteger1 function files.readcardinal2(f) - local a,b=byte(f:read(2),1,2) - return 0x100*a+b + local a,b=byte(f:read(2),1,2) + return 0x100*a+b end function files.readcardinal2le(f) - local b,a=byte(f:read(2),1,2) - return 0x100*a+b + local b,a=byte(f:read(2),1,2) + return 0x100*a+b end function files.readinteger2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readinteger2le(f) - local b,a=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local b,a=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readcardinal3(f) - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readcardinal3le(f) - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readinteger3(f) - local a,b,c=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local a,b,c=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readinteger3le(f) - local c,b,a=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local c,b,a=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readcardinal4(f) - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readcardinal4le(f) - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readinteger4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readinteger4le(f) - local d,c,b,a=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local d,c,b,a=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readfixed2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return (a-0x100)+b/0x100 - else - return (a )+b/0x100 - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function files.readfixed4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end if bit32 then - local extract=bit32.extract - local band=bit32.band - function files.read2dot14(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local extract=bit32.extract + local band=bit32.band + function files.read2dot14(f) + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) + else + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function files.skipshort(f,n) - f:read(2*(n or 1)) + f:read(2*(n or 1)) end function files.skiplong(f,n) - f:read(4*(n or 1)) + f:read(4*(n or 1)) end if bit32 then - local rshift=bit32.rshift - function files.writecardinal2(f,n) - local a=char(n%256) - n=rshift(n,8) - local b=char(n%256) - f:write(b,a) - end -else - local floor=math.floor - function files.writecardinal2(f,n) - local a=char(n%256) - n=floor(n/256) - local b=char(n%256) - f:write(b,a) - end -end -function files.writecardinal4(f,n) + local rshift=bit32.rshift + function files.writecardinal2(f,n) local a=char(n%256) n=rshift(n,8) local b=char(n%256) - n=rshift(n,8) - local c=char(n%256) - n=rshift(n,8) - local d=char(n%256) - f:write(d,c,b,a) + f:write(b,a) + end +else + local floor=math.floor + function files.writecardinal2(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + f:write(b,a) + end +end +function files.writecardinal4(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(d,c,b,a) end function files.writestring(f,s) - f:write(char(byte(s,1,#s))) + f:write(char(byte(s,1,#s))) end function files.writebyte(f,b) - f:write(char(b)) + f:write(char(b)) end if fio and fio.readcardinal1 then - files.readcardinal1=fio.readcardinal1 - files.readcardinal2=fio.readcardinal2 - files.readcardinal3=fio.readcardinal3 - files.readcardinal4=fio.readcardinal4 - files.readinteger1=fio.readinteger1 - files.readinteger2=fio.readinteger2 - files.readinteger3=fio.readinteger3 - files.readinteger4=fio.readinteger4 - files.readfixed2=fio.readfixed2 - files.readfixed4=fio.readfixed4 - files.read2dot14=fio.read2dot14 - files.setposition=fio.setposition - files.getposition=fio.getposition - files.readbyte=files.readcardinal1 - files.readsignedbyte=files.readinteger1 - files.readcardinal=files.readcardinal1 - files.readinteger=files.readinteger1 - local skipposition=fio.skipposition - files.skipposition=skipposition - files.readbytes=fio.readbytes - files.readbytetable=fio.readbytetable - function files.skipshort(f,n) - skipposition(f,2*(n or 1)) - end - function files.skiplong(f,n) - skipposition(f,4*(n or 1)) - end + files.readcardinal1=fio.readcardinal1 + files.readcardinal2=fio.readcardinal2 + files.readcardinal3=fio.readcardinal3 + files.readcardinal4=fio.readcardinal4 + files.readinteger1=fio.readinteger1 + files.readinteger2=fio.readinteger2 + files.readinteger3=fio.readinteger3 + files.readinteger4=fio.readinteger4 + files.readfixed2=fio.readfixed2 + files.readfixed4=fio.readfixed4 + files.read2dot14=fio.read2dot14 + files.setposition=fio.setposition + files.getposition=fio.getposition + files.readbyte=files.readcardinal1 + files.readsignedbyte=files.readinteger1 + files.readcardinal=files.readcardinal1 + files.readinteger=files.readinteger1 + local skipposition=fio.skipposition + files.skipposition=skipposition + files.readbytes=fio.readbytes + files.readbytetable=fio.readbytetable + function files.skipshort(f,n) + skipposition(f,2*(n or 1)) + end + function files.skiplong(f,n) + skipposition(f,4*(n or 1)) + end +end +if fio and fio.readcardinaltable then + files.readcardinaltable=fio.readcardinaltable + files.readintegertable=fio.readintegertable +else + local readcardinal1=files.readcardinal1 + local readcardinal2=files.readcardinal2 + local readcardinal3=files.readcardinal3 + local readcardinal4=files.readcardinal4 + function files.readcardinaltable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end + return t + end + local readinteger1=files.readinteger1 + local readinteger2=files.readinteger2 + local readinteger3=files.readinteger3 + local readinteger4=files.readinteger4 + function files.readintegertable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end + return t + end end @@ -7809,338 +8269,412 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sac"] = package.loaded["util-sac"] or true --- original size: 8716, stripped down to: 6754 +-- original size: 11065, stripped down to: 8209 if not modules then modules={} end modules ['util-sac']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local byte,sub=string.byte,string.sub -local extract=bit32 and bit32.extract +local tonumber=tonumber utilities=utilities or {} local streams={} utilities.streams=streams function streams.open(filename,zerobased) - local f=io.loaddata(filename) + local f=filename and io.loaddata(filename) + if f then return { f,1,#f,zerobased or false } + end +end +function streams.openstring(f,zerobased) + if f then + return { f,1,#f,zerobased or false } + end end function streams.close() end function streams.size(f) - return f and f[3] or 0 + return f and f[3] or 0 end function streams.setposition(f,i) - if f[4] then - if i<=0 then - f[2]=1 - else - f[2]=i+1 - end + if f[4] then + if i<=0 then + f[2]=1 else - if i<=1 then - f[2]=1 - else - f[2]=i - end + f[2]=i+1 end -end -function streams.getposition(f) - if f[4] then - return f[2]-1 + else + if i<=1 then + f[2]=1 else - return f[2] + f[2]=i end + end +end +function streams.getposition(f) + if f[4] then + return f[2]-1 + else + return f[2] + end end function streams.look(f,n,chars) - local b=f[2] - local e=b+n-1 - if chars then - return sub(f[1],b,e) - else - return byte(f[1],b,e) - end + local b=f[2] + local e=b+n-1 + if chars then + return sub(f[1],b,e) + else + return byte(f[1],b,e) + end end function streams.skip(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readbyte(f) - local i=f[2] - f[2]=i+1 - return byte(f[1],i) + local i=f[2] + f[2]=i+1 + return byte(f[1],i) end function streams.readbytes(f,n) - local i=f[2] - local j=i+n - f[2]=j - return byte(f[1],i,j-1) + local i=f[2] + local j=i+n + f[2]=j + return byte(f[1],i,j-1) end function streams.readbytetable(f,n) - local i=f[2] - local j=i+n - f[2]=j - return { byte(f[1],i,j-1) } + local i=f[2] + local j=i+n + f[2]=j + return { byte(f[1],i,j-1) } end function streams.skipbytes(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readchar(f) - local i=f[2] - f[2]=i+1 - return sub(f[1],i,i) + local i=f[2] + f[2]=i+1 + return sub(f[1],i,i) end function streams.readstring(f,n) - local i=f[2] - local j=i+n - f[2]=j - return sub(f[1],i,j-1) -end -function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - local n=byte(f[1],i) - if n>=0x80 then - return n-0x100 - else - return n - end + local i=f[2] + local j=i+n + f[2]=j + return sub(f[1],i,j-1) +end +function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + local n=byte(f[1],i) + if n>=0x80 then + return n-0x100 + else + return n + end end -streams.readcardinal1=streams.readbyte +streams.readcardinal1=streams.readbyte streams.readcardinal=streams.readcardinal1 streams.readinteger=streams.readinteger1 function streams.readcardinal2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + return 0x100*a+b end function streams.readcardinal2LE(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + return 0x100*a+b end function streams.readinteger2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readinteger2le(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readcardinal3(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readcardinal3le(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readinteger3(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readinteger3le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readcardinal4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - return 0x1000000*a+0x10000*b+0x100*c+d + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + return 0x1000000*a+0x10000*b+0x100*c+d end function streams.readinteger4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function streams.readinteger4le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local d,c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local d,c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end +end +function streams.readfixed2(f) + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function streams.readfixed4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end -function streams.readfixed2(f) +if bit32 then + local extract=bit32.extract + local band=bit32.band + function streams.read2dot14(f) local i=f[2] local j=i+1 f[2]=j+1 local a,b=byte(f[1],i,j) if a>=0x80 then - return (a-0x100)+b/0x100 + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) else - return (a )+b/0x100 - end -end -if extract then - local extract=bit32.extract - local band=bit32.band - function streams.read2dot14(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function streams.skipshort(f,n) - f[2]=f[2]+2*(n or 1) + f[2]=f[2]+2*(n or 1) end function streams.skiplong(f,n) - f[2]=f[2]+4*(n or 1) + f[2]=f[2]+4*(n or 1) end if sio and sio.readcardinal2 then - local readcardinal1=sio.readcardinal1 - local readcardinal2=sio.readcardinal2 - local readcardinal3=sio.readcardinal3 - local readcardinal4=sio.readcardinal4 - local readinteger1=sio.readinteger1 - local readinteger2=sio.readinteger2 - local readinteger3=sio.readinteger3 - local readinteger4=sio.readinteger4 - local readfixed2=sio.readfixed2 - local readfixed4=sio.readfixed4 - local read2dot14=sio.read2dot14 - local readbytes=sio.readbytes - local readbytetable=sio.readbytetable - function streams.readcardinal1(f) - local i=f[2] - f[2]=i+1 - return readcardinal1(f[1],i) - end - function streams.readcardinal2(f) - local i=f[2] - f[2]=i+2 - return readcardinal2(f[1],i) - end - function streams.readcardinal3(f) - local i=f[2] - f[2]=i+3 - return readcardinal3(f[1],i) - end - function streams.readcardinal4(f) - local i=f[2] - f[2]=i+4 - return readcardinal4(f[1],i) - end - function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - return readinteger1(f[1],i) - end - function streams.readinteger2(f) - local i=f[2] - f[2]=i+2 - return readinteger2(f[1],i) - end - function streams.readinteger3(f) - local i=f[2] - f[2]=i+3 - return readinteger3(f[1],i) - end - function streams.readinteger4(f) - local i=f[2] - f[2]=i+4 - return readinteger4(f[1],i) - end - function streams.read2dot4(f) - local i=f[2] - f[2]=i+2 - return read2dot4(f[1],i) - end - function streams.readbytes(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytes(f[1],i,n) + local readcardinal1=sio.readcardinal1 + local readcardinal2=sio.readcardinal2 + local readcardinal3=sio.readcardinal3 + local readcardinal4=sio.readcardinal4 + local readinteger1=sio.readinteger1 + local readinteger2=sio.readinteger2 + local readinteger3=sio.readinteger3 + local readinteger4=sio.readinteger4 + local readfixed2=sio.readfixed2 + local readfixed4=sio.readfixed4 + local read2dot14=sio.read2dot14 + local readbytes=sio.readbytes + local readbytetable=sio.readbytetable + function streams.readcardinal1(f) + local i=f[2] + f[2]=i+1 + return readcardinal1(f[1],i) + end + function streams.readcardinal2(f) + local i=f[2] + f[2]=i+2 + return readcardinal2(f[1],i) + end + function streams.readcardinal3(f) + local i=f[2] + f[2]=i+3 + return readcardinal3(f[1],i) + end + function streams.readcardinal4(f) + local i=f[2] + f[2]=i+4 + return readcardinal4(f[1],i) + end + function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + return readinteger1(f[1],i) + end + function streams.readinteger2(f) + local i=f[2] + f[2]=i+2 + return readinteger2(f[1],i) + end + function streams.readinteger3(f) + local i=f[2] + f[2]=i+3 + return readinteger3(f[1],i) + end + function streams.readinteger4(f) + local i=f[2] + f[2]=i+4 + return readinteger4(f[1],i) + end + function streams.read2dot4(f) + local i=f[2] + f[2]=i+2 + return read2dot4(f[1],i) + end + function streams.readbytes(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p end - function streams.readbytetable(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytetable(f[1],i,n) + return readbytes(f[1],i,n) + end + function streams.readbytetable(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readbytetable(f[1],i,n) + end + streams.readbyte=streams.readcardinal1 + streams.readsignedbyte=streams.readinteger1 + streams.readcardinal=streams.readcardinal1 + streams.readinteger=streams.readinteger1 +end +if sio and sio.readcardinaltable then + local readcardinaltable=sio.readcardinaltable + local readintegertable=sio.readintegertable + function utilities.streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readcardinaltable(f[1],i,n,b) + end + function utilities.streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readintegertable(f[1],i,n,b) + end +else + local readcardinal1=streams.readcardinal1 + local readcardinal2=streams.readcardinal2 + local readcardinal3=streams.readcardinal3 + local readcardinal4=streams.readcardinal4 + function streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p end - streams.readbyte=streams.readcardinal1 - streams.readsignedbyte=streams.readinteger1 - streams.readcardinal=streams.readcardinal1 - streams.readinteger=streams.readinteger1 + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end + return t + end + local readinteger1=streams.readinteger1 + local readinteger2=streams.readinteger2 + local readinteger3=streams.readinteger3 + local readinteger4=streams.readinteger4 + function streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end + return t + end end @@ -8150,156 +8684,168 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sto"] = package.loaded["util-sto"] or true --- original size: 6449, stripped down to: 3069 +-- original size: 6661, stripped down to: 3074 if not modules then modules={} end modules ['util-sto']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local setmetatable,getmetatable,rawset,type=setmetatable,getmetatable,rawset,type utilities=utilities or {} utilities.storage=utilities.storage or {} local storage=utilities.storage function storage.mark(t) - if not t then - print("\nfatal error: storage cannot be marked\n") - os.exit() - return - end - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + if not t then + print("\nfatal error: storage cannot be marked\n") + os.exit() + return + end + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.allocate(t) - t=t or {} - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + t=t or {} + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.marked(t) - local m=getmetatable(t) - return m and m.__storage__ + local m=getmetatable(t) + return m and m.__storage__ end function storage.checked(t) - if not t then - report("\nfatal error: storage has not been allocated\n") - os.exit() - return - end - return t + if not t then + report("\nfatal error: storage has not been allocated\n") + os.exit() + return + end + return t end function storage.setinitializer(data,initialize) - local m=getmetatable(data) or {} - m.__index=function(data,k) - m.__index=nil - initialize() - return data[k] - end - setmetatable(data,m) + local m=getmetatable(data) or {} + m.__index=function(data,k) + m.__index=nil + initialize() + return data[k] + end + setmetatable(data,m) end local keyisvalue={ __index=function(t,k) - t[k]=k - return k + t[k]=k + return k end } function storage.sparse(t) - t=t or {} - setmetatable(t,keyisvalue) - return t -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 + t=t or {} + setmetatable(t,keyisvalue) + return t +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 f_index={ - ["empty"]=f_empty, - ["self"]=f_self, - ["table"]=f_table, - ["number"]=f_number, + ["empty"]=f_empty, + ["self"]=f_self, + ["table"]=f_table, + ["number"]=f_number, } function table.setmetatableindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - else - setmetatable(t,{ __index=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + else + setmetatable(t,{ __index=i }) + end + return t end local f_index={ - ["ignore"]=f_ignore, + ["ignore"]=f_ignore, } function table.setmetatablenewindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__newindex=i - else - setmetatable(t,{ __newindex=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__newindex=i + else + setmetatable(t,{ __newindex=i }) + end + return t end function table.setmetatablecall(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - if m then - m.__call=f - else - setmetatable(t,{ __call=f }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + if m then + m.__call=f + else + setmetatable(t,{ __call=f }) + end + return t end function table.setmetatableindices(t,f,n,c) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - m.__newindex=n - m.__call=c - else - setmetatable(t,{ - __index=i, - __newindex=n, - __call=c, - }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + m.__newindex=n + m.__call=c + else + setmetatable(t,{ + __index=i, + __newindex=n, + __call=c, + }) + end + return t end function table.setmetatablekey(t,key,value) - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m[key]=value - return t + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m[key]=value + return t end function table.getmetatablekey(t,key,value) - local m=getmetatable(t) - return m and m[key] + local m=getmetatable(t) + return m and m[key] +end +function table.makeweak(t) + if not t then + t={} + end + local m=getmetatable(t) + if m then + m.__mode="v" + else + setmetatable(t,{ __mode="v" }) + end + return t end @@ -8309,14 +8855,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-prs"] = package.loaded["util-prs"] or true --- original size: 22956, stripped down to: 16106 +-- original size: 23460, stripped down to: 15834 if not modules then modules={} end modules ['util-prs']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } 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 @@ -8338,6 +8884,7 @@ utilities.parsers.hashes=hashes local digit=R("09") local space=P(' ') local equal=P("=") +local colon=P(":") local comma=P(",") local lbrace=P("{") local rbrace=P("}") @@ -8357,8 +8904,8 @@ local noparent=1-(lparent+rparent) local nobracket=1-(lbracket+rbracket) local escape,left,right=P("\\"),P('{'),P('}') lpegpatterns.balanced=P { - [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, - [2]=left*V(1)*right + [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, + [2]=left*V(1)*right } local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace } local nestedparents=P { lparent*(noparent+V(1))^0*rparent } @@ -8366,311 +8913,329 @@ local nestedbrackets=P { lbracket*(nobracket+V(1))^0*rbracket } local spaces=space^0 local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/"")) local content=(1-endofstring)^0 -lpegpatterns.nestedbraces=nestedbraces +lpegpatterns.nestedbraces=nestedbraces lpegpatterns.nestedparents=nestedparents -lpegpatterns.nested=nestedbraces +lpegpatterns.nested=nestedbraces lpegpatterns.argument=argument lpegpatterns.content=content -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local key=C((1-equal-comma)^1) local pattern_a=(space+comma)^0*(key*equal*value+key*C("")) local pattern_c=(space+comma)^0*(key*equal*value) +local pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C("")) local key=C((1-space-equal-comma)^1) local pattern_b=spaces*comma^0*spaces*(key*((spaces*equal*spaces*value)+C(""))) local hash={} local function set(key,value) - hash[key]=value + hash[key]=value end local pattern_a_s=(pattern_a/set)^1 local pattern_b_s=(pattern_b/set)^1 local pattern_c_s=(pattern_c/set)^1 +local pattern_d_s=(pattern_d/set)^1 patterns.settings_to_hash_a=pattern_a_s patterns.settings_to_hash_b=pattern_b_s patterns.settings_to_hash_c=pattern_c_s +patterns.settings_to_hash_d=pattern_d_s function parsers.make_settings_to_hash_pattern(set,how) - if how=="strict" then - return (pattern_c/set)^1 - elseif how=="tolerant" then - return (pattern_b/set)^1 - else - return (pattern_a/set)^1 - end + if how=="strict" then + return (pattern_c/set)^1 + elseif how=="tolerant" then + return (pattern_b/set)^1 + else + return (pattern_a/set)^1 + end end function parsers.settings_to_hash(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_a_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_a_s,str) + return hash + end +end +function parsers.settings_to_hash_colon_too(str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + else + hash={} + lpegmatch(pattern_d_s,str) + return hash + end end function parsers.settings_to_hash_tolerant(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_b_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_b_s,str) + return hash + end end function parsers.settings_to_hash_strict(str,existing) - if not str or str=="" then - return nil - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end - elseif str and str~="" then - hash=existing or {} - lpegmatch(pattern_c_s,str) - return next(hash) and hash + if not str or str=="" then + return nil + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting + else + return str end + elseif str and str~="" then + hash=existing or {} + lpegmatch(pattern_c_s,str) + return next(hash) and hash + end end local separator=comma*space^0 -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) patterns.settings_to_array=pattern function parsers.settings_to_array(str,strict) - if not str or str=="" then - return {} - elseif type(str)=="table" then - return str - elseif strict then - if find(str,"{",1,true) then - return lpegmatch(pattern,str) - else - return { str } - end - elseif find(str,",",1,true) then - return lpegmatch(pattern,str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + elseif strict then + if find(str,"{",1,true) then + return lpegmatch(pattern,str) else - return { str } + return { str } end + elseif find(str,",",1,true) then + return lpegmatch(pattern,str) + else + return { str } + end end function parsers.settings_to_numbers(str) - if not str or str=="" then - return {} - end - if type(str)=="table" then - elseif find(str,",",1,true) then - str=lpegmatch(pattern,str) - else - return { tonumber(str) } - end - for i=1,#str do - str[i]=tonumber(str[i]) - end - return str -end -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) + if not str or str=="" then + return {} + end + if type(str)=="table" then + elseif find(str,",",1,true) then + str=lpegmatch(pattern,str) + else + return { tonumber(str) } + end + for i=1,#str do + str[i]=tonumber(str[i]) + end + return str +end +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_obey_fences(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache_a={} local cache_b={} function parsers.groupedsplitat(symbol,withaction) - if not symbol then - symbol="," - end - local pattern=(withaction and cache_b or cache_a)[symbol] - if not pattern then - local symbols=S(symbol) - local separator=space^0*symbols*space^0 - local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) - if withaction then - local withvalue=Carg(1)*value/function(f,s) return f(s) end - pattern=spaces*withvalue*(separator*withvalue)^0 - cache_b[symbol]=pattern - else - pattern=spaces*Ct(value*(separator*value)^0) - cache_a[symbol]=pattern - end - end - return pattern + if not symbol then + symbol="," + end + local pattern=(withaction and cache_b or cache_a)[symbol] + if not pattern then + local symbols=S(symbol) + local separator=space^0*symbols*space^0 + local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) + if withaction then + local withvalue=Carg(1)*value/function(f,s) return f(s) end + pattern=spaces*withvalue*(separator*withvalue)^0 + cache_b[symbol]=pattern + else + pattern=spaces*Ct(value*(separator*value)^0) + cache_a[symbol]=pattern + end + end + return pattern end local pattern_a=parsers.groupedsplitat(",",false) local pattern_b=parsers.groupedsplitat(",",true) function parsers.stripped_settings_to_array(str) - if not str or str=="" then - return {} - else - return lpegmatch(pattern_a,str) - end + 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 + if not str or str=="" then + return {} + else + return lpegmatch(pattern_b,str,1,action) + end end local function set(t,v) - t[#t+1]=v + t[#t+1]=v end local value=P(Carg(1)*value)/set local pattern=value*(separator*value)^0*Carg(1) function parsers.add_settings_to_array(t,str) - return lpegmatch(pattern,str,nil,t) + return lpegmatch(pattern,str,nil,t) end function parsers.hash_to_string(h,separator,yes,no,strict,omit) - if h then - local t,tn,s={},0,sortedkeys(h) - omit=omit and tohash(omit) - for i=1,#s do - local key=s[i] - if not omit or not omit[key] then - local value=h[key] - if type(value)=="boolean" then - if yes and no then - if value then - tn=tn+1 - t[tn]=key..'='..yes - elseif not strict then - tn=tn+1 - t[tn]=key..'='..no - end - elseif value or not strict then - tn=tn+1 - t[tn]=key..'='..tostring(value) - end - else - tn=tn+1 - t[tn]=key..'='..value - end - end + if h then + local t={} + local tn=0 + local s=sortedkeys(h) + omit=omit and tohash(omit) + for i=1,#s do + local key=s[i] + if not omit or not omit[key] then + local value=h[key] + if type(value)=="boolean" then + if yes and no then + if value then + tn=tn+1 + t[tn]=key..'='..yes + elseif not strict then + tn=tn+1 + t[tn]=key..'='..no + end + elseif value or not strict then + tn=tn+1 + t[tn]=key..'='..tostring(value) + end + else + tn=tn+1 + t[tn]=key..'='..value end - return concat(t,separator or ",") - else - return "" + end end + return concat(t,separator or ",") + else + return "" + end end function parsers.array_to_string(a,separator) - if a then - return concat(a,separator or ",") - else - return "" - end + if a then + return concat(a,separator or ",") + else + return "" + end end local pattern=Cf(Ct("")*Cg(C((1-S(", "))^1)*S(", ")^0*Cc(true))^1,rawset) function utilities.parsers.settings_to_set(str) - return str and lpegmatch(pattern,str) or {} + return str and lpegmatch(pattern,str) or {} end hashes.settings_to_set=table.setmetatableindex(function(t,k) - local v=k and lpegmatch(pattern,k) or {} - t[k]=v - return v + local v=k and lpegmatch(pattern,k) or {} + t[k]=v + return v end) getmetatable(hashes.settings_to_set).__mode="kv" function parsers.simple_hash_to_string(h,separator) - local t,tn={},0 - for k,v in sortedhash(h) do - if v then - tn=tn+1 - t[tn]=k - end + local t={} + local tn=0 + for k,v in sortedhash(h) do + if v then + tn=tn+1 + t[tn]=k end - return concat(t,separator or ",") + end + return concat(t,separator or ",") end local str=Cs(lpegpatterns.unquoted)+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 {} + return str and lpegmatch(splitter,str,1,target or {}) or {} end local splitter=lpeg.tsplitat(" ") function utilities.parsers.options_to_array(str) - return str and lpegmatch(splitter,str) or {} + return str and lpegmatch(splitter,str) 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) - if not n then - return str + if not n then + return str + else + local s=lpegmatch(pattern_a,str) + if n==1 then + return unpack(s) else - local s=lpegmatch(pattern_a,str) - if n==1 then - return unpack(s) - else - local t,tn={},0 - for i=1,n do - for j=1,#s do - tn=tn+1 - t[tn]=s[j] - end - end - return unpack(t) + local t={} + local tn=0 + for i=1,n do + for j=1,#s do + tn=tn+1 + t[tn]=s[j] end + end + return unpack(t) end + end end local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+(C(digit^1)/tonumber*lparent*Cs((noparent+nestedparents)^1)*rparent)/repeater+C((nestedbraces+(1-comma))^1) local pattern_b=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_with_repeat(str,expand) - if expand then - return lpegmatch(pattern_b,str) or {} - else - return lpegmatch(pattern_a,str) or {} - end + if expand then + return lpegmatch(pattern_b,str) or {} + else + return lpegmatch(pattern_a,str) or {} + end end local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace local pattern=Ct((space+value)^0) function parsers.arguments_to_table(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function parsers.getparameters(self,class,parentclass,settings) - local sc=self[class] - if not sc then - sc={} - self[class]=sc - if parentclass then - local sp=self[parentclass] - if not sp then - sp={} - self[parentclass]=sp - end - setmetatableindex(sc,sp) - end + local sc=self[class] + if not sc then + sc={} + self[class]=sc + if parentclass then + local sp=self[parentclass] + if not sp then + sp={} + self[parentclass]=sp + end + setmetatableindex(sc,sp) end - parsers.settings_to_hash(settings,sc) + end + parsers.settings_to_hash(settings,sc) end function parsers.listitem(str) - return gmatch(str,"[^, ]+") + return gmatch(str,"[^, ]+") end local pattern=Cs { "start", - start=V("one")+V("two")+V("three"), - rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, - thousand=digit*digit*digit, - one=digit*V("rest"), - two=digit*digit*V("rest"), - three=V("thousand")*V("rest"), + start=V("one")+V("two")+V("three"), + rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, + thousand=digit*digit*digit, + one=digit*V("rest"), + two=digit*digit*V("rest"), + three=V("thousand")*V("rest"), } lpegpatterns.splitthousands=pattern function parsers.splitthousands(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local optionalwhitespace=whitespace^0 lpegpatterns.words=Ct((Cs((1-punctuation-whitespace)^1)+anything)^1) @@ -8684,75 +9249,75 @@ local key=C((1-equal)^1) local value=dquote*C((1-dquote-escape*dquote)^0)*dquote local pattern=Cf(Ct("")*(Cg(key*equal*value)*separator^0)^1,rawset)^0*P(-1) function parsers.keq_to_hash(str) - if str and str~="" then - return lpegmatch(pattern,str) - else - return {} - end + if str and str~="" then + return lpegmatch(pattern,str) + else + return {} + end end local defaultspecification={ separator=",",quote='"' } function parsers.csvsplitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=specification.quote - local separator=S(separator~="" and separator or ",") - local whatever=C((1-separator-newline)^0) - if quotechar and quotechar~="" then - local quotedata=nil - for chr in gmatch(quotechar,".") do - local quotechar=P(chr) - local quoteword=quotechar*C((1-quotechar)^0)*quotechar - if quotedata then - quotedata=quotedata+quoteword - else - quotedata=quoteword - end - end - whatever=quotedata+whatever - end - local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) - return function(data) - return lpegmatch(parser,data) + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=specification.quote + local separator=S(separator~="" and separator or ",") + local whatever=C((1-separator-newline)^0) + if quotechar and quotechar~="" then + local quotedata=nil + for chr in gmatch(quotechar,".") do + local quotechar=P(chr) + local quoteword=quotechar*C((1-quotechar)^0)*quotechar + if quotedata then + quotedata=quotedata+quoteword + else + quotedata=quoteword + end end + whatever=quotedata+whatever + end + local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) + return function(data) + return lpegmatch(parser,data) + end end function parsers.rfc4180splitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=P(specification.quote) - local dquotechar=quotechar*quotechar + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=P(specification.quote) + local dquotechar=quotechar*quotechar /specification.quote - 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+Cc("") - local record=Ct(field*(separator*field)^1) - local headerline=record*Cp() - local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 - local headeryes=Ct(morerecords) - local headernop=Ct(record*morerecords) - return function(data,getheader) - if getheader then - local header,position=lpegmatch(headerline,data) - local data=lpegmatch(headeryes,data,position) - return data,header - else - return lpegmatch(headernop,data) - end - end + 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+Cc("") + local record=Ct(field*(separator*field)^1) + local headerline=record*Cp() + local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 + local headeryes=Ct(morerecords) + local headernop=Ct(record*morerecords) + return function(data,getheader) + if getheader then + local header,position=lpegmatch(headerline,data) + local data=lpegmatch(headeryes,data,position) + return data,header + else + return lpegmatch(headernop,data) + end + end end local function ranger(first,last,n,action) - if not first then - elseif last==true then - for i=first,n or first do - action(i) - end - elseif last then - for i=first,last do - action(i) - end - else - action(first) + if not first then + elseif last==true then + for i=first,n or first do + action(i) end + elseif last then + for i=first,last do + action(i) + end + else + action(first) + end end local cardinal=lpegpatterns.cardinal/tonumber local spacers=lpegpatterns.spacer^0 @@ -8760,89 +9325,89 @@ local endofstring=lpegpatterns.endofstring local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1 local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring function parsers.stepper(str,n,action) - if type(n)=="function" then - lpegmatch(stepper,str,1,false,n or print) - else - lpegmatch(stepper,str,1,n,action or print) - end + if type(n)=="function" then + lpegmatch(stepper,str,1,false,n or print) + else + lpegmatch(stepper,str,1,n,action or print) + end end local pattern_math=Cs((P("%")/"\\percent "+P("^")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) local pattern_text=Cs((P("%")/"\\percent "+(P("^")/"\\high")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) patterns.unittotex=pattern function parsers.unittotex(str,textmode) - return lpegmatch(textmode and pattern_text or pattern_math,str) + return lpegmatch(textmode and pattern_text or pattern_math,str) end local pattern=Cs((P("^")/"<sup>"*lpegpatterns.integer*Cc("</sup>")+anything)^0) function parsers.unittoxml(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache={} local spaces=lpegpatterns.space^0 local dummy=function() end setmetatableindex(cache,function(t,k) - local separator=P(k) - local value=(1-separator)^0 - local pattern=spaces*C(value)*separator^0*Cp() - t[k]=pattern - return pattern + local separator=P(k) + local value=(1-separator)^0 + local pattern=spaces*C(value)*separator^0*Cp() + t[k]=pattern + return pattern end) local commalistiterator=cache[","] function utilities.parsers.iterator(str,separator) - local n=#str - if n==0 then - return dummy - else - local pattern=separator and cache[separator] or commalistiterator - local p=1 - return function() - if p<=n then - local s,e=lpegmatch(pattern,str,p) - if e then - p=e - return s - end - end + local n=#str + if n==0 then + return dummy + else + local pattern=separator and cache[separator] or commalistiterator + local p=1 + return function() + if p<=n then + local s,e=lpegmatch(pattern,str,p) + if e then + p=e + return s end + end end + end end local function initialize(t,name) - local source=t[name] - if source then - local result={} - for k,v in next,t[name] do - result[k]=v - end - return result - else - return {} + local source=t[name] + if source then + local result={} + for k,v in next,t[name] do + result[k]=v end + return result + else + return {} + end end local function fetch(t,name) - return t[name] or {} + return t[name] or {} end local function process(result,more) - for k,v in next,more do - result[k]=v - end - return result + for k,v in next,more do + result[k]=v + end + return result end local name=C((1-S(", "))^1) local parser=(Carg(1)*name/initialize)*(S(", ")^1*(Carg(1)*name/fetch))^0 local merge=Cf(parser,process) function utilities.parsers.mergehashes(hash,list) - return lpegmatch(merge,list,1,hash) + 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 + 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 local spacing=whitespace^0 local apply=P("->") @@ -8850,11 +9415,11 @@ local method=C((1-apply)^1) local token=lbrace*C((1-rbrace)^1)*rbrace+C(anything^1) local pattern=spacing*(method*spacing*apply+Carg(1))*spacing*token function utilities.parsers.splitmethod(str,default) - if str then - return lpegmatch(pattern,str,1,default or false) - else - return default or false,"" - end + if str then + return lpegmatch(pattern,str,1,default or false) + else + return default or false,"" + end end @@ -8864,14 +9429,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fmt"] = package.loaded["util-fmt"] or true --- original size: 2274, stripped down to: 1781 +-- original size: 2541, stripped down to: 1624 if not modules then modules={} end modules ['util-fmt']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.formatters=utilities.formatters or {} @@ -8882,61 +9447,2887 @@ local strip=string.strip local lpegmatch=lpeg.match local stripper=lpeg.patterns.stripzeros function formatters.stripzeros(str) - return lpegmatch(stripper,str) + return lpegmatch(stripper,str) end function formatters.formatcolumns(result,between) - if result and #result>0 then - between=between or " " - local widths,numbers={},{} - local first=result[1] - local n=#first - for i=1,n do - widths[i]=0 + if result and #result>0 then + between=between or " " + local widths,numbers={},{} + local first=result[1] + local n=#first + for i=1,n do + widths[i]=0 + end + for i=1,#result do + local r=result[i] + for j=1,n do + local rj=r[j] + local tj=type(rj) + if tj=="number" then + numbers[j]=true + rj=tostring(rj) + elseif tj~="string" then + rj=tostring(rj) + r[j]=rj + end + local w=#rj + if w>widths[j] then + widths[j]=w end - for i=1,#result do - local r=result[i] - for j=1,n do - local rj=r[j] - local tj=type(rj) - if tj=="number" then - numbers[j]=true - end - if tj~="string" then - rj=tostring(rj) - r[j]=rj - end - local w=#rj - if w>widths[j] then - widths[j]=w - end + end + end + for i=1,n do + local w=widths[i] + if numbers[i] then + if w>80 then + widths[i]="%s"..between + else + widths[i]="%0"..w.."i"..between + end + else + if w>80 then + widths[i]="%s"..between + elseif w>0 then + widths[i]="%-"..w.."s"..between + else + widths[i]="%s" + end + end + end + local template=strip(concat(widths)) + for i=1,#result do + local str=format(template,unpack(result[i])) + result[i]=strip(str) + end + end + return result +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-reset"] = package.loaded["util-soc-imp-reset"] or true + +-- original size: 374, stripped down to: 282 + +local loaded=package.loaded +loaded["socket"]=nil +loaded["copas"]=nil +loaded["ltn12"]=nil +loaded["mbox"]=nil +loaded["mime"]=nil +loaded["socket.url"]=nil +loaded["socket.headers"]=nil +loaded["socket.tp"]=nil +loaded["socket.http"]=nil +loaded["socket.ftp"]=nil +loaded["socket.smtp"]=nil + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-socket"] = package.loaded["util-soc-imp-socket"] or true + +-- original size: 4870, stripped down to: 3527 + + +local type,tostring,setmetatable=type,tostring,setmetatable +local min=math.min +local format=string.format +local socket=require("socket.core") +local connect=socket.connect +local tcp4=socket.tcp4 +local tcp6=socket.tcp6 +local getaddrinfo=socket.dns.getaddrinfo +local defaulthost="0.0.0.0" +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("socket") + report(fmt,first,...) + elseif fmt then + fmt="socket: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +socket.report=report +function socket.connect4(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet") +end +function socket.connect6(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet6") +end +function socket.bind(host,port,backlog) + if host=="*" or host=="" then + host=defaulthost + end + local addrinfo,err=getaddrinfo(host) + if not addrinfo then + return nil,err + end + for i=1,#addrinfo do + local alt=addrinfo[i] + local sock,err=(alt.family=="inet" and tcp4 or tcp6)() + if not sock then + return nil,err or "unknown error" + end + sock:setoption("reuseaddr",true) + local res,err=sock:bind(alt.addr,port) + if res then + res,err=sock:listen(backlog) + if res then + return sock + else + sock:close() + end + else + sock:close() + end + end + return nil,"invalid address" +end +socket.try=socket.newtry() +function socket.choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local f=list[name or "nil"] + if f then + return f(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end +end +local sourcet={} +local sinkt={} +socket.sourcet=sourcet +socket.sinkt=sinkt +socket.BLOCKSIZE=2048 +sinkt["close-when-done"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + sock:close() + return 1 + end + end + } + ) +end +sinkt["keep-open"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + return 1 + end + end + } + ) +end +sinkt["default"]=sinkt["keep-open"] +socket.sink=socket.choose(sinkt) +sourcet["by-length"]=function(sock,length) + local blocksize=socket.BLOCKSIZE + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function() + if length<=0 then + return nil + end + local chunk,err=sock:receive(min(blocksize,length)) + if err then + return nil,err + end + length=length-#chunk + return chunk + end + } + ) +end +sourcet["until-closed"]=function(sock) + local blocksize=socket.BLOCKSIZE + local done=false + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + if done then + return nil + end + local chunk,status,partial=sock:receive(blocksize) + if not status then + return chunk + elseif status=="closed" then + sock:close() + done=true + return partial + else + return nil,status + end + end + } + ) +end +sourcet["default"]=sourcet["until-closed"] +socket.source=socket.choose(sourcet) +_G.socket=socket +package.loaded["socket"]=socket + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-copas"] = package.loaded["util-soc-imp-copas"] or true + +-- original size: 25844, stripped down to: 14821 + + +local socket=socket or require("socket") +local ssl=ssl or nil +local WATCH_DOG_TIMEOUT=120 +local UDP_DATAGRAM_MAX=8192 +local type,next,pcall,getmetatable,tostring=type,next,pcall,getmetatable,tostring +local min,max,random=math.min,math.max,math.random +local find=string.find +local insert,remove=table.insert,table.remove +local gettime=socket.gettime +local selectsocket=socket.select +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.yield +local runningcoroutine=coroutine.running +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("copas") + report(fmt,first,...) + elseif fmt then + fmt="copas: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local copas={ + _COPYRIGHT="Copyright (C) 2005-2016 Kepler Project", + _DESCRIPTION="Coroutine Oriented Portable Asynchronous Services", + _VERSION="Copas 2.0.1", + autoclose=true, + running=false, + report=report, +} +local function statushandler(status,...) + if status then + return... + end + local err=(...) + if type(err)=="table" then + err=err[1] + end + report("error: %s",tostring(err)) + return nil,err +end +function socket.protect(func) + return function(...) + return statushandler(pcall(func,...)) + end +end +function socket.newtry(finalizer) + return function (...) + local status=(...) + if not status then + local detail=select(2,...) + pcall(finalizer,detail) + report("error: %s",tostring(detail)) + return + end + return... + end +end +local function newset() + local reverse={} + local set={} + local queue={} + setmetatable(set,{ + __index={ + insert=function(set,value) + if not reverse[value] then + local n=#set+1 + set[n]=value + reverse[value]=n + end + end, + remove=function(set,value) + local index=reverse[value] + if index then + reverse[value]=nil + local n=#set + local top=set[n] + set[n]=nil + if top~=value then + reverse[top]=index + set[index]=top end + end + end, + push=function (set,key,itm) + local entry=queue[key] + if entry==nil then + queue[key]={ itm } + else + entry[#entry+1]=itm + end + end, + pop=function (set,key) + local top=queue[key] + if top~=nil then + local ret=remove(top,1) + if top[1]==nil then + queue[key]=nil + end + return ret + end end - for i=1,n do - local w=widths[i] - if numbers[i] then - if w>80 then - widths[i]="%s"..between - else - widths[i]="%0"..w.."i"..between - end - else - if w>80 then - widths[i]="%s"..between - elseif w>0 then - widths[i]="%-"..w.."s"..between - else - widths[i]="%s" - end + } + } ) + return set +end +local _sleeping={ + times={}, + cos={}, + lethargy={}, + insert=function() + end, + remove=function() + end, + push=function(self,sleeptime,co) + if not co then + return + end + if sleeptime<0 then + self.lethargy[co]=true + return + else + sleeptime=gettime()+sleeptime + end + local t=self.times + local c=self.cos + local i=1 + local n=#t + while i<=n and t[i]<=sleeptime do + i=i+1 + end + insert(t,i,sleeptime) + insert(c,i,co) + end, + getnext= + function(self) + local t=self.times + local delay=t[1] and t[1]-gettime() or nil + return delay and max(delay,0) or nil + end, + pop= + function(self,time) + local t=self.times + local c=self.cos + if #t==0 or time<t[1] then + return + end + local co=c[1] + remove(t,1) + remove(c,1) + return co + end, + wakeup=function(self,co) + local let=self.lethargy + if let[co] then + self:push(0,co) + let[co]=nil + else + local c=self.cos + local t=self.times + for i=1,#c do + if c[i]==co then + remove(c,i) + remove(t,i) + self:push(0,co) + return end + end end - local template=strip(concat(widths)) - for i=1,#result do - local str=format(template,unpack(result[i])) - result[i]=strip(str) + end +} +local _servers=newset() +local _reading=newset() +local _writing=newset() +local _reading_log={} +local _writing_log={} +local _is_timeout={ + timeout=true, + wantread=true, + wantwrite=true, +} +local function isTCP(socket) + return not find(tostring(socket),"^udp") +end +local function copasreceive(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local current_log=_reading_log + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (not _is_timeout[err]) then + current_log[client]=nil + return s,err,part + end + if err=="wantwrite" then + current_log=_writing_log + current_log[client]=gettime() + yieldcoroutine(client,_writing) + else + current_log=_reading_log + current_log[client]=gettime() + yieldcoroutine(client,_reading) + end + until false +end +local function copasreceivefrom(client,size) + local s,err,port + if not size or size==0 then + size=UDP_DATAGRAM_MAX + end + repeat + s,err,port=client:receivefrom(size) + if s or err~="timeout" then + _reading_log[client]=nil + return s,err,port + end + _reading_log[client]=gettime() + yieldcoroutine(client,_reading) + until false +end +local function copasreceivepartial(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local logger=_reading_log + local queue=_reading + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (type(pattern)=="number" and part~="" and part) or not _is_timeout[err] then + logger[client]=nil + return s,err,part + end + if err=="wantwrite" then + logger=_writing_log + queue=_writing + else + logger=_reading_log + queue=_reading + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassend(client,data,from,to) + if not from then + from=1 + end + local lastIndex=from-1 + local logger=_writing_log + local queue=_writing + local s,err + repeat + s,err,lastIndex=client:send(data,lastIndex+1,to) + if random(100)>90 then + logger[client]=gettime() + yieldcoroutine(client,queue) + end + if s or not _is_timeout[err] then + logger[client]=nil + return s,err,lastIndex + end + if err=="wantread" then + logger=_reading_log + queue=_reading + else + logger=_writing_log + queue=_writing + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassendto(client,data,ip,port) + repeat + local s,err=client:sendto(data,ip,port) + if random(100)>90 then + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + end + if s or err~="timeout" then + _writing_log[client]=nil + return s,err + end + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + until false +end +local function copasconnect(skt,host,port) + skt:settimeout(0) + local ret,err,tried_more_than_once + repeat + ret,err=skt:connect (host,port) + if ret or (err~="timeout" and err~="Operation already in progress") then + if not ret and err=="already connected" and tried_more_than_once then + ret=1 + err=nil + end + _writing_log[skt]=nil + return ret,err + end + tried_more_than_once=tried_more_than_once or true + _writing_log[skt]=gettime() + yieldcoroutine(skt,_writing) + until false +end +local function copasdohandshake(skt,sslt) + if not ssl then + ssl=require("ssl") + end + if not ssl then + report("error: no ssl library") + return + end + local nskt,err=ssl.wrap(skt,sslt) + if not nskt then + report("error: %s",tostring(err)) + return + end + nskt:settimeout(0) + local queue + repeat + local success,err=nskt:dohandshake() + if success then + return nskt + elseif err=="wantwrite" then + queue=_writing + elseif err=="wantread" then + queue=_reading + else + report("error: %s",tostring(err)) + return + end + yieldcoroutine(nskt,queue) + until false +end +local function copasflush(client) +end +copas.connect=copassconnect +copas.send=copassend +copas.sendto=copassendto +copas.receive=copasreceive +copas.receivefrom=copasreceivefrom +copas.copasreceivepartial=copasreceivepartial +copas.copasreceivePartial=copasreceivepartial +copas.dohandshake=copasdohandshake +copas.flush=copasflush +local function _skt_mt_tostring(self) + return tostring(self.socket).." (copas wrapped)" +end +local _skt_mt_tcp_index={ + send=function(self,data,from,to) + return copassend (self.socket,data,from,to) + end, + receive=function (self,pattern,prefix) + if self.timeout==0 then + return copasreceivePartial(self.socket,pattern,prefix) + else + return copasreceive(self.socket,pattern,prefix) + end + end, + flush=function (self) + return copasflush(self.socket) + end, + settimeout=function (self,time) + self.timeout=time + return true + end, + connect=function(self,...) + local res,err=copasconnect(self.socket,...) + if res and self.ssl_params then + res,err=self:dohandshake() + end + return res,err + end, + close=function(self,...) + return self.socket:close(...) + end, + bind=function(self,...) + return self.socket:bind(...) + end, + getsockname=function(self,...) + return self.socket:getsockname(...) + end, + getstats=function(self,...) + return self.socket:getstats(...) + end, + setstats=function(self,...) + return self.socket:setstats(...) + end, + listen=function(self,...) + return self.socket:listen(...) + end, + accept=function(self,...) + return self.socket:accept(...) + end, + setoption=function(self,...) + return self.socket:setoption(...) + end, + getpeername=function(self,...) + return self.socket:getpeername(...) + end, + shutdown=function(self,...) + return self.socket:shutdown(...) + end, + dohandshake=function(self,sslt) + self.ssl_params=sslt or self.ssl_params + local nskt,err=copasdohandshake(self.socket,self.ssl_params) + if not nskt then + return nskt,err + end + self.socket=nskt + return self + end, +} +local _skt_mt_tcp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_tcp_index, +} +local _skt_mt_udp_index={ + sendto=function (self,...) + return copassendto(self.socket,...) + end, + receive=function (self,size) + return copasreceive(self.socket,size or UDP_DATAGRAM_MAX) + end, + receivefrom=function (self,size) + return copasreceivefrom(self.socket,size or UDP_DATAGRAM_MAX) + end, + setpeername=function(self,...) + return self.socket:getpeername(...) + end, + setsockname=function(self,...) + return self.socket:setsockname(...) + end, + close=function(self,...) + return true + end +} +local _skt_mt_udp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_udp_index, +} +for k,v in next,_skt_mt_tcp_index do + if not _skt_mt_udp_index[k] then + _skt_mt_udp_index[k]=v + end +end +local function wrap(skt,sslt) + if getmetatable(skt)==_skt_mt_tcp or getmetatable(skt)==_skt_mt_udp then + return skt + end + skt:settimeout(0) + if isTCP(skt) then + return setmetatable ({ socket=skt,ssl_params=sslt },_skt_mt_tcp) + else + return setmetatable ({ socket=skt },_skt_mt_udp) + end +end +copas.wrap=wrap +function copas.handler(handler,sslparams) + return function (skt,...) + skt=wrap(skt) + if sslparams then + skt:dohandshake(sslparams) + end + return handler(skt,...) + end +end +local _errhandlers={} +function copas.setErrorHandler(err) + local co=runningcoroutine() + if co then + _errhandlers[co]=err + end +end +local function _deferror (msg,co,skt) + report("%s (%s) (%s)",msg,tostring(co),tostring(skt)) +end +local function _doTick (co,skt,...) + if not co then + return + end + local ok,res,new_q=resumecoroutine(co,skt,...) + if ok and res and new_q then + new_q:insert(res) + new_q:push(res,co) + else + if not ok then + pcall(_errhandlers[co] or _deferror,res,co,skt) + end + if skt and copas.autoclose and isTCP(skt) then + skt:close() + end + _errhandlers[co]=nil + end +end +local function _accept(input,handler) + local client=input:accept() + if client then + client:settimeout(0) + local co=createcoroutine(handler) + _doTick (co,client) + end + return client +end +local function _tickRead(skt) + _doTick(_reading:pop(skt),skt) +end +local function _tickWrite(skt) + _doTick(_writing:pop(skt),skt) +end +local function addTCPserver(server,handler,timeout) + server:settimeout(timeout or 0) + _servers[server]=handler + _reading:insert(server) +end +local function addUDPserver(server,handler,timeout) + server:settimeout(timeout or 0) + local co=createcoroutine(handler) + _reading:insert(server) + _doTick(co,server) +end +function copas.addserver(server,handler,timeout) + if isTCP(server) then + addTCPserver(server,handler,timeout) + else + addUDPserver(server,handler,timeout) + end +end +function copas.removeserver(server,keep_open) + local s=server + local mt=getmetatable(server) + if mt==_skt_mt_tcp or mt==_skt_mt_udp then + s=server.socket + end + _servers[s]=nil + _reading:remove(s) + if keep_open then + return true + end + return server:close() +end +function copas.addthread(handler,...) + local thread=createcoroutine(function(_,...) return handler(...) end) + _doTick(thread,nil,...) + return thread +end +local _tasks={} +local function addtaskRead(task) + task.def_tick=_tickRead + _tasks[task]=true +end +local function addtaskWrite(task) + task.def_tick=_tickWrite + _tasks[task]=true +end +local function tasks() + return next,_tasks +end +local _readable_t={ + events=function(self) + local i=0 + return function () + i=i+1 + return self._evs[i] + end + end, + tick=function(self,input) + local handler=_servers[input] + if handler then + input=_accept(input,handler) + else + _reading:remove(input) + self.def_tick(input) + end + end +} +addtaskRead(_readable_t) +local _writable_t={ + events=function(self) + local i=0 + return function() + i=i+1 + return self._evs[i] + end + end, + tick=function(self,output) + _writing:remove(output) + self.def_tick(output) + end +} +addtaskWrite(_writable_t) +local _sleeping_t={ + tick=function(self,time,...) + _doTick(_sleeping:pop(time),...) + end +} +function copas.sleep(sleeptime) + yieldcoroutine((sleeptime or 0),_sleeping) +end +function copas.wakeup(co) + _sleeping:wakeup(co) +end +local last_cleansing=0 +local function _select(timeout) + local now=gettime() + local r_evs,w_evs,err=selectsocket(_reading,_writing,timeout) + _readable_t._evs=r_evs + _writable_t._evs=w_evs + if (last_cleansing-now)>WATCH_DOG_TIMEOUT then + last_cleansing=now + for skt,time in next,_reading_log do + if not r_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#r_evs+1 + _reading_log[skt]=nil + r_evs[n]=skt + r_evs[skt]=n + end + end + for skt,time in next,_writing_log do + if not w_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#w_evs+1 + _writing_log[skt]=nil + w_evs[n]=skt + w_evs[skt]=n + end + end + end + if err=="timeout" and #r_evs+#w_evs>0 then + return nil + else + return err + end +end +local function copasfinished() + return not (next(_reading) or next(_writing) or _sleeping:getnext()) +end +local function copasstep(timeout) + _sleeping_t:tick(gettime()) + local nextwait=_sleeping:getnext() + if nextwait then + timeout=timeout and min(nextwait,timeout) or nextwait + elseif copasfinished() then + return false + end + local err=_select(timeout) + if err then + if err=="timeout" then + return false + end + return nil,err + end + for task in tasks() do + for event in task:events() do + task:tick(event) + end + end + return true +end +copas.finished=copasfinished +copas.step=copasstep +function copas.loop(timeout) + copas.running=true + while not copasfinished() do + copasstep(timeout) + end + copas.running=false +end +package.loaded["copas"]=copas + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ltn12"] = package.loaded["util-soc-imp-ltn12"] or true + +-- original size: 8709, stripped down to: 5411 + + +local select,unpack=select,unpack +local insert,remove=table.insert,table.remove +local sub=string.sub +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("ltn12") + report(fmt,first,...) + elseif fmt then + fmt="ltn12: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local filter={} +local source={} +local sink={} +local pump={} +local ltn12={ + _VERSION="LTN12 1.0.3", + BLOCKSIZE=2048, + filter=filter, + source=source, + sink=sink, + pump=pump, + report=report, +} +function filter.cycle(low,ctx,extra) + if low then + return function(chunk) + return (low(ctx,chunk,extra)) + end + end +end +function filter.chain(...) + local arg={... } + local n=select('#',...) + local top=1 + local index=1 + local retry="" + return function(chunk) + retry=chunk and retry + while true do + local action=arg[index] + if index==top then + chunk=action(chunk) + if chunk=="" or top==n then + return chunk + elseif chunk then + index=index+1 + else + top=top+1 + index=top + end + else + chunk=action(chunk or "") + if chunk=="" then + index=index-1 + chunk=retry + elseif chunk then + if index==n then + return chunk + else + index=index+1 + end + else + report("error: filter returned inappropriate 'nil'") + return end + end end - return result + end +end +local function empty() + return nil +end +function source.empty() + return empty +end +local function sourceerror(err) + return function() + return nil,err + end +end +source.error=sourceerror +function source.file(handle,io_err) + if handle then + local blocksize=ltn12.BLOCKSIZE + return function() + local chunk=handle:read(blocksize) + if not chunk then + handle:close() + end + return chunk + end + else + return sourceerror(io_err or "unable to open file") + end +end +function source.simplify(src) + return function() + local chunk,err_or_new=src() + if err_or_new then + src=err_or_new + end + if chunk then + return chunk + else + return nil,err_or_new + end + end +end +function source.string(s) + if s then + local blocksize=ltn12.BLOCKSIZE + local i=1 + return function() + local nexti=i+blocksize + local chunk=sub(s,i,nexti-1) + i=nexti + if chunk~="" then + return chunk + else + return nil + end + end + else return source.empty() end +end +function source.rewind(src) + local t={} + return function(chunk) + if chunk then + insert(t,chunk) + else + chunk=remove(t) + if chunk then + return chunk + else + return src() + end + end + end +end +function source.chain(src,f,...) + if... then + f=filter.chain(f,...) + end + local last_in="" + local last_out="" + local state="feeding" + local err + return function() + if not last_out then + report("error: source is empty") + return + end + while true do + if state=="feeding" then + last_in,err=src() + if err then + return nil,err + end + last_out=f(last_in) + if not last_out then + if last_in then + report("error: filter returned inappropriate 'nil'") + end + return nil + elseif last_out~="" then + state="eating" + if last_in then + last_in="" + end + return last_out + end + else + last_out=f(last_in) + if last_out=="" then + if last_in=="" then + state="feeding" + else + report("error: filter returned nothing") + return + end + elseif not last_out then + if last_in then + report("filter returned inappropriate 'nil'") + end + return nil + else + return last_out + end + end + end + end +end +function source.cat(...) + local arg={... } + local src=remove(arg,1) + return function() + while src do + local chunk,err=src() + if chunk then + return chunk + end + if err then + return nil,err + end + src=remove(arg,1) + end + end +end +function sink.table(t) + if not t then + t={} + end + local f=function(chunk,err) + if chunk then + insert(t,chunk) + end + return 1 + end + return f,t +end +function sink.simplify(snk) + return function(chunk,err) + local ret,err_or_new=snk(chunk,err) + if not ret then + return nil,err_or_new + end + if err_or_new then + snk=err_or_new + end + return 1 + end +end +local function null() + return 1 +end +function sink.null() + return null +end +local function sinkerror(err) + return function() + return nil,err + end +end +sink.error=sinkerror +function sink.file(handle,io_err) + if handle then + return function(chunk,err) + if not chunk then + handle:close() + return 1 + else + return handle:write(chunk) + end + end + else + return sinkerror(io_err or "unable to open file") + end +end +function sink.chain(f,snk,...) + if... then + local args={ f,snk,... } + snk=remove(args,#args) + f=filter.chain(unpack(args)) + end + return function(chunk,err) + if chunk~="" then + local filtered=f(chunk) + local done=chunk and "" + while true do + local ret,snkerr=snk(filtered,err) + if not ret then + return nil,snkerr + end + if filtered==done then + return 1 + end + filtered=f(done) + end + else + return 1 + end + end +end +function pump.step(src,snk) + local chunk,src_err=src() + local ret,snk_err=snk(chunk,src_err) + if chunk and ret then + return 1 + else + return nil,src_err or snk_err + end +end +function pump.all(src,snk,step) + if not step then + step=pump.step + end + while true do + local ret,err=step(src,snk) + if not ret then + if err then + return nil,err + else + return 1 + end + end + end +end +package.loaded["ltn12"]=ltn12 + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-mime"] = package.loaded["util-soc-imp-mime"] or true + +-- original size: 2328, stripped down to: 1874 + + +local type,tostring=type,tostring +local mime=require("mime.core") +local ltn12=ltn12 or require("ltn12") +local filtercycle=ltn12.filter.cycle +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("mime") + report(fmt,first,...) + elseif fmt then + fmt="mime: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +mime.report=report +local encodet={} +local decodet={} +local wrapt={} +mime.encodet=encodet +mime.decodet=decodet +mime.wrapt=wrapt +local mime_b64=mime.b64 +local mime_qp=mime.qp +local mime_unb64=mime.unb64 +local mime_unqp=mime.unqp +local mime_wrp=mime.wrp +local mime_qpwrp=mime.qpwrp +local mime_eol=mime_eol +local mime_dot=mime_dot +encodet['base64']=function() + return filtercycle(mime_b64,"") +end +encodet['quoted-printable']=function(mode) + return filtercycle(mime_qp,"",mode=="binary" and "=0D=0A" or "\r\n") +end +decodet['base64']=function() + return filtercycle(mime_unb64,"") +end +decodet['quoted-printable']=function() + return filtercycle(mime_unqp,"") +end +local wraptext=function(length) + if not length then + length=76 + end + return filtercycle(mime_wrp,length,length) +end +local wrapquoted=function() + return filtercycle(mime_qpwrp,76,76) +end +wrapt['text']=wraptext +wrapt['base64']=wraptext +wrapt['default']=wraptext +wrapt['quoted-printable']=wrapquoted +function mime.normalize(marker) + return filtercycle(mime_eol,0,marker) +end +function mime.stuff() + return filtercycle(mime_dot,2) +end +local function choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local filter=list[name or "nil"] + if filter then + return filter(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end end +mime.encode=choose(encodet) +mime.decode=choose(decodet) +mime.wrap=choose(wrapt) +package.loaded["mime"]=mime + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-url"] = package.loaded["util-soc-imp-url"] or true + +-- original size: 6863, stripped down to: 5269 + + +local tonumber,tostring,type=tonumber,tostring,type +local gsub,sub,match,find,format,byte,char=string.gsub,string.sub,string.match,string.find,string.format,string.byte,string.char +local insert=table.insert +local socket=socket or require("socket") +local url={ + _VERSION="URL 1.0.3", +} +socket.url=url +function url.escape(s) + return (gsub(s,"([^A-Za-z0-9_])",function(c) + return format("%%%02x",byte(c)) + end)) +end +local function make_set(t) + local s={} + for i=1,#t do + s[t[i]]=true + end + return s +end +local segment_set=make_set { + "-","_",".","!","~","*","'","(", + ")",":","@","&","=","+","$",",", +} +local function protect_segment(s) + return gsub(s,"([^A-Za-z0-9_])",function(c) + if segment_set[c] then + return c + else + return format("%%%02X",byte(c)) + end + end) +end +function url.unescape(s) + return (gsub(s,"%%(%x%x)",function(hex) + return char(tonumber(hex,16)) + end)) +end +local function absolute_path(base_path,relative_path) + if find(relative_path,"^/") then + return relative_path + end + local path=gsub(base_path,"[^/]*$","") + path=path..relative_path + path=gsub(path,"([^/]*%./)",function (s) + if s~="./" then + return s + else + return "" + end + end) + path=gsub(path,"/%.$","/") + local reduced + while reduced~=path do + reduced=path + path=gsub(reduced,"([^/]*/%.%./)",function (s) + if s~="../../" then + return "" + else + return s + end + end) + end + path=gsub(reduced,"([^/]*/%.%.)$",function (s) + if s~="../.." then + return "" + else + return s + end + end) + return path +end +function url.parse(url,default) + local parsed={} + for k,v in next,default or parsed do + parsed[k]=v + end + if not url or url=="" then + return nil,"invalid url" + end + url=gsub(url,"#(.*)$",function(f) + parsed.fragment=f + return "" + end) + url=gsub(url,"^([%w][%w%+%-%.]*)%:",function(s) + parsed.scheme=s + return "" + end) + url=gsub(url,"^//([^/]*)",function(n) + parsed.authority=n + return "" + end) + url=gsub(url,"%?(.*)",function(q) + parsed.query=q + return "" + end) + url=gsub(url,"%;(.*)",function(p) + parsed.params=p + return "" + end) + if url~="" then + parsed.path=url + end + local authority=parsed.authority + if not authority then + return parsed + end + authority=gsub(authority,"^([^@]*)@",function(u) + parsed.userinfo=u + return "" + end) + authority=gsub(authority,":([^:%]]*)$",function(p) + parsed.port=p + return "" + end) + if authority~="" then + parsed.host=match(authority,"^%[(.+)%]$") or authority + end + local userinfo=parsed.userinfo + if not userinfo then + return parsed + end + userinfo=gsub(userinfo,":([^:]*)$",function(p) + parsed.password=p + return "" + end) + parsed.user=userinfo + return parsed +end +function url.build(parsed) + local url=parsed.path or "" + if parsed.params then + url=url..";"..parsed.params + end + if parsed.query then + url=url.."?"..parsed.query + end + local authority=parsed.authority + if parsed.host then + authority=parsed.host + if find(authority,":") then + authority="["..authority.."]" + end + if parsed.port then + authority=authority..":"..tostring(parsed.port) + end + local userinfo=parsed.userinfo + if parsed.user then + userinfo=parsed.user + if parsed.password then + userinfo=userinfo..":"..parsed.password + end + end + if userinfo then authority=userinfo.."@"..authority end + end + if authority then + url="//"..authority..url + end + if parsed.scheme then + url=parsed.scheme..":"..url + end + if parsed.fragment then + url=url.."#"..parsed.fragment + end + return url +end +function url.absolute(base_url,relative_url) + local base_parsed + if type(base_url)=="table" then + base_parsed=base_url + base_url=url.build(base_parsed) + else + base_parsed=url.parse(base_url) + end + local relative_parsed=url.parse(relative_url) + if not base_parsed then + return relative_url + elseif not relative_parsed then + return base_url + elseif relative_parsed.scheme then + return relative_url + else + relative_parsed.scheme=base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority=base_parsed.authority + if not relative_parsed.path then + relative_parsed.path=base_parsed.path + if not relative_parsed.params then + relative_parsed.params=base_parsed.params + if not relative_parsed.query then + relative_parsed.query=base_parsed.query + end + end + else + relative_parsed.path=absolute_path(base_parsed.path or "",relative_parsed.path) + end + end + return url.build(relative_parsed) + end +end +function url.parse_path(path) + local parsed={} + path=path or "" + gsub(path,"([^/]+)",function (s) + insert(parsed,s) + end) + for i=1,#parsed do + parsed[i]=url.unescape(parsed[i]) + end + if sub(path,1,1)=="/" then + parsed.is_absolute=1 + end + if sub(path,-1,-1)=="/" then + parsed.is_directory=1 + end + return parsed +end +function url.build_path(parsed,unsafe) + local path="" + local n=#parsed + if unsafe then + for i=1,n-1 do + path=path..parsed[i].."/" + end + if n>0 then + path=path..parsed[n] + if parsed.is_directory then + path=path.."/" + end + end + else + for i=1,n-1 do + path=path..protect_segment(parsed[i]).."/" + end + if n>0 then + path=path..protect_segment(parsed[n]) + if parsed.is_directory then + path=path.."/" + end + end + end + if parsed.is_absolute then + path="/"..path + end + return path +end +package.loaded["socket.url"]=url + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-headers"] = package.loaded["util-soc-imp-headers"] or true + +-- original size: 5721, stripped down to: 3754 + + +local next=next +local lower=string.lower +local concat=table.concat +local socket=socket or require("socket") +local headers={} +socket.headers=headers +local canonic={ + ["accept"]="Accept", + ["accept-charset"]="Accept-Charset", + ["accept-encoding"]="Accept-Encoding", + ["accept-language"]="Accept-Language", + ["accept-ranges"]="Accept-Ranges", + ["action"]="Action", + ["alternate-recipient"]="Alternate-Recipient", + ["age"]="Age", + ["allow"]="Allow", + ["arrival-date"]="Arrival-Date", + ["authorization"]="Authorization", + ["bcc"]="Bcc", + ["cache-control"]="Cache-Control", + ["cc"]="Cc", + ["comments"]="Comments", + ["connection"]="Connection", + ["content-description"]="Content-Description", + ["content-disposition"]="Content-Disposition", + ["content-encoding"]="Content-Encoding", + ["content-id"]="Content-ID", + ["content-language"]="Content-Language", + ["content-length"]="Content-Length", + ["content-location"]="Content-Location", + ["content-md5"]="Content-MD5", + ["content-range"]="Content-Range", + ["content-transfer-encoding"]="Content-Transfer-Encoding", + ["content-type"]="Content-Type", + ["cookie"]="Cookie", + ["date"]="Date", + ["diagnostic-code"]="Diagnostic-Code", + ["dsn-gateway"]="DSN-Gateway", + ["etag"]="ETag", + ["expect"]="Expect", + ["expires"]="Expires", + ["final-log-id"]="Final-Log-ID", + ["final-recipient"]="Final-Recipient", + ["from"]="From", + ["host"]="Host", + ["if-match"]="If-Match", + ["if-modified-since"]="If-Modified-Since", + ["if-none-match"]="If-None-Match", + ["if-range"]="If-Range", + ["if-unmodified-since"]="If-Unmodified-Since", + ["in-reply-to"]="In-Reply-To", + ["keywords"]="Keywords", + ["last-attempt-date"]="Last-Attempt-Date", + ["last-modified"]="Last-Modified", + ["location"]="Location", + ["max-forwards"]="Max-Forwards", + ["message-id"]="Message-ID", + ["mime-version"]="MIME-Version", + ["original-envelope-id"]="Original-Envelope-ID", + ["original-recipient"]="Original-Recipient", + ["pragma"]="Pragma", + ["proxy-authenticate"]="Proxy-Authenticate", + ["proxy-authorization"]="Proxy-Authorization", + ["range"]="Range", + ["received"]="Received", + ["received-from-mta"]="Received-From-MTA", + ["references"]="References", + ["referer"]="Referer", + ["remote-mta"]="Remote-MTA", + ["reply-to"]="Reply-To", + ["reporting-mta"]="Reporting-MTA", + ["resent-bcc"]="Resent-Bcc", + ["resent-cc"]="Resent-Cc", + ["resent-date"]="Resent-Date", + ["resent-from"]="Resent-From", + ["resent-message-id"]="Resent-Message-ID", + ["resent-reply-to"]="Resent-Reply-To", + ["resent-sender"]="Resent-Sender", + ["resent-to"]="Resent-To", + ["retry-after"]="Retry-After", + ["return-path"]="Return-Path", + ["sender"]="Sender", + ["server"]="Server", + ["smtp-remote-recipient"]="SMTP-Remote-Recipient", + ["status"]="Status", + ["subject"]="Subject", + ["te"]="TE", + ["to"]="To", + ["trailer"]="Trailer", + ["transfer-encoding"]="Transfer-Encoding", + ["upgrade"]="Upgrade", + ["user-agent"]="User-Agent", + ["vary"]="Vary", + ["via"]="Via", + ["warning"]="Warning", + ["will-retry-until"]="Will-Retry-Until", + ["www-authenticate"]="WWW-Authenticate", + ["x-mailer"]="X-Mailer", +} +headers.canonic=setmetatable(canonic,{ + __index=function(t,k) + socket.report("invalid header: %s",k) + t[k]=k + return k + end +}) +function headers.normalize(headers) + if not headers then + return {} + end + local normalized={} + for k,v in next,headers do + normalized[#normalized+1]=canonic[k]..": "..v + end + normalized[#normalized+1]="" + normalized[#normalized+1]="" + return concat(normalized,"\r\n") +end +function headers.lower(lowered,headers) + if not lowered then + return {} + end + if not headers then + lowered,headers={},lowered + end + for k,v in next,headers do + lowered[lower(k)]=v + end + return lowered +end +socket.headers=headers +package.loaded["socket.headers"]=headers + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-tp"] = package.loaded["util-soc-imp-tp"] or true + +-- original size: 3116, stripped down to: 2533 + + +local setmetatable,next,type,tonumber=setmetatable,next,type,tonumber +local find,upper=string.find,string.upper +local socket=socket or require("socket") +local ltn12=ltn12 or require("ltn12") +local skipsocket=socket.skip +local sinksocket=socket.sink +local tcpsocket=socket.tcp +local ltn12pump=ltn12.pump +local pumpall=ltn12pump.all +local pumpstep=ltn12pump.step +local tp={ + TIMEOUT=60, +} +socket.tp=tp +local function get_reply(c) + local line,err=c:receive() + local reply=line + if err then return + nil,err + end + local code,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + if not code then + return nil,"invalid server reply" + end + if sep=="-" then + local current + repeat + line,err=c:receive() + if err then + return nil,err + end + current,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + reply=reply.."\n"..line + until code==current and sep==" " + end + return code,reply +end +local methods={} +local mt={ __index=methods } +function methods.getpeername(self) + return self.c:getpeername() +end +function methods.getsockname(self) + return self.c:getpeername() +end +function methods.check(self,ok) + local code,reply=get_reply(self.c) + if not code then + return nil,reply + end + local c=tonumber(code) + local t=type(ok) + if t=="function" then + return ok(c,reply) + elseif t=="table" then + for i=1,#ok do + if find(code,ok[i]) then + return c,reply + end + end + return nil,reply + elseif find(code,ok) then + return c,reply + else + return nil,reply + end +end +function methods.command(self,cmd,arg) + cmd=upper(cmd) + if arg then + cmd=cmd.." "..arg.."\r\n" + else + cmd=cmd.."\r\n" + end + return self.c:send(cmd) +end +function methods.sink(self,snk,pat) + local chunk,err=self.c:receive(pat) + return snk(chunk,err) +end +function methods.send(self,data) + return self.c:send(data) +end +function methods.receive(self,pat) + return self.c:receive(pat) +end +function methods.getfd(self) + return self.c:getfd() +end +function methods.dirty(self) + return self.c:dirty() +end +function methods.getcontrol(self) + return self.c +end +function methods.source(self,source,step) + local sink=sinksocket("keep-open",self.c) + local ret,err=pumpall(source,sink,step or pumpstep) + return ret,err +end +function methods.close(self) + self.c:close() + return 1 +end +function tp.connect(host,port,timeout,create) + local c,e=(create or tcpsocket)() + if not c then + return nil,e + end + c:settimeout(timeout or tp.TIMEOUT) + local r,e=c:connect(host,port) + if not r then + c:close() + return nil,e + end + return setmetatable({ c=c },mt) +end +package.loaded["socket.tp"]=tp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-http"] = package.loaded["util-soc-imp-http"] or true + +-- original size: 12577, stripped down to: 9577 + + +local tostring,tonumber,setmetatable,next,type=tostring,tonumber,setmetatable,next,type +local find,lower,format,gsub,match=string.find,string.lower,string.format,string.gsub,string.match +local concat=table.concat +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local ltn12=ltn12 or require("ltn12") +local mime=mime or require("mime") +local headers=socket.headers or require("socket.headers") +local normalizeheaders=headers.normalize +local parseurl=url.parse +local buildurl=url.build +local absoluteurl=url.absolute +local unescapeurl=url.unescape +local skipsocket=socket.skip +local sinksocket=socket.sink +local sourcesocket=socket.source +local trysocket=socket.try +local tcpsocket=socket.tcp +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local emptysource=ltn12.source.empty +local stringsource=ltn12.source.string +local rewindsource=ltn12.source.rewind +local pumpstep=ltn12.pump.step +local pumpall=ltn12.pump.all +local sinknull=ltn12.sink.null +local sinktable=ltn12.sink.table +local lowerheaders=headers.lower +local mimeb64=mime.b64 +local http={ + TIMEOUT=60, + USERAGENT=socket._VERSION, +} +socket.http=http +local PORT=80 +local SCHEMES={ + http=true, +} +local function receiveheaders(sock,headers) + if not headers then + headers={} + end + local line,err=sock:receive() + if err then + return nil,err + end + while line~="" do + local name,value=skipsocket(2,find(line,"^(.-):%s*(.*)")) + if not (name and value) then + return nil,"malformed reponse headers" + end + name=lower(name) + line,err=sock:receive() + if err then + return nil,err + end + while find(line,"^%s") do + value=value..line + line=sock:receive() + if err then + return nil,err + end + end + local found=headers[name] + if found then + value=found..", "..value + end + headers[name]=value + end + return headers +end +socket.sourcet["http-chunked"]=function(sock,headers) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + local line,err=sock:receive() + if err then + return nil,err + end + local size=tonumber(gsub(line,";.*",""),16) + if not size then + return nil,"invalid chunk size" + end + if size>0 then + local chunk,err,part=sock:receive(size) + if chunk then + sock:receive() + end + return chunk,err + else + headers,err=receiveheaders(sock,headers) + if not headers then + return nil,err + end + end + end + } + ) +end +socket.sinkt["http-chunked"]=function(sock) + return setmetatable( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if not chunk then + chunk="" + end + return sock:send(format("%X\r\n%s\r\n",#chunk,chunk)) + end + }) +end +local methods={} +local mt={ __index=methods } +local function openhttp(host,port,create) + local c=trysocket((create or tcpsocket)()) + local h=setmetatable({ c=c },mt) + local try=newtrysocket(function() h:close() end) + h.try=try + try(c:settimeout(http.TIMEOUT)) + try(c:connect(host,port or PORT)) + return h +end +http.open=openhttp +function methods.sendrequestline(self,method,uri) + local requestline=format("%s %s HTTP/1.1\r\n",method or "GET",uri) + return self.try(self.c:send(requestline)) +end +function methods.sendheaders(self,headers) + self.try(self.c:send(normalizeheaders(headers))) + return 1 +end +function methods.sendbody(self,headers,source,step) + if not source then + source=emptysource() + end + if not step then + step=pumpstep + end + local mode="http-chunked" + if headers["content-length"] then + mode="keep-open" + end + return self.try(pumpall(source,sinksocket(mode,self.c),step)) +end +function methods.receivestatusline(self) + local try=self.try + local status=try(self.c:receive(5)) + if status~="HTTP/" then + return nil,status + end + status=try(self.c:receive("*l",status)) + local code=skipsocket(2,find(status,"HTTP/%d*%.%d* (%d%d%d)")) + return try(tonumber(code),status) +end +function methods.receiveheaders(self) + return self.try(receiveheaders(self.c)) +end +function methods.receivebody(self,headers,sink,step) + if not sink then + sink=sinknull() + end + if not step then + step=pumpstep + end + local length=tonumber(headers["content-length"]) + local encoding=headers["transfer-encoding"] + local mode="default" + if encoding and encoding~="identity" then + mode="http-chunked" + elseif length then + mode="by-length" + end + return self.try(pumpall(sourcesocket(mode,self.c,length),sink,step)) +end +function methods.receive09body(self,status,sink,step) + local source=rewindsource(sourcesocket("until-closed",self.c)) + source(status) + return self.try(pumpall(source,sink,step)) +end +function methods.close(self) + return self.c:close() +end +local function adjusturi(request) + if not request.proxy and not http.PROXY then + request={ + path=trysocket(request.path,"invalid path 'nil'"), + params=request.params, + query=request.query, + fragment=request.fragment, + } + end + return buildurl(request) +end +local function adjustheaders(request) + local headers={ + ["user-agent"]=http.USERAGENT, + ["host"]=gsub(request.authority,"^.-@",""), + ["connection"]="close, TE", + ["te"]="trailers" + } + local username=request.user + local password=request.password + if username and password then + headers["authorization"]="Basic "..(mimeb64(username..":"..unescapeurl(password))) + end + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + local username=proxy.user + local password=proxy.password + if username and password then + headers["proxy-authorization"]="Basic "..(mimeb64(username..":"..password)) + end + end + local requestheaders=request.headers + if requestheaders then + headers=lowerheaders(headers,requestheaders) + end + return headers +end +local default={ + host="", + port=PORT, + path="/", + scheme="http" +} +local function adjustrequest(originalrequest) + local url=originalrequest.url + local request=url and parseurl(url,default) or {} + for k,v in next,originalrequest do + request[k]=v + end + local host=request.host + local port=request.port + local uri=request.uri + if not host or host=="" then + trysocket(nil,"invalid host '"..tostring(host).."'") + end + if port=="" then + request.port=PORT + end + if not uri or uri=="" then + request.uri=adjusturi(request) + end + request.headers=adjustheaders(request) + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + request.host=proxy.host + request.port=proxy.port or 3128 + end + return request +end +local maxredericts=4 +local validredirects={ [301]=true,[302]=true,[303]=true,[307]=true } +local validmethods={ [false]=true,GET=true,HEAD=true } +local function shouldredirect(request,code,headers) + local location=headers.location + if not location then + return false + end + location=gsub(location,"%s","") + if location=="" then + return false + end + local scheme=match(location,"^([%w][%w%+%-%.]*)%:") + if scheme and not SCHEMES[scheme] then + return false + end + local method=request.method + local redirect=request.redirect + local redirects=request.nredirects or 0 + return redirect and validredirects[code] and validmethods[method] and redirects<=maxredericts +end +local function shouldreceivebody(request,code) + if request.method=="HEAD" then + return nil + end + if code==204 or code==304 then + return nil + end + if code>=100 and code<200 then + return nil + end + return 1 +end +local tredirect,trequest,srequest +tredirect=function(request,location) + local result,code,headers,status=trequest { + url=absoluteurl(request.url,location), + source=request.source, + sink=request.sink, + headers=request.headers, + proxy=request.proxy, + nredirects=(request.nredirects or 0)+1, + create=request.create, + } + if not headers then + headers={} + end + if not headers.location then + headers.location=location + end + return result,code,headers,status +end +trequest=function(originalrequest) + local request=adjustrequest(originalrequest) + local connection=openhttp(request.host,request.port,request.create) + local headers=request.headers + connection:sendrequestline(request.method,request.uri) + connection:sendheaders(headers) + if request.source then + connection:sendbody(headers,request.source,request.step) + end + local code,status=connection:receivestatusline() + if not code then + connection:receive09body(status,request.sink,request.step) + return 1,200 + end + while code==100 do + headers=connection:receiveheaders() + code,status=connection:receivestatusline() + end + headers=connection:receiveheaders() + if shouldredirect(request,code,headers) and not request.source then + connection:close() + return tredirect(originalrequest,headers.location) + end + if shouldreceivebody(request,code) then + connection:receivebody(headers,request.sink,request.step) + end + connection:close() + return 1,code,headers,status +end +local function genericform(url,body) + local buffer={} + local request={ + url=url, + sink=sinktable(buffer), + target=buffer, + } + if body then + request.source=stringsource(body) + request.method="POST" + request.headers={ + ["content-length"]=#body, + ["content-type"]="application/x-www-form-urlencoded" + } + end + return request +end +http.genericform=genericform +srequest=function(url,body) + local request=genericform(url,body) + local _,code,headers,status=trequest(request) + return concat(request.target),code,headers,status +end +http.request=protectsocket(function(request,body) + if type(request)=="string" then + return srequest(request,body) + else + return trequest(request) + end +end) +package.loaded["socket.http"]=http + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ftp"] = package.loaded["util-soc-imp-ftp"] or true + +-- original size: 10357, stripped down to: 8548 + + +local setmetatable,type,next=setmetatable,type,next +local find,format,gsub,match=string.find,string.format,string.gsub,string.match +local concat=table.concat +local mod=math.mod +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local tp=socket.tp or require("socket.tp") +local ltn12=ltn12 or require("ltn12") +local tcpsocket=socket.tcp +local trysocket=socket.try +local skipsocket=socket.skip +local sinksocket=socket.sink +local selectsocket=socket.select +local bindsocket=socket.bind +local newtrysocket=socket.newtry +local sourcesocket=socket.source +local protectsocket=socket.protect +local parseurl=url.parse +local unescapeurl=url.unescape +local pumpall=ltn12.pump.all +local pumpstep=ltn12.pump.step +local sourcestring=ltn12.source.string +local sinktable=ltn12.sink.table +local ftp={ + TIMEOUT=60, + USER="ftp", + PASSWORD="anonymous@anonymous.org", +} +socket.ftp=ftp +local PORT=21 +local methods={} +local mt={ __index=methods } +function ftp.open(server,port,create) + local tp=trysocket(tp.connect(server,port or PORT,ftp.TIMEOUT,create)) + local f=setmetatable({ tp=tp },metat) + f.try=newtrysocket(function() f:close() end) + return f +end +function methods.portconnect(self) + local try=self.try + local server=self.server + try(server:settimeout(ftp.TIMEOUT)) + self.data=try(server:accept()) + try(self.data:settimeout(ftp.TIMEOUT)) +end +function methods.pasvconnect(self) + local try=self.try + self.data=try(tcpsocket()) + self(self.data:settimeout(ftp.TIMEOUT)) + self(self.data:connect(self.pasvt.address,self.pasvt.port)) +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("user",user or ftp.USER)) + local code,reply=try(tp:check{"2..",331}) + if code==331 then + try(tp:command("pass",password or ftp.PASSWORD)) + try(tp:check("2..")) + end + return 1 +end +function methods.pasv(self) + local try=self.try + local tp=self.tp + try(tp:command("pasv")) + local code,reply=try(self.tp:check("2..")) + local pattern="(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a,b,c,d,p1,p2=skipsocket(2,find(reply,pattern)) + try(a and b and c and d and p1 and p2,reply) + local address=format("%d.%d.%d.%d",a,b,c,d) + local port=p1*256+p2 + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if server then + server:close() + self.server=nil + end + return address,port +end +function methods.epsv(self) + local try=self.try + local tp=self.tp + try(tp:command("epsv")) + local code,reply=try(tp:check("229")) + local pattern="%((.)(.-)%1(.-)%1(.-)%1%)" + local d,prt,address,port=match(reply,pattern) + try(port,"invalid epsv response") + local address=tp:getpeername() + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if self.server then + server:close() + self.server=nil + end + return address,port +end +function methods.port(self,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local pl=mod(port,256) + local ph=(port-pl)/256 + local arg=gsub(format("%s,%d,%d",address,ph,pl),"%.",",") + try(tp:command("port",arg)) + try(tp:check("2..")) + return 1 +end +function methods.eprt(self,family,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local arg=format("|%s|%s|%d|",family,address,port) + try(tp:command("eprt",arg)) + try(tp:check("2..")) + return 1 +end +function methods.send(self,sendt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then + self:pasvconnect() + end + local argument=sendt.argument or unescapeurl(gsub(sendt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=sendt.command or "stor" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"2..","1.."}) + if not self.pasvt then + self:portconnect() + end + local step=sendt.step or pumpstep + local readt={ tp } + local checkstep=function(src,snk) + local readyt=selectsocket(readt,nil,0) + if readyt[tp] then + code=try(tp:check("2..")) + end + return step(src,snk) + end + local sink=sinksocket("close-when-done",self.data) + try(pumpall(sendt.source,sink,checkstep)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + local sent=skipsocket(1,self.data:getstats()) + self.data=nil + return sent +end +function methods.receive(self,recvt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument=recvt.argument or unescapeurl(gsub(recvt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=recvt.command or "retr" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"1..","2.."}) + if code>=200 and code<=299 then + recvt.sink(reply) + return 1 + end + if not self.pasvt then + self:portconnect() + end + local source=sourcesocket("until-closed",self.data) + local step=recvt.step or pumpstep + try(pumpall(source,recvt.sink,step)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + self.data=nil + return 1 +end +function methods.cwd(self,dir) + local try=self.try + local tp=self.tp + try(tp:command("cwd",dir)) + try(tp:check(250)) + return 1 +end +function methods.type(self,typ) + local try=self.try + local tp=self.tp + try(tp:command("type",typ)) + try(tp:check(200)) + return 1 +end +function methods.greet(self) + local try=self.try + local tp=self.tp + local code=try(tp:check{"1..","2.."}) + if find(code,"1..") then + try(tp:check("2..")) + end + return 1 +end +function methods.quit(self) + local try=self.try + try(self.tp:command("quit")) + try(self.tp:check("2..")) + return 1 +end +function methods.close(self) + local data=self.data + if data then + data:close() + end + local server=self.server + if server then + server:close() + end + local tp=self.tp + if tp then + tp:close() + end +end +local function override(t) + if t.url then + local u=parseurl(t.url) + for k,v in next,t do + u[k]=v + end + return u + else + return t + end +end +local function tput(putt) + putt=override(putt) + local host=putt.host + trysocket(host,"missing hostname") + local f=ftp.open(host,putt.port,putt.create) + f:greet() + f:login(putt.user,putt.password) + local typ=putt.type + if typ then + f:type(typ) + end + f:epsv() + local sent=f:send(putt) + f:quit() + f:close() + return sent +end +local default={ + path="/", + scheme="ftp", +} +local function genericform(u) + local t=trysocket(parseurl(u,default)) + trysocket(t.scheme=="ftp","wrong scheme '"..t.scheme.."'") + trysocket(t.host,"missing hostname") + local pat="^type=(.)$" + if t.params then + local typ=skipsocket(2,find(t.params,pat)) + t.type=typ + trysocket(typ=="a" or typ=="i","invalid type '"..typ.."'") + end + return t +end +ftp.genericform=genericform +local function sput(u,body) + local putt=genericform(u) + putt.source=sourcestring(body) + return tput(putt) +end +ftp.put=protectsocket(function(putt,body) + if type(putt)=="string" then + return sput(putt,body) + else + return tput(putt) + end +end) +local function tget(gett) + gett=override(gett) + local host=gett.host + trysocket(host,"missing hostname") + local f=ftp.open(host,gett.port,gett.create) + f:greet() + f:login(gett.user,gett.password) + if gett.type then + f:type(gett.type) + end + f:epsv() + f:receive(gett) + f:quit() + return f:close() +end +local function sget(u) + local gett=genericform(u) + local t={} + gett.sink=sinktable(t) + tget(gett) + return concat(t) +end +ftp.command=protectsocket(function(cmdt) + cmdt=override(cmdt) + local command=cmdt.command + local argument=cmdt.argument + local check=cmdt.check + local host=cmdt.host + trysocket(host,"missing hostname") + trysocket(command,"missing command") + local f=ftp.open(host,cmdt.port,cmdt.create) + local try=f.try + local tp=f.tp + f:greet() + f:login(cmdt.user,cmdt.password) + if type(command)=="table" then + local argument=argument or {} + for i=1,#command do + local cmd=command[i] + try(tp:command(cmd,argument[i])) + if check and check[i] then + try(tp:check(check[i])) + end + end + else + try(tp:command(command,argument)) + if check then + try(tp:check(check)) + end + end + f:quit() + return f:close() +end) +ftp.get=protectsocket(function(gett) + if type(gett)=="string" then + return sget(gett) + else + return tget(gett) + end +end) +package.loaded["socket.ftp"]=ftp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-smtp"] = package.loaded["util-soc-imp-smtp"] or true + +-- original size: 7018, stripped down to: 5883 + + +local type,setmetatable,next=type,setmetatable,next +local find,lower,format=string.find,string.lower,string.format +local osdate,osgetenv=os.date,os.getenv +local random=math.random +local socket=socket or require("socket") +local headers=socket.headers or require("socket.headers") +local ltn12=ltn12 or require("ltn12") +local tp=socket.tp or require("socket.tp") +local mime=mime or require("mime") +local mimeb64=mime.b64 +local mimestuff=mime.stuff +local skipsocket=socket.skip +local trysocket=socket.try +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local normalizeheaders=headers.normalize +local lowerheaders=headers.lower +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.resume +local smtp={ + TIMEOUT=60, + SERVER="localhost", + PORT=25, + DOMAIN=osgetenv("SERVER_NAME") or "localhost", + ZONE="-0000", +} +socket.smtp=smtp +local methods={} +local mt={ __index=methods } +function methods.greet(self,domain) + local try=self.try + local tp=self.tp + try(tp:check("2..")) + try(tp:command("EHLO",domain or _M.DOMAIN)) + return skipsocket(1,try(tp:check("2.."))) +end +function methods.mail(self,from) + local try=self.try + local tp=self.tp + try(tp:command("MAIL","FROM:"..from)) + return try(tp:check("2..")) +end +function methods.rcpt(self,to) + local try=self.try + local tp=self.tp + try(tp:command("RCPT","TO:"..to)) + return try(tp:check("2..")) +end +function methods.data(self,src,step) + local try=self.try + local tp=self.tp + try(tp:command("DATA")) + try(tp:check("3..")) + try(tp:source(src,step)) + try(tp:send("\r\n.\r\n")) + return try(tp:check("2..")) +end +function methods.quit(self) + local try=self.try + local tp=self.tp + try(tp:command("QUIT")) + return try(tp:check("2..")) +end +function methods.close(self) + return self.tp:close() +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("AUTH","LOGIN")) + try(tp:check("3..")) + try(tp:send(mimeb64(user).."\r\n")) + try(tp:check("3..")) + try(tp:send(mimeb64(password).."\r\n")) + return try(tp:check("2..")) +end +function methods.plain(self,user,password) + local try=self.try + local tp=self.tp + local auth="PLAIN "..mimeb64("\0"..user.."\0"..password) + try(tp:command("AUTH",auth)) + return try(tp:check("2..")) +end +function methods.auth(self,user,password,ext) + if not user or not password then + return 1 + end + local try=self.try + if find(ext,"AUTH[^\n]+LOGIN") then + return self:login(user,password) + elseif find(ext,"AUTH[^\n]+PLAIN") then + return self:plain(user,password) + else + try(nil,"authentication not supported") + end +end +function methods.send(self,mail) + self:mail(mail.from) + local receipt=mail.rcpt + if type(receipt)=="table" then + for i=1,#receipt do + self:rcpt(receipt[i]) + end + elseif receipt then + self:rcpt(receipt) + end + self:data(ltn12.source.chain(mail.source,mimestuff()),mail.step) +end +local function opensmtp(self,server,port,create) + if not server or server=="" then + server=smtp.SERVER + end + if not port or port=="" then + port=smtp.PORT + end + local s={ + tp=trysocket(tp.connect(server,port,smtp.TIMEOUT,create)), + try=newtrysocket(function() + s:close() + end), + } + setmetatable(s,mt) + return s +end +smtp.open=opensmtp +local nofboundaries=0 +local function newboundary() + nofboundaries=nofboundaries+1 + return format('%s%05d==%05u',osdate('%d%m%Y%H%M%S'),random(0,99999),nofboundaries) +end +local send_message +local function send_headers(headers) + yieldcoroutine(normalizeheaders(headers)) +end +local function send_multipart(message) + local boundary=newboundary() + local headers=lowerheaders(message.headers) + local body=message.body + local preamble=body.preamble + local epilogue=body.epilogue + local content=headers['content-type'] or 'multipart/mixed' + headers['content-type']=content..'; boundary="'..boundary..'"' + send_headers(headers) + if preamble then + yieldcoroutine(preamble) + yieldcoroutine("\r\n") + end + for i=1,#body do + yieldcoroutine("\r\n--"..boundary.."\r\n") + send_message(body[i]) + end + yieldcoroutine("\r\n--"..boundary.."--\r\n\r\n") + if epilogue then + yieldcoroutine(epilogue) + yieldcoroutine("\r\n") + end +end +local default_content_type='text/plain; charset="UTF-8"' +local function send_source(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + local getchunk=message.body + while true do + local chunk,err=getchunk() + if err then + yieldcoroutine(nil,err) + elseif chunk then + yieldcoroutine(chunk) + else + break + end + end +end +local function send_string(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + yieldcoroutine(message.body) +end +function send_message(message) + local body=message.body + if type(body)=="table" then + send_multipart(message) + elseif type(body)=="function" then + send_source(message) + else + send_string(message) + end +end +local function adjust_headers(message) + local headers=lowerheaders(message.headers) + if not headers["date"] then + headers["date"]=osdate("!%a, %d %b %Y %H:%M:%S ")..(message.zone or smtp.ZONE) + end + if not headers["x-mailer"] then + headers["x-mailer"]=socket._VERSION + end + headers["mime-version"]="1.0" + return headers +end +function smtp.message(message) + message.headers=adjust_headers(message) + local action=createcoroutine(function() + send_message(message) + end) + return function() + local ret,a,b=resumecoroutine(action) + if ret then + return a,b + else + return nil,a + end + end +end +smtp.send=protectsocket(function(mail) + local snd=opensmtp(smtp,mail.server,mail.port,mail.create) + local ext=snd:greet(mail.domain) + snd:auth(mail.user,mail.password,ext) + snd:send(mail) + snd:quit() + return snd:close() +end) +package.loaded["socket.smtp"]=smtp end -- of closure @@ -8945,14 +12336,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-set"] = package.loaded["trac-set"] or true --- original size: 13044, stripped down to: 9231 +-- original size: 13340, stripped down to: 8826 if not modules then modules={} end modules ['trac-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber=type,next,tostring,tonumber local concat,sortedhash=table.concat,table.sortedhash @@ -8967,305 +12358,318 @@ utilities.setters=setters local data={} local trace_initialize=false function setters.initialize(filename,name,values) - local setter=data[name] - if setter then - frozen=true - local data=setter.data - if data then - for key,newvalue in sortedhash(values) do - local newvalue=is_boolean(newvalue,newvalue,true) - local functions=data[key] - if functions then - local oldvalue=functions.value - if functions.frozen then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) - end - elseif #functions>0 and not oldvalue then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) - end - for i=1,#functions do - functions[i](newvalue) - end - functions.value=newvalue - functions.frozen=functions.frozen or frozen - else - if trace_initialize then - setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) - end - end - else - functions={ default=newvalue,frozen=frozen } - data[key]=functions - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) - end - end + local setter=data[name] + if setter then + frozen=true + local data=setter.data + if data then + for key,newvalue in sortedhash(values) do + local newvalue=is_boolean(newvalue,newvalue,true) + local functions=data[key] + if functions then + local oldvalue=functions.value + if functions.frozen then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) + end + elseif #functions>0 and not oldvalue then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) + end + for i=1,#functions do + functions[i](newvalue) + end + functions.value=newvalue + functions.frozen=functions.frozen or frozen + else + if trace_initialize then + setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) end - return true + end + else + functions={ default=newvalue,frozen=frozen } + data[key]=functions + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) + end end + end + return true end + end end local function set(t,what,newvalue) - local data=t.data - if not data.frozen then - local done=t.done - if type(what)=="string" then - what=settings_to_hash(what) - end - if type(what)~="table" then - return - end - if not done then - done={} - t.done=done - end - for w,value in sortedhash(what) do - if value=="" then - value=newvalue - elseif not value then - value=false - else - value=is_boolean(value,value,true) - end - w=topattern(w,true,true) - for name,functions in sortedhash(data) do - if done[name] then - elseif find(name,w) then - done[name]=true - for i=1,#functions do - functions[i](value) - end - functions.value=value - end - end + local data=t.data + if not data.frozen then + local done=t.done + if type(what)=="string" then + what=settings_to_hash(what) + end + if type(what)~="table" then + return + end + if not done then + done={} + t.done=done + end + for w,value in sortedhash(what) do + if value=="" then + value=newvalue + elseif not value then + value=false + else + value=is_boolean(value,value,true) + end + w=topattern(w,true,true) + for name,functions in sortedhash(data) do + if done[name] then + elseif find(name,w) then + done[name]=true + for i=1,#functions do + functions[i](value) + end + functions.value=value end + end end + end end local function reset(t) - local data=t.data - if not data.frozen then - for name,functions in sortedthash(data) do - for i=1,#functions do - functions[i](false) - end - functions.value=false - end + local data=t.data + if not data.frozen then + for name,functions in sortedthash(data) do + for i=1,#functions do + functions[i](false) + end + functions.value=false end + end end local function enable(t,what) - set(t,what,true) + set(t,what,true) end local function disable(t,what) - local data=t.data - if not what or what=="" then - t.done={} - reset(t) - else - set(t,what,false) - end + local data=t.data + if not what or what=="" then + t.done={} + reset(t) + else + set(t,what,false) + end end function setters.register(t,what,...) - local data=t.data - what=lower(what) - local functions=data[what] - if not functions then - functions={} - data[what]=functions - if trace_initialize then - t.report("defining %a",what) - end - end - local default=functions.default - for i=1,select("#",...) do - local fnc=select(i,...) - local typ=type(fnc) - if typ=="string" then - if trace_initialize then - t.report("coupling %a to %a",what,fnc) - end - local s=fnc - fnc=function(value) set(t,s,value) end - elseif typ~="function" then - fnc=nil - end - if fnc then - functions[#functions+1]=fnc - local value=functions.value or default - if value~=nil then - fnc(value) - functions.value=value - end - end + local data=t.data + what=lower(what) + local functions=data[what] + if not functions then + functions={} + data[what]=functions + if trace_initialize then + t.report("defining %a",what) + end + end + local default=functions.default + for i=1,select("#",...) do + local fnc=select(i,...) + local typ=type(fnc) + if typ=="string" then + if trace_initialize then + t.report("coupling %a to %a",what,fnc) + end + local s=fnc + fnc=function(value) set(t,s,value) end + elseif typ~="function" then + fnc=nil + end + if fnc then + functions[#functions+1]=fnc + local value=functions.value or default + if value~=nil then + fnc(value) + functions.value=value + end end - return false + end + return false end function setters.enable(t,what) - local e=t.enable - t.enable,t.done=enable,{} - enable(t,what) - t.enable,t.done=e,{} + local e=t.enable + t.enable,t.done=enable,{} + enable(t,what) + t.enable,t.done=e,{} end function setters.disable(t,what) - local e=t.disable - t.disable,t.done=disable,{} - disable(t,what) - t.disable,t.done=e,{} + local e=t.disable + t.disable,t.done=disable,{} + disable(t,what) + t.disable,t.done=e,{} end function setters.reset(t) - t.done={} - reset(t) + t.done={} + reset(t) end function setters.list(t) - local list=table.sortedkeys(t.data) - local user,system={},{} - for l=1,#list do - local what=list[l] - if find(what,"^%*") then - system[#system+1]=what - else - user[#user+1]=what - end + local list=table.sortedkeys(t.data) + local user,system={},{} + for l=1,#list do + local what=list[l] + if find(what,"^%*") then + system[#system+1]=what + else + user[#user+1]=what end - return user,system + end + return user,system end function setters.show(t) - local list=setters.list(t) - t.report() - for k=1,#list do - local name=list[k] - local functions=t.data[name] - if functions then - local value=functions.value - local default=functions.default - local modules=#functions - if default==nil then - default="unset" - elseif type(default)=="table" then - default=concat(default,"|") - else - default=tostring(default) - end - if value==nil then - value="unset" - elseif type(value)=="table" then - value=concat(value,"|") - else - value=tostring(value) - end - t.report(name) - t.report(" modules : %i",modules) - t.report(" default : %s",default) - t.report(" value : %s",value) - t.report() - end + local list=setters.list(t) + t.report() + for k=1,#list do + local name=list[k] + local functions=t.data[name] + if functions then + local value=functions.value + local default=functions.default + local modules=#functions + if default==nil then + default="unset" + elseif type(default)=="table" then + default=concat(default,"|") + else + default=tostring(default) + end + if value==nil then + value="unset" + elseif type(value)=="table" then + value=concat(value,"|") + else + value=tostring(value) + end + t.report(name) + t.report(" modules : %i",modules) + t.report(" default : %s",default) + t.report(" value : %s",value) + t.report() end + end end local enable,disable,register,list,show=setters.enable,setters.disable,setters.register,setters.list,setters.show function setters.report(setter,...) - print(format("%-15s : %s\n",setter.name,format(...))) + print(format("%-15s : %s\n",setter.name,format(...))) end local function default(setter,name) - local d=setter.data[name] - return d and d.default + local d=setter.data[name] + return d and d.default end local function value(setter,name) - local d=setter.data[name] - return d and (d.value or d.default) + local d=setter.data[name] + return d and (d.value or d.default) end function setters.new(name) - local setter - setter={ - data=allocate(), - name=name, - report=function(...) setters.report (setter,...) end, - enable=function(...) enable (setter,...) end, - disable=function(...) disable (setter,...) end, - reset=function(...) reset (setter,...) end, - register=function(...) register(setter,...) end, - list=function(...) list (setter,...) end, - show=function(...) show (setter,...) end, - default=function(...) return default (setter,...) end, - value=function(...) return value (setter,...) end, - } - data[name]=setter - return setter + local setter + setter={ + data=allocate(), + name=name, + report=function(...) setters.report (setter,...) end, + enable=function(...) enable (setter,...) end, + disable=function(...) disable (setter,...) end, + reset=function(...) reset (setter,...) end, + register=function(...) register(setter,...) end, + list=function(...) list (setter,...) end, + show=function(...) show (setter,...) end, + default=function(...) return default (setter,...) end, + value=function(...) return value (setter,...) end, + } + data[name]=setter + return setter end trackers=setters.new("trackers") directives=setters.new("directives") experiments=setters.new("experiments") -local t_enable,t_disable=trackers .enable,trackers .disable +local t_enable,t_disable=trackers .enable,trackers .disable local d_enable,d_disable=directives .enable,directives .disable local e_enable,e_disable=experiments.enable,experiments.disable -local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) -local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) +local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) +local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) function directives.enable(...) - if trace_directives then - directives.report("enabling: % t",{...}) - end - d_enable(...) + if trace_directives then + directives.report("enabling: % t",{...}) + end + d_enable(...) end function directives.disable(...) - if trace_directives then - directives.report("disabling: % t",{...}) - end - d_disable(...) + if trace_directives then + directives.report("disabling: % t",{...}) + end + d_disable(...) end function experiments.enable(...) - if trace_experiments then - experiments.report("enabling: % t",{...}) - end - e_enable(...) + if trace_experiments then + experiments.report("enabling: % t",{...}) + end + e_enable(...) end function experiments.disable(...) - if trace_experiments then - experiments.report("disabling: % t",{...}) - end - e_disable(...) + if trace_experiments then + experiments.report("disabling: % t",{...}) + end + e_disable(...) end directives.register("system.nostatistics",function(v) - if statistics then - statistics.enable=not v - else - end + if statistics then + statistics.enable=not v + else + end end) directives.register("system.nolibraries",function(v) - if libraries then - libraries=nil - else - end + if libraries then + libraries=nil + else + end end) if environment then - local engineflags=environment.engineflags - if engineflags then - local list=engineflags["c:trackers"] or engineflags["trackers"] - if type(list)=="string" then - setters.initialize("commandline flags","trackers",settings_to_hash(list)) - end - local list=engineflags["c:directives"] or engineflags["directives"] - if type(list)=="string" then - setters.initialize("commandline flags","directives",settings_to_hash(list)) - end + local engineflags=environment.engineflags + if engineflags then + local list=engineflags["c:trackers"] or engineflags["trackers"] + if type(list)=="string" then + setters.initialize("commandline flags","trackers",settings_to_hash(list)) end -end -if texconfig then - local function set(k,v) - v=tonumber(v) - if v then - texconfig[k]=v - end + local list=engineflags["c:directives"] or engineflags["directives"] + if type(list)=="string" then + setters.initialize("commandline flags","directives",settings_to_hash(list)) end - directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) - directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) - directives.register("luatex.nestsize",function(v) set("nest_size",v) end) - directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) - directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) - directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) - directives.register("luatex.paramsize",function(v) set("param_size",v) end) - directives.register("luatex.savesize",function(v) set("save_size",v) end) - directives.register("luatex.stacksize",function(v) set("stack_size",v) end) + end end +if texconfig then + local function set(k,v) + v=tonumber(v) + if v then + texconfig[k]=v + end + end + directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) + directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) + directives.register("luatex.nestsize",function(v) set("nest_size",v) end) + directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) + directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) + directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) + directives.register("luatex.paramsize",function(v) set("param_size",v) end) + directives.register("luatex.savesize",function(v) set("save_size",v) end) + directives.register("luatex.stacksize",function(v) set("stack_size",v) end) +end +local data=table.setmetatableindex("table") +updaters={ + register=function(what,f) + local d=data[what] + d[#d+1]=f + end, + apply=function(what,...) + local d=data[what] + for i=1,#d do + d[i](...) + end + end, +} end -- of closure @@ -9274,14 +12678,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-log"] = package.loaded["trac-log"] or true --- original size: 32922, stripped down to: 23011 +-- original size: 32608, stripped down to: 20925 if not modules then modules={} end modules ['trac-log']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,select,print=next,type,select,print local format,gmatch,find=string.format,string.gmatch,string.find @@ -9292,7 +12696,7 @@ local datetime=os.date local openfile=io.open local runningtex=tex and (tex.jobname or tex.formatname) local write_nl=runningtex and texio and texio.write_nl or print -local write=runningtex and texio and texio.write or io.write +local write=runningtex and texio and texio.write or io.write local setmetatableindex=table.setmetatableindex local formatters=string.formatters local settings_to_hash=utilities.parsers.settings_to_hash @@ -9308,404 +12712,404 @@ webpage : http://www.pragma-ade.nl / http://tex.aanhet.net wiki : http://contextgarden.net ]] formatters.add ( - formatters,"unichr", - [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] + formatters,"unichr", + [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] ) formatters.add ( - formatters,"chruni", - [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] + formatters,"chruni", + [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] ) 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,setlogfile,settimedlog,setprocessor,setformatters,newline if runningtex then - if texio.setescape then - texio.setescape(0) - end - if arg then - for k,v in next,arg do - if v=="--ansi" or v=="--c:ansi" then - variant="ansi" - break - end - end - end - local function useluawrites() - local texio_write_nl=texio.write_nl - local texio_write=texio.write - local io_write=io.write - write_nl=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write_nl("log",...) - texio_write_nl("term","") - io_write(...) - elseif target=="log" then - texio_write_nl("log",...) - elseif target=="term" then - texio_write_nl("term","") - io_write(...) - elseif type(target)=="number" then - texio_write_nl(target,...) - elseif target~="none" then - texio_write_nl("log",target,...) - texio_write_nl("term","") - io_write(target,...) - end - end - write=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write("log",...) - io_write(...) - elseif target=="log" then - texio_write("log",...) - elseif target=="term" then - io_write(...) - elseif type(target)=="number" then - texio_write(target,...) - elseif target~="none" then - texio_write("log",target,...) - io_write(target,...) - end - end - texio.write=write - texio.write_nl=write_nl - useluawrites=ignore - end - local whereto="both" - local target=nil - local targets=nil - local formats=table.setmetatableindex("self") - local translations=table.setmetatableindex("self") - local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes - local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s > %s\n"], - report_nop=formatters["%-15s >\n"], - direct_yes=formatters["%-15s > %s"], - direct_nop=formatters["%-15s >"], - subreport_yes=formatters["%-15s > %s > %s\n"], - subreport_nop=formatters["%-15s > %s >\n"], - subdirect_yes=formatters["%-15s > %s > %s"], - subdirect_nop=formatters["%-15s > %s >"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - targets={ - logfile="log", - log="log", - file="log", - console="term", - terminal="term", - both="term and log", - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], - report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], - direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], - direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], - subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], - subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], - subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], - subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], - status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], - }, - targets={ - logfile="none", - log="none", - file="none", - console="term", - terminal="term", - both="term", - }, - } - } - logs.flush=io.flush - writer=function(...) - write_nl(target,...) - end - newline=function() - write_nl(target,"\n") - end - report=function(a,b,c,...) - if c~=nil then - write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,report_yes(translations[a],formats[b])) - elseif a then - write_nl(target,report_nop(translations[a])) - else - write_nl(target,"\n") - end - end - direct=function(a,b,c,...) - if c~=nil then - return direct_yes(translations[a],formatters[formats[b]](c,...)) - elseif b then - return direct_yes(translations[a],formats[b]) - elseif a then - return direct_nop(translations[a]) - else - return "" - end - end - subreport=function(a,s,b,c,...) - if c~=nil then - write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) - elseif a then - write_nl(target,subreport_nop(translations[a],translations[s])) - else - write_nl(target,"\n") - end - end - subdirect=function(a,s,b,c,...) - if c~=nil then - return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) - elseif b then - return subdirect_yes(translations[a],translations[s],formats[b]) - elseif a then - return subdirect_nop(translations[a],translations[s]) - else - return "" - end + if texio.setescape then + texio.setescape(0) + end + if arg then + for k,v in next,arg do + if v=="--ansi" or v=="--c:ansi" then + variant="ansi" + break + end end - status=function(a,b,c,...) - if c~=nil then - write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,status_yes(translations[a],formats[b])) - elseif a then - write_nl(target,status_nop(translations[a])) - else - write_nl(target,"\n") - end + end + local function useluawrites() + local texio_write_nl=texio.write_nl + local texio_write=texio.write + local io_write=io.write + write_nl=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write_nl("log",...) + texio_write_nl("term","") + io_write(...) + elseif target=="log" then + texio_write_nl("log",...) + elseif target=="term" then + texio_write_nl("term","") + io_write(...) + elseif type(target)=="number" then + texio_write_nl(target,...) + elseif target~="none" then + texio_write_nl("log",target,...) + texio_write_nl("term","") + io_write(target,...) + end end - settarget=function(askedwhereto) - whereto=askedwhereto or whereto or "both" - target=targets[whereto] - if not target then - whereto="both" - target=targets[whereto] - end - if target=="term" or target=="term and log" then - logs.flush=io.flush - else - logs.flush=ignore - end + write=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write("log",...) + io_write(...) + elseif target=="log" then + texio_write("log",...) + elseif target=="term" then + io_write(...) + elseif type(target)=="number" then + texio_write(target,...) + elseif target~="none" then + texio_write("log",target,...) + io_write(target,...) + end end - local stack={} - pushtarget=function(newtarget) - insert(stack,target) - settarget(newtarget) + texio.write=write + texio.write_nl=write_nl + useluawrites=ignore + end + local whereto="both" + local target=nil + local targets=nil + local formats=table.setmetatableindex("self") + local translations=table.setmetatableindex("self") + local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes + local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s > %s\n"], + report_nop=formatters["%-15s >\n"], + direct_yes=formatters["%-15s > %s"], + direct_nop=formatters["%-15s >"], + subreport_yes=formatters["%-15s > %s > %s\n"], + subreport_nop=formatters["%-15s > %s >\n"], + subdirect_yes=formatters["%-15s > %s > %s"], + subdirect_nop=formatters["%-15s > %s >"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + targets={ + logfile="log", + log="log", + file="log", + console="term", + terminal="term", + both="term and log", + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], + report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], + direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], + direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], + subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], + subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], + subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], + subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], + status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], + }, + targets={ + logfile="none", + log="none", + file="none", + console="term", + terminal="term", + both="term", + }, + } + } + logs.flush=io.flush + writer=function(...) + write_nl(target,...) + end + newline=function() + write_nl(target,"\n") + end + report=function(a,b,c,...) + if c~=nil then + write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,report_yes(translations[a],formats[b])) + elseif a then + write_nl(target,report_nop(translations[a])) + else + write_nl(target,"\n") end - poptarget=function() - if #stack>0 then - settarget(remove(stack)) - end + end + direct=function(a,b,c,...) + if c~=nil then + return direct_yes(translations[a],formatters[formats[b]](c,...)) + elseif b then + return direct_yes(translations[a],formats[b]) + elseif a then + return direct_nop(translations[a]) + else + return "" end - setformats=function(f) - formats=f + end + subreport=function(a,s,b,c,...) + if c~=nil then + write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) + elseif a then + write_nl(target,subreport_nop(translations[a],translations[s])) + else + write_nl(target,"\n") end - settranslations=function(t) - translations=t + end + subdirect=function(a,s,b,c,...) + if c~=nil then + return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) + elseif b then + return subdirect_yes(translations[a],translations[s],formats[b]) + elseif a then + return subdirect_nop(translations[a],translations[s]) + else + return "" end - setprocessor=function(f) - local writeline=write_nl - write_nl=function(target,...) - writeline(target,f(...)) - end + end + status=function(a,b,c,...) + if c~=nil then + write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,status_yes(translations[a],formats[b])) + elseif a then + write_nl(target,status_nop(translations[a])) + else + write_nl(target,"\n") + end + end + settarget=function(askedwhereto) + whereto=askedwhereto or whereto or "both" + target=targets[whereto] + if not target then + whereto="both" + target=targets[whereto] + end + if target=="term" or target=="term and log" then + logs.flush=io.flush + else + logs.flush=ignore + end + end + local stack={} + pushtarget=function(newtarget) + insert(stack,target) + settarget(newtarget) + end + poptarget=function() + if #stack>0 then + settarget(remove(stack)) + end + end + setformats=function(f) + formats=f + end + settranslations=function(t) + translations=t + end + setprocessor=function(f) + local writeline=write_nl + write_nl=function(target,...) + writeline(target,f(...)) + end + end + setformatters=function(specification) + local t=nil + local f=nil + local d=variants.default + if not specification then + elseif type(specification)=="table" then + t=specification.targets + f=specification.formats or specification + else + local v=variants[specification] + if v then + t=v.targets + f=v.formats + variant=specification + end end - setformatters=function(specification) - local t=nil - local f=nil - local d=variants.default - if not specification then - elseif type(specification)=="table" then - t=specification.targets - f=specification.formats or specification - else - local v=variants[specification] - if v then - t=v.targets - f=v.formats - variant=specification - end - end - targets=t or d.targets - target=targets[whereto] or target - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - direct_yes=f.direct_yes - direct_nop=f.direct_nop - subdirect_yes=f.subdirect_yes - subdirect_nop=f.subdirect_nop - status_yes=f.status_yes - status_nop=f.status_nop - if variant=="ansi" then - useluawrites() - end - settarget(whereto) - end - setformatters(variant) - setlogfile=ignore - settimedlog=ignore + targets=t or d.targets + target=targets[whereto] or target + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + direct_yes=f.direct_yes + direct_nop=f.direct_nop + subdirect_yes=f.subdirect_yes + subdirect_nop=f.subdirect_nop + status_yes=f.status_yes + status_nop=f.status_nop + if variant=="ansi" then + useluawrites() + end + settarget(whereto) + end + setformatters(variant) + setlogfile=ignore + settimedlog=ignore else - local report_yes,subreport_yes,status_yes - local report_nop,subreport_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s | %s"], - report_nop=formatters["%-15s |"], - subreport_yes=formatters["%-15s | %s | %s"], - subreport_nop=formatters["%-15s | %s |"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], - report_nop=formatters["[0;32m%-15s [0;1m|[0m"], - subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], - subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], - status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], - }, - }, - } - logs.flush=ignore - writer=function(s) - write_nl(s) - end - newline=function() - write_nl("\n") + local report_yes,subreport_yes,status_yes + local report_nop,subreport_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s | %s"], + report_nop=formatters["%-15s |"], + subreport_yes=formatters["%-15s | %s | %s"], + subreport_nop=formatters["%-15s | %s |"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], + report_nop=formatters["[0;32m%-15s [0;1m|[0m"], + subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], + subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], + status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], + }, + }, + } + logs.flush=ignore + writer=function(s) + write_nl(s) + end + newline=function() + write_nl("\n") + end + report=function(a,b,c,...) + if c then + write_nl(report_yes(a,formatters[b](c,...))) + elseif b then + write_nl(report_yes(a,b)) + elseif a then + write_nl(report_nop(a)) + else + write_nl("") end - report=function(a,b,c,...) - if c then - write_nl(report_yes(a,formatters[b](c,...))) - elseif b then - write_nl(report_yes(a,b)) - elseif a then - write_nl(report_nop(a)) - else - write_nl("") - end + end + subreport=function(a,sub,b,c,...) + if c then + write_nl(subreport_yes(a,sub,formatters[b](c,...))) + elseif b then + write_nl(subreport_yes(a,sub,b)) + elseif a then + write_nl(subreport_nop(a,sub)) + else + write_nl("") end - subreport=function(a,sub,b,c,...) - if c then - write_nl(subreport_yes(a,sub,formatters[b](c,...))) - elseif b then - write_nl(subreport_yes(a,sub,b)) - elseif a then - write_nl(subreport_nop(a,sub)) - else - write_nl("") + end + status=function(a,b,c,...) + if c then + write_nl(status_yes(a,formatters[b](c,...))) + elseif b then + write_nl(status_yes(a,b)) + elseif a then + write_nl(status_nop(a)) + else + write_nl("\n") + end + end + direct=ignore + subdirect=ignore + settarget=ignore + pushtarget=ignore + poptarget=ignore + setformats=ignore + settranslations=ignore + setprocessor=function(f) + local writeline=write_nl + write_nl=function(s) + writeline(f(s)) + end + end + setformatters=function(specification) + local f=nil + local d=variants.default + if specification then + if type(specification)=="table" then + f=specification.formats or specification + else + local v=variants[specification] + if v then + f=v.formats end + end end - status=function(a,b,c,...) - if c then - write_nl(status_yes(a,formatters[b](c,...))) - elseif b then - write_nl(status_yes(a,b)) - elseif a then - write_nl(status_nop(a)) - else - write_nl("\n") - end - end - direct=ignore - subdirect=ignore - settarget=ignore - pushtarget=ignore - poptarget=ignore - setformats=ignore - settranslations=ignore - setprocessor=function(f) - local writeline=write_nl + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + status_yes=f.status_yes + status_nop=f.status_nop + end + setformatters(variant) + 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(f(s)) - end - end - setformatters=function(specification) - local f=nil - local d=variants.default - if specification then - if type(specification)=="table" then - f=specification.formats or specification - else - local v=variants[specification] - if v then - f=v.formats - end - end - end - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - status_yes=f.status_yes - status_nop=f.status_nop - end - setformatters(variant) - 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 + writeline(s) + f:write(localtime()," | ",s,"\n") end - setlogfile=ignore - end - settimedlog=function() - local localtime=os.localtime - local writeline=write_nl + else write_nl=function(s) - writeline(localtime().." | "..s) + writeline(s) + local f=io.open(name,"ab") + f:write(localtime()," | ",s,"\n") + f:close() end - settimedlog=ignore + 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 @@ -9727,198 +13131,186 @@ local data={} local states=nil local force=false function logs.reporter(category,subcategory) - local logger=data[category] - if not logger then - local state=states==true - if not state and type(states)=="table" then - for c,_ in next,states do - if find(category,c) then - state=true - break - end - end + local logger=data[category] + if not logger then + local state=states==true + if not state and type(states)=="table" then + for c,_ in next,states do + if find(category,c) then + state=true + break end - logger={ - reporters={}, - state=state, - } - data[category]=logger - end - local reporter=logger.reporters[subcategory or "default"] - if not reporter then - if subcategory then - reporter=function(...) - if force or not logger.state then - subreport(category,subcategory,...) - end - end - logger.reporters[subcategory]=reporter - else - local tag=category - reporter=function(...) - if force or not logger.state then - report(category,...) - end - end - logger.reporters.default=reporter + end + end + logger={ + reporters={}, + state=state, + } + data[category]=logger + end + local reporter=logger.reporters[subcategory or "default"] + if not reporter then + if subcategory then + reporter=function(...) + if force or not logger.state then + subreport(category,subcategory,...) end + end + logger.reporters[subcategory]=reporter + else + local tag=category + reporter=function(...) + if force or not logger.state then + report(category,...) + end + end + logger.reporters.default=reporter end - return reporter + end + return reporter end logs.new=logs.reporter local ctxreport=logs.writer function logs.setmessenger(m) - ctxreport=m + ctxreport=m end function logs.messenger(category,subcategory) - if subcategory then - return function(...) - ctxreport(subdirect(category,subcategory,...)) - end - else - return function(...) - ctxreport(direct(category,...)) - end + if subcategory then + return function(...) + ctxreport(subdirect(category,subcategory,...)) end + else + return function(...) + ctxreport(direct(category,...)) + end + end end local function setblocked(category,value) - if category==true or category=="all" then - category,value="*",true - elseif category==false then - category,value="*",false - elseif value==nil then - value=true - end - if category=="*" then - states=value + if category==true or category=="all" then + category,value="*",true + elseif category==false then + category,value="*",false + elseif value==nil then + value=true + end + if category=="*" then + states=value + for k,v in next,data do + v.state=value + end + else + alllocked=false + states=settings_to_hash(category,type(states)=="table" and states or nil) + for c in next,states do + local v=data[c] + if v then + v.state=value + else + c=topattern(c,true,true) for k,v in next,data do + if find(k,c) then v.state=value + end end - else - alllocked=false - states=settings_to_hash(category,type(states)=="table" and states or nil) - for c in next,states do - local v=data[c] - if v then - v.state=value - else - c=topattern(c,true,true) - for k,v in next,data do - if find(k,c) then - v.state=value - end - end - end - end + end end + end end function logs.disable(category,value) - setblocked(category,value==nil and true or value) + setblocked(category,value==nil and true or value) end function logs.enable(category) - setblocked(category,false) + setblocked(category,false) end function logs.categories() - return sortedkeys(data) + return sortedkeys(data) end function logs.show() - local n,c,s,max=0,0,0,0 - for category,v in table.sortedpairs(data) do - n=n+1 - local state=v.state - local reporters=v.reporters - local nc=#category - if nc>c then - c=nc - end - for subcategory,_ in next,reporters do - local ns=#subcategory - if ns>c then - s=ns - end - local m=nc+ns - if m>max then - max=m - end - end - local subcategories=concat(sortedkeys(reporters),", ") - if state==true then - state="disabled" - elseif state==false then - state="enabled" - else - state="unknown" - end - report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + local n,c,s,max=0,0,0,0 + for category,v in table.sortedpairs(data) do + n=n+1 + local state=v.state + local reporters=v.reporters + local nc=#category + if nc>c then + c=nc + end + for subcategory,_ in next,reporters do + local ns=#subcategory + if ns>c then + s=ns + end + local m=nc+ns + if m>max then + max=m + end + end + local subcategories=concat(sortedkeys(reporters),", ") + if state==true then + state="disabled" + elseif state==false then + state="enabled" + else + state="unknown" end - report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) + report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + end + report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) end local delayed_reporters={} setmetatableindex(delayed_reporters,function(t,k) - local v=logs.reporter(k.name) - t[k]=v - return v + local v=logs.reporter(k.name) + t[k]=v + return v end) function utilities.setters.report(setter,...) - delayed_reporters[setter](...) + delayed_reporters[setter](...) end directives.register("logs.blocked",function(v) - setblocked(v,true) + setblocked(v,true) end) directives.register("logs.target",function(v) - settarget(v) + settarget(v) end) if tex then - local report=logs.reporter("pages") - local texgetcount=tex and tex.getcount - local real,user,sub - function logs.start_page_number() - real=texgetcount("realpageno") - user=texgetcount("userpageno") - sub=texgetcount("subpageno") - end - local timing=false - local starttime=nil - local lasttime=nil - trackers.register("pages.timing",function(v) - starttime=os.clock() - timing=true - end) - function logs.stop_page_number() - if timing then - local elapsed,average - local stoptime=os.clock() - if not lasttime or real<2 then - elapsed=stoptime - average=stoptime - starttime=stoptime - else - elapsed=stoptime-lasttime - average=(stoptime-starttime)/(real-1) - end - lasttime=stoptime - if real<=0 then - report("flushing page, time %0.04f / %0.04f",elapsed,average) - elseif user<=0 then - report("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average) - elseif sub<=0 then - report("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average) - else - report("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average) - end - else - if real<=0 then - report("flushing page") - elseif user<=0 then - report("flushing realpage %s",real) - elseif sub<=0 then - report("flushing realpage %s, userpage %s",real,user) - else - report("flushing realpage %s, userpage %s, subpage %s",real,user,sub) - end - end - logs.flush() + local report=logs.reporter("pages") + local texgetcount=tex and tex.getcount + local real,user,sub=0,0,0 + function logs.start_page_number() + real=texgetcount("realpageno") + user=texgetcount("userpageno") + sub=texgetcount("subpageno") + end + local timing=false + local lasttime=nil + trackers.register("pages.timing",function(v) + timing="" + end) + function logs.stop_page_number() + if timing then + local elapsed=statistics.currenttime(statistics) + local average,page + if not lasttime or real<2 then + average=elapsed + page=elapsed + else + average=elapsed/(real-1) + page=elapsed-lasttime + end + lasttime=elapsed + timing=formatters[", total %0.03f, page %0.03f, average %0.03f"](elapsed,page,average) end + if real<=0 then + report("flushing page%s",timing) + elseif user<=0 then + report("flushing realpage %s%s",real,timing) + elseif sub<=0 then + report("flushing realpage %s, userpage %s%s",real,user,timing) + else + report("flushing realpage %s, userpage %s, subpage %s%s",real,user,sub,timing) + end + logs.flush() + end end local nesting=0 local verbose=false @@ -9942,222 +13334,222 @@ logs.help=ignore local Carg,C,lpegmatch=lpeg.Carg,lpeg.C,lpeg.match local p_newline=lpeg.patterns.newline local linewise=( - Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline + Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline )^1 local function reportlines(t,str) - if str then - lpegmatch(linewise,str,1,t) - end + if str then + lpegmatch(linewise,str,1,t) + end end local function reportbanner(t) - local banner=t.banner - if banner then - t.report(banner) - t.report() - end + local banner=t.banner + if banner then + t.report(banner) + t.report() + end end local function reportversion(t) - local banner=t.banner - if banner then - t.report(banner) - end + local banner=t.banner + if banner then + t.report(banner) + end end local function reporthelp(t,...) - local helpinfo=t.helpinfo - if type(helpinfo)=="string" then - reportlines(t,helpinfo) - elseif type(helpinfo)=="table" then - for i=1,select("#",...) do - reportlines(t,t.helpinfo[select(i,...)]) - if i<n then - t.report() - end - end + local helpinfo=t.helpinfo + if type(helpinfo)=="string" then + reportlines(t,helpinfo) + elseif type(helpinfo)=="table" then + for i=1,select("#",...) do + reportlines(t,t.helpinfo[select(i,...)]) + if i<n then + t.report() + end end + end end local function reportinfo(t) - t.report() - reportlines(t,t.moreinfo) + t.report() + reportlines(t,t.moreinfo) end local function reportexport(t,method) - report(t.helpinfo) + report(t.helpinfo) end local reporters={ - lines=reportlines, - banner=reportbanner, - version=reportversion, - help=reporthelp, - info=reportinfo, - export=reportexport, + lines=reportlines, + banner=reportbanner, + version=reportversion, + help=reporthelp, + info=reportinfo, + export=reportexport, } local exporters={ } logs.reporters=reporters logs.exporters=exporters function logs.application(t) - t.name=t.name or "unknown" - t.banner=t.banner - t.moreinfo=moreinfo - t.report=logs.reporter(t.name) - t.help=function(...) - reporters.banner(t) - reporters.help(t,...) - reporters.info(t) - end - t.export=function(...) - reporters.export(t,...) - end - t.identify=function() - reporters.banner(t) - end - t.version=function() - reporters.version(t) - end - return t + t.name=t.name or "unknown" + t.banner=t.banner + t.moreinfo=moreinfo + t.report=logs.reporter(t.name) + t.help=function(...) + reporters.banner(t) + reporters.help(t,...) + reporters.info(t) + end + t.export=function(...) + reporters.export(t,...) + end + t.identify=function() + reporters.banner(t) + end + t.version=function() + reporters.version(t) + end + return t end local f_syslog=formatters["%s %s => %s => %s => %s\r"] function logs.system(whereto,process,jobname,category,fmt,arg,...) - local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) - for i=1,10 do - local f=openfile(whereto,"a") - if f then - f:write(message) - f:close() - break - else - sleep(0.1) - end + local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) + for i=1,10 do + local f=openfile(whereto,"a") + if f then + f:write(message) + f:close() + break + else + sleep(0.1) end + end end local report_system=logs.reporter("system","logs") function logs.obsolete(old,new) - local o=loadstring("return "..new)() - if type(o)=="function" then - return function(...) - report_system("function %a is obsolete, use %a",old,new) - loadstring(old.."="..new.." return "..old)()(...) - end - elseif type(o)=="table" then - local t,m={},{} - m.__index=function(t,k) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - return o[k] - end - m.__newindex=function(t,k,v) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - o[k]=v - end - if libraries then - libraries.obsolete[old]=t - end - setmetatable(t,m) - return t + local o=loadstring("return "..new)() + if type(o)=="function" then + return function(...) + report_system("function %a is obsolete, use %a",old,new) + loadstring(old.."="..new.." return "..old)()(...) + end + elseif type(o)=="table" then + local t,m={},{} + m.__index=function(t,k) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + return o[k] + end + m.__newindex=function(t,k,v) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + o[k]=v + end + if libraries then + libraries.obsolete[old]=t end + setmetatable(t,m) + return t + end end if utilities then - utilities.report=report_system + utilities.report=report_system end if tex and tex.error then - function logs.texerrormessage(...) - tex.error(format(...),{}) - end + function logs.texerrormessage(...) + tex.error(format(...)) + end else - function logs.texerrormessage(...) - print(format(...)) - end + function logs.texerrormessage(...) + print(format(...)) + end end io.stdout:setvbuf('no') io.stderr:setvbuf('no') if package.helpers.report then - package.helpers.report=logs.reporter("package loader") + package.helpers.report=logs.reporter("package loader") end if tex then - local finalactions={} - local fatalerrors={} - local possiblefatal={} - local loggingerrors=false - function logs.loggingerrors() - return loggingerrors - end - directives.register("logs.errors",function(v) - loggingerrors=v - if type(v)=="string" then - fatalerrors=settings_to_hash(v) - else - fatalerrors={} - end - end) - function logs.registerfinalactions(...) - insert(finalactions,...) - end - local what=nil - local report=nil - local state=nil - local target=nil - local function startlogging(t,r,w,s) - target=t - state=force - force=true - report=type(r)=="function" and r or logs.reporter(r) - what=w - pushtarget(target) + local finalactions={} + local fatalerrors={} + local possiblefatal={} + local loggingerrors=false + function logs.loggingerrors() + return loggingerrors + end + directives.register("logs.errors",function(v) + loggingerrors=v + if type(v)=="string" then + fatalerrors=settings_to_hash(v) + else + fatalerrors={} + end + end) + function logs.registerfinalactions(...) + insert(finalactions,...) + end + local what=nil + local report=nil + local state=nil + local target=nil + local function startlogging(t,r,w,s) + target=t + state=force + force=true + report=type(r)=="function" and r or logs.reporter(r) + what=w + pushtarget(target) + newline() + if s then + report("start %s: %s",what,s) + else + report("start %s",what) + end + if target=="logfile" then + newline() + end + return report + end + local function stoplogging() + if target=="logfile" then + newline() + end + report("stop %s",what) + if target=="logfile" then + newline() + end + poptarget() + state=oldstate + end + function logs.startfilelogging(...) + return startlogging("logfile",...) + end + logs.stopfilelogging=stoplogging + local done=false + function logs.starterrorlogging(r,w,...) + if not done then + pushtarget("terminal") + newline() + logs.report("error logging","start possible issues") + poptarget() + done=true + end + if fatalerrors[w] then + possiblefatal[w]=true + end + return startlogging("terminal",r,w,...) + end + logs.stoperrorlogging=stoplogging + function logs.finalactions() + if #finalactions>0 then + for i=1,#finalactions do + finalactions[i]() + end + if done then + pushtarget("terminal") newline() - if s then - report("start %s: %s",what,s) - else - report("start %s",what) - end - if target=="logfile" then - newline() - end - return report - end - local function stoplogging() - if target=="logfile" then - newline() - end - report("stop %s",what) - if target=="logfile" then - newline() - end + logs.report("error logging","stop possible issues") poptarget() - state=oldstate - end - function logs.startfilelogging(...) - return startlogging("logfile",...) - end - logs.stopfilelogging=stoplogging - local done=false - function logs.starterrorlogging(r,w,...) - if not done then - pushtarget("terminal") - newline() - logs.report("error logging","start possible issues") - poptarget() - done=true - end - if fatalerrors[w] then - possiblefatal[w]=true - end - return startlogging("terminal",r,w,...) - end - logs.stoperrorlogging=stoplogging - function logs.finalactions() - if #finalactions>0 then - for i=1,#finalactions do - finalactions[i]() - end - if done then - pushtarget("terminal") - newline() - logs.report("error logging","stop possible issues") - poptarget() - end - return next(possiblefatal) and sortedkeys(possiblefatal) or false - end + end + return next(possiblefatal) and sortedkeys(possiblefatal) or false end + end end @@ -10167,14 +13559,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8097, stripped down to: 5534 +-- original size: 9072, stripped down to: 6055 if not modules then modules={} end modules ['trac-inf']={ - version=1.001, - comment="companion to trac-inf.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-inf.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber,select=type,tonumber,select local format,lower,find=string.format,string.lower,string.find @@ -10189,161 +13581,191 @@ statistics.enable=true statistics.threshold=0.01 local statusinfo,n,registered,timers={},0,{},{} setmetatableindex(timers,function(t,k) - local v={ timing=0,loadtime=0 } - t[k]=v - return v + local v={ timing=0,loadtime=0 } + t[k]=v + return v end) local function hastiming(instance) - return instance and timers[instance] + return instance and timers[instance] end local function resettiming(instance) - timers[instance or "notimer"]={ timing=0,loadtime=0 } + timers[instance or "notimer"]={ timing=0,loadtime=0 } end local ticks=clock local seconds=function(n) return n or 0 end -local function starttiming(instance) - local timer=timers[instance or "notimer"] - local it=timer.timing - if it==0 then - timer.starttime=ticks() - if not timer.loadtime then - timer.loadtime=0 - end - end - timer.timing=it+1 +local function starttiming(instance,reset) + local timer=timers[instance or "notimer"] + local it=timer.timing + if reset then + it=0 + timer.loadtime=0 + end + if it==0 then + timer.starttime=ticks() + if not timer.loadtime then + timer.loadtime=0 + end + end + timer.timing=it+1 end local function stoptiming(instance) + local timer=timers[instance or "notimer"] + local it=timer.timing + if it>1 then + timer.timing=it-1 + else + local starttime=timer.starttime + if starttime and starttime>0 then + local stoptime=ticks() + local loadtime=stoptime-starttime + timer.stoptime=stoptime + timer.loadtime=timer.loadtime+loadtime + timer.timing=0 + timer.starttime=0 + return loadtime + end + end + return 0 +end +local function elapsed(instance) + if type(instance)=="number" then + return instance + else + local timer=timers[instance or "notimer"] + return timer and seconds(timer.loadtime) or 0 + end +end +local function currenttime(instance) + if type(instance)=="number" then + return instance + else local timer=timers[instance or "notimer"] local it=timer.timing if it>1 then - timer.timing=it-1 else - local starttime=timer.starttime - if starttime and starttime>0 then - local stoptime=ticks() - local loadtime=stoptime-starttime - timer.stoptime=stoptime - timer.loadtime=timer.loadtime+loadtime - timer.timing=0 - timer.starttime=0 - return loadtime - end + local starttime=timer.starttime + if starttime and starttime>0 then + return seconds(timer.loadtime+ticks()-starttime) + end end return 0 -end -local function elapsed(instance) - if type(instance)=="number" then - return instance - else - local timer=timers[instance or "notimer"] - return timer and seconds(timer.loadtime) or 0 - end + end end local function elapsedtime(instance) - return format("%0.3f",elapsed(instance)) + return format("%0.3f",elapsed(instance)) end local function elapsedindeed(instance) - return elapsed(instance)>statistics.threshold + return elapsed(instance)>statistics.threshold end local function elapsedseconds(instance,rest) - if elapsedindeed(instance) then - return format("%0.3f seconds %s",elapsed(instance),rest or "") - end + if elapsedindeed(instance) then + return format("%0.3f seconds %s",elapsed(instance),rest or "") + end end statistics.hastiming=hastiming statistics.resettiming=resettiming statistics.starttiming=starttiming statistics.stoptiming=stoptiming +statistics.currenttime=currenttime statistics.elapsed=elapsed statistics.elapsedtime=elapsedtime statistics.elapsedindeed=elapsedindeed statistics.elapsedseconds=elapsedseconds function statistics.register(tag,fnc) - if statistics.enable and type(fnc)=="function" then - local rt=registered[tag] or (#statusinfo+1) - statusinfo[rt]={ tag,fnc } - registered[tag]=rt - if #tag>n then n=#tag end - end + if statistics.enable and type(fnc)=="function" then + local rt=registered[tag] or (#statusinfo+1) + statusinfo[rt]={ tag,fnc } + registered[tag]=rt + if #tag>n then n=#tag end + end end 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("used engine",function() - return format("%s version %s with functionality level %s, banner: %s", - LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) - end) - register("control sequences",function() - return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) - end) - register("callbacks",statistics.callbacks) - if TEXENGINE=="luajittex" and JITSUPPORTED then - local jitstatus=jit.status - if jitstatus then - local jitstatus={ jitstatus() } - if jitstatus[1] then - register("luajit options",concat(jitstatus," ",2)) - end - end - end - register("lua properties",function() - local hashchar=tonumber(status.luatex_hashchars) - local hashtype=status.luatex_hashtype - local mask=lua.mask or "ascii" - return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", - jit and "luajit" or "lua", - LUAVERSION, - statistics.memused(), - 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 - local s=statusinfo[i] - local r=s[2]() - if r then - report("%s: %s",s[1],r) - end + 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("used engine",function() + return format("%s version %s with functionality level %s, banner: %s", + LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) + end) + register("control sequences",function() + return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) + end) + register("callbacks",statistics.callbacks) + if TEXENGINE=="luajittex" and JITSUPPORTED then + local jitstatus=jit.status + if jitstatus then + local jitstatus={ jitstatus() } + if jitstatus[1] then + register("luajit options",concat(jitstatus," ",2)) end - statistics.enable=false + end end + register("lua properties",function() + local hashchar=tonumber(status.luatex_hashchars) + local hashtype=status.luatex_hashtype + local mask=lua.mask or "ascii" + return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", + jit and "luajit" or "lua", + LUAVERSION, + statistics.memused(), + 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 + local s=statusinfo[i] + local r=s[2]() + if r then + report("%s: %s",s[1],r) + end + end + statistics.enable=false + end end function statistics.memused() - local round=math.round or math.floor - return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) + local round=math.round or math.floor + return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) end starttiming(statistics) function statistics.formatruntime(runtime) - return format("%s seconds",runtime) + return format("%s seconds",runtime) end function statistics.runtime() - stoptiming(statistics) - return statistics.formatruntime(elapsedtime(statistics)) + stoptiming(statistics) + local runtime=lua.getruntime and lua.getruntime() or elapsedtime(statistics) + return statistics.formatruntime(runtime) end local report=logs.reporter("system") -function statistics.timed(action) - starttiming("run") - action() - stoptiming("run") - report("total runtime: %s seconds",elapsedtime("run")) +function statistics.timed(action,all) + starttiming("run") + action() + stoptiming("run") + local runtime=tonumber(elapsedtime("run")) + if all then + local alltime=tonumber(lua.getruntime and lua.getruntime() or elapsedtime(statistics)) + if alltime and alltime>0 then + report("total runtime: %0.3f seconds of %0.3f seconds",runtime,alltime) + return + end + end + report("total runtime: %0.3f seconds",runtime) 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 + 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 @@ -10353,144 +13775,144 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-pro"] = package.loaded["trac-pro"] or true --- original size: 5841, stripped down to: 3511 +-- original size: 5841, stripped down to: 3352 if not modules then modules={} end modules ['trac-pro']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local getmetatable,setmetatable,rawset,type,next=getmetatable,setmetatable,rawset,type,next -local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) +local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) local report_system=logs.reporter("system","protection") namespaces=namespaces or {} 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) - debugger.showtraceback(report_system) - else - report_system("reference to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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) - debugger.showtraceback(report_system) - else - report_system("assignment to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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 end local function register(name) - local data=name=="global" and _G or _G[name] - if not data then - return - end - registered[name]=data - local m=getmetatable(data) - if not m then - m={} - setmetatable(data,m) - end - local index,newindex={},{} - m.__saved__index=m.__index - m.__no__index=function(t,k) - if not index[k] then - index[k]=true - report_index(k,name) - end - return nil + local data=name=="global" and _G or _G[name] + if not data then + return + end + registered[name]=data + local m=getmetatable(data) + if not m then + m={} + setmetatable(data,m) + end + local index,newindex={},{} + m.__saved__index=m.__index + m.__no__index=function(t,k) + if not index[k] then + index[k]=true + report_index(k,name) end - m.__saved__newindex=m.__newindex - m.__no__newindex=function(t,k,v) - if not newindex[k] then - newindex[k]=true - report_newindex(k,name) - end - rawset(t,k,v) + return nil + end + m.__saved__newindex=m.__newindex + m.__no__newindex=function(t,k,v) + if not newindex[k] then + newindex[k]=true + report_newindex(k,name) end - m.__protection__depth=0 + rawset(t,k,v) + end + m.__protection__depth=0 end local function private(name) - local data=registered[name] + local data=registered[name] + if not data then + data=_G[name] if not data then - data=_G[name] - if not data then - data={} - _G[name]=data - end - register(name) + data={} + _G[name]=data end - return data + register(name) + end + return data end local function protect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>0 then - m.__protection__depth=pd+1 - else - m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex - m.__index,m.__newindex=m.__no__index,m.__no__newindex - m.__protection__depth=1 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>0 then + m.__protection__depth=pd+1 + else + m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex + m.__index,m.__newindex=m.__no__index,m.__no__newindex + m.__protection__depth=1 + end end local function unprotect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>1 then - m.__protection__depth=pd-1 - else - m.__index,m.__newindex=m.__saved__index,m.__saved__newindex - m.__protection__depth=0 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>1 then + m.__protection__depth=pd-1 + else + m.__index,m.__newindex=m.__saved__index,m.__saved__newindex + m.__protection__depth=0 + end end local function protectall() - for name,_ in next,registered do - if name~="global" then - protect(name) - end + for name,_ in next,registered do + if name~="global" then + protect(name) end + end end local function unprotectall() - for name,_ in next,registered do - if name~="global" then - unprotect(name) - end + for name,_ in next,registered do + if name~="global" then + unprotect(name) end + end end -namespaces.register=register -namespaces.private=private +namespaces.register=register +namespaces.private=private namespaces.protect=protect namespaces.unprotect=unprotect namespaces.protectall=protectall namespaces.unprotectall=unprotectall namespaces.private("namespaces") registered={} register("global") directives.register("system.protect",function(v) - if v then - protectall() - else - unprotectall() - end + if v then + protectall() + else + unprotectall() + end end) directives.register("system.checkglobals",function(v) - if v then - report_system("enabling global namespace guard") - protect("global") - else - report_system("disabling global namespace guard") - unprotect("global") - end + if v then + report_system("enabling global namespace guard") + protect("global") + else + report_system("disabling global namespace guard") + unprotect("global") + end end) @@ -10500,15 +13922,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lua"] = package.loaded["util-lua"] or true --- original size: 6621, stripped down to: 4764 +-- original size: 6664, stripped down to: 4589 if not modules then modules={} end modules ['util-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - comment="the strip code is written by Peter Cawley", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + comment="the strip code is written by Peter Cawley", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local rep,sub,byte,dump,format=string.rep,string.sub,string.byte,string.dump,string.format local load,loadfile,type,collectgarbage=load,loadfile,type,collectgarbage @@ -10519,150 +13941,151 @@ local report_lua=logs.reporter("system","lua") local report_mem=logs.reporter("system","lua memory") local tracestripping=false local tracememory=false -luautilities.stripcode=true +luautilities.stripcode=true luautilities.alwaysstripcode=false luautilities.nofstrippedchunks=0 luautilities.nofstrippedbytes=0 local strippedchunks={} luautilities.strippedchunks=strippedchunks luautilities.suffixes={ - tma="tma", - tmc=jit and "tmb" or "tmc", - lua="lua", - luc=jit and "lub" or "luc", - lui="lui", - luv="luv", - luj="luj", - tua="tua", - tuc="tuc", + tma="tma", + tmc=jit and "tmb" or "tmc", + lua="lua", + luc=jit and "lub" or "luc", + lui="lui", + luv="luv", + luj="luj", + tua="tua", + tuc="tuc", } 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 + 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 -end -function luautilities.loadedluacode(fullname,forcestrip,name,macros) - name=name or fullname - if macros then - macros=lua.macros - end - local code,message - if macros then - code,message=macros.loaded(fullname,true,false) - else - code,message=loadfile(fullname) - end + local code=io.loaddata(luafile) + if code and code~="" then + code=load(code) if code then - code() - else - report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") - end - if forcestrip and luautilities.stripcode then - if type(forcestrip)=="function" then - forcestrip=forcestrip(fullname) - end - if forcestrip or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end - elseif 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 + io.savedata(lucfile,code) + return true,0 + end else - return code,0 + 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 +end +function luautilities.loadedluacode(fullname,forcestrip,name,macros) + name=name or fullname + if macros then + macros=lua.macros + end + local code,message + if macros then + code,message=macros.loaded(fullname,true,false) + else + code,message=loadfile(fullname) + end + if code then + code() + else + report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") + code,message=loadfile(fullname) + end + if forcestrip and luautilities.stripcode then + if type(forcestrip)=="function" then + forcestrip=forcestrip(fullname) + end + 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 end function luautilities.strippedloadstring(code,name,forcestrip) - 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 - if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end + 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 + if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 + else + return code,0 + end end function luautilities.loadstring(code,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 - return code,0 + 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 + return 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 - end - return done + 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 + end + return done end function luautilities.loadstripped(...) - local l=load(...) - if l then - return load(dump(l,true)) - end + local l=load(...) + if l then + return load(dump(l,true)) + end end local finalizers={} setmetatable(finalizers,{ - __gc=function(t) - for i=1,#t do - pcall(t[i]) - end + __gc=function(t) + for i=1,#t do + pcall(t[i]) end + end } ) function luautilities.registerfinalizer(f) - finalizers[#finalizers+1]=f + finalizers[#finalizers+1]=f end function luautilities.checkmemory(previous,threshold,trace) - local current=collectgarbage("count") - if previous then - local checked=(threshold or 64)*1024 - local delta=current-previous - if current-previous>checked then - collectgarbage("collect") - local afterwards=collectgarbage("count") - if trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB, afterwards %i MB", - previous/1024,current/1024,delta/1024,threshold,afterwards) - end - return afterwards - elseif trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB", - previous/1024,current/1024,delta/1024,threshold) - end + local current=collectgarbage("count") + if previous then + local checked=(threshold or 64)*1024 + local delta=current-previous + if current-previous>checked then + collectgarbage("collect") + local afterwards=collectgarbage("count") + if trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB", + previous/1024,current/1024,delta/1024,threshold,afterwards) + end + return afterwards + elseif trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB", + previous/1024,current/1024,delta/1024,threshold) end - return current + end + return current end @@ -10672,17 +14095,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-deb"] = package.loaded["util-deb"] or true --- original size: 8984, stripped down to: 6573 +-- original size: 9955, stripped down to: 6693 if not modules then modules={} end modules ['util-deb']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local debug=require "debug" -local getinfo,sethook=debug.getinfo,debug.sethook local type,next,tostring,tonumber=type,next,tostring,tonumber local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub local insert,remove,sort=table.insert,table.remove,table.sort @@ -10700,228 +14121,266 @@ local names={} local initialize=false if not (FFISUPPORTED and ffi) then elseif os.type=="windows" then - initialize=function() - local kernel=ffilib("kernel32","system") - if kernel then - local tonumber=ffi.number or tonumber - ffi.cdef[[ + initialize=function() + local kernel=ffilib("kernel32","system") + if kernel then + local tonumber=ffi.number or tonumber + ffi.cdef[[ int QueryPerformanceFrequency(int64_t *lpFrequency); int QueryPerformanceCounter(int64_t *lpPerformanceCount); ]] - local target=ffi.new("__int64[1]") - ticks=function() - if kernel.QueryPerformanceCounter(target)==1 then - return tonumber(target[0]) - else - return 0 - end - end - local target=ffi.new("__int64[1]") - seconds=function(ticks) - if kernel.QueryPerformanceFrequency(target)==1 then - return ticks/tonumber(target[0]) - else - return 0 - end - end + local target=ffi.new("__int64[1]") + ticks=function() + if kernel.QueryPerformanceCounter(target)==1 then + return tonumber(target[0]) + else + return 0 end - initialize=false + end + local target=ffi.new("__int64[1]") + seconds=function(ticks) + if kernel.QueryPerformanceFrequency(target)==1 then + return ticks/tonumber(target[0]) + else + return 0 + end + end end + initialize=false + end elseif os.type=="unix" then - initialize=function() - local C=ffi.C - local tonumber=ffi.number or tonumber - ffi.cdef [[ + initialize=function() + local C=ffi.C + local tonumber=ffi.number or tonumber + ffi.cdef [[ /* what a mess */ typedef int clk_id_t; typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID } clk_id; typedef struct timespec { long sec; long nsec; } ctx_timespec; int clock_gettime(clk_id_t timerid, struct timespec *t); ]] - local target=ffi.new("ctx_timespec[?]",1) - local clock=C.CLOCK_PROCESS_CPUTIME_ID - ticks=function () - C.clock_gettime(clock,target) - return tonumber(target[0].sec*1000000000+target[0].nsec) - end - seconds=function(ticks) - return ticks/1000000000 - end - initialize=false + local target=ffi.new("ctx_timespec[?]",1) + local clock=C.CLOCK_PROCESS_CPUTIME_ID + ticks=function () + C.clock_gettime(clock,target) + return tonumber(target[0].sec*1000000000+target[0].nsec) + end + seconds=function(ticks) + return ticks/1000000000 end + initialize=false + end end setmetatableindex(names,function(t,name) - local v=setmetatableindex(function(t,source) - local v=setmetatableindex(function(t,line) - local v={ total=0,count=0 } - t[line]=v - return v - end) - t[source]=v - return v + local v=setmetatableindex(function(t,source) + local v=setmetatableindex(function(t,line) + local v={ total=0,count=0,nesting=0 } + t[line]=v + return v end) - t[name]=v + t[source]=v return v + end) + t[name]=v + return v end) +local getinfo=nil +local sethook=nil local function hook(where) - local f=getinfo(2,"nSl") - if f then - local source=f.short_src - if not source then - return - end - local line=f.linedefined or 0 - local name=f.name - if not name then - local what=f.what - if what=="C" then - name="<anonymous>" - else - name=f.namewhat or what or "<unknown>" - end - end - local data=names[name][source][line] - if where=="call" then - data.count=data.count+1 - insert(data,ticks()) - elseif where=="return" then - local t=remove(data) - if t then - data.total=data.total+ticks()-t - end + local f=getinfo(2,"nSl") + if f then + local source=f.short_src + if not source then + return + end + local line=f.linedefined or 0 + local name=f.name + if not name then + local what=f.what + if what=="C" then + name="<anonymous>" + else + name=f.namewhat or what or "<unknown>" + end + end + local data=names[name][source][line] + if where=="call" then + local nesting=data.nesting + if nesting==0 then + data.count=data.count+1 + insert(data,ticks()) + data.nesting=1 + else + data.nesting=nesting+1 + end + elseif where=="return" then + local nesting=data.nesting + if nesting==1 then + local t=remove(data) + if t then + data.total=data.total+ticks()-t end + data.nesting=0 + else + data.nesting=nesting-1 + end end + end end function debugger.showstats(printer,threshold) - local printer=printer or report - local calls=0 - local functions=0 - local dataset={} - local length=0 - local realtime=0 - local totaltime=0 - local threshold=threshold or 0 - for name,sources in next,names do - for source,lines in next,sources do - for line,data in next,lines do - local count=data.count - if count>threshold then - if #name>length then - length=#name - end - local total=data.total - local real=total - if real>0 then - real=total-(count*overhead/dummycalls) - if real<0 then - real=0 - end - realtime=realtime+real - end - totaltime=totaltime+total - if line<0 then - line=0 - end - dataset[#dataset+1]={ real,total,count,name,source,line } - end - end + local printer=printer or report + local calls=0 + local functions=0 + local dataset={} + local length=0 + local realtime=0 + local totaltime=0 + local threshold=threshold or 0 + for name,sources in next,names do + for source,lines in next,sources do + for line,data in next,lines do + local count=data.count + if count>threshold then + if #name>length then + length=#name + end + local total=data.total + local real=total + if real>0 then + real=total-(count*overhead/dummycalls) + if real<0 then + real=0 + end + realtime=realtime+real + end + totaltime=totaltime+total + if line<0 then + line=0 + end + dataset[#dataset+1]={ real,total,count,name,source,line } end + end end - sort(dataset,function(a,b) - if a[1]==b[1] then - if a[2]==b[2] then - if a[3]==b[3] then - if a[4]==b[4] then - if a[5]==b[5] then - return a[6]<b[6] - else - return a[5]<b[5] - end - else - return a[4]<b[4] - end - else - return b[3]<a[3] - end + end + sort(dataset,function(a,b) + if a[1]==b[1] then + if a[2]==b[2] then + if a[3]==b[3] then + if a[4]==b[4] then + if a[5]==b[5] then + return a[6]<b[6] else - return b[2]<a[2] + return a[5]<b[5] end + else + return a[4]<b[4] + end else - return b[1]<a[1] + return b[3]<a[3] end - end) - if length>50 then - length=50 - end - local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] - for i=1,#dataset do - local data=dataset[i] - local real=data[1] - local total=data[2] - local count=data[3] - local name=data[4] - local source=data[5] - local line=data[6] - calls=calls+count - functions=functions+1 - name=gsub(name,"%s+"," ") - if #name>length then - name=sub(name,1,length) - end - printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) - end - printer("") - printer(format("functions : %i",functions)) - printer(format("calls : %i",calls)) - printer(format("overhead : %f",seconds(overhead/1000))) + else + return b[2]<a[2] + end + else + return b[1]<a[1] + end + end) + if length>50 then + length=50 + end + local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] + for i=1,#dataset do + local data=dataset[i] + local real=data[1] + local total=data[2] + local count=data[3] + local name=data[4] + local source=data[5] + local line=data[6] + calls=calls+count + functions=functions+1 + name=gsub(name,"%s+"," ") + if #name>length then + name=sub(name,1,length) + end + printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) + end + printer("") + printer(format("functions : %i",functions)) + printer(format("calls : %i",calls)) + printer(format("overhead : %f",seconds(overhead/1000))) +end +local function getdebug() + if sethook and getinfo then + return + end + if not debug then + local okay + okay,debug=pcall(require,"debug") + end + if type(debug)~="table" then + return + end + getinfo=debug.getinfo + sethook=debug.sethook + if type(getinfo)~="function" then + getinfo=nil + end + if type(sethook)~="function" then + sethook=nil + end end function debugger.savestats(filename,threshold) - local f=io.open(filename,'w') - if f then - debugger.showstats(function(str) f:write(str,"\n") end,threshold) - f:close() - end + local f=io.open(filename,'w') + if f then + debugger.showstats(function(str) f:write(str,"\n") end,threshold) + f:close() + end end function debugger.enable() - if nesting==0 then - running=true - if initialize then - initialize() - end - sethook(hook,"cr") - local function dummy() end - local t=ticks() - for i=1,dummycalls do - dummy() - end - overhead=ticks()-t - end - if nesting>0 then - nesting=nesting+1 - end + getdebug() + if sethook and getinfo and nesting==0 then + running=true + if initialize then + initialize() + end + sethook(hook,"cr") + local function dummy() end + local t=ticks() + for i=1,dummycalls do + dummy() + end + overhead=ticks()-t + end + if nesting>0 then + nesting=nesting+1 + end end function debugger.disable() - if nesting>0 then - nesting=nesting-1 - end - if nesting==0 then - sethook() - end + if nesting>0 then + nesting=nesting-1 + end + if sethook and getinfo and nesting==0 then + sethook() + end end local function showtraceback(rep) + getdebug() + if getinfo then local level=2 local reporter=rep or report while true do - local info=getinfo(level,"Sl") - if not info then - break - elseif info.what=="C" then - reporter("%2i : %s",level-1,"C function") - else - reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) - end - level=level+1 + local info=getinfo(level,"Sl") + if not info then + break + elseif info.what=="C" then + reporter("%2i : %s",level-1,"C function") + else + reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) + end + level=level+1 end + end end debugger.showtraceback=showtraceback @@ -10932,91 +14391,91 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tpl"] = package.loaded["util-tpl"] or true --- original size: 7112, stripped down to: 3988 +-- original size: 7112, stripped down to: 3887 if not modules then modules={} end modules ['util-tpl']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities.templates=utilities.templates or {} local templates=utilities.templates -local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) +local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) local report_template=logs.reporter("template") local tostring,next=tostring,next 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] - if not v then - if trace_template then - report_template("unknown key %a",k) - end - return "" + local v=t[k] + if not v then + if trace_template then + report_template("unknown key %a",k) + end + return "" + else + v=tostring(v) + if trace_template then + report_template("setting key %a to value %a",k,v) + end + if recursive then + return lpegmatch(replacer,v,1,t,how,recursive) else - v=tostring(v) - if trace_template then - report_template("setting key %a to value %a",k,v) - end - if recursive then - return lpegmatch(replacer,v,1,t,how,recursive) - else - return v - end + return v end + end end local sqlescape=lpeg.replacer { - { "'","''" }, - { "\\","\\\\" }, - { "\r\n","\\n" }, - { "\r","\\n" }, + { "'","''" }, + { "\\","\\\\" }, + { "\r\n","\\n" }, + { "\r","\\n" }, } local sqlquoted=Cs(Cc("'")*sqlescape*Cc("'")) lpegpatterns.sqlescape=sqlescape lpegpatterns.sqlquoted=sqlquoted local luaescape=lpegpatterns.luaescape local escapers={ - lua=function(s) - return lpegmatch(luaescape,s) - end, - sql=function(s) - return lpegmatch(sqlescape,s) - end, + lua=function(s) + return lpegmatch(luaescape,s) + end, + sql=function(s) + return lpegmatch(sqlescape,s) + end, } local quotedescapers={ - lua=function(s) - return format("%q",s) - end, - sql=function(s) - return lpegmatch(sqlquoted,s) - end, + lua=function(s) + return format("%q",s) + end, + sql=function(s) + return lpegmatch(sqlquoted,s) + end, } local luaescaper=escapers.lua local quotedluaescaper=quotedescapers.lua local function replacekeyunquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and escapers[how] or luaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and escapers[how] or luaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replacekeyquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and quotedescapers[how] or quotedluaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and quotedescapers[how] or quotedluaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replaceoptional(l,m,r,t,how,recurse) - local v=t[l] - return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" + local v=t[l] + return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" end -local single=P("%") +local single=P("%") local double=P("%%") local lquoted=P("%[") local rquoted=P("]%") @@ -11033,41 +14492,41 @@ local noloptional=P("%?")/'' local noroptional=P("?%")/'' local nomoptional=P(":")/'' local args=Carg(1)*Carg(2)*Carg(3) -local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle -local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq -local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted +local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle +local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq +local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted local optional=noloptional*((C((1-nomoptional)^1)*nomoptional*C((1-noroptional)^1)*args)/replaceoptional)*noroptional local any=P(1) replacer=Cs((unquoted+quoted+escape+optional+key+any)^0) local function replace(str,mapping,how,recurse) - if mapping and str then - return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str - else - return str - end + if mapping and str then + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + else + return str + 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 + 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 - return replace(data,mapping,how,recurse) - else - return data - end + local data=io.loaddata(filename) or "" + if mapping and next(mapping) then + return replace(data,mapping,how,recurse) + else + return data + end end function templates.resolve(t,mapping,how,recurse) - if not mapping then - mapping=t - end - for k,v in next,t do - t[k]=replace(v,mapping,how,recurse) - end - return t + if not mapping then + mapping=t + end + for k,v in next,t do + t[k]=replace(v,mapping,how,recurse) + end + return t end @@ -11077,14 +14536,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sbx"] = package.loaded["util-sbx"] or true --- original size: 20393, stripped down to: 13924 +-- original size: 20393, stripped down to: 13121 if not modules then modules={} end modules ['util-sbx']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not sandbox then require("l-sandbox") end local next,type=next,type @@ -11117,144 +14576,144 @@ local report=logs.reporter("sandbox") trackers.register("sandbox",function(v) trace=v end) sandbox.setreporter(report) sandbox.finalizer { - category="files", - action=function() - finalized=true - end + category="files", + action=function() + finalized=true + end } local function registerroot(root,what) - if finalized then - report("roots are already finalized") - else - if type(root)=="table" then - root,what=root[1],root[2] - end - if type(root)=="string" and root~="" then - root=collapsepath(expandname(root)) - if what=="r" or what=="ro" or what=="readable" then - what="read" - elseif what=="w" or what=="wo" or what=="writable" then - what="write" - end - validroots[root]=what=="write" or false - end + if finalized then + report("roots are already finalized") + else + if type(root)=="table" then + root,what=root[1],root[2] + end + if type(root)=="string" and root~="" then + root=collapsepath(expandname(root)) + if what=="r" or what=="ro" or what=="readable" then + what="read" + elseif what=="w" or what=="wo" or what=="writable" then + what="write" + end + validroots[root]=what=="write" or false end + end end sandbox.finalizer { - category="files", - action=function() + category="files", + action=function() + if p_validroot then + report("roots are already initialized") + else + sandbox.registerroot(".","write") + for name in sortedhash(validroots) do if p_validroot then - report("roots are already initialized") + p_validroot=P(name)+p_validroot else - sandbox.registerroot(".","write") - for name in sortedhash(validroots) do - if p_validroot then - p_validroot=P(name)+p_validroot - else - p_validroot=P(name) - end - end - p_validroot=p_validroot/validroots + p_validroot=P(name) end + end + p_validroot=p_validroot/validroots end + end } local function registerbinary(name) - if finalized then - report("binaries are already finalized") - elseif type(name)=="string" and name~="" then - if not validbinaries then - return - end - if validbinaries==true then - validbinaries={ [name]=true } - else - validbinaries[name]=true - end - elseif name==true then - validbinaries={} + if finalized then + report("binaries are already finalized") + elseif type(name)=="string" and name~="" then + if not validbinaries then + return + end + if validbinaries==true then + validbinaries={ [name]=true } + else + validbinaries[name]=true end + elseif name==true then + validbinaries={} + end end local function registerlibrary(name) - if finalized then - report("libraries are already finalized") - elseif type(name)=="string" and name~="" then - if not validlibraries then - return - end - if validlibraries==true then - validlibraries={ [nameonly(name)]=true } - else - validlibraries[nameonly(name)]=true - end - elseif name==true then - validlibraries={} + if finalized then + report("libraries are already finalized") + elseif type(name)=="string" and name~="" then + if not validlibraries then + return + end + if validlibraries==true then + validlibraries={ [nameonly(name)]=true } + else + validlibraries[nameonly(name)]=true end + elseif name==true then + validlibraries={} + end end local p_write=S("wa") p_write=(1-p_write)^0*p_write -local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path +local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path local function normalized(name) - if platform=="windows" then - name=gsub(name,"/","\\") - end - return name + if platform=="windows" then + name=gsub(name,"/","\\") + end + return name end function sandbox.possiblepath(name) - return lpegmatch(p_path,name) and true or false + return lpegmatch(p_path,name) and true or false end local filenamelogger=false function sandbox.setfilenamelogger(l) - filenamelogger=type(l)=="function" and l or false + filenamelogger=type(l)=="function" and l or false end local function validfilename(name,what) - if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then - local asked=collapsepath(expandname(name)) - local okay=lpegmatch(p_validroot,asked) - if okay==true then - if filenamelogger then - filenamelogger(name,"w",asked,true) - end - return name - elseif okay==false then - if not what then - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - elseif lpegmatch(p_write,what) then - if filenamelogger then - filenamelogger(name,"w",asked,false) - end - return - else - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - end - elseif filenamelogger then - filenamelogger(name,"*",name,false) + if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then + local asked=collapsepath(expandname(name)) + local okay=lpegmatch(p_validroot,asked) + if okay==true then + if filenamelogger then + filenamelogger(name,"w",asked,true) + end + return name + elseif okay==false then + if not what then + if filenamelogger then + filenamelogger(name,"r",asked,true) end - else return name + elseif lpegmatch(p_write,what) then + if filenamelogger then + filenamelogger(name,"w",asked,false) + end + return + else + if filenamelogger then + filenamelogger(name,"r",asked,true) + end + return name + end + elseif filenamelogger then + filenamelogger(name,"*",name,false) end + else + return name + end end local function readable(name,finalized) - return validfilename(name,"r") + return validfilename(name,"r") end local function normalizedreadable(name,finalized) - local valid=validfilename(name,"r") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"r") + if valid then + return normalized(valid) + end end local function writeable(name,finalized) - return validfilename(name,"w") + return validfilename(name,"w") end local function normalizedwriteable(name,finalized) - local valid=validfilename(name,"w") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"w") + if valid then + return normalized(valid) + end end validators.readable=readable validators.writeable=normalizedwriteable @@ -11262,316 +14721,316 @@ validators.normalizedreadable=normalizedreadable validators.normalizedwriteable=writeable validators.filename=readable table.setmetatableindex(validators,function(t,k) - if k then - t[k]=readable - end - return readable + if k then + t[k]=readable + end + return readable end) function validators.string(s,finalized) - if finalized and suspicious(s) then - return "" - else - return s - end + if finalized and suspicious(s) then + return "" + else + return s + end end function validators.cache(s) - if finalized then - return basename(s) - else - return s - end + if finalized then + return basename(s) + else + return s + end end function validators.url(s) - if finalized and find("^file:") then - return "" - else - return s - end + if finalized and find("^file:") then + return "" + else + return s + end end local function filehandlerone(action,one,...) - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - else - end + local checkedone=validfilename(one) + if checkedone then + return action(one,...) + else + end end local function filehandlertwo(action,one,two,...) - local checkedone=validfilename(one) - if checkedone then - local checkedtwo=validfilename(two) - if checkedtwo then - return action(one,two,...) - else - end + local checkedone=validfilename(one) + if checkedone then + local checkedtwo=validfilename(two) + if checkedtwo then + return action(one,two,...) else end + else + end end local function iohandler(action,one,...) - if type(one)=="string" then - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - end - elseif one then - return action(one,...) - else - return action() + if type(one)=="string" then + local checkedone=validfilename(one) + if checkedone then + return action(one,...) end + elseif one then + return action(one,...) + else + return action() + end end local osexecute=sandbox.original(os.execute) local iopopen=sandbox.original(io.popen) local reported={} local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict) - if validbinaries~=false and (validbinaries==true or validbinaries[program]) then - if variables then - for variable,value in next,variables do - local checker=validators[checkers[variable]] - if checker then - value=checker(unquoted(value),strict) - if value then - variables[variable]=optionalquoted(value) - else - report("variable %a with value %a fails the check",variable,value) - return - end - else - report("variable %a has no checker",variable) - return - end - end - for variable,default in next,defaults do - local value=variables[variable] - if not value or value=="" then - local checker=validators[checkers[variable]] - if checker then - default=checker(unquoted(default),strict) - if default then - variables[variable]=optionalquoted(default) - else - report("variable %a with default %a fails the check",variable,default) - return - end - end - end - end - end - local command=program.." "..replace(template,variables) - if reporter then - reporter("executing runner %a: %s",name,command) - elseif trace then - report("executing runner %a: %s",name,command) - end - return command - elseif not reported[name] then - report("executing program %a of runner %a is not permitted",program,name) - reported[name]=true - end -end -local runners={ - resultof=function(...) - local command=validcommand(...) - if command then - if trace then - report("resultof: %s",command) - end - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - end - end - end, - execute=function(...) - local command=validcommand(...) - if command then - if trace then - report("execute: %s",command) - end - return osexecute(command) + if validbinaries~=false and (validbinaries==true or validbinaries[program]) then + if variables then + for variable,value in next,variables do + local checker=validators[checkers[variable]] + if checker then + value=checker(unquoted(value),strict) + if value then + variables[variable]=optionalquoted(value) + else + report("variable %a with value %a fails the check",variable,value) + return + end + else + report("variable %a has no checker",variable) + return end - end, - pipeto=function(...) - local command=validcommand(...) - if command then - if trace then - report("pipeto: %s",command) + end + for variable,default in next,defaults do + local value=variables[variable] + if not value or value=="" then + local checker=validators[checkers[variable]] + if checker then + default=checker(unquoted(default),strict) + if default then + variables[variable]=optionalquoted(default) + else + report("variable %a with default %a fails the check",variable,default) + return end - return iopopen(command,"w") - end - end, -} -function sandbox.registerrunner(specification) - if type(specification)=="string" then - local wrapped=validrunners[specification] - inspect(table.sortedkeys(validrunners)) - if wrapped then - return wrapped - else - report("unknown predefined runner %a",specification) - return + end end + end end - if type(specification)~="table" then - report("specification should be a table (or string)") - return - end - local name=specification.name - if type(name)~="string" then - report("invalid name, string expected",name) - return - end - if validrunners[name] then - report("invalid name, runner %a already defined") - return - end - local program=specification.program - if type(program)=="string" then - elseif type(program)=="table" then - program=program[platform] or program.default or program.unix - end - if type(program)~="string" or program=="" then - report("invalid runner %a specified for platform %a",name,platform) - return + local command=program.." "..replace(template,variables) + if reporter then + reporter("executing runner %a: %s",name,command) + elseif trace then + report("executing runner %a: %s",name,command) end - local template=specification.template - if not template then - report("missing template for runner %a",name) - return + return command + elseif not reported[name] then + report("executing program %a of runner %a is not permitted",program,name) + reported[name]=true + end +end +local runners={ + resultof=function(...) + local command=validcommand(...) + if command then + if trace then + report("resultof: %s",command) + end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + end end - local method=specification.method or "execute" - local checkers=specification.checkers or {} - local defaults=specification.defaults or {} - local runner=runners[method] - if runner then - local finalized=finalized - local wrapped=function(variables) - return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) - end - validrunners[name]=wrapped - return wrapped - else - validrunners[name]=nil - report("invalid method for runner %a",name) + end, + execute=function(...) + local command=validcommand(...) + if command then + if trace then + report("execute: %s",command) + end + return osexecute(command) + end + end, + pipeto=function(...) + local command=validcommand(...) + if command then + if trace then + report("pipeto: %s",command) + end + return iopopen(command,"w") end + end, +} +function sandbox.registerrunner(specification) + if type(specification)=="string" then + local wrapped=validrunners[specification] + inspect(table.sortedkeys(validrunners)) + if wrapped then + return wrapped + else + report("unknown predefined runner %a",specification) + return + end + end + if type(specification)~="table" then + report("specification should be a table (or string)") + return + end + local name=specification.name + if type(name)~="string" then + report("invalid name, string expected",name) + return + end + if validrunners[name] then + report("invalid name, runner %a already defined") + return + end + local program=specification.program + if type(program)=="string" then + elseif type(program)=="table" then + program=program[platform] or program.default or program.unix + end + if type(program)~="string" or program=="" then + report("invalid runner %a specified for platform %a",name,platform) + return + end + local template=specification.template + if not template then + report("missing template for runner %a",name) + return + end + local method=specification.method or "execute" + local checkers=specification.checkers or {} + local defaults=specification.defaults or {} + local runner=runners[method] + if runner then + local finalized=finalized + local wrapped=function(variables) + return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) + end + validrunners[name]=wrapped + return wrapped + else + validrunners[name]=nil + report("invalid method for runner %a",name) + end end function sandbox.getrunner(name) - return name and validrunners[name] + return name and validrunners[name] end local function suspicious(str) - return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false + return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false end local function binaryrunner(action,command,...) - if validbinaries==false then - report("no binaries permitted, ignoring command: %s",command) - return - end - if type(command)~="string" then - report("command should be a string") - return - end - local program=lpegmatch(p_split,command) - if not program or program=="" then - report("unable to filter binary from command: %s",command) - return - end - if validbinaries==true then - elseif not validbinaries[program] then - report("binary not permitted, ignoring command: %s",command) - return - elseif suspicious(command) then - report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) - return - end - return action(command,...) + if validbinaries==false then + report("no binaries permitted, ignoring command: %s",command) + return + end + if type(command)~="string" then + report("command should be a string") + return + end + local program=lpegmatch(p_split,command) + if not program or program=="" then + report("unable to filter binary from command: %s",command) + return + end + if validbinaries==true then + elseif not validbinaries[program] then + report("binary not permitted, ignoring command: %s",command) + return + elseif suspicious(command) then + report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) + return + end + return action(command,...) end local function dummyrunner(action,command,...) - if type(command)=="table" then - command=concat(command," ",command[0] and 0 or 1) - end - report("ignoring command: %s",command) + if type(command)=="table" then + command=concat(command," ",command[0] and 0 or 1) + end + report("ignoring command: %s",command) end sandbox.filehandlerone=filehandlerone sandbox.filehandlertwo=filehandlertwo sandbox.iohandler=iohandler function sandbox.disablerunners() - validbinaries=false + validbinaries=false end function sandbox.disablelibraries() - validlibraries=false + validlibraries=false end if FFISUPPORTED and ffi then - function sandbox.disablelibraries() - validlibraries=false - for k,v in next,ffi do - if k~="gc" then - ffi[k]=nil - end - end + function sandbox.disablelibraries() + validlibraries=false + for k,v in next,ffi do + if k~="gc" then + ffi[k]=nil + end end - local fiiload=ffi.load - if fiiload then - local reported={} - function ffi.load(name,...) - if validlibraries==false then - elseif validlibraries==true then - return fiiload(name,...) - elseif validlibraries[nameonly(name)] then - return fiiload(name,...) - else - end - if not reported[name] then - report("using library %a is not permitted",name) - reported[name]=true - end - return nil - end + end + local fiiload=ffi.load + if fiiload then + local reported={} + function ffi.load(name,...) + if validlibraries==false then + elseif validlibraries==true then + return fiiload(name,...) + elseif validlibraries[nameonly(name)] then + return fiiload(name,...) + else + end + if not reported[name] then + report("using library %a is not permitted",name) + reported[name]=true + end + return nil end + end end local overload=sandbox.overload local register=sandbox.register - overload(loadfile,filehandlerone,"loadfile") + overload(loadfile,filehandlerone,"loadfile") if io then - overload(io.open,filehandlerone,"io.open") - overload(io.popen,binaryrunner,"io.popen") - overload(io.input,iohandler,"io.input") - overload(io.output,iohandler,"io.output") - overload(io.lines,filehandlerone,"io.lines") + overload(io.open,filehandlerone,"io.open") + overload(io.popen,binaryrunner,"io.popen") + overload(io.input,iohandler,"io.input") + overload(io.output,iohandler,"io.output") + overload(io.lines,filehandlerone,"io.lines") end if os then - overload(os.execute,binaryrunner,"os.execute") - overload(os.spawn,dummyrunner,"os.spawn") - overload(os.exec,dummyrunner,"os.exec") - overload(os.resultof,binaryrunner,"os.resultof") - overload(os.pipeto,binaryrunner,"os.pipeto") - overload(os.rename,filehandlertwo,"os.rename") - overload(os.remove,filehandlerone,"os.remove") + overload(os.execute,binaryrunner,"os.execute") + overload(os.spawn,dummyrunner,"os.spawn") + overload(os.exec,dummyrunner,"os.exec") + overload(os.resultof,binaryrunner,"os.resultof") + overload(os.pipeto,binaryrunner,"os.pipeto") + overload(os.rename,filehandlertwo,"os.rename") + overload(os.remove,filehandlerone,"os.remove") end if lfs then - overload(lfs.chdir,filehandlerone,"lfs.chdir") - overload(lfs.mkdir,filehandlerone,"lfs.mkdir") - overload(lfs.rmdir,filehandlerone,"lfs.rmdir") - overload(lfs.isfile,filehandlerone,"lfs.isfile") - overload(lfs.isdir,filehandlerone,"lfs.isdir") - overload(lfs.attributes,filehandlerone,"lfs.attributes") - overload(lfs.dir,filehandlerone,"lfs.dir") - overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") - overload(lfs.touch,filehandlerone,"lfs.touch") - overload(lfs.link,filehandlertwo,"lfs.link") - overload(lfs.setmode,filehandlerone,"lfs.setmode") - overload(lfs.readlink,filehandlerone,"lfs.readlink") - overload(lfs.shortname,filehandlerone,"lfs.shortname") - overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") + overload(lfs.chdir,filehandlerone,"lfs.chdir") + overload(lfs.mkdir,filehandlerone,"lfs.mkdir") + overload(lfs.rmdir,filehandlerone,"lfs.rmdir") + overload(lfs.isfile,filehandlerone,"lfs.isfile") + overload(lfs.isdir,filehandlerone,"lfs.isdir") + overload(lfs.attributes,filehandlerone,"lfs.attributes") + overload(lfs.dir,filehandlerone,"lfs.dir") + overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") + overload(lfs.touch,filehandlerone,"lfs.touch") + overload(lfs.link,filehandlertwo,"lfs.link") + overload(lfs.setmode,filehandlerone,"lfs.setmode") + overload(lfs.readlink,filehandlerone,"lfs.readlink") + overload(lfs.shortname,filehandlerone,"lfs.shortname") + overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") end if zip then - zip.open=register(zip.open,filehandlerone,"zip.open") + zip.open=register(zip.open,filehandlerone,"zip.open") end if fontloader then - fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") - fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") + fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") + fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") end if epdf then - epdf.open=register(epdf.open,filehandlerone,"epdf.open") + epdf.open=register(epdf.open,filehandlerone,"epdf.open") end sandbox.registerroot=registerroot sandbox.registerbinary=registerbinary @@ -11585,14 +15044,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-mrg"] = package.loaded["util-mrg"] or true --- original size: 7757, stripped down to: 6015 +-- original size: 7819, stripped down to: 5881 if not modules then modules={} end modules ['util-mrg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gsub,format=string.gsub,string.format local concat=table.concat @@ -11620,19 +15079,19 @@ local m_report=[[ ]] local m_preloaded=[[package.loaded[%q] = package.loaded[%q] or true]] local function self_fake() - return m_faked + return m_faked end local function self_nothing() - return "" + return "" end local function self_load(name) - local data=io.loaddata(name) or "" - if data=="" then - report("unknown file %a",name) - else - report("inserting file %a",name) - end - return data or "" + local data=io.loaddata(name) or "" + if data=="" then + report("unknown file %a",name) + else + report("inserting file %a",name) + end + return data or "" end local space=patterns.space local eol=patterns.newline @@ -11661,98 +15120,99 @@ local mandatespacing=(eol+space)^1/"" local pack=digit*space^1*operator4*optionalspacing+optionalspacing*operator1*optionalspacing+optionalspacing*operator2*optionalspaces+mandatespacing*operator3*mandatespaces+optionalspaces*separator*optionalspaces local lines=emptyline^2/"\n" local spaces=(space*space)/" " +local spaces=(space*space*space*space)/" " local compact=Cs (( - ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 + ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 )^1 ) local strip=Cs((emptyline^2/"\n"+1)^0) local stripreturn=Cs((1-P("return")*space^1*P(1-space-eol)^1*(space+eol)^0*P(-1))^1) function merger.compact(data) - return lpegmatch(strip,lpegmatch(compact,data)) + return lpegmatch(strip,lpegmatch(compact,data)) end local function self_compact(data) - local delta=0 - if merger.strip_comment then - local before=#data - data=lpegmatch(compact,data) - data=lpegmatch(strip,data) - local after=#data - delta=before-after - report("original size %s, compacted to %s, stripped %s",before,after,delta) - data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) - end - return lpegmatch(stripreturn,data) or data,delta + local delta=0 + if merger.strip_comment then + local before=#data + data=lpegmatch(compact,data) + data=lpegmatch(strip,data) + local after=#data + delta=before-after + report("original size %s, compacted to %s, stripped %s",before,after,delta) + data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) + end + return lpegmatch(stripreturn,data) or data,delta end local function self_save(name,data) - if data~="" then - io.savedata(name,data) - report("saving %s with size %s",name,#data) - end + if data~="" then + io.savedata(name,data) + report("saving %s with size %s",name,#data) + end end local function self_swap(data,code) - return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" + return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" end local function self_libs(libs,list) - local result,f,frozen,foundpath={},nil,false,nil - result[#result+1]="\n" - if type(libs)=='string' then libs={ libs } end - if type(list)=='string' then list={ list } end + local result,f,frozen,foundpath={},nil,false,nil + result[#result+1]="\n" + if type(libs)=='string' then libs={ libs } end + if type(list)=='string' then list={ list } end + for i=1,#libs do + local lib=libs[i] + for j=1,#list do + local pth=gsub(list[j],"\\","/") + report("checking library path %a",pth) + local name=pth.."/"..lib + if lfs.isfile(name) then + foundpath=pth + end + end + if foundpath then break end + end + if foundpath then + report("using library path %a",foundpath) + local right,wrong,original,stripped={},{},0,0 for i=1,#libs do - local lib=libs[i] - for j=1,#list do - local pth=gsub(list[j],"\\","/") - report("checking library path %a",pth) - local name=pth.."/"..lib - if lfs.isfile(name) then - foundpath=pth - end - end - if foundpath then break end - end - if foundpath then - report("using library path %a",foundpath) - local right,wrong,original,stripped={},{},0,0 - for i=1,#libs do - local lib=libs[i] - local fullname=foundpath.."/"..lib - if lfs.isfile(fullname) then - report("using library %a",fullname) - local preloaded=file.nameonly(lib) - local data=io.loaddata(fullname,true) - original=original+#data - local data,delta=self_compact(data) - right[#right+1]=lib - result[#result+1]=m_begin_closure - result[#result+1]=format(m_preloaded,preloaded,preloaded) - result[#result+1]=data - result[#result+1]=m_end_closure - stripped=stripped+delta - else - report("skipping library %a",fullname) - wrong[#wrong+1]=lib - end - end - right=#right>0 and concat(right," ") or "-" - wrong=#wrong>0 and concat(wrong," ") or "-" - report("used libraries: %a",right) - report("skipped libraries: %a",wrong) - report("original bytes: %a",original) - report("stripped bytes: %a",stripped) - result[#result+1]=format(m_report,right,wrong,original,stripped) - else - report("no valid library path found") + local lib=libs[i] + local fullname=foundpath.."/"..lib + if lfs.isfile(fullname) then + report("using library %a",fullname) + local preloaded=file.nameonly(lib) + local data=io.loaddata(fullname,true) + original=original+#data + local data,delta=self_compact(data) + right[#right+1]=lib + result[#result+1]=m_begin_closure + result[#result+1]=format(m_preloaded,preloaded,preloaded) + result[#result+1]=data + result[#result+1]=m_end_closure + stripped=stripped+delta + else + report("skipping library %a",fullname) + wrong[#wrong+1]=lib + end end - return concat(result,"\n\n") + right=#right>0 and concat(right," ") or "-" + wrong=#wrong>0 and concat(wrong," ") or "-" + report("used libraries: %a",right) + report("skipped libraries: %a",wrong) + report("original bytes: %a",original) + report("stripped bytes: %a",stripped) + result[#result+1]=format(m_report,right,wrong,original,stripped) + else + report("no valid library path found") + end + return concat(result,"\n\n") end function merger.selfcreate(libs,list,target) - if target then - self_save(target,self_swap(self_fake(),self_libs(libs,list))) - end + if target then + self_save(target,self_swap(self_fake(),self_libs(libs,list))) + end end function merger.selfmerge(name,libs,list,target) - self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) + self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) end function merger.selfclean(name) - self_save(name,self_swap(self_load(name),self_nothing())) + self_save(name,self_swap(self_load(name),self_nothing())) end @@ -11762,14 +15222,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 9400, stripped down to: 5499 +-- original size: 9738, stripped down to: 5531 if not modules then modules={} end modules ['util-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find @@ -11781,178 +15241,193 @@ local setlocale=os.setlocale setlocale(nil,nil) local report=logs.reporter("system") function os.setlocale(a,b) - if a or b then - if report then - report() - report("You're messing with os.locale in a supposedly locale neutral enviroment. From") - report("now on are on your own and without support. Crashes or unexpected side effects") - report("can happen but don't bother the luatex and context developer team with it.") - report() - report=nil - end - setlocale(a,b) - end + if a or b then + if report then + report() + report("You're messing with os.locale in a supposedly locale neutral enviroment. From") + report("now on are on your own and without support. Crashes or unexpected side effects") + report("can happen but don't bother the luatex and context developer team with it.") + report() + report=nil + end + setlocale(a,b) + end end local validengines=allocate { - ["luatex"]=true, - ["luajittex"]=true, + ["luatex"]=true, + ["luajittex"]=true, } local basicengines=allocate { - ["luatex"]="luatex", - ["texlua"]="luatex", - ["texluac"]="luatex", - ["luajittex"]="luajittex", - ["texluajit"]="luajittex", + ["luatex"]="luatex", + ["texlua"]="luatex", + ["texluac"]="luatex", + ["luajittex"]="luajittex", + ["texluajit"]="luajittex", } local luaengines=allocate { - ["lua"]=true, - ["luajit"]=true, + ["lua"]=true, + ["luajit"]=true, } environment.validengines=validengines environment.basicengines=basicengines if not arg then - environment.used_as_library=true + environment.used_as_library=true elseif luaengines[file.removesuffix(arg[-1])] then elseif validengines[file.removesuffix(arg[0])] then - if arg[1]=="--luaonly" then - arg[-1]=arg[0] - arg[ 0]=arg[2] - for k=3,#arg do - arg[k-2]=arg[k] - end - remove(arg) - remove(arg) - else - end - local originalzero=file.basename(arg[0]) - local specialmapping={ luatools=="base" } - if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then + if arg[1]=="--luaonly" then + arg[-1]=arg[0] + arg[ 0]=arg[2] + for k=3,#arg do + arg[k-2]=arg[k] + end + remove(arg) + remove(arg) + else + end + local originalzero=file.basename(arg[0]) + local specialmapping={ luatools=="base" } + if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then arg[0]=specialmapping[originalzero] or originalzero insert(arg,0,"--script") insert(arg,0,"mtxrun") - end + end end environment.arguments=allocate() environment.files=allocate() environment.sortedflags=nil function environment.initializearguments(arg) - local arguments,files={},{} - environment.arguments,environment.files,environment.sortedflags=arguments,files,nil - for index=1,#arg do - local argument=arg[index] - if index>0 then - local flag,value=match(argument,"^%-+(.-)=(.-)$") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=unquoted(value or "") - else - flag=match(argument,"^%-+(.+)") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=true - else - files[#files+1]=argument - end - end + local arguments={} + local files={} + environment.arguments=arguments + environment.files=files + environment.sortedflags=nil + for index=1,#arg do + local argument=arg[index] + if index>0 then + local flag,value=match(argument,"^%-+(.-)=(.-)$") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=unquoted(value or "") + else + flag=match(argument,"^%-+(.+)") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=true + else + files[#files+1]=argument end + end + end + end + if not environment.ownname then + if os.selfpath and os.selfname then + environment.ownname=file.addsuffix(file.join(os.selfpath,os.selfname),"lua") end - environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') + end + environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') end function environment.setargument(name,value) - environment.arguments[name]=value + environment.arguments[name]=value end function environment.getargument(name,partial) - local arguments,sortedflags=environment.arguments,environment.sortedflags - if arguments[name] then - return arguments[name] - elseif partial then - if not sortedflags then - sortedflags=allocate(table.sortedkeys(arguments)) - for k=1,#sortedflags do - sortedflags[k]="^"..sortedflags[k] - end - environment.sortedflags=sortedflags - end - for k=1,#sortedflags do - local v=sortedflags[k] - if find(name,v) then - return arguments[sub(v,2,#v)] - end - end + local arguments,sortedflags=environment.arguments,environment.sortedflags + if arguments[name] then + return arguments[name] + elseif partial then + if not sortedflags then + sortedflags=allocate(table.sortedkeys(arguments)) + for k=1,#sortedflags do + sortedflags[k]="^"..sortedflags[k] + end + environment.sortedflags=sortedflags end - return nil + for k=1,#sortedflags do + local v=sortedflags[k] + if find(name,v) then + return arguments[sub(v,2,#v)] + end + end + end + return nil end environment.argument=environment.getargument function environment.splitarguments(separator) - local done,before,after=false,{},{} - local originalarguments=environment.originalarguments - for k=1,#originalarguments do - local v=originalarguments[k] - if not done and v==separator then - done=true - elseif done then - after[#after+1]=v - else - before[#before+1]=v - end + local done,before,after=false,{},{} + local originalarguments=environment.originalarguments + for k=1,#originalarguments do + local v=originalarguments[k] + if not done and v==separator then + done=true + elseif done then + after[#after+1]=v + else + before[#before+1]=v end - return before,after + end + return before,after end function environment.reconstructcommandline(arg,noquote) - local resolveprefix=resolvers.resolve - arg=arg or environment.originalarguments - if noquote and #arg==1 then - return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) - elseif #arg>0 then - local result={} - for i=1,#arg do - result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) - end - return concat(result," ") - else - return "" + local resolveprefix=resolvers.resolve + arg=arg or environment.originalarguments + if noquote and #arg==1 then + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) + elseif #arg>0 then + local result={} + for i=1,#arg do + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end + return concat(result," ") + else + return "" + end end function environment.relativepath(path,root) - if not path then - path="" + if not path then + path="" + end + if not file.is_rootbased_path(path) then + if not root then + root=file.pathpart(environment.ownscript or environment.ownname or ".") end - if not file.is_rootbased_path(path) then - if not root then - root=file.pathpart(environment.ownscript or environment.ownname or ".") - end - if root=="" then - root="." - end - path=root.."/"..path + if root=="" then + root="." end - return file.collapsepath(path,true) + path=root.."/"..path + end + return file.collapsepath(path,true) end if arg then - local newarg,instring={},false - for index=1,#arg do - local argument=arg[index] - if find(argument,"^\"") then - newarg[#newarg+1]=gsub(argument,"^\"","") - if not find(argument,"\"$") then - instring=true - end - elseif find(argument,"\"$") then - newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") - instring=false - elseif instring then - newarg[#newarg]=newarg[#newarg].." "..argument - else - newarg[#newarg+1]=argument - end - end - for i=1,-5,-1 do - newarg[i]=arg[i] + local newarg,instring={},false + for index=1,#arg do + local argument=arg[index] + if find(argument,"^\"") then + if find(argument,"\"$") then + newarg[#newarg+1]=gsub(argument,"^\"(.-)\"$","%1") + instring=false + else + newarg[#newarg+1]=gsub(argument,"^\"","") + instring=true + end + elseif find(argument,"\"$") then + if instring then + newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") + instring=false + else + newarg[#newarg+1]=argument + end + elseif instring then + newarg[#newarg]=newarg[#newarg].." "..argument + else + newarg[#newarg+1]=argument end - environment.initializearguments(newarg) - environment.originalarguments=mark(newarg) - environment.rawarguments=mark(arg) - arg={} + end + for i=1,-5,-1 do + newarg[i]=arg[i] + end + environment.initializearguments(newarg) + environment.originalarguments=mark(newarg) + environment.rawarguments=mark(arg) + arg={} end @@ -11962,17 +15437,18 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-env"] = package.loaded["luat-env"] or true --- original size: 5820, stripped down to: 4155 +-- original size: 6134, stripped down to: 4118 if not modules then modules={} end modules ['luat-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local rawset,rawget,loadfile,assert=rawset,rawget,loadfile,assert -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local rawset,rawget,loadfile=rawset,rawget,loadfile +local gsub=string.gsub +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_lua=logs.reporter("resolvers","lua") local luautilities=utilities.lua local luasuffixes=luautilities.suffixes @@ -11980,133 +15456,146 @@ local texgettoks=tex and tex.gettoks environment=environment or {} local environment=environment local mt={ - __index=function(_,k) - if k=="version" then - local version=texgettoks and texgettoks("contextversiontoks") - if version and version~="" then - rawset(environment,"version",version) - return version - else - return "unknown" - end - elseif k=="kind" then - local kind=texgettoks and texgettoks("contextkindtoks") - if kind and kind~="" then - rawset(environment,"kind",kind) - return kind - else - return "unknown" - end - elseif k=="jobname" or k=="formatname" then - local name=tex and tex[k] - if name or name=="" then - rawset(environment,k,name) - return name - else - return "unknown" - end - elseif k=="outputfilename" then - local name=environment.jobname - rawset(environment,k,name) - return name - end + __index=function(_,k) + if k=="version" then + local version=texgettoks and texgettoks("contextversiontoks") + if version and version~="" then + rawset(environment,"version",version) + return version + else + return "unknown" + end + elseif k=="kind" then + local kind=texgettoks and texgettoks("contextkindtoks") + if kind and kind~="" then + rawset(environment,"kind",kind) + return kind + else + return "unknown" + end + elseif k=="jobname" or k=="formatname" then + local name=tex and tex[k] + if name or name=="" then + rawset(environment,k,name) + return name + else + return "unknown" + end + elseif k=="outputfilename" then + local name=environment.jobname + rawset(environment,k,name) + return name end + end } setmetatable(environment,mt) function environment.texfile(filename) - return resolvers.findfile(filename,'tex') + return resolvers.findfile(filename,'tex') end function environment.luafile(filename) - local resolved=resolvers.findfile(filename,'tex') or "" - if resolved~="" then - return resolved - end - resolved=resolvers.findfile(filename,'texmfscripts') or "" - if resolved~="" then - return resolved - end - return resolvers.findfile(filename,'luatexlibs') or "" -end -local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) + local resolved=resolvers.findfile(filename,'tex') or "" + if resolved~="" then + return resolved + end + resolved=resolvers.findfile(filename,'texmfscripts') or "" + if resolved~="" then + return resolved + end + return resolvers.findfile(filename,'luatexlibs') or "" +end +local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) local function strippable(filename) - if stripindeed then - local modu=modules[file.nameonly(filename)] - return modu and modu.dataonly - else - return false - end + if stripindeed then + local modu=modules[file.nameonly(filename)] + return modu and modu.dataonly + else + return false + end end function environment.luafilechunk(filename,silent,macros) - filename=file.replacesuffix(filename,"lua") - local fullname=environment.luafile(filename) - if fullname and fullname~="" then - local data=luautilities.loadedluacode(fullname,strippable,filename,macros) - if not silent then - report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") - end - return data - else - if not silent then - report_lua("unknown file %a",filename) - end - return nil + filename=file.replacesuffix(filename,"lua") + local fullname=environment.luafile(filename) + if fullname and fullname~="" then + local data=luautilities.loadedluacode(fullname,strippable,filename,macros) + if not silent then + report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") + end + return data + else + if not silent then + report_lua("unknown file %a",filename) end + return nil + end end function environment.loadluafile(filename,version) - local lucname,luaname,chunk - local basename=file.removesuffix(filename) - if basename==filename then - luaname=file.addsuffix(basename,luasuffixes.lua) - lucname=file.addsuffix(basename,luasuffixes.luc) - else - luaname=basename - lucname=nil - end - local fullname=(lucname and environment.luafile(lucname)) or "" - if fullname~="" then + local lucname,luaname,chunk + local basename=file.removesuffix(filename) + if basename==filename then + luaname=file.addsuffix(basename,luasuffixes.lua) + lucname=file.addsuffix(basename,luasuffixes.luc) + else + luaname=filename + lucname=nil + end + local fullname=(lucname and environment.luafile(lucname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) + end + chunk=loadfile(fullname) + end + if chunk then + chunk() + if version then + local v=version + if modules and modules[filename] then + v=modules[filename].version + elseif versions and versions[filename] then + v=versions[filename] + end + if v==version then + return true + else if trace_locating then - report_lua("loading %a",fullname) + report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) end - chunk=loadfile(fullname) + environment.loadluafile(filename) + end + else + return true end - if chunk then - assert(chunk)() - if version then - local v=version - if modules and modules[filename] then - v=modules[filename].version - elseif versions and versions[filename] then - v=versions[filename] - end - if v==version then - return true - else - if trace_locating then - report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) - end - environment.loadluafile(filename) - end - else - return true - end + end + fullname=(luaname and environment.luafile(luaname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) end - fullname=(luaname and environment.luafile(luaname)) or "" - if fullname~="" then - if trace_locating then - report_lua("loading %a",fullname) - end - chunk=loadfile(fullname) - if not chunk then - if trace_locating then - report_lua("unknown file %a",filename) - end - else - assert(chunk)() - return true - end + chunk=loadfile(fullname) + if not chunk then + if trace_locating then + report_lua("unknown file %a",filename) + end + else + chunk() + return true end - return false + end + return false end +environment.filenames=setmetatable({},{ + __index=function(t,k) + local v=environment.files[k] + if v then + return (gsub(v,"%.+$","")) + end + end, + __newindex=function(t,k) + end, + __len=function(t) + return #environment.files + end, +} ) end -- of closure @@ -12115,16 +15604,16 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true --- original size: 60383, stripped down to: 38562 +-- original size: 60383, stripped down to: 35698 if not modules then modules={} end modules ['lxml-tab']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_entities=false trackers.register("xml.entities",function(v) trace_entities=v end) +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 {} @@ -12142,17 +15631,17 @@ xml.xmlns=xml.xmlns or {} local check=P(false) local parse=check function xml.registerns(namespace,pattern) - check=check+C(P(lower(pattern)))/namespace - parse=P { P(check)+1*V(1) } + check=check+C(P(lower(pattern)))/namespace + parse=P { P(check)+1*V(1) } end function xml.checkns(namespace,url) - local ns=lpegmatch(parse,lower(url)) - if ns and namespace~=ns then - xml.xmlns[namespace]=ns - end + local ns=lpegmatch(parse,lower(url)) + if ns and namespace~=ns then + xml.xmlns[namespace]=ns + end end function xml.resolvens(url) - return lpegmatch(parse,lower(url)) or "" + return lpegmatch(parse,lower(url)) or "" end end local nsremap,resolvens=xml.xmlns,xml.resolvens @@ -12170,661 +15659,661 @@ local handle_dec_entity local handle_any_entity_dtd local handle_any_entity_text local function preparexmlstate(settings) - if settings then - linenumbers=settings.linenumbers - stack={} - level=0 - top={} - at={} - mt={} - dt={} - nt=0 - xmlns={} - errorstr=nil - strip=settings.strip_cm_and_dt - utfize=settings.utfize_entities - resolve=settings.resolve_entities - resolve_predefined=settings.resolve_predefined_entities - unify_predefined=settings.unify_predefined_entities - cleanup=settings.text_cleanup - entities=settings.entities or {} - currentfilename=settings.currentresource - currentline=1 - parameters={} - reported_at_errors={} - dcache={} - hcache={} - acache={} - if utfize==nil then - settings.utfize_entities=true - utfize=true - end - if resolve_predefined==nil then - settings.resolve_predefined_entities=true - resolve_predefined=true - end - else - linenumbers=false - stack=nil - level=nil - top=nil - at=nil - mt=nil - dt=nil - nt=nil - xmlns=nil - errorstr=nil - strip=nil - utfize=nil - resolve=nil - resolve_predefined=nil - unify_predefined=nil - cleanup=nil - entities=nil - parameters=nil - reported_at_errors=nil - dcache=nil - hcache=nil - acache=nil - currentfilename=nil - currentline=1 - end + if settings then + linenumbers=settings.linenumbers + stack={} + level=0 + top={} + at={} + mt={} + dt={} + nt=0 + xmlns={} + errorstr=nil + strip=settings.strip_cm_and_dt + utfize=settings.utfize_entities + resolve=settings.resolve_entities + resolve_predefined=settings.resolve_predefined_entities + unify_predefined=settings.unify_predefined_entities + cleanup=settings.text_cleanup + entities=settings.entities or {} + currentfilename=settings.currentresource + currentline=1 + parameters={} + reported_at_errors={} + dcache={} + hcache={} + acache={} + if utfize==nil then + settings.utfize_entities=true + utfize=true + end + if resolve_predefined==nil then + settings.resolve_predefined_entities=true + resolve_predefined=true + end + else + linenumbers=false + stack=nil + level=nil + top=nil + at=nil + mt=nil + dt=nil + nt=nil + xmlns=nil + errorstr=nil + strip=nil + utfize=nil + resolve=nil + resolve_predefined=nil + unify_predefined=nil + cleanup=nil + entities=nil + parameters=nil + reported_at_errors=nil + dcache=nil + hcache=nil + acache=nil + currentfilename=nil + currentline=1 + end end local function initialize_mt(root) - mt={ __index=root } + mt={ __index=root } end function xml.setproperty(root,k,v) - getmetatable(root).__index[k]=v + getmetatable(root).__index[k]=v end function xml.checkerror(top,toclose) - return "" + return "" end local checkns=xml.checkns local function add_attribute(namespace,tag,value) - if cleanup and value~="" then - value=cleanup(value) - end - if tag=="xmlns" then - xmlns[#xmlns+1]=resolvens(value) - at[tag]=value - elseif namespace=="" then - at[tag]=value - elseif namespace=="xmlns" then - checkns(tag,value) - at["xmlns:"..tag]=value - else - at[namespace..":"..tag]=value - end + if cleanup and value~="" then + value=cleanup(value) + end + if tag=="xmlns" then + xmlns[#xmlns+1]=resolvens(value) + at[tag]=value + elseif namespace=="" then + at[tag]=value + elseif namespace=="xmlns" then + checkns(tag,value) + at["xmlns:"..tag]=value + else + at[namespace..":"..tag]=value + end end local function add_empty(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - top=stack[level] - dt=top.dt - nt=#dt+1 - local t=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - cf=currentfilename, - cl=currentline, - __p__=top, - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - __p__=top, - } - dt[nt]=t - setmetatable(t,mt) - if at.xmlns then - remove(xmlns) - end - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + top=stack[level] + dt=top.dt + nt=#dt+1 + local t=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + cf=currentfilename, + cl=currentline, + __p__=top, + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + __p__=top, + } + dt[nt]=t + setmetatable(t,mt) + if at.xmlns then + remove(xmlns) + end + at={} end local function add_begin(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - dt={} - top=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - cf=currentfilename, - cl=currentline, - __p__=stack[level], - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - __p__=stack[level], - } - setmetatable(top,mt) - nt=0 - level=level+1 - stack[level]=top - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + dt={} + top=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + cf=currentfilename, + cl=currentline, + __p__=stack[level], + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + __p__=stack[level], + } + setmetatable(top,mt) + nt=0 + level=level+1 + stack[level]=top + at={} end local function add_end(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local toclose=stack[level] - level=level-1 - top=stack[level] - if level<1 then - errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - elseif toclose.tg~=tag then - errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - end - dt=top.dt - nt=#dt+1 - dt[nt]=toclose - toclose.ni=nt - if toclose.at.xmlns then - remove(xmlns) - end + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local toclose=stack[level] + level=level-1 + top=stack[level] + if level<1 then + errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + elseif toclose.tg~=tag then + errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + end + dt=top.dt + nt=#dt+1 + dt[nt]=toclose + toclose.ni=nt + if toclose.at.xmlns then + remove(xmlns) + end end local function add_text(text) - if text=="" then - return - end - if cleanup then - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..cleanup(text) - else - nt=nt+1 - dt[nt]=cleanup(text) - end - else - nt=1 - dt[1]=cleanup(text) - end + if text=="" then + return + end + if cleanup then + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..cleanup(text) + else + nt=nt+1 + dt[nt]=cleanup(text) + end else - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..text - else - nt=nt+1 - dt[nt]=text - end - else - nt=1 - dt[1]=text - end + nt=1 + dt[1]=cleanup(text) end -end -local function add_special(what,spacing,text) - if spacing~="" then + else + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..text + else nt=nt+1 - dt[nt]=spacing - end - if strip and (what=="@cm@" or what=="@dt@") then + dt[nt]=text + end else - nt=nt+1 - dt[nt]=linenumbers and { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - cf=currentfilename, - cl=currentline, - } or { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - } + nt=1 + dt[1]=text end + end +end +local function add_special(what,spacing,text) + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + if strip and (what=="@cm@" or what=="@dt@") then + else + nt=nt+1 + dt[nt]=linenumbers and { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + cf=currentfilename, + cl=currentline, + } or { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + } + end end local function set_message(txt) - errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") + errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") end local function attribute_value_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute value %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute value %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end local function attribute_specification_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute specification %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute specification %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end do - local badentity="&" - xml.placeholders={ - unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, - unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, - unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, - } - local function fromhex(s) - local n=tonumber(s,16) - if n then - return utfchar(n) - else - return formatters["h:%s"](s),true + local badentity="&" + xml.placeholders={ + unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, + unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, + unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, + } + local function fromhex(s) + local n=tonumber(s,16) + if n then + return utfchar(n) + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return utfchar(n) + else + return formatters["d:%s"](s),true + end + end + local p_rest=(1-P(";"))^0 + local p_many=P(1)^0 + local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) + xml.parsedentitylpeg=parsedentity + local predefined_unified={ + [38]="&", + [42]=""", + [47]="'", + [74]="<", + [76]=">", + } + local predefined_simplified={ + [38]="&",amp="&", + [42]='"',quot='"', + [47]="'",apos="'", + [74]="<",lt="<", + [76]=">",gt=">", + } + local nofprivates=0xF0000 + local privates_u={ + [ [[&]] ]="&", + [ [["]] ]=""", + [ [[']] ]="'", + [ [[<]] ]="<", + [ [[>]] ]=">", + } + local privates_p={ + } + local privates_s={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[&]] ]="&U+26;", + [ [[']] ]="&U+27;", + [ [[<]] ]="&U+3C;", + [ [[>]] ]="&U+3E;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_x={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[']] ]="&U+27;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_n={ + } + local escaped=utf.remapper(privates_u,"dynamic") + local unprivatized=utf.remapper(privates_p,"dynamic") + local unspecialized=utf.remapper(privates_s,"dynamic") + local despecialized=utf.remapper(privates_x,"dynamic") + xml.unprivatized=unprivatized + xml.unspecialized=unspecialized + xml.despecialized=despecialized + xml.escaped=escaped + local function unescaped(s) + local p=privates_n[s] + if not p then + nofprivates=nofprivates+1 + p=utfchar(nofprivates) + privates_n[s]=p + s="&"..s..";" + privates_u[p]=s + privates_p[p]=s + privates_s[p]=s + end + return p + end + xml.privatetoken=unescaped + xml.privatecodes=privates_n + xml.specialcodes=privates_s + function xml.addspecialcode(key,value) + privates_s[key]=value or "&"..s..";" + end + handle_hex_entity=function(str) + local h=hcache[str] + if not h then + local n=tonumber(str,16) + h=unify_predefined and predefined_unified[n] + if h then + if trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + elseif utfize then + h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" + if not n then + report_xml("utfize, ignoring hex entity &#x%s;",str) + elseif trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + else + if trace_entities then + report_xml("found entity &#x%s;",str) end + h="&#x"..str..";" + end + hcache[str]=h end - local function fromdec(s) - local n=tonumber(s) - if n then - return utfchar(n) - else - return formatters["d:%s"](s),true - end - end - local p_rest=(1-P(";"))^0 - local p_many=P(1)^0 - local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) - xml.parsedentitylpeg=parsedentity - local predefined_unified={ - [38]="&", - [42]=""", - [47]="'", - [74]="<", - [76]=">", - } - local predefined_simplified={ - [38]="&",amp="&", - [42]='"',quot='"', - [47]="'",apos="'", - [74]="<",lt="<", - [76]=">",gt=">", - } - local nofprivates=0xF0000 - local privates_u={ - [ [[&]] ]="&", - [ [["]] ]=""", - [ [[']] ]="'", - [ [[<]] ]="<", - [ [[>]] ]=">", - } - local privates_p={ - } - local privates_s={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[&]] ]="&U+26;", - [ [[']] ]="&U+27;", - [ [[<]] ]="&U+3C;", - [ [[>]] ]="&U+3E;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_x={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[']] ]="&U+27;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_n={ - } - local escaped=utf.remapper(privates_u,"dynamic") - local unprivatized=utf.remapper(privates_p,"dynamic") - local unspecialized=utf.remapper(privates_s,"dynamic") - local despecialized=utf.remapper(privates_x,"dynamic") - xml.unprivatized=unprivatized - xml.unspecialized=unspecialized - xml.despecialized=despecialized - xml.escaped=escaped - local function unescaped(s) - local p=privates_n[s] - if not p then - nofprivates=nofprivates+1 - p=utfchar(nofprivates) - privates_n[s]=p - s="&"..s..";" - privates_u[p]=s - privates_p[p]=s - privates_s[p]=s - end - return p - end - xml.privatetoken=unescaped - xml.privatecodes=privates_n - xml.specialcodes=privates_s - function xml.addspecialcode(key,value) - privates_s[key]=value or "&"..s..";" - end - handle_hex_entity=function(str) - local h=hcache[str] - if not h then - local n=tonumber(str,16) - h=unify_predefined and predefined_unified[n] - if h then - if trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - elseif utfize then - h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" - if not n then - report_xml("utfize, ignoring hex entity &#x%s;",str) - elseif trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - else - if trace_entities then - report_xml("found entity &#x%s;",str) - end - h="&#x"..str..";" - end - hcache[str]=h - end - return h - end - handle_dec_entity=function(str) - local d=dcache[str] - if not d then - local n=tonumber(str) - d=unify_predefined and predefined_unified[n] - if d then - if trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - elseif utfize then - d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" - if not n then - report_xml("utfize, ignoring dec entity &#%s;",str) - elseif trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - else - if trace_entities then - report_xml("found entity &#%s;",str) - end - d="&#"..str..";" - end - dcache[str]=d + return h + end + handle_dec_entity=function(str) + local d=dcache[str] + if not d then + local n=tonumber(str) + d=unify_predefined and predefined_unified[n] + if d then + if trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + elseif utfize then + d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" + if not n then + report_xml("utfize, ignoring dec entity &#%s;",str) + elseif trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + else + if trace_entities then + report_xml("found entity &#%s;",str) end - return d + d="&#"..str..";" + end + dcache[str]=d end - handle_any_entity_dtd=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end - end - return a + return d + end + handle_any_entity_dtd=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end - end - return a + a=entities[str] end - end - handle_any_entity_text=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(grammar_parsed_text_two,a) or a - if type(a)=="number" then - return "" - else - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - end - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) end - return a + a=a(str) or "" + end + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) end - return a - end - end - local p_rest=(1-P(";"))^1 - local spec={ - [0x23]="\\Ux{23}", - [0x24]="\\Ux{24}", - [0x25]="\\Ux{25}", - [0x5C]="\\Ux{5C}", - [0x7B]="\\Ux{7B}", - [0x7C]="\\Ux{7C}", - [0x7D]="\\Ux{7D}", - [0x7E]="\\Ux{7E}", - } - local hash=table.setmetatableindex(spec,function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] - else - return formatters["u:%s"](s),true + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end - end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] + end + return a + end + end + handle_any_entity_text=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - return formatters["d:%s"](s),true + a=entities[str] end - end - local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - local hash=table.setmetatableindex(function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) + end + a=a(str) or "" + end + a=lpegmatch(grammar_parsed_text_two,a) or a + if type(a)=="number" then + return "" + else + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end + end + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - return formatters["u:%s"](s),true + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) + end + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end + end + return a + end + end + local p_rest=(1-P(";"))^1 + local spec={ + [0x23]="\\Ux{23}", + [0x24]="\\Ux{24}", + [0x25]="\\Ux{25}", + [0x5C]="\\Ux{5C}", + [0x7B]="\\Ux{7B}", + [0x7C]="\\Ux{7C}", + [0x7D]="\\Ux{7D}", + [0x7E]="\\Ux{7E}", + } + local hash=table.setmetatableindex(spec,function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] - else - return formatters["d:%s"](s),true - end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true end - local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - xml.reparsedentitylpeg=reparsedentity - xml.unescapedentitylpeg=unescapedentity + end + local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + local hash=table.setmetatableindex(function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true + end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true + end + end + local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + xml.reparsedentitylpeg=reparsedentity + xml.unescapedentitylpeg=unescapedentity end local escaped=xml.escaped local unescaped=xml.unescaped local placeholders=xml.placeholders local function handle_end_entity(str) - report_xml("error in entity, %a found without ending %a",str,";") - return str + report_xml("error in entity, %a found without ending %a",str,";") + return str end local function handle_crap_error(chr) - report_xml("error in parsing, unexpected %a found ",chr) - add_text(chr) - return chr + report_xml("error in parsing, unexpected %a found ",chr) + add_text(chr) + return chr end local function handlenewline() - currentline=currentline+1 + currentline=currentline+1 end local spacetab=S(' \t') local space=S(' \r\n\t') @@ -12849,141 +16338,141 @@ local space_nl=spacetab+newline local spacing_nl=Cs((space_nl)^0) local anything_nl=newline+P(1) local function weirdentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","weird",k,v) - end - parameters[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","weird",k,v) + end + parameters[k]=v end local function normalentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","normal",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","normal",k,v) + end + entities[k]=v end local function systementity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","system",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","system",k,v) + end + entities[k]=v end local function publicentity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","public",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","public",k,v) + end + entities[k]=v end local function entityfile(pattern,k,v,n) - if n then - local okay,data - if resolvers then - okay,data=resolvers.loadbinfile(n) - else - data=io.loaddata(n) - okay=data and data~="" - end - if okay then - if trace_entities then - report_xml("loading public entities %a as %a from %a",k,v,n) - end - lpegmatch(pattern,data) - return - end + if n then + local okay,data + if resolvers then + okay,data=resolvers.loadbinfile(n) + else + data=io.loaddata(n) + okay=data and data~="" end - report_xml("ignoring public entities %a as %a from %a",k,v,n) + if okay then + if trace_entities then + report_xml("loading public entities %a as %a from %a",k,v,n) + end + lpegmatch(pattern,data) + return + end + end + report_xml("ignoring public entities %a as %a from %a",k,v,n) end local function install(spacenewline,spacing,anything) - local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 - local hexentitycontent=R("AF","af","09")^1 - local decentitycontent=R("09")^1 - local parsedentity=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_dtd) - local parsedentity_text=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_text) - local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local text_unparsed=Cs((anything-open)^1) - local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 - local somespace=(spacenewline)^1 - local optionalspace=(spacenewline)^0 - local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) - local endofattributes=slash*close+close - local whatever=space*name*optionalspace*equal - local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error - local attributevalue=value+wrongvalue - local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute - local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 - local parsedtext=text_parsed - local unparsedtext=text_unparsed/add_text - local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } - local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty - local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin - local endelement=(spacing*open*slash*name*optionalspace*close)/add_end - local begincomment=open*P("!--") - local endcomment=P("--")*close - local begininstruction=open*P("?") - local endinstruction=P("?")*close - local begincdata=open*P("![CDATA[") - local endcdata=P("]]")*close - local someinstruction=C((anything-endinstruction)^0) - local somecomment=C((anything-endcomment )^0) - local somecdata=C((anything-endcdata )^0) - local begindoctype=open*P("!DOCTYPE") - local enddoctype=close - local beginset=P("[") - local endset=P("]") - local wrdtypename=C((anything-somespace-P(";"))^1) - local doctypename=C((anything-somespace-close)^0) - local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close - local basiccomment=begincomment*((anything-endcomment)^0)*endcomment - local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity - local normalentitytype=(doctypename*somespace*value)/normalentity - local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity - local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity - local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close - local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) - entityfile(entitydoctype,...) - end - local function weirdresolve(s) - lpegmatch(entitydoctype,parameters[s]) - end - local function normalresolve(s) - lpegmatch(entitydoctype,entities[s]) - end - local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") - entitydoctype=entitydoctype+entityresolve - local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset - local definitiondoctype=doctypename*somespace*doctypeset - local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset - local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset - local simpledoctype=(anything-close)^1 - local somedoctype=C((somespace*( + local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 + local hexentitycontent=R("AF","af","09")^1 + local decentitycontent=R("09")^1 + local parsedentity=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_dtd) + local parsedentity_text=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_text) + local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local text_unparsed=Cs((anything-open)^1) + local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 + local somespace=(spacenewline)^1 + local optionalspace=(spacenewline)^0 + local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) + local endofattributes=slash*close+close + local whatever=space*name*optionalspace*equal + local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error + local attributevalue=value+wrongvalue + local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute + local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 + local parsedtext=text_parsed + local unparsedtext=text_unparsed/add_text + local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } + local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty + local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin + local endelement=(spacing*open*slash*name*optionalspace*close)/add_end + local begincomment=open*P("!--") + local endcomment=P("--")*close + local begininstruction=open*P("?") + local endinstruction=P("?")*close + local begincdata=open*P("![CDATA[") + local endcdata=P("]]")*close + local someinstruction=C((anything-endinstruction)^0) + local somecomment=C((anything-endcomment )^0) + local somecdata=C((anything-endcdata )^0) + local begindoctype=open*P("!DOCTYPE") + local enddoctype=close + local beginset=P("[") + local endset=P("]") + local wrdtypename=C((anything-somespace-P(";"))^1) + local doctypename=C((anything-somespace-close)^0) + local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close + local basiccomment=begincomment*((anything-endcomment)^0)*endcomment + local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity + local normalentitytype=(doctypename*somespace*value)/normalentity + local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity + local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity + local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close + local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) + entityfile(entitydoctype,...) + end + local function weirdresolve(s) + lpegmatch(entitydoctype,parameters[s]) + end + local function normalresolve(s) + lpegmatch(entitydoctype,entities[s]) + end + local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") + entitydoctype=entitydoctype+entityresolve + local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset + local definitiondoctype=doctypename*somespace*doctypeset + local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset + local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset + local simpledoctype=(anything-close)^1 + local somedoctype=C((somespace*( publicentityfile+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 - local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end - local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand - local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error - local trailer=space^0*(text_unparsed/set_message)^0 - local grammar_parsed_text_one=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, - } - local grammar_parsed_text_two=P { "followup", - followup=V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, - } - local grammar_unparsed_text=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, - } - return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text + 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 + local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end + local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand + local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error + local trailer=space^0*(text_unparsed/set_message)^0 + local grammar_parsed_text_one=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, + } + local grammar_parsed_text_two=P { "followup", + followup=V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, + } + local grammar_unparsed_text=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, + } + return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text end grammar_parsed_text_one_nop, grammar_parsed_text_two_nop, @@ -12992,576 +16481,576 @@ grammar_parsed_text_one_yes, grammar_parsed_text_two_yes, grammar_unparsed_text_yes=install(space_nl,spacing_nl,anything_nl) local function _xmlconvert_(data,settings,detail) - settings=settings or {} - preparexmlstate(settings) - if settings.linenumbers then - grammar_parsed_text_one=grammar_parsed_text_one_yes - grammar_parsed_text_two=grammar_parsed_text_two_yes - grammar_unparsed_text=grammar_unparsed_text_yes - else - grammar_parsed_text_one=grammar_parsed_text_one_nop - grammar_parsed_text_two=grammar_parsed_text_two_nop - grammar_unparsed_text=grammar_unparsed_text_nop - end - local preprocessor=settings.preprocessor - if data and data~="" and type(preprocessor)=="function" then - data=preprocessor(data,settings) or data + settings=settings or {} + preparexmlstate(settings) + if settings.linenumbers then + grammar_parsed_text_one=grammar_parsed_text_one_yes + grammar_parsed_text_two=grammar_parsed_text_two_yes + grammar_unparsed_text=grammar_unparsed_text_yes + else + grammar_parsed_text_one=grammar_parsed_text_one_nop + grammar_parsed_text_two=grammar_parsed_text_two_nop + grammar_unparsed_text=grammar_unparsed_text_nop + end + local preprocessor=settings.preprocessor + if data and data~="" and type(preprocessor)=="function" then + data=preprocessor(data,settings) or data + end + if settings.parent_root then + mt=getmetatable(settings.parent_root) + else + initialize_mt(top) + end + level=level+1 + stack[level]=top + top.dt={} + dt=top.dt + nt=0 + if not data or data=="" then + errorstr="empty xml file" + elseif data==true then + errorstr=detail or "problematic xml file" + elseif utfize or resolve then + local m=lpegmatch(grammar_parsed_text_one,data) + if m then + m=lpegmatch(grammar_parsed_text_two,data,m) end - if settings.parent_root then - mt=getmetatable(settings.parent_root) - else - initialize_mt(top) - end - level=level+1 - stack[level]=top - top.dt={} - dt=top.dt - nt=0 - if not data or data=="" then - errorstr="empty xml file" - elseif data==true then - errorstr=detail or "problematic xml file" - elseif utfize or resolve then - local m=lpegmatch(grammar_parsed_text_one,data) - if m then - m=lpegmatch(grammar_parsed_text_two,data,m) - end - if m then - else - errorstr="invalid xml file - parsed text" - end - elseif type(data)=="string" then - if lpegmatch(grammar_unparsed_text,data) then - errorstr="" - else - errorstr="invalid xml file - unparsed text" - end + if m then else - errorstr="invalid xml file - no text at all" - end - local result - if errorstr and errorstr~="" then - result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } - setmetatable(result,mt) - setmetatable(result.dt[1],mt) - setmetatable(stack,mt) - local errorhandler=settings.error_handler - if errorhandler==false then + errorstr="invalid xml file - parsed text" + end + elseif type(data)=="string" then + if lpegmatch(grammar_unparsed_text,data) then + errorstr="" + else + errorstr="invalid xml file - unparsed text" + end + else + errorstr="invalid xml file - no text at all" + end + local result + if errorstr and errorstr~="" then + result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } + setmetatable(result,mt) + setmetatable(result.dt[1],mt) + setmetatable(stack,mt) + local errorhandler=settings.error_handler + if errorhandler==false then + else + errorhandler=errorhandler or xml.errorhandler + if errorhandler then + local currentresource=settings.currentresource + if currentresource and currentresource~="" then + xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) else - errorhandler=errorhandler or xml.errorhandler - if errorhandler then - local currentresource=settings.currentresource - if currentresource and currentresource~="" then - xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) - else - xml.errorhandler(formatters["load error: %s"](errorstr)) - end - end - end - else - result=stack[1] - end - if not settings.no_root then - result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } - setmetatable(result,mt) - local rdt=result.dt - for k=1,#rdt do - local v=rdt[k] - if type(v)=="table" and not v.special then - result.ri=k - v.__p__=result - break - end + xml.errorhandler(formatters["load error: %s"](errorstr)) end + end end - if errorstr and errorstr~="" then - result.error=true - else - errorstr=nil - end - result.statistics={ - errormessage=errorstr, - entities={ - decimals=dcache, - hexadecimals=hcache, - names=acache, - intermediates=parameters, - } + else + result=stack[1] + end + if not settings.no_root then + result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } + setmetatable(result,mt) + local rdt=result.dt + for k=1,#rdt do + local v=rdt[k] + if type(v)=="table" and not v.special then + result.ri=k + v.__p__=result + break + end + end + end + if errorstr and errorstr~="" then + result.error=true + else + errorstr=nil + end + result.statistics={ + errormessage=errorstr, + entities={ + decimals=dcache, + hexadecimals=hcache, + names=acache, + intermediates=parameters, } - preparexmlstate() - return result + } + preparexmlstate() + return result end local function xmlconvert(data,settings) - local ok,result=pcall(function() return _xmlconvert_(data,settings) end) - if ok then - return result - elseif type(result)=="string" then - return _xmlconvert_(true,settings,result) - else - return _xmlconvert_(true,settings) - end + local ok,result=pcall(function() return _xmlconvert_(data,settings) end) + if ok then + return result + elseif type(result)=="string" then + return _xmlconvert_(true,settings,result) + else + return _xmlconvert_(true,settings) + end end xml.convert=xmlconvert function xml.inheritedconvert(data,xmldata) - local settings=xmldata.settings - if settings then - settings.parent_root=xmldata - end - local xc=xmlconvert(data,settings) - return xc + local settings=xmldata.settings + if settings then + settings.parent_root=xmldata + end + local xc=xmlconvert(data,settings) + return xc end function xml.is_valid(root) - return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er + return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er end function xml.package(tag,attributes,data) - local ns,tg=match(tag,"^(.-):?([^:]+)$") - local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } - setmetatable(t,mt) - return t + local ns,tg=match(tag,"^(.-):?([^:]+)$") + local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } + setmetatable(t,mt) + return t end function xml.is_valid(root) - return root and not root.error + return root and not root.error end xml.errorhandler=report_xml function xml.load(filename,settings) - local data="" - if type(filename)=="string" then - local f=io.open(filename,'r') - if f then - data=f:read("*all") - f:close() - end - elseif filename then - data=filename:read("*all") - end - if settings then - settings.currentresource=filename - local result=xmlconvert(data,settings) - settings.currentresource=nil - return result - else - return xmlconvert(data,{ currentresource=filename }) - end + local data="" + if type(filename)=="string" then + local f=io.open(filename,'r') + if f then + data=f:read("*all") + f:close() + end + elseif filename then + data=filename:read("*all") + end + if settings then + settings.currentresource=filename + local result=xmlconvert(data,settings) + settings.currentresource=nil + return result + else + return xmlconvert(data,{ currentresource=filename }) + end end local no_root={ no_root=true } function xml.toxml(data) - if type(data)=="string" then - local root={ xmlconvert(data,no_root) } - return (#root>1 and root) or root[1] - else - return data - end + if type(data)=="string" then + local root={ xmlconvert(data,no_root) } + return (#root>1 and root) or root[1] + else + return data + end end local function copy(old,p) - if old then - local new={} - for k,v in next,old do - local t=type(v)=="table" - if k=="at" then - local t={} - for k,v in next,v do - t[k]=v - end - new[k]=t - elseif k=="dt" then - v.__p__=nil - v=copy(v,new) - new[k]=v - v.__p__=p - else - new[k]=v - end - end - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + local t=type(v)=="table" + if k=="at" then + local t={} + for k,v in next,v do + t[k]=v + end + new[k]=t + elseif k=="dt" then + v.__p__=nil + v=copy(v,new) + new[k]=v + v.__p__=p + else + new[k]=v + end end + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end + return new + else + return {} + end end xml.copy=copy function xml.checkbom(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then - return - end - end - insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) - insert(dt,2,"\n" ) + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then + return + end end + insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) + insert(dt,2,"\n" ) + end end local f_attribute=formatters['%s=%q'] local function verbose_element(e,handlers,escape) - local handle=handlers.handle - local serialize=handlers.serialize - local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn - local ats=eat and next(eat) and {} - if ats then - local n=0 - for k in next,eat do - n=n+1 - ats[n]=k - end - if n==1 then - local k=ats[1] - ats=f_attribute(k,escaped(eat[k])) - else - sort(ats) - for i=1,n do - local k=ats[i] - ats[i]=f_attribute(k,escaped(eat[k])) - end - ats=concat(ats," ") - end - end - if ern and trace_entities and ern~=ens then - ens=ern + local handle=handlers.handle + local serialize=handlers.serialize + local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn + local ats=eat and next(eat) and {} + if ats then + local n=0 + for k in next,eat do + n=n+1 + ats[n]=k end - local n=edt and #edt - if ens~="" then - if n and n>0 then - if ats then - handle("<",ens,":",etg," ",ats,">") - else - handle("<",ens,":",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",ens,":",etg,">") + if n==1 then + local k=ats[1] + ats=f_attribute(k,escaped(eat[k])) + else + sort(ats) + for i=1,n do + local k=ats[i] + ats[i]=f_attribute(k,escaped(eat[k])) + end + ats=concat(ats," ") + end + end + if ern and trace_entities and ern~=ens then + ens=ern + end + local n=edt and #edt + if ens~="" then + if n and n>0 then + if ats then + handle("<",ens,":",etg," ",ats,">") + else + handle("<",ens,":",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",ens,":",etg," ",ats,"/>") - else - handle("<",ens,":",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",ens,":",etg,">") else - if n and n>0 then - if ats then - handle("<",etg," ",ats,">") - else - handle("<",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",etg,">") + if ats then + handle("<",ens,":",etg," ",ats,"/>") + else + handle("<",ens,":",etg,"/>") + end + end + else + if n and n>0 then + if ats then + handle("<",etg," ",ats,">") + else + handle("<",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",etg," ",ats,"/>") - else - handle("<",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",etg,">") + else + if ats then + handle("<",etg," ",ats,"/>") + else + handle("<",etg,"/>") + end end + end end local function verbose_pi(e,handlers) - handlers.handle("<?",e.dt[1],"?>") + handlers.handle("<?",e.dt[1],"?>") end local function verbose_comment(e,handlers) - handlers.handle("<!--",e.dt[1],"-->") + handlers.handle("<!--",e.dt[1],"-->") end local function verbose_cdata(e,handlers) - handlers.handle("<![CDATA[",e.dt[1],"]]>") + handlers.handle("<![CDATA[",e.dt[1],"]]>") end local function verbose_doctype(e,handlers) - handlers.handle("<!DOCTYPE",e.dt[1],">") + handlers.handle("<!DOCTYPE",e.dt[1],">") end local function verbose_root(e,handlers) - handlers.serialize(e.dt,handlers) + handlers.serialize(e.dt,handlers) end local function verbose_text(e,handlers) - handlers.handle(escaped(e)) + handlers.handle(escaped(e)) end local function verbose_document(e,handlers) - local serialize=handlers.serialize - local functions=handlers.functions - for i=1,#e do - local ei=e[i] - if type(ei)=="string" then - functions["@tx@"](ei,handlers) - else - serialize(ei,handlers) - end + local serialize=handlers.serialize + local functions=handlers.functions + for i=1,#e do + local ei=e[i] + if type(ei)=="string" then + functions["@tx@"](ei,handlers) + else + serialize(ei,handlers) end + end end local function serialize(e,handlers,...) - 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 + 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 end local function xserialize(e,handlers) - if e then - local functions=handlers.functions - local etg=e.tg - if etg then - (functions[etg] or functions["@el@"])(e,handlers) - else - functions["@dc@"](e,handlers) - end + if e then + local functions=handlers.functions + local etg=e.tg + if etg then + (functions[etg] or functions["@el@"])(e,handlers) + else + functions["@dc@"](e,handlers) end + end end local handlers={} local function newhandlers(settings) - local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) - if settings then - for k,v in next,settings do - if type(v)=="table" then - local tk=t[k] if not tk then tk={} t[k]=tk end - for kk,vv in next,v do - tk[kk]=vv - end - else - t[k]=v - end - end - if settings.name then - handlers[settings.name]=t - end + local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) + if settings then + for k,v in next,settings do + if type(v)=="table" then + local tk=t[k] if not tk then tk={} t[k]=tk end + for kk,vv in next,v do + tk[kk]=vv + end + else + t[k]=v + end end - utilities.storage.mark(t) - return t + if settings.name then + handlers[settings.name]=t + end + end + utilities.storage.mark(t) + return t end local nofunction=function() end function xml.sethandlersfunction(handler,name,fnc) - handler.functions[name]=fnc or nofunction + handler.functions[name]=fnc or nofunction end function xml.gethandlersfunction(handler,name) - return handler.functions[name] + return handler.functions[name] end function xml.gethandlers(name) - return handlers[name] + return handlers[name] end newhandlers { - name="verbose", - initialize=false, - finalize=false, - serialize=xserialize, - handle=print, - functions={ - ["@dc@"]=verbose_document, - ["@dt@"]=verbose_doctype, - ["@rt@"]=verbose_root, - ["@el@"]=verbose_element, - ["@pi@"]=verbose_pi, - ["@cm@"]=verbose_comment, - ["@cd@"]=verbose_cdata, - ["@tx@"]=verbose_text, - } + name="verbose", + initialize=false, + finalize=false, + serialize=xserialize, + handle=print, + functions={ + ["@dc@"]=verbose_document, + ["@dt@"]=verbose_doctype, + ["@rt@"]=verbose_root, + ["@el@"]=verbose_element, + ["@pi@"]=verbose_pi, + ["@cm@"]=verbose_comment, + ["@cd@"]=verbose_cdata, + ["@tx@"]=verbose_text, + } } local result local xmlfilehandler=newhandlers { - name="file", - initialize=function(name) - result=io.open(name,"wb") - return result - end, - finalize=function() - result:close() - return true - end, - handle=function(...) - result:write(...) - end, + name="file", + initialize=function(name) + result=io.open(name,"wb") + return result + end, + finalize=function() + result:close() + return true + end, + handle=function(...) + result:write(...) + end, } function xml.save(root,name) - serialize(root,xmlfilehandler,name) + serialize(root,xmlfilehandler,name) end local result,r,threshold={},0,512 local xmlstringhandler=newhandlers { - name="string", - initialize=function() - r=0 - return result - end, - finalize=function() - local done=concat(result,"",1,r) - r=0 - if r>threshold then - result={} - end - return done - end, - handle=function(...) - for i=1,select("#",...) do - r=r+1 - result[r]=select(i,...) - end - end, + name="string", + initialize=function() + r=0 + return result + end, + finalize=function() + local done=concat(result,"",1,r) + r=0 + if r>threshold then + result={} + end + return done + end, + handle=function(...) + for i=1,select("#",...) do + r=r+1 + result[r]=select(i,...) + end + end, } local function xmltostring(root) - if not root then - return "" - elseif type(root)=="string" then - return root - else - return serialize(root,xmlstringhandler) or "" - end + if not root then + return "" + elseif type(root)=="string" then + return root + else + return serialize(root,xmlstringhandler) or "" + end end local function __tostring(root) - return (root and xmltostring(root)) or "" + return (root and xmltostring(root)) or "" end initialize_mt=function(root) - mt={ __tostring=__tostring,__index=root } + mt={ __tostring=__tostring,__index=root } end xml.defaulthandlers=handlers xml.newhandlers=newhandlers xml.serialize=serialize xml.tostring=xmltostring local function xmlstring(e,handle) - if not handle or (e.special and e.tg~="@rt@") then - elseif e.tg then - local edt=e.dt - if edt then - for i=1,#edt do - xmlstring(edt[i],handle) - end - end - else - handle(e) + if not handle or (e.special and e.tg~="@rt@") then + elseif e.tg then + local edt=e.dt + if edt then + for i=1,#edt do + xmlstring(edt[i],handle) + end end + else + handle(e) + end end xml.string=xmlstring function xml.settings(e) - while e do - local s=e.settings - if s then - return s - else - e=e.__p__ - end + while e do + local s=e.settings + if s then + return s + else + e=e.__p__ end - return nil + end + return nil end function xml.root(e) - local r=e - while e do - e=e.__p__ - if e then - r=e - end + local r=e + while e do + e=e.__p__ + if e then + r=e end - return r + end + return r end function xml.parent(root) - return root.__p__ + return root.__p__ end function xml.body(root) - return root.ri and root.dt[root.ri] or root + return root.ri and root.dt[root.ri] or root end function xml.name(root) - if not root then - return "" - end - local ns=root.ns - local tg=root.tg - if ns=="" then - return tg - else - return ns..":"..tg - end + if not root then + return "" + end + local ns=root.ns + local tg=root.tg + if ns=="" then + return tg + else + return ns..":"..tg + end end function xml.erase(dt,k) - if dt then - if k then - dt[k]="" - else for k=1,#dt do - dt[1]={ "" } - end end - end + if dt then + if k then + dt[k]="" + else for k=1,#dt do + dt[1]={ "" } + end end + end end function xml.assign(dt,k,root) - if dt and k then - dt[k]=type(root)=="table" and xml.body(root) or root - return dt[k] - else - return xml.body(root) - end + if dt and k then + dt[k]=type(root)=="table" and xml.body(root) or root + return dt[k] + else + return xml.body(root) + end end function xml.tocdata(e,wrapper) - local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" - if wrapper then - whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) - end - local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } - setmetatable(t,getmetatable(e)) - e.dt={ t } + local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" + if wrapper then + whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) + end + local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } + setmetatable(t,getmetatable(e)) + e.dt={ t } end function xml.makestandalone(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" then - local txt=v.dt[1] - if find(txt,"xml.*version=") then - v.dt[1]=txt.." standalone='yes'" - break - end - end + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" then + local txt=v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1]=txt.." standalone='yes'" + break end + end end - return root + end + return root end function xml.kind(e) - local dt=e and e.dt - if dt then - local n=#dt - if n==1 then - local d=dt[1] - if d.special then - local tg=d.tg - if tg=="@cd@" then - return "cdata" - elseif tg=="@cm" then - return "comment" - elseif tg=="@pi@" then - return "instruction" - elseif tg=="@dt@" then - return "declaration" - end - elseif type(d)=="string" then - return "text" - end - return "element" - elseif n>0 then - return "mixed" - end + local dt=e and e.dt + if dt then + local n=#dt + if n==1 then + local d=dt[1] + if d.special then + local tg=d.tg + if tg=="@cd@" then + return "cdata" + elseif tg=="@cm" then + return "comment" + elseif tg=="@pi@" then + return "instruction" + elseif tg=="@dt@" then + return "declaration" + end + elseif type(d)=="string" then + return "text" + end + return "element" + elseif n>0 then + return "mixed" end - return "empty" + end + return "empty" end @@ -13571,14 +17060,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true --- original size: 53301, stripped down to: 32477 +-- original size: 55145, stripped down to: 30992 if not modules then modules={} end modules ['lxml-lpt']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local concat,remove,insert=table.concat,table.remove,table.insert local type,next,tonumber,tostring,setmetatable,load,select=type,next,tonumber,tostring,setmetatable,load,select @@ -13591,21 +17080,21 @@ local trace_lparse=false local trace_lprofile=false local report_lpath=logs.reporter("xml","lpath") if trackers then - trackers.register("xml.path",function(v) - trace_lpath=v - end) - trackers.register("xml.parse",function(v) - trace_lparse=v - end) - trackers.register("xml.profile",function(v) - trace_lpath=v - trace_lparse=v - trace_lprofile=v - end) + trackers.register("xml.path",function(v) + trace_lpath=v + end) + trackers.register("xml.parse",function(v) + trace_lparse=v + end) + trackers.register("xml.profile",function(v) + trace_lpath=v + trace_lparse=v + trace_lprofile=v + end) end local xml=xml -local lpathcalls=0 function xml.lpathcalls () return lpathcalls end -local lpathcached=0 function xml.lpathcached() return lpathcached end +local lpathcalls=0 function xml.lpathcalls () return lpathcalls end +local lpathcached=0 function xml.lpathcached() return lpathcached end xml.functions=xml.functions or {} local functions=xml.functions xml.expressions=xml.expressions or {} @@ -13619,216 +17108,271 @@ local xmlpatterns=lpegpatterns.xml finalizers.xml=finalizers.xml or {} finalizers.tex=finalizers.tex or {} local function fallback (t,name) - local fn=finalizers[name] - if fn then - t[name]=fn - else - report_lpath("unknown sub finalizer %a",name) - fn=function() end - end - return fn + local fn=finalizers[name] + if fn then + t[name]=fn + else + report_lpath("unknown sub finalizer %a",name) + fn=function() end + end + return fn end setmetatableindex(finalizers.xml,fallback) setmetatableindex(finalizers.tex,fallback) xml.defaultprotocol="xml" local apply_axis={} apply_axis['root']=function(list) - local collected={} - for l=1,#list do - local ll=list[l] - local rt=ll - while ll do - ll=ll.__p__ - if ll then - rt=ll - end - end - collected[l]=rt + local collected={} + for l=1,#list do + local ll=list[l] + local rt=ll + while ll do + ll=ll.__p__ + if ll then + rt=ll + end end - return collected + collected[l]=rt + end + return collected end apply_axis['self']=function(list) - return list + return list end apply_axis['child']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local dt=ll.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - end - end - ll.en=en + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local dt=ll.dt + if dt then + local n=#dt + if n==0 then + ll.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + ll.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + end end + ll.en=en + end end - return collected + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + else + list.en=0 + end + else + local en=0 + for k=1,n do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant']=function(list) - local collected,c={},0 - for l=1,#list do - c=collect(list[l],collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + c=collect(list[l],collected,c) + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - if ll.special~=true then - c=c+1 - collected[c]=ll - end - c=collect(ll,collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + if ll.special~=true then + c=c+1 + collected[c]=ll + end + c=collect(ll,collected,c) + end + return collected end apply_axis['ancestor']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + while ll do + ll=ll.__p__ + if ll then + c=c+1 + collected[c]=ll + end end - return collected + end + return collected end apply_axis['ancestor-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + c=c+1 + collected[c]=ll + while ll do + ll=ll.__p__ + if ll then c=c+1 collected[c]=ll - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + end end - return collected + end + return collected end apply_axis['parent']=function(list) - local collected,c={},0 - for l=1,#list do - local pl=list[l].__p__ - if pl then - c=c+1 - collected[c]=pl - end + local collected={} + local c=0 + for l=1,#list do + local pl=list[l].__p__ + if pl then + c=c+1 + collected[c]=pl end - return collected + end + return collected end apply_axis['attribute']=function(list) - return {} + return {} end apply_axis['namespace']=function(list) - return {} + return {} end apply_axis['following']=function(list) - return {} + return {} end apply_axis['preceding']=function(list) - return {} + return {} end apply_axis['following-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni+1,#d do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni+1,#d do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['preceding-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=1,ll.ni-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=1,ll.ni-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['reverse-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni-1,1,-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni-1,1,-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['auto-descendant-or-self']=apply_axis['descendant-or-self'] apply_axis['auto-descendant']=apply_axis['descendant'] @@ -13836,130 +17380,147 @@ apply_axis['auto-child']=apply_axis['child'] apply_axis['auto-self']=apply_axis['self'] apply_axis['initial-child']=apply_axis['child'] local function apply_nodes(list,directive,nodes) - local maxn=#nodes - if maxn==3 then - local nns,ntg=nodes[2],nodes[3] - if not nns and not ntg then + local maxn=#nodes + if maxn==3 then + local nns=nodes[2] + local ntg=nodes[3] + if not nns and not ntg then + if directive then + return list + else + return {} + end + else + local collected={} + local c=0 + local m=0 + local p=nil + if not nns then + for l=1,#list do + local ll=list[l] + local ltg=ll.tg + if ltg then if directive then - return list - else - return {} + if ntg==ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif ntg~=ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - else - local collected,c,m,p={},0,0,nil - if not nns then - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - if directive then - if ntg==ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif ntg~=ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - elseif not ntg then - for l=1,#list do - local ll=list[l] - local lns=ll.rn or ll.ns - if lns then - if directive then - if lns==nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif lns~=nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - else - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=ltg==ntg and lns==nns - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end + end + end + elseif not ntg then + for l=1,#list do + local ll=list[l] + local lns=ll.rn or ll.ns + if lns then + if directive then + if lns==nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif lns~=nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - return collected + end end - else - local collected,c,m,p={},0,0,nil + else for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=false - for n=1,maxn,3 do - local nns,ntg=nodes[n+1],nodes[n+2] - ok=(not ntg or ltg==ntg) and (not nns or lns==nns) - if ok then - break - end - end - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=ltg==ntg and lns==nns + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end + end end - return collected + end + return collected end -end -local quit_expression=false -local function apply_expression(list,expression,order) - local collected,c={},0 - quit_expression=false + else + local collected={} + local c=0 + local m=0 + local p=nil for l=1,#list do - local ll=list[l] - if expression(list,ll,l,order) then + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=false + for n=1,maxn,3 do + local nns=nodes[n+1] + local ntg=nodes[n+2] + ok=(not ntg or ltg==ntg) and (not nns or lns==nns) + if ok then + break + end + end + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end c=c+1 collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - if quit_expression then - break - end + end end return collected + end end -local function apply_selector(list,specification) - if xml.applyselector then - apply_selector=xml.applyselector - return apply_selector(list,specification) - else - return list +local quit_expression=false +local function apply_expression(list,expression,order) + local collected={} + local c=0 + quit_expression=false + for l=1,#list do + local ll=list[l] + if expression(list,ll,l,order) then + c=c+1 + collected[c]=ll + end + if quit_expression then + break end + end + return collected +end +local function apply_selector(list,specification) + if xml.applyselector then + apply_selector=xml.applyselector + return apply_selector(list,specification) + else + return list + end end local P,V,C,Cs,Cc,Ct,R,S,Cg,Cb=lpeg.P,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.R,lpeg.S,lpeg.Cg,lpeg.Cb local spaces=S(" \n\r\t\f")^0 @@ -13970,24 +17531,24 @@ local lp_doequal=P("=")/"==" local lp_or=P("|")/" or " local lp_and=P("&")/" and " local builtin={ - text="(ll.dt[1] or '')", - content="ll.dt", - name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", - tag="ll.tg", - position="l", - firstindex="1", - firstelement="1", - first="1", - lastindex="(#ll.__p__.dt or 1)", - lastelement="(ll.__p__.en or 1)", - last="#list", - rootposition="order", - order="order", - element="(ll.ei or 1)", - index="(ll.ni or 1)", - match="(ll.mi or 1)", - namespace="ll.ns", - ns="ll.ns", + text="(ll.dt[1] or '')", + content="ll.dt", + name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", + tag="ll.tg", + position="l", + firstindex="1", + firstelement="1", + first="1", + lastindex="(#ll.__p__.dt or 1)", + lastelement="(ll.__p__.en or 1)", + last="#list", + rootposition="order", + order="order", + element="(ll.ei or 1)", + index="(ll.ni or 1)", + match="(ll.mi or 1)", + namespace="ll.ns", + ns="ll.ns", } local lp_builtin=lpeg.utfchartabletopattern(builtin)/builtin*((spaces*P("(")*spaces*P(")"))/"") local lp_attribute=(P("@")+P("attribute::"))/""*Cc("(ll.at and ll.at['")*((R("az","AZ")+S("-_:"))^1)*Cc("'])") @@ -13997,11 +17558,11 @@ local lp_fastpos=lp_fastpos_n+lp_fastpos_p local lp_reserved=C("and")+C("or")+C("not")+C("div")+C("mod")+C("true")+C("false") local lp_lua_function=Cs((R("az","AZ","__")^1*(P(".")*R("az","AZ","__")^1)^1)*("("))/"%0" local lp_function=C(R("az","AZ","__")^1)*P("(")/function(t) - if expressions[t] then - return "expr."..t.."(" - else - return "expr.error(" - end + if expressions[t] then + return "expr."..t.."(" + else + return "expr.error(" + end end local lparent=P("(") local rparent=P(")") @@ -14014,24 +17575,24 @@ local lp_string=Cc("'")*R("az","AZ","--","__")^1*Cc("'") local lp_content=(P("'")*(1-P("'"))^0*P("'")+P('"')*(1-P('"'))^0*P('"')) local cleaner local lp_special=(C(P("name")+P("text")+P("tag")+P("count")+P("child")))*value/function(t,s) - if expressions[t] then - s=s and s~="" and lpegmatch(cleaner,s) - if s and s~="" then - return "expr."..t.."(ll,"..s..")" - else - return "expr."..t.."(ll)" - end + if expressions[t] then + s=s and s~="" and lpegmatch(cleaner,s) + if s and s~="" then + return "expr."..t.."(ll,"..s..")" else - return "expr.error("..t..")" + return "expr."..t.."(ll)" end + else + return "expr.error("..t..")" + end end local content=lp_builtin+lp_attribute+lp_special+lp_noequal+lp_doequal+lp_or+lp_and+lp_reserved+lp_lua_function+lp_function+lp_content+ - lp_child+lp_any + lp_child+lp_any local converter=Cs ( - lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 + lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 ) cleaner=Cs (( - lp_reserved+lp_number+lp_string+1 )^1 ) + lp_reserved+lp_number+lp_string+1 )^1 ) local template_e=[[ local expr = xml.expressions return function(list,ll,l,order) @@ -14047,75 +17608,75 @@ local template_f_y=[[ local template_f_n=[[ return xml.finalizers['%s']['%s'] ]] -local register_last_match={ kind="axis",axis="last-match" } -local register_self={ kind="axis",axis="self" } -local register_parent={ kind="axis",axis="parent" } -local register_descendant={ kind="axis",axis="descendant" } -local register_child={ kind="axis",axis="child" } +local register_last_match={ kind="axis",axis="last-match" } +local register_self={ kind="axis",axis="self" } +local register_parent={ kind="axis",axis="parent" } +local register_descendant={ kind="axis",axis="descendant" } +local register_child={ kind="axis",axis="child" } local register_descendant_or_self={ kind="axis",axis="descendant-or-self" } -local register_root={ kind="axis",axis="root" } -local register_ancestor={ kind="axis",axis="ancestor" } -local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } -local register_attribute={ kind="axis",axis="attribute" } -local register_namespace={ kind="axis",axis="namespace" } -local register_following={ kind="axis",axis="following" } +local register_root={ kind="axis",axis="root" } +local register_ancestor={ kind="axis",axis="ancestor" } +local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } +local register_attribute={ kind="axis",axis="attribute" } +local register_namespace={ kind="axis",axis="namespace" } +local register_following={ kind="axis",axis="following" } local register_following_sibling={ kind="axis",axis="following-sibling" } -local register_preceding={ kind="axis",axis="preceding" } +local register_preceding={ kind="axis",axis="preceding" } local register_preceding_sibling={ kind="axis",axis="preceding-sibling" } -local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } +local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } local register_auto_descendant_or_self={ kind="axis",axis="auto-descendant-or-self" } -local register_auto_descendant={ kind="axis",axis="auto-descendant" } -local register_auto_self={ kind="axis",axis="auto-self" } -local register_auto_child={ kind="axis",axis="auto-child" } -local register_initial_child={ kind="axis",axis="initial-child" } +local register_auto_descendant={ kind="axis",axis="auto-descendant" } +local register_auto_self={ kind="axis",axis="auto-self" } +local register_auto_child={ kind="axis",axis="auto-child" } +local register_initial_child={ kind="axis",axis="initial-child" } local register_all_nodes={ kind="nodes",nodetest=true,nodes={ true,false,false } } local skip={} local function errorrunner_e(str,cnv) - if not skip[str] then - report_lpath("error in expression: %s => %s",str,cnv) - skip[str]=cnv or str - end - return false + if not skip[str] then + report_lpath("error in expression: %s => %s",str,cnv) + skip[str]=cnv or str + end + return false end local function errorrunner_f(str,arg) - report_lpath("error in finalizer: %s(%s)",str,arg or "") - return false + report_lpath("error in finalizer: %s(%s)",str,arg or "") + return false end local function register_nodes(nodetest,nodes) - return { kind="nodes",nodetest=nodetest,nodes=nodes } + return { kind="nodes",nodetest=nodetest,nodes=nodes } end local function register_selector(specification) - return { kind="selector",specification=specification } + return { kind="selector",specification=specification } end local function register_expression(expression) - local converted=lpegmatch(converter,expression) - local runner=load(format(template_e,converted)) - runner=(runner and runner()) or function() errorrunner_e(expression,converted) end - return { kind="expression",expression=expression,converted=converted,evaluator=runner } + local converted=lpegmatch(converter,expression) + local runner=load(format(template_e,converted)) + runner=(runner and runner()) or function() errorrunner_e(expression,converted) end + return { kind="expression",expression=expression,converted=converted,evaluator=runner } end local function register_finalizer(protocol,name,arguments) - local runner - if arguments and arguments~="" then - runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) - else - runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) - end - runner=(runner and runner()) or function() errorrunner_f(name,arguments) end - return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } + local runner + if arguments and arguments~="" then + runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) + else + runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) + end + runner=(runner and runner()) or function() errorrunner_f(name,arguments) end + return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } end local expression=P { "ex", - ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", - sq="'"*(1-S("'"))^0*"'", - dq='"'*(1-S('"'))^0*'"', + ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", + sq="'"*(1-S("'"))^0*"'", + dq='"'*(1-S('"'))^0*'"', } local arguments=P { "ar", - ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", - nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, - sq=P("'")*(1-P("'"))^0*P("'"), - dq=P('"')*(1-P('"'))^0*P('"'), + ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", + nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, + sq=P("'")*(1-P("'"))^0*P("'"), + dq=P('"')*(1-P('"'))^0*P('"'), } local function register_error(str) - return { kind="error",error=format("unparsed: %s",str) } + return { kind="error",error=format("unparsed: %s",str) } end local special_1=P("*")*Cc(register_auto_descendant)*Cc(register_all_nodes) local special_2=P("/")*Cc(register_auto_self) @@ -14123,367 +17684,368 @@ local special_3=P("")*Cc(register_auto_self) local no_nextcolon=P(-1)+#(1-P(":")) local no_nextlparent=P(-1)+#(1-P("(")) local pathparser=Ct { "patterns", - patterns=spaces*V("protocol")*spaces*( - (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) - ), - protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), - step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, - axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), - special=special_1+special_2+special_3, - initial=(P("/")*spaces*Cc(register_initial_child))^-1, - error=(P(1)^1)/register_error, - shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), - shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, - s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), - s_descendant=P("**")*Cc(register_descendant), - s_child=P("*")*no_nextcolon*Cc(register_child), - s_parent=P("..")*Cc(register_parent), - s_self=P("." )*Cc(register_self), - s_root=P("^^")*Cc(register_root), - s_ancestor=P("^")*Cc(register_ancestor), - s_lastmatch=P("=")*Cc(register_last_match), - descendant=P("descendant::")*Cc(register_descendant), - child=P("child::")*Cc(register_child), - parent=P("parent::")*Cc(register_parent), - self=P("self::")*Cc(register_self), - root=P('root::')*Cc(register_root), - ancestor=P('ancestor::')*Cc(register_ancestor), - descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), - ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), - following=P('following::')*Cc(register_following), - following_sibling=P('following-sibling::')*Cc(register_following_sibling), - preceding=P('preceding::')*Cc(register_preceding), - preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), - reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), - last_match=P('last-match::')*Cc(register_last_match), - selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, - nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, - expressions=expression/register_expression, - letters=R("az")^1, - name=(1-S("/[]()|:*!"))^1, - negate=P("!")*Cc(false), - nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), - nodetest=V("negate")+Cc(true), - nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), - wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, - nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, - finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, + patterns=spaces*V("protocol")*spaces*( + (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) + ), + protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), + step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, + axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), + special=special_1+special_2+special_3, + initial=(P("/")*spaces*Cc(register_initial_child))^-1, + error=(P(1)^1)/register_error, + shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), + shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, + s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), + s_descendant=P("**")*Cc(register_descendant), + s_child=P("*")*no_nextcolon*Cc(register_child), + s_parent=P("..")*Cc(register_parent), + s_self=P("." )*Cc(register_self), + s_root=P("^^")*Cc(register_root), + s_ancestor=P("^")*Cc(register_ancestor), + s_lastmatch=P("=")*Cc(register_last_match), + descendant=P("descendant::")*Cc(register_descendant), + child=P("child::")*Cc(register_child), + parent=P("parent::")*Cc(register_parent), + self=P("self::")*Cc(register_self), + root=P('root::')*Cc(register_root), + ancestor=P('ancestor::')*Cc(register_ancestor), + descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), + ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), + following=P('following::')*Cc(register_following), + following_sibling=P('following-sibling::')*Cc(register_following_sibling), + preceding=P('preceding::')*Cc(register_preceding), + preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), + reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), + last_match=P('last-match::')*Cc(register_last_match), + selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, + nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, + expressions=expression/register_expression, + letters=R("az")^1, + name=(1-S("/[]()|:*!"))^1, + negate=P("!")*Cc(false), + nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), + nodetest=V("negate")+Cc(true), + nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), + wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, + nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, + finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, } xmlpatterns.pathparser=pathparser local cache={} local function nodesettostring(set,nodetest) - local t={} - for i=1,#set,3 do - local directive,ns,tg=set[i],set[i+1],set[i+2] - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - t[#t+1]=(directive and tg) or format("not(%s)",tg) - end - if nodetest==false then - return format("not(%s)",concat(t,"|")) - else - return concat(t,"|") - end + local t={} + for i=1,#set,3 do + local directive,ns,tg=set[i],set[i+1],set[i+2] + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) + t[#t+1]=(directive and tg) or format("not(%s)",tg) + end + if nodetest==false then + return format("not(%s)",concat(t,"|")) + else + return concat(t,"|") + end end local function tagstostring(list) - if #list==0 then - return "no elements" - else - local t={} - for i=1,#list do - local li=list[i] - local ns,tg=li.ns,li.tg - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - end - return concat(t," ") + if #list==0 then + return "no elements" + else + local t={} + for i=1,#list do + local li=list[i] + local ns=li.ns + local tg=li.tg + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) end + return concat(t," ") + end end xml.nodesettostring=nodesettostring local lpath local function lshow(parsed) - if type(parsed)=="string" then - parsed=lpath(parsed) - end - report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, - table.serialize(parsed,false)) + if type(parsed)=="string" then + parsed=lpath(parsed) + end + report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, + table.serialize(parsed,false)) end xml.lshow=lshow local function add_comment(p,str) - local pc=p.comment - if not pc then - p.comment={ str } - else - pc[#pc+1]=str - end + local pc=p.comment + if not pc then + p.comment={ str } + else + pc[#pc+1]=str + end end lpath=function (pattern) - lpathcalls=lpathcalls+1 - if type(pattern)=="table" then - return pattern - else - local parsed=cache[pattern] - if parsed then - lpathcached=lpathcached+1 + lpathcalls=lpathcalls+1 + if type(pattern)=="table" then + return pattern + else + local parsed=cache[pattern] + if parsed then + lpathcached=lpathcached+1 + else + parsed=lpegmatch(pathparser,pattern) + if parsed then + parsed.pattern=pattern + local np=#parsed + if np==0 then + parsed={ pattern=pattern,register_self,state="parsing error" } + report_lpath("parsing error in pattern: %s",pattern) + lshow(parsed) else - parsed=lpegmatch(pathparser,pattern) - if parsed then - parsed.pattern=pattern - local np=#parsed - if np==0 then - parsed={ pattern=pattern,register_self,state="parsing error" } - report_lpath("parsing error in pattern: %s",pattern) - lshow(parsed) - else - local pi=parsed[1] - if pi.axis=="auto-child" then - if false then - add_comment(parsed,"auto-child replaced by auto-descendant-or-self") - parsed[1]=register_auto_descendant_or_self - else - add_comment(parsed,"auto-child replaced by auto-descendant") - parsed[1]=register_auto_descendant - end - elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then - add_comment(parsed,"initial-child removed") - remove(parsed,1) - end - local np=#parsed - if np>1 then - local pnp=parsed[np] - if pnp.kind=="nodes" and pnp.nodetest==true then - local nodes=pnp.nodes - if nodes[1]==true and nodes[2]==false and nodes[3]==false then - add_comment(parsed,"redundant final wildcard filter removed") - remove(parsed,np) - end - end - end - end + local pi=parsed[1] + if pi.axis=="auto-child" then + if false then + add_comment(parsed,"auto-child replaced by auto-descendant-or-self") + parsed[1]=register_auto_descendant_or_self else - parsed={ pattern=pattern } + add_comment(parsed,"auto-child replaced by auto-descendant") + parsed[1]=register_auto_descendant end - cache[pattern]=parsed - if trace_lparse and not trace_lprofile then - lshow(parsed) + elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then + add_comment(parsed,"initial-child removed") + remove(parsed,1) + end + local np=#parsed + if np>1 then + local pnp=parsed[np] + if pnp.kind=="nodes" and pnp.nodetest==true then + local nodes=pnp.nodes + if nodes[1]==true and nodes[2]==false and nodes[3]==false then + add_comment(parsed,"redundant final wildcard filter removed") + remove(parsed,np) + end end + end end - return parsed + else + parsed={ pattern=pattern } + end + cache[pattern]=parsed + if trace_lparse and not trace_lprofile then + lshow(parsed) + end end + return parsed + end end xml.lpath=lpath do - local profiled={} - xml.profiled=profiled - local lastmatch=nil - local keepmatch=nil - if directives then - directives.register("xml.path.keeplastmatch",function(v) - keepmatch=v - lastmatch=nil - end) - end - apply_axis["last-match"]=function() - return lastmatch or {} - end - local function profiled_apply(list,parsed,nofparsed,order) - local p=profiled[parsed.pattern] - if p then - p.tested=p.tested+1 - else - p={ tested=1,matched=0,finalized=0 } - profiled[parsed.pattern]=p - end - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - p.matched=p.matched+1 - p.finalized=p.finalized+1 - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - p.finalized=p.finalized+1 - return collected - end - return nil - end - end - if collected then - p.matched=p.matched+1 - end - return collected - end - local function traced_apply(list,parsed,nofparsed,order) - if trace_lparse then - lshow(parsed) - end - report_lpath("collecting: %s",parsed.pattern) - report_lpath("root tags : %s",tagstostring(list)) - report_lpath("order : %s",order or "unset") - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") - return collected - end - return nil - end - end + local profiled={} + xml.profiled=profiled + local lastmatch=nil + local keepmatch=nil + if directives then + directives.register("xml.path.keeplastmatch",function(v) + keepmatch=v + lastmatch=nil + end) + end + apply_axis["last-match"]=function() + return lastmatch or {} + end + local function profiled_apply(list,parsed,nofparsed,order) + local p=profiled[parsed.pattern] + if p then + p.tested=p.tested+1 + else + p={ tested=1,matched=0,finalized=0 } + profiled[parsed.pattern]=p + end + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + p.matched=p.matched+1 + p.finalized=p.finalized+1 return collected - end - local function normal_apply(list,parsed,nofparsed,order) - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - local axis=pi.axis - if axis~="self" then - collected=apply_axis[axis](collected) - end - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - return pi.finalizer(collected) - end - if not collected or #collected==0 then - local pf=i<nofparsed and parsed[nofparsed].finalizer - if pf then - return pf(collected) - end - return nil - end + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + p.finalized=p.finalized+1 + return collected end - return collected + return nil + end end - local apply=normal_apply - if trackers then - trackers.register("xml.path,xml.parse,xml.profile",function() - if trace_lprofile then - apply=profiled_apply - elseif trace_lpath then - apply=traced_apply - else - apply=normal_apply - end - end) + if collected then + p.matched=p.matched+1 end - function xml.applylpath(list,pattern) - if not list then - lastmatch=nil - return - end - local parsed=cache[pattern] - if parsed then - lpathcalls=lpathcalls+1 - lpathcached=lpathcached+1 - elseif type(pattern)=="table" then - lpathcalls=lpathcalls+1 - parsed=pattern - else - parsed=lpath(pattern) or pattern - end - if not parsed then - lastmatch=nil - return - end - local nofparsed=#parsed - if nofparsed==0 then - lastmatch=nil - return - end - local collected=apply({ list },parsed,nofparsed,list.mi) - lastmatch=keepmatch and collected or nil + return collected + end + local function traced_apply(list,parsed,nofparsed,order) + if trace_lparse then + lshow(parsed) + end + report_lpath("collecting: %s",parsed.pattern) + report_lpath("root tags : %s",tagstostring(list)) + report_lpath("order : %s",order or "unset") + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") return collected + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") + return collected + end + return nil + end end - function xml.lastmatch() - return lastmatch - end - local stack={} - function xml.pushmatch() - insert(stack,lastmatch) - end - function xml.popmatch() - lastmatch=remove(stack) + return collected + end + local function normal_apply(list,parsed,nofparsed,order) + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + local axis=pi.axis + if axis~="self" then + collected=apply_axis[axis](collected) + end + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + return pi.finalizer(collected) + end + if not collected or #collected==0 then + local pf=i<nofparsed and parsed[nofparsed].finalizer + if pf then + return pf(collected) + end + return nil + end end + return collected + end + local apply=normal_apply + if trackers then + trackers.register("xml.path,xml.parse,xml.profile",function() + if trace_lprofile then + apply=profiled_apply + elseif trace_lpath then + apply=traced_apply + else + apply=normal_apply + end + end) + end + function xml.applylpath(list,pattern) + if not list then + lastmatch=nil + return + end + local parsed=cache[pattern] + if parsed then + lpathcalls=lpathcalls+1 + lpathcached=lpathcached+1 + elseif type(pattern)=="table" then + lpathcalls=lpathcalls+1 + parsed=pattern + else + parsed=lpath(pattern) or pattern + end + if not parsed then + lastmatch=nil + return + end + local nofparsed=#parsed + if nofparsed==0 then + lastmatch=nil + return + end + local collected=apply({ list },parsed,nofparsed,list.mi) + lastmatch=keepmatch and collected or nil + return collected + end + function xml.lastmatch() + return lastmatch + end + local stack={} + function xml.pushmatch() + insert(stack,lastmatch) + end + function xml.popmatch() + lastmatch=remove(stack) + end end local applylpath=xml.applylpath function xml.filter(root,pattern) - return applylpath(root,pattern) + return applylpath(root,pattern) end expressions.child=function(e,pattern) - return applylpath(e,pattern) + return applylpath(e,pattern) end expressions.count=function(e,pattern) - local collected=applylpath(e,pattern) - return pattern and (collected and #collected) or 0 + local collected=applylpath(e,pattern) + return pattern and (collected and #collected) or 0 end expressions.oneof=function(s,...) - for i=1,select("#",...) do - if s==select(i,...) then - return true - end + for i=1,select("#",...) do + if s==select(i,...) then + return true end - return false + end + return false end expressions.error=function(str) - xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) - return false + xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) + return false end expressions.undefined=function(s) - return s==nil + return s==nil end expressions.quit=function(s) - if s or s==nil then - quit_expression=true - end - return true + if s or s==nil then + quit_expression=true + end + return true end expressions.print=function(...) - print(...) - return true + print(...) + return true end expressions.find=find expressions.upper=upper @@ -14491,233 +18053,238 @@ expressions.lower=lower expressions.number=tonumber expressions.boolean=toboolean function expressions.contains(str,pattern) - local t=type(str) - if t=="string" then - if find(str,pattern) then - return true - end - elseif t=="table" then - for i=1,#str do - local d=str[i] - if type(d)=="string" and find(d,pattern) then - return true - end - end + local t=type(str) + if t=="string" then + if find(str,pattern) then + return true end - return false + elseif t=="table" then + for i=1,#str do + local d=str[i] + if type(d)=="string" and find(d,pattern) then + return true + end + end + end + return false end function xml.expressions.idstring(str) - return type(str)=="string" and gsub(str,"^#","") or "" + return type(str)=="string" and gsub(str,"^#","") or "" end local function traverse(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local r=e.__p__ - handle(r,r.dt,e.ni) - end + local collected=applylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local r=e.__p__ + handle(r,r.dt,e.ni) end + end end local function selection(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - if handle then - for c=1,#collected do - handle(collected[c]) - end - else - return collected - end + local collected=applylpath(root,pattern) + if collected then + if handle then + for c=1,#collected do + handle(collected[c]) + end + else + return collected end + end end -xml.traverse=traverse +xml.traverse=traverse xml.selection=selection local function dofunction(collected,fnc,...) - if collected then - local f=functions[fnc] - if f then - for c=1,#collected do - f(collected[c],...) - end - else - report_lpath("unknown function %a",fnc) - end + if collected then + local f=functions[fnc] + if f then + for c=1,#collected do + f(collected[c],...) + end + else + report_lpath("unknown function %a",fnc) end + end end finalizers.xml["function"]=dofunction finalizers.tex["function"]=dofunction expressions.text=function(e,n) - local rdt=e.__p__.dt - return rdt and rdt[n] or "" + local rdt=e.__p__.dt + return rdt and rdt[n] or "" end expressions.name=function(e,n) - local found=false - n=tonumber(n) or 0 - if n==0 then - found=type(e)=="table" and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end + local found=false + n=tonumber(n) or 0 + if n==0 then + found=type(e)=="table" and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 end + end end - if found then - local ns,tg=found.rn or found.ns or "",found.tg - if ns~="" then - return ns..":"..tg + else + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break else - return tg + n=n-1 end + end + end + end + if found then + local ns=found.rn or found.ns or "" + local tg=found.tg + if ns~="" then + return ns..":"..tg else - return "" + return tg end + else + return "" + end end expressions.tag=function(e,n) - if not e then - return "" + if not e then + return "" + else + local found=false + n=tonumber(n) or 0 + if n==0 then + found=(type(e)=="table") and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 + end + end + end else - local found=false - n=tonumber(n) or 0 - if n==0 then - found=(type(e)=="table") and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end - end + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break + else + n=n-1 + end end - return (found and found.tg) or "" + end end + return (found and found.tg) or "" + end end local dummy=function() end function xml.elements(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end 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 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end end + end end function xml.collected(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + return collected[c] + end 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 - return collected[c] - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - return collected[c] - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + return collected[c] + end end + end end function xml.inspect(collection,pattern) - pattern=pattern or "." - for e in xml.collected(collection,pattern or ".") do - report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) - end + pattern=pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) + end end local function split(e) - local dt=e.dt - if dt then - for i=1,#dt do - local dti=dt[i] - if type(dti)=="string" then - dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") - dti=gsub(dti,"[\n\r]+","\n\n") - dt[i]=dti - else - split(dti) - end - end + local dt=e.dt + if dt then + for i=1,#dt do + local dti=dt[i] + if type(dti)=="string" then + dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") + dti=gsub(dti,"[\n\r]+","\n\n") + dt[i]=dti + else + split(dti) + end end - return e + end + return e end function xml.finalizers.paragraphs(c) - for i=1,#c do - split(c[i]) - end - return c + for i=1,#c do + split(c[i]) + end + return c end @@ -14727,14 +18294,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-mis"] = package.loaded["lxml-mis"] or true --- original size: 3574, stripped down to: 1863 +-- original size: 3574, stripped down to: 1808 if not modules then modules={} end modules ['lxml-mis']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local xml,lpeg,string=xml,lpeg,string local type=type @@ -14745,26 +18312,26 @@ local P,S,R,C,V,Cc,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.Cc,lpeg.Cs lpegpatterns.xml=lpegpatterns.xml or {} local xmlpatterns=lpegpatterns.xml local function xmlgsub(t,old,new) - local dt=t.dt - if dt then - for k=1,#dt do - local v=dt[k] - if type(v)=="string" then - dt[k]=gsub(v,old,new) - else - xmlgsub(v,old,new) - end - end + local dt=t.dt + if dt then + for k=1,#dt do + local v=dt[k] + if type(v)=="string" then + dt[k]=gsub(v,old,new) + else + xmlgsub(v,old,new) + end end + end end function xml.stripleadingspaces(dk,d,k) - if d and k then - local dkm=d[k-1] - if dkm and type(dkm)=="string" then - local s=match(dkm,"\n(%s+)") - xmlgsub(dk,"\n"..rep(" ",#s),"\n") - end + if d and k then + local dkm=d[k-1] + if dkm and type(dkm)=="string" then + local s=match(dkm,"\n(%s+)") + xmlgsub(dk,"\n"..rep(" ",#s),"\n") end + end end local normal=(1-S("<&>"))^0 local special=P("<")/"<"+P(">")/">"+P("&")/"&" @@ -14776,17 +18343,17 @@ local cleansed=Cs(((P("<")*(1-P(">"))^0*P(">"))/""+1)^0) xmlpatterns.escaped=escaped xmlpatterns.unescaped=unescaped xmlpatterns.cleansed=cleansed -function xml.escaped (str) return lpegmatch(escaped,str) end +function xml.escaped (str) return lpegmatch(escaped,str) end function xml.unescaped(str) return lpegmatch(unescaped,str) end -function xml.cleansed (str) return lpegmatch(cleansed,str) end +function xml.cleansed (str) return lpegmatch(cleansed,str) end function xml.fillin(root,pattern,str,check) - local e=xml.first(root,pattern) - if e then - local n=#e.dt - if not check or n==0 or (n==1 and e.dt[1]=="") then - e.dt={ str } - end + local e=xml.first(root,pattern) + if e then + local n=#e.dt + if not check or n==0 or (n==1 and e.dt[1]=="") then + e.dt={ str } end + end end @@ -14796,17 +18363,17 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true --- original size: 30650, stripped down to: 21793 +-- original size: 30771, stripped down to: 19680 if not modules then modules={} end modules ['lxml-aux']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) -local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) +local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) +local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) local report_xml=logs.reporter("xml") local xml=xml local xmlcopy,xmlname=xml.copy,xml.name @@ -14819,308 +18386,313 @@ local utfbyte=utf.byte local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local striplinepatterns=utilities.strings.striplinepatterns local function report(what,pattern,c,e) - report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) + report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) end local function withelements(e,handle,depth) - if e and handle then - local edt=e.dt - if edt then - depth=depth or 0 - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - handle(e,depth) - withelements(e,handle,depth+1) - end - end + if e and handle then + local edt=e.dt + if edt then + depth=depth or 0 + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + handle(e,depth) + withelements(e,handle,depth+1) end + end end + end end xml.withelements=withelements function xml.withelement(e,n,handle) - if e and n~=0 and handle then - local edt=e.dt - if edt then - if n>0 then - for i=1,#edt do - local ei=edt[i] - if type(ei)=="table" then - if n==1 then - handle(ei) - return - else - n=n-1 - end - end - end - elseif n<0 then - for i=#edt,1,-1 do - local ei=edt[i] - if type(ei)=="table" then - if n==-1 then - handle(ei) - return - else - n=n+1 - end - end - end + if e and n~=0 and handle then + local edt=e.dt + if edt then + if n>0 then + for i=1,#edt do + local ei=edt[i] + if type(ei)=="table" then + if n==1 then + handle(ei) + return + else + n=n-1 end + end end - end -end -function xml.each(root,pattern,handle,reverse) - local collected=xmlapplylpath(root,pattern) - if collected then - if handle then - if reverse then - for c=#collected,1,-1 do - handle(collected[c]) - end + elseif n<0 then + for i=#edt,1,-1 do + local ei=edt[i] + if type(ei)=="table" then + if n==-1 then + handle(ei) + return else - for c=1,#collected do - handle(collected[c]) - end + n=n+1 end + end end - return collected + end end + end end -function xml.processattributes(root,pattern,handle) - local collected=xmlapplylpath(root,pattern) - if collected and handle then +function xml.each(root,pattern,handle,reverse) + local collected=xmlapplylpath(root,pattern) + if collected then + if handle then + if reverse then + for c=#collected,1,-1 do + handle(collected[c]) + end + else for c=1,#collected do - handle(collected[c].at) + handle(collected[c]) end + end end return collected + end +end +function xml.processattributes(root,pattern,handle) + local collected=xmlapplylpath(root,pattern) + if collected and handle then + for c=1,#collected do + handle(collected[c].at) + end + end + return collected end function xml.collect(root,pattern) - return xmlapplylpath(root,pattern) + return xmlapplylpath(root,pattern) end function xml.collecttexts(root,pattern,flatten) - local collected=xmlapplylpath(root,pattern) - if collected and flatten then - local xmltostring=xml.tostring - for c=1,#collected do - collected[c]=xmltostring(collected[c].dt) - end + local collected=xmlapplylpath(root,pattern) + if collected and flatten then + local xmltostring=xml.tostring + for c=1,#collected do + collected[c]=xmltostring(collected[c].dt) end - return collected or {} + end + return collected or {} end function xml.collect_tags(root,pattern,nonamespace) - local collected=xmlapplylpath(root,pattern) - if collected then - local t,n={},0 - for c=1,#collected do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace then - t[n]=tg - elseif ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end - end - return t + local collected=xmlapplylpath(root,pattern) + if collected then + local t={} + local n=0 + for c=1,#collected do + local e=collected[c] + local ns=e.ns + local tg=e.tg + n=n+1 + if nonamespace then + t[n]=tg + elseif ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg + end end + return t + end end local no_root={ no_root=true } local function redo_ni(d) - for k=1,#d do - local dk=d[k] - if type(dk)=="table" then - dk.ni=k - end + for k=1,#d do + local dk=d[k] + if type(dk)=="table" then + dk.ni=k end + end end xml.reindex=redo_ni local function xmltoelement(whatever,root) - if not whatever then - return nil - end - local element - if type(whatever)=="string" then - element=xmlinheritedconvert(whatever,root) - else - element=whatever - end - if element.error then - return whatever - end - if element then - end - return element + if not whatever then + return nil + end + local element + if type(whatever)=="string" then + element=xmlinheritedconvert(whatever,root) + else + element=whatever + end + if element.error then + return whatever + end + if element then + end + return element end xml.toelement=xmltoelement local function copiedelement(element,newparent) - if type(element)=="string" then - return element - else - element=xmlcopy(element).dt - if newparent and type(element)=="table" then - element.__p__=newparent - end - return element + if type(element)=="string" then + return element + else + element=xmlcopy(element).dt + if newparent and type(element)=="table" then + element.__p__=newparent end + return element + end end function xml.delete(root,pattern) - if not pattern or pattern=="" then - local p=root.__p__ + if not pattern or pattern=="" then + local p=root.__p__ + if p then + if trace_manipulations then + report('deleting',"--",c,root) + end + local d=p.dt + remove(d,root.ni) + redo_ni(d) + end + else + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ if p then - if trace_manipulations then - report('deleting',"--",c,root) - end - local d=p.dt - remove(d,root.ni) - redo_ni(d) - end - else - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('deleting',pattern,c,e) - end - local d=p.dt - local ni=e.ni - if ni<=#d then - if false then - p.dt[ni]="" - else - remove(d,ni) - redo_ni(d) - end - else - end - end + if trace_manipulations then + report('deleting',pattern,c,e) + end + local d=p.dt + local ni=e.ni + if ni<=#d then + if false then + p.dt[ni]="" + else + remove(d,ni) + redo_ni(d) end + else + end end + end end + end end function xml.replace(root,pattern,whatever) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('replacing',pattern,c,e) - end - local d=p.dt - local n=e.ni - local t=copiedelement(element,p) - if type(t)=="table" then - d[n]=t[1] - for i=2,#t do - n=n+1 - insert(d,n,t[i]) - end - else - d[n]=t - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ + if p then + if trace_manipulations then + report('replacing',pattern,c,e) + end + local d=p.dt + local n=e.ni + local t=copiedelement(element,p) + if type(t)=="table" then + d[n]=t[1] + for i=2,#t do + n=n+1 + insert(d,n,t[i]) + end + else + d[n]=t end + redo_ni(d) + end end + end end local function wrap(e,wrapper) - local t={ - rn=e.rn, - tg=e.tg, - ns=e.ns, - at=e.at, - dt=e.dt, - __p__=e, - } - setmetatable(t,getmetatable(e)) - e.rn=wrapper.rn or e.rn or "" - e.tg=wrapper.tg or e.tg or "" - e.ns=wrapper.ns or e.ns or "" - e.at=fastcopy(wrapper.at) - e.dt={ t } + local t={ + rn=e.rn, + tg=e.tg, + ns=e.ns, + at=e.at, + dt=e.dt, + __p__=e, + } + setmetatable(t,getmetatable(e)) + e.rn=wrapper.rn or e.rn or "" + e.tg=wrapper.tg or e.tg or "" + e.ns=wrapper.ns or e.ns or "" + e.at=fastcopy(wrapper.at) + e.dt={ t } end function xml.wrap(root,pattern,whatever) - if whatever then - local wrapper=xmltoelement(whatever,root) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if trace_manipulations then - report('wrapping',pattern,c,e) - end - wrap(e,wrapper) - end + if whatever then + local wrapper=xmltoelement(whatever,root) + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if trace_manipulations then + report('wrapping',pattern,c,e) end - else - wrap(root,xmltoelement(pattern)) + wrap(e,wrapper) + end end + else + wrap(root,xmltoelement(pattern)) + end end local function inject_element(root,pattern,whatever,prepend) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function inject_e(e) - local r=e.__p__ - local d,k,rri=r.dt,e.ni,r.ri - local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) - if edt then - local be,af - local cp=copiedelement(element,e) - if prepend then - be,af=cp,edt - else - be,af=edt,cp - end - local bn=#be - for i=1,#af do - bn=bn+1 - be[bn]=af[i] - end - if rri then - r.dt[rri].dt=be - else - d[k].dt=be - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function inject_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + local rri=r.ri + local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) + if edt then + local be,af + local cp=copiedelement(element,e) + if prepend then + be,af=cp,edt + else + be,af=edt,cp + end + local bn=#be + for i=1,#af do + bn=bn+1 + be[bn]=af[i] + end + if rri then + r.dt[rri].dt=be + else + d[k].dt=be + end + redo_ni(d) end - if not collected then - elseif collected.tg then - inject_e(collected) - else - for c=1,#collected do - inject_e(collected[c]) - end + end + if not collected then + elseif collected.tg then + inject_e(collected) + else + for c=1,#collected do + inject_e(collected[c]) end + end end local function insert_element(root,pattern,whatever,before) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function insert_e(e) - local r=e.__p__ - local d,k=r.dt,e.ni - if not before then - k=k+1 - end - insert(d,k,copiedelement(element,r)) - redo_ni(d) - end - if not collected then - elseif collected.tg then - insert_e(collected) - else - for c=1,#collected do - insert_e(collected[c]) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function insert_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + if not before then + k=k+1 + end + insert(d,k,copiedelement(element,r)) + redo_ni(d) + end + if not collected then + elseif collected.tg then + insert_e(collected) + else + for c=1,#collected do + insert_e(collected[c]) end + end end xml.insert_element=insert_element xml.insertafter=insert_element @@ -15128,124 +18700,124 @@ xml.insertbefore=function(r,p,e) insert_element(r,p,e,true) end xml.injectafter=inject_element xml.injectbefore=function(r,p,e) inject_element(r,p,e,true) end local function include(xmldata,pattern,attribute,recursive,loaddata,level) - pattern=pattern or 'include' - loaddata=loaddata or io.loaddata - local collected=xmlapplylpath(xmldata,pattern) - if collected then - if not level then - level=1 - end - for c=1,#collected do - local ek=collected[c] - local name=nil - local ekdt=ek.dt - if ekdt then - local ekat=ek.at - local ekrt=ek.__p__ - if ekrt then - local epdt=ekrt.dt - if not attribute or attribute=="" then - name=(type(ekdt)=="table" and ekdt[1]) or ekdt - end - if not name then - for a in gmatch(attribute or "href","([^|]+)") do - name=ekat[a] - if name then - break - end - end - end - local data=nil - if name and name~="" then - local d,n=loaddata(name) - data=d or "" - name=n or name - if trace_inclusions then - report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") - end - end - if not data or data=="" then - epdt[ek.ni]="" - elseif ekat["parse"]=="text" then - epdt[ek.ni]=xml.escaped(data) - else + pattern=pattern or 'include' + loaddata=loaddata or io.loaddata + local collected=xmlapplylpath(xmldata,pattern) + if collected then + if not level then + level=1 + end + for c=1,#collected do + local ek=collected[c] + local name=nil + local ekdt=ek.dt + if ekdt then + local ekat=ek.at + local ekrt=ek.__p__ + if ekrt then + local epdt=ekrt.dt + if not attribute or attribute=="" then + name=(type(ekdt)=="table" and ekdt[1]) or ekdt + end + if not name then + for a in gmatch(attribute or "href","([^|]+)") do + name=ekat[a] + if name then + break + end + end + end + local data=nil + if name and name~="" then + local d,n=loaddata(name) + data=d or "" + name=n or name + if trace_inclusions then + report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") + end + end + if not data or data=="" then + epdt[ek.ni]="" + elseif ekat["parse"]=="text" then + epdt[ek.ni]=xml.escaped(data) + else local settings=xmldata.settings local savedresource=settings.currentresource settings.currentresource=name - local xi=xmlinheritedconvert(data,xmldata) - if not xi then - epdt[ek.ni]="" - else - if recursive then - include(xi,pattern,attribute,recursive,loaddata,level+1) - end - local child=xml.body(xi) - child.__p__=ekrt - child.__f__=name + local xi=xmlinheritedconvert(data,xmldata) + if not xi then + epdt[ek.ni]="" + else + if recursive then + include(xi,pattern,attribute,recursive,loaddata,level+1) + end + local child=xml.body(xi) + child.__p__=ekrt + child.__f__=name child.cf=name - epdt[ek.ni]=child - local settings=xmldata.settings - local inclusions=settings and settings.inclusions - if inclusions then - inclusions[#inclusions+1]=name - elseif settings then - settings.inclusions={ name } - else - settings={ inclusions={ name } } - xmldata.settings=settings - end - if child.er then - local badinclusions=settings.badinclusions - if badinclusions then - badinclusions[#badinclusions+1]=name - else - settings.badinclusions={ name } - end - end - end -settings.currentresource=savedresource - end + epdt[ek.ni]=child + local settings=xmldata.settings + local inclusions=settings and settings.inclusions + if inclusions then + inclusions[#inclusions+1]=name + elseif settings then + settings.inclusions={ name } + else + settings={ inclusions={ name } } + xmldata.settings=settings + end + if child.er then + local badinclusions=settings.badinclusions + if badinclusions then + badinclusions[#badinclusions+1]=name + else + settings.badinclusions={ name } end + end end +settings.currentresource=savedresource + end end + end end + end end xml.include=include function xml.inclusion(e,default) - while e do - local f=e.__f__ - if f then - return f - else - e=e.__p__ - end + while e do + local f=e.__f__ + if f then + return f + else + e=e.__p__ end - return default + end + return default end local function getinclusions(key,e,sorted) - while e do - local settings=e.settings - if settings then - local inclusions=settings[key] - if inclusions then - inclusions=table.unique(inclusions) - if sorted then - table.sort(inclusions) - end - return inclusions - else - e=e.__p__ - end - else - e=e.__p__ - end + while e do + local settings=e.settings + if settings then + local inclusions=settings[key] + if inclusions then + inclusions=table.unique(inclusions) + if sorted then + table.sort(inclusions) + end + return inclusions + else + e=e.__p__ + end + else + e=e.__p__ end + end end function xml.inclusions(e,sorted) - return getinclusions("inclusions",e,sorted) + return getinclusions("inclusions",e,sorted) end function xml.badinclusions(e,sorted) - return getinclusions("badinclusions",e,sorted) + return getinclusions("badinclusions",e,sorted) end local b_collapser=lpegpatterns.b_collapser local m_collapser=lpegpatterns.m_collapser @@ -15254,194 +18826,194 @@ local b_stripper=lpegpatterns.b_stripper local m_stripper=lpegpatterns.m_stripper local e_stripper=lpegpatterns.e_stripper local function stripelement(e,nolines,anywhere) - local edt=e.dt - if edt then - local n=#edt - if n==0 then - return e - elseif anywhere then - local t={} - local m=0 - for e=1,n do - local str=edt[e] - if type(str)~="string" then - m=m+1 - t[m]=str - elseif str~="" then - if nolines then - str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) - else - str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) - end - if str~="" then - m=m+1 - t[m]=str - end - end - end - e.dt=t + local edt=e.dt + if edt then + local n=#edt + if n==0 then + return e + elseif anywhere then + local t={} + local m=0 + for e=1,n do + local str=edt[e] + if type(str)~="string" then + m=m+1 + t[m]=str + elseif str~="" then + if nolines then + str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) + else + str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) + end + if str~="" then + m=m+1 + t[m]=str + end + end + end + e.dt=t + else + local str=edt[1] + if type(str)=="string" then + if str~="" then + str=lpegmatch(nolines and b_collapser or b_stripper,str) + end + if str=="" then + remove(edt,1) + n=n-1 else - local str=edt[1] - if type(str)=="string" then - if str~="" then - str=lpegmatch(nolines and b_collapser or b_stripper,str) - end - if str=="" then - remove(edt,1) - n=n-1 - else - edt[1]=str - end - end - if n>0 then - str=edt[n] - if type(str)=="string" then - if str=="" then - remove(edt) - else - str=lpegmatch(nolines and e_collapser or e_stripper,str) - if str=="" then - remove(edt) - else - edt[n]=str - end - end - end + edt[1]=str + end + end + if n>0 then + str=edt[n] + if type(str)=="string" then + if str=="" then + remove(edt) + else + str=lpegmatch(nolines and e_collapser or e_stripper,str) + if str=="" then + remove(edt) + else + edt[n]=str end + end end + end end - return e + end + return e end xml.stripelement=stripelement function xml.strip(root,pattern,nolines,anywhere) - local collected=xmlapplylpath(root,pattern) - if collected then - for i=1,#collected do - stripelement(collected[i],nolines,anywhere) - end + local collected=xmlapplylpath(root,pattern) + if collected then + for i=1,#collected do + stripelement(collected[i],nolines,anywhere) end + end end local function renamespace(root,oldspace,newspace) - local ndt=#root.dt - for i=1,ndt or 0 do - local e=root[i] - if type(e)=="table" then - if e.ns==oldspace then - e.ns=newspace - if e.rn then - e.rn=newspace - end - end - local edt=e.dt - if edt then - renamespace(edt,oldspace,newspace) - end + local ndt=#root.dt + for i=1,ndt or 0 do + local e=root[i] + if type(e)=="table" then + if e.ns==oldspace then + e.ns=newspace + if e.rn then + e.rn=newspace end + end + local edt=e.dt + if edt then + renamespace(edt,oldspace,newspace) + end end + end end xml.renamespace=renamespace function xml.remaptag(root,pattern,newtg) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].tg=newtg - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].tg=newtg end + end end function xml.remapnamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].ns=newns - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].ns=newns end + end end function xml.checknamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if (not e.rn or e.rn=="") and e.ns=="" then - e.rn=newns - end - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if (not e.rn or e.rn=="") and e.ns=="" then + e.rn=newns + end end + end end function xml.remapname(root,pattern,newtg,newns,newrn) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - e.tg,e.ns,e.rn=newtg,newns,newrn - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + e.tg,e.ns,e.rn=newtg,newns,newrn end + end end function xml.cdatatotext(e) - local dt=e.dt - if #dt==1 then - local first=dt[1] - if first.tg=="@cd@" then - e.dt=first.dt - end - else + local dt=e.dt + if #dt==1 then + local first=dt[1] + if first.tg=="@cd@" then + e.dt=first.dt end + else + end end function xml.texttocdata(e) - local dt=e.dt - local s=xml.tostring(dt) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(dt) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end function xml.elementtocdata(e) - local dt=e.dt - local s=xml.tostring(e) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(e) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end xml.builtinentities=table.tohash { "amp","quot","apos","lt","gt" } local entities=characters and characters.entities or nil local builtinentities=xml.builtinentities function xml.addentitiesdoctype(root,option) - if not entities then - require("char-ent") - entities=characters.entities - end - if entities and root and root.tg=="@rt@" and root.statistics then - local list={} - local hexify=option=="hexadecimal" - for k,v in table.sortedhash(root.statistics.entities.names) do - if not builtinentities[k] then - local e=entities[k] - if not e then - e=format("[%s]",k) - elseif hexify then - e=format("&#%05X;",utfbyte(k)) - end - list[#list+1]=format(" <!ENTITY %s %q >",k,e) - end - end - local dt=root.dt - local n=dt[1].tg=="@pi@" and 2 or 1 - if #list>0 then - insert(dt,n,{ "\n" }) - insert(dt,n,{ - tg="@dt@", - dt={ format("Something [\n%s\n] ",concat(list)) }, - ns="", - special=true, - }) - insert(dt,n,{ "\n\n" }) - else - end + if not entities then + require("char-ent") + entities=characters.entities + end + if entities and root and root.tg=="@rt@" and root.statistics then + local list={} + local hexify=option=="hexadecimal" + for k,v in table.sortedhash(root.statistics.entities.names) do + if not builtinentities[k] then + local e=entities[k] + if not e then + e=format("[%s]",k) + elseif hexify then + e=format("&#%05X;",utfbyte(k)) + end + list[#list+1]=format(" <!ENTITY %s %q >",k,e) + end end + local dt=root.dt + local n=dt[1].tg=="@pi@" and 2 or 1 + if #list>0 then + insert(dt,n,{ "\n" }) + insert(dt,n,{ + tg="@dt@", + dt={ format("Something [\n%s\n] ",concat(list)) }, + ns="", + special=true, + }) + insert(dt,n,{ "\n\n" }) + else + end + end end xml.all=xml.each xml.insert=xml.insertafter @@ -15451,239 +19023,241 @@ xml.before=xml.insertbefore xml.process=xml.each xml.obsolete=xml.obsolete or {} local obsolete=xml.obsolete -xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip -xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect -xml.delete_element=xml.delete obsolete.delete_element=xml.delete -xml.replace_element=xml.replace obsolete.replace_element=xml.replace -xml.each_element=xml.each obsolete.each_element=xml.each -xml.process_elements=xml.process obsolete.process_elements=xml.process -xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter -xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore -xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter -xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore -xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes -xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts -xml.inject_element=xml.inject obsolete.inject_element=xml.inject -xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag -xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname -xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace +xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip +xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect +xml.delete_element=xml.delete obsolete.delete_element=xml.delete +xml.replace_element=xml.replace obsolete.replace_element=xml.replace +xml.each_element=xml.each obsolete.each_element=xml.each +xml.process_elements=xml.process obsolete.process_elements=xml.process +xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter +xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore +xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter +xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore +xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes +xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts +xml.inject_element=xml.inject obsolete.inject_element=xml.inject +xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag +xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname +xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace function xml.cdata(e) - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" end - return "" + end + return "" end function xml.finalizers.xml.cdata(collected) - if collected then - local e=collected[1] - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end - end + if collected then + local e=collected[1] + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" + end end - return "" + end + return "" end function xml.insertcomment(e,str,n) - insert(e.dt,n or 1,{ - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.insertcdata(e,str,n) - insert(e.dt,n or 1,{ - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.setcomment(e,str,n) - e.dt={ { - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.setcdata(e,str) - e.dt={ { - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.separate(x,pattern) - local collected=xmlapplylpath(x,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local d=e.dt - if d==x then - report_xml("warning: xml.separate changes root") - x=d - end - local t,n={ "\n" },1 - local i,nd=1,#d - while i<=nd do - while i<=nd do - local di=d[i] - if type(di)=="string" then - if di=="\n" or find(di,"^%s+$") then - i=i+1 - else - d[i]=strip(di) - break - end - else - break - end - end - if i>nd then - break - end - t[n+1]="\n" - t[n+2]=d[i] - t[n+3]="\n" - n=n+3 - i=i+1 + local collected=xmlapplylpath(x,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local d=e.dt + if d==x then + report_xml("warning: xml.separate changes root") + x=d + end + local t={ "\n" } + local n=1 + local i=1 + local nd=#d + while i<=nd do + while i<=nd do + local di=d[i] + if type(di)=="string" then + if di=="\n" or find(di,"^%s+$") then + i=i+1 + else + d[i]=strip(di) + break end - t[n+1]="\n" - setmetatable(t,getmetatable(d)) - e.dt=t + else + break + end + end + if i>nd then + break end + t[n+1]="\n" + t[n+2]=d[i] + t[n+3]="\n" + n=n+3 + i=i+1 + end + t[n+1]="\n" + setmetatable(t,getmetatable(d)) + e.dt=t end - return x + end + return x end local helpers=xml.helpers or {} xml.helpers=helpers local function normal(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)=="string" and str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)=="string" and str~="" then + edt[i]=action(str) + end end + end end local function recurse(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)~="string" then - recurse(str,action) - elseif str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)~="string" then + recurse(str,action) + elseif str~="" then + edt[i]=action(str) + end end + end end function helpers.recursetext(collected,action,recursive) - if recursive then - for i=1,#collected do - recurse(collected[i],action) - end - else - for i=1,#collected do - normal(collected[i],action) - end + if recursive then + for i=1,#collected do + recurse(collected[i],action) end + else + for i=1,#collected do + normal(collected[i],action) + end + end end local specials={ - ["@rt@"]="root", - ["@pi@"]="instruction", - ["@cm@"]="comment", - ["@dt@"]="declaration", - ["@cd@"]="cdata", + ["@rt@"]="root", + ["@pi@"]="instruction", + ["@cm@"]="comment", + ["@dt@"]="declaration", + ["@cd@"]="cdata", } local function convert(x,strip,flat) - local ns=x.ns - local tg=x.tg - local at=x.at - local dt=x.dt - local node=flat and { - [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, - } or { - _namespace=ns~="" and ns or nil, - _tag=not x.special and tg or nil, - _type=specials[tg] or "_element", - } - if at then - for k,v in next,at do - node[k]=v - end - end - local n=0 - for i=1,#dt do - local di=dt[i] - if type(di)=="table" then - if flat and di.special then - else - di=convert(di,strip,flat) - if di then - n=n+1 - node[n]=di - end - end - elseif strip then - di=lpegmatch(strip,di) - if di~="" then - n=n+1 - node[n]=di - end - else - n=n+1 - node[n]=di + local ns=x.ns + local tg=x.tg + local at=x.at + local dt=x.dt + local node=flat and { + [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, + } or { + _namespace=ns~="" and ns or nil, + _tag=not x.special and tg or nil, + _type=specials[tg] or "_element", + } + if at then + for k,v in next,at do + node[k]=v + end + end + local n=0 + for i=1,#dt do + local di=dt[i] + if type(di)=="table" then + if flat and di.special then + else + di=convert(di,strip,flat) + if di then + n=n+1 + node[n]=di end + end + elseif strip then + di=lpegmatch(strip,di) + if di~="" then + n=n+1 + node[n]=di + end + else + n=n+1 + node[n]=di end - if next(node) then - return node - end + end + if next(node) then + return node + end end function xml.totable(x,strip,flat) - if type(x)=="table" then - if strip then - strip=striplinepatterns[strip] - end - return convert(x,strip,flat) + if type(x)=="table" then + if strip then + strip=striplinepatterns[strip] end + return convert(x,strip,flat) + end end function xml.rename(e,namespace,name,attributes) - if type(e)~="table" or not e.tg then - return - end - if type(name)=="table" then - attributes=name - name=namespace - namespace="" - elseif type(name)~="string" then - attributes={} - name=namespace - namespace="" - end - if type(attributes)~="table" then - attributes={} - end - e.ns=namespace - e.rn=namespace - e.tg=name - e.at=attributes + if type(e)~="table" or not e.tg then + return + end + if type(name)=="table" then + attributes=name + name=namespace + namespace="" + elseif type(name)~="string" then + attributes={} + name=namespace + namespace="" + end + if type(attributes)~="table" then + attributes={} + end + e.ns=namespace + e.rn=namespace + e.tg=name + e.at=attributes end @@ -15693,14 +19267,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-xml"] = package.loaded["lxml-xml"] or true --- original size: 11096, stripped down to: 8243 +-- original size: 11096, stripped down to: 7702 if not modules then modules={} end modules ['lxml-xml']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tonumber,next=tonumber,next local concat=table.concat @@ -15712,241 +19286,241 @@ local xmltostring=xml.tostring local xmlserialize=xml.serialize local xmlcollected=xml.collected local xmlnewhandlers=xml.newhandlers -local reparsedentity=xml.reparsedentitylpeg +local reparsedentity=xml.reparsedentitylpeg local unescapedentity=xml.unescapedentitylpeg local parsedentity=reparsedentity local function first(collected) - return collected and collected[1] + return collected and collected[1] end local function last(collected) - return collected and collected[#collected] + return collected and collected[#collected] end local function all(collected) - return collected + return collected end local reverse=table.reversed local function attribute(collected,name) - if collected and #collected>0 then - local at=collected[1].at - return at and at[name] - end + if collected and #collected>0 then + local at=collected[1].at + return at and at[name] + end end local function att(id,name) - local at=id.at - return at and at[name] + local at=id.at + return at and at[name] end local function count(collected) - return collected and #collected or 0 + return collected and #collected or 0 end local function position(collected,n) - if not collected then - return 0 - end - local nc=#collected - if nc==0 then - return 0 - end - n=tonumber(n) or 0 - if n<0 then - return collected[nc+n+1] - elseif n>0 then - return collected[n] - else - return collected[1].mi or 0 - end + if not collected then + return 0 + end + local nc=#collected + if nc==0 then + return 0 + end + n=tonumber(n) or 0 + if n<0 then + return collected[nc+n+1] + elseif n>0 then + return collected[n] + else + return collected[1].mi or 0 + end end local function match(collected) - return collected and #collected>0 and collected[1].mi or 0 + return collected and #collected>0 and collected[1].mi or 0 end local function index(collected) - return collected and #collected>0 and collected[1].ni or 0 + return collected and #collected>0 and collected[1].ni or 0 end local function attributes(collected,arguments) - if collected and #collected>0 then - local at=collected[1].at - if arguments then - return at[arguments] - elseif next(at) then - return at - end + if collected and #collected>0 then + local at=collected[1].at + if arguments then + return at[arguments] + elseif next(at) then + return at end + end end local function chainattribute(collected,arguments) - if collected and #collected>0 then - local e=collected[1] - while e do - local at=e.at - if at then - local a=at[arguments] - if a then - return a - end - else - break - end - e=e.__p__ + if collected and #collected>0 then + local e=collected[1] + while e do + local at=e.at + if at then + local a=at[arguments] + if a then + return a end + else + break + end + e=e.__p__ end - return "" + end + return "" end local function raw(collected) - if collected and #collected>0 then - local e=collected[1] or collected - return e and xmltostring(e) or "" - else - return "" - end + if collected and #collected>0 then + local e=collected[1] or collected + return e and xmltostring(e) or "" + else + return "" + end end local xmltexthandler=xmlnewhandlers { - name="string", - initialize=function() - result={} - return result - end, - finalize=function() - return concat(result) - end, - handle=function(...) - result[#result+1]=concat {... } - end, - escape=false, + name="string", + initialize=function() + result={} + return result + end, + finalize=function() + return concat(result) + end, + handle=function(...) + result[#result+1]=concat {... } + end, + escape=false, } local function xmltotext(root) - local dt=root.dt - if not dt then - return "" - end - local nt=#dt - if nt==0 then - return "" - elseif nt==1 and type(dt[1])=="string" then - return dt[1] - else - return xmlserialize(root,xmltexthandler) or "" - end + local dt=root.dt + if not dt then + return "" + end + local nt=#dt + if nt==0 then + return "" + elseif nt==1 and type(dt[1])=="string" then + return dt[1] + else + return xmlserialize(root,xmltexthandler) or "" + end end function xml.serializetotext(root) - return root and xmlserialize(root,xmltexthandler) or "" + return root and xmlserialize(root,xmltexthandler) or "" end local function text(collected) - if collected then - local e=collected[1] or collected - return e and xmltotext(e) or "" - else - return "" - end + if collected then + local e=collected[1] or collected + return e and xmltotext(e) or "" + else + return "" + end end local function texts(collected) - if not collected then - return {} - end - local nc=#collected - if nc==0 then - return {} - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - if e and e.dt then - n=n+1 - t[n]=e.dt - end - end - return t + if not collected then + return {} + end + local nc=#collected + if nc==0 then + return {} + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + if e and e.dt then + n=n+1 + t[n]=e.dt + end + end + return t end local function tag(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - return c and c.tg + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + return c and c.tg end local function name(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - if not c then - elseif c.ns=="" then - return c.tg - else - return c.ns..":"..c.tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + if not c then + elseif c.ns=="" then + return c.tg + else + return c.ns..":"..c.tg + end end local function tags(collected,nonamespace) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace or ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + local ns,tg=e.ns,e.tg + n=n+1 + if nonamespace or ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg end - return t + end + return t end local function empty(collected,spacesonly) - if not collected then - return true - end - local nc=#collected - if nc==0 then - return true - end - for c=1,nc do - local e=collected[c] - if e then - local edt=e.dt - if edt then - local n=#edt - if n==1 then - local edk=edt[1] - local typ=type(edk) - if typ=="table" then - return false - elseif edk~="" then - return false - elseif spacesonly and not find(edk,"%S") then - return false - end - elseif n>1 then - return false - end - end + if not collected then + return true + end + local nc=#collected + if nc==0 then + return true + end + for c=1,nc do + local e=collected[c] + if e then + local edt=e.dt + if edt then + local n=#edt + if n==1 then + local edk=edt[1] + local typ=type(edk) + if typ=="table" then + return false + elseif edk~="" then + return false + elseif spacesonly and not find(edk,"%S") then + return false + end + elseif n>1 then + return false end + end end - return true + end + return true end finalizers.first=first finalizers.last=last @@ -15969,124 +19543,124 @@ finalizers.name=name finalizers.tags=tags finalizers.empty=empty function xml.first(id,pattern) - return first(xmlfilter(id,pattern)) + return first(xmlfilter(id,pattern)) end function xml.last(id,pattern) - return last(xmlfilter(id,pattern)) + return last(xmlfilter(id,pattern)) end function xml.count(id,pattern) - return count(xmlfilter(id,pattern)) + return count(xmlfilter(id,pattern)) end function xml.attribute(id,pattern,a,default) - return attribute(xmlfilter(id,pattern),a,default) + return attribute(xmlfilter(id,pattern),a,default) end function xml.raw(id,pattern) - if pattern then - return raw(xmlfilter(id,pattern)) - else - return raw(id) - end + if pattern then + return raw(xmlfilter(id,pattern)) + else + return raw(id) + end end function xml.text(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - return collected and #collected>0 and xmltotext(collected[1]) or "" - elseif id then - return xmltotext(id) or "" - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + return collected and #collected>0 and xmltotext(collected[1]) or "" + elseif id then + return xmltotext(id) or "" + else + return "" + end end function xml.pure(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - if collected and #collected>0 then - parsedentity=unescapedentity - local s=collected and #collected>0 and xmltotext(collected[1]) or "" - parsedentity=reparsedentity - return s - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + if collected and #collected>0 then + parsedentity=unescapedentity + local s=collected and #collected>0 and xmltotext(collected[1]) or "" + parsedentity=reparsedentity + return s else - parsedentity=unescapedentity - local s=xmltotext(id) or "" - parsedentity=reparsedentity - return s + return "" end + else + parsedentity=unescapedentity + local s=xmltotext(id) or "" + parsedentity=reparsedentity + return s + end end xml.content=text function xml.position(id,pattern,n) - return position(xmlfilter(id,pattern),n) + return position(xmlfilter(id,pattern),n) end function xml.match(id,pattern) - return match(xmlfilter(id,pattern)) + return match(xmlfilter(id,pattern)) end function xml.empty(id,pattern,spacesonly) - return empty(xmlfilter(id,pattern),spacesonly) + return empty(xmlfilter(id,pattern),spacesonly) end xml.all=xml.filter xml.index=xml.position xml.found=xml.filter local function totable(x) - local t={} - for e in xmlcollected(x[1] or x,"/*") do - t[e.tg]=xmltostring(e.dt) or "" - end - return next(t) and t or nil + local t={} + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg]=xmltostring(e.dt) or "" + end + return next(t) and t or nil end xml.table=totable finalizers.table=totable local function textonly(e,t) - if e then - local edt=e.dt - if edt then - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - textonly(e,t) - else - t[#t+1]=e - end - end + if e then + local edt=e.dt + if edt then + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + textonly(e,t) + else + t[#t+1]=e end + end end - return t + end + return t end function xml.textonly(e) - return concat(textonly(e,{})) + return concat(textonly(e,{})) end function finalizers.lowerall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=lower(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[lower(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=lower(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[lower(k)]=v end + e.at=t + end end + end end function finalizers.upperall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=upper(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[upper(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=upper(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[upper(k)]=v end + e.at=t + end end + end end @@ -16096,14 +19670,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-xml"] = package.loaded["trac-xml"] or true --- original size: 6407, stripped down to: 4965 +-- original size: 6407, stripped down to: 4640 if not modules then modules={} end modules ['trac-xml']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local formatters=string.formatters local reporters=logs.reporters @@ -16112,152 +19686,152 @@ local xmlcollected=xml.collected local xmltext=xml.text local xmlfirst=xml.first local function showhelp(specification,...) - local root=xml.convert(specification.helpinfo or "") - if not root then - return - end - local xs=xml.gethandlers("string") - xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) - xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) - local wantedcategories=select("#",...)==0 and true or table.tohash {... } - local nofcategories=xml.count(root,"/application/flags/category") - local report=specification.report - for category in xmlcollected(root,"/application/flags/category") do - local categoryname=category.at.name or "" - if wantedcategories==true or wantedcategories[categoryname] then - if nofcategories>1 then - report("%s options:",categoryname) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for flag in xmlcollected(subcategory,"/flag") do - local name=flag.at.name - local value=flag.at.value - local short=xmltext(xmlfirst(flag,"/short")) - if value then - report("--%-20s %s",formatters["%s=%s"](name,value),short) - else - report("--%-20s %s",name,short) - end - end - report() - end - end - end - for category in xmlcollected(root,"/application/examples/category") do - local title=xmltext(xmlfirst(category,"/title")) - if title and title~="" then - report() - report(title) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for example in xmlcollected(subcategory,"/example") do - local command=xmltext(xmlfirst(example,"/command")) - local comment=xmltext(xmlfirst(example,"/comment")) - report(command) - end - report() - end - end - for comment in xmlcollected(root,"/application/comments/comment") do - local comment=xmltext(comment) + local root=xml.convert(specification.helpinfo or "") + if not root then + return + end + local xs=xml.gethandlers("string") + xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) + xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) + local wantedcategories=select("#",...)==0 and true or table.tohash {... } + local nofcategories=xml.count(root,"/application/flags/category") + local report=specification.report + for category in xmlcollected(root,"/application/flags/category") do + local categoryname=category.at.name or "" + if wantedcategories==true or wantedcategories[categoryname] then + if nofcategories>1 then + report("%s options:",categoryname) report() - report(comment) + end + for subcategory in xmlcollected(category,"/subcategory") do + for flag in xmlcollected(subcategory,"/flag") do + local name=flag.at.name + local value=flag.at.value + local short=xmltext(xmlfirst(flag,"/short")) + if value then + report("--%-20s %s",formatters["%s=%s"](name,value),short) + else + report("--%-20s %s",name,short) + end + end report() + end + end + end + for category in xmlcollected(root,"/application/examples/category") do + local title=xmltext(xmlfirst(category,"/title")) + if title and title~="" then + report() + report(title) + report() + end + for subcategory in xmlcollected(category,"/subcategory") do + for example in xmlcollected(subcategory,"/example") do + local command=xmltext(xmlfirst(example,"/command")) + local comment=xmltext(xmlfirst(example,"/comment")) + report(command) + end + report() end + end + for comment in xmlcollected(root,"/application/comments/comment") do + local comment=xmltext(comment) + report() + report(comment) + report() + end end local reporthelp=reporters.help local exporthelp=reporters.export local function xmlfound(t) - local helpinfo=t.helpinfo - if type(helpinfo)=="table" then - return false + local helpinfo=t.helpinfo + if type(helpinfo)=="table" then + return false + end + if type(helpinfo)~="string" then + helpinfo="Warning: no helpinfo found." + t.helpinfo=helpinfo + return false + end + if string.find(helpinfo,".xml$") then + local ownscript=environment.ownscript + local helpdata=false + if ownscript then + local helpfile=file.join(file.pathpart(ownscript),helpinfo) + helpdata=io.loaddata(helpfile) + if helpdata=="" then + helpdata=false + end end - if type(helpinfo)~="string" then - helpinfo="Warning: no helpinfo found." - t.helpinfo=helpinfo - return false + if not helpdata then + local helpfile=resolvers.findfile(helpinfo,"tex") + helpdata=helpfile and io.loaddata(helpfile) end - if string.find(helpinfo,".xml$") then - local ownscript=environment.ownscript - local helpdata=false - if ownscript then - local helpfile=file.join(file.pathpart(ownscript),helpinfo) - helpdata=io.loaddata(helpfile) - if helpdata=="" then - helpdata=false - end - end - if not helpdata then - local helpfile=resolvers.findfile(helpinfo,"tex") - helpdata=helpfile and io.loaddata(helpfile) - end - if helpdata and helpdata~="" then - helpinfo=helpdata - else - helpinfo=formatters["Warning: help file %a is not found."](helpinfo) - end + if helpdata and helpdata~="" then + helpinfo=helpdata + else + helpinfo=formatters["Warning: help file %a is not found."](helpinfo) end - t.helpinfo=helpinfo - return string.find(t.helpinfo,"^<%?xml") and true or false + end + t.helpinfo=helpinfo + return string.find(t.helpinfo,"^<%?xml") and true or false end function reporters.help(t,...) - if xmlfound(t) then - showhelp(t,...) - else - reporthelp(t,...) - end + if xmlfound(t) then + showhelp(t,...) + else + reporthelp(t,...) + end end function reporters.export(t,methods,filename) - if not xmlfound(t) then - return exporthelp(t) - end - if not methods or methods=="" then - methods=environment.arguments["exporthelp"] - end - if not filename or filename=="" then - filename=environment.files[1] - end - dofile(resolvers.findfile("trac-exp.lua","tex")) - local exporters=logs.exporters - if not exporters or not methods then - return exporthelp(t) - end - if methods=="all" then - methods=table.keys(exporters) - elseif type(methods)=="string" then - methods=utilities.parsers.settings_to_array(methods) - else - return exporthelp(t) - end - if type(filename)~="string" or filename=="" then - filename=false - elseif file.pathpart(filename)=="" then - t.report("export file %a will not be saved on the current path (safeguard)",filename) - return - end - for i=1,#methods do - local method=methods[i] - local exporter=exporters[method] - if exporter then - local result=exporter(t,method) - if result and result~="" then - if filename then - local fullname=file.replacesuffix(filename,method) - t.report("saving export in %a",fullname) - dir.mkdirs(file.pathpart(fullname)) - io.savedata(fullname,result) - else - reporters.lines(t,result) - end - else - t.report("no output from exporter %a",method) - end + if not xmlfound(t) then + return exporthelp(t) + end + if not methods or methods=="" then + methods=environment.arguments["exporthelp"] + end + if not filename or filename=="" then + filename=environment.files[1] + end + dofile(resolvers.findfile("trac-exp.lua","tex")) + local exporters=logs.exporters + if not exporters or not methods then + return exporthelp(t) + end + if methods=="all" then + methods=table.keys(exporters) + elseif type(methods)=="string" then + methods=utilities.parsers.settings_to_array(methods) + else + return exporthelp(t) + end + if type(filename)~="string" or filename=="" then + filename=false + elseif file.pathpart(filename)=="" then + t.report("export file %a will not be saved on the current path (safeguard)",filename) + return + end + for i=1,#methods do + local method=methods[i] + local exporter=exporters[method] + if exporter then + local result=exporter(t,method) + if result and result~="" then + if filename then + local fullname=file.replacesuffix(filename,method) + t.report("saving export in %a",fullname) + dir.mkdirs(file.pathpart(fullname)) + io.savedata(fullname,result) else - t.report("unknown exporter %a",method) + reporters.lines(t,result) end + else + t.report("no output from exporter %a",method) + end + else + t.report("unknown exporter %a",method) end + end end @@ -16267,149 +19841,149 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 11099, stripped down to: 7516 +-- original size: 11099, stripped down to: 7152 if not modules then modules={} end modules ['data-ini']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false texconfig.shell_escape='t' if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then - local default_texmfcnf=kpse.default_texmfcnf() - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") - default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") - environment.default_texmfcnf=default_texmfcnf + local default_texmfcnf=kpse.default_texmfcnf() + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") + default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") + environment.default_texmfcnf=default_texmfcnf end kpse={ original=kpse } setmetatable(kpse,{ - __index=function(kp,name) - report_initialization("fatal error: kpse library is accessed (key: %s)",name) - os.exit() - end + __index=function(kp,name) + report_initialization("fatal error: kpse library is accessed (key: %s)",name) + os.exit() + end } ) do - local osfontdir=osgetenv("OSFONTDIR") - if osfontdir and osfontdir~="" then - elseif osname=="windows" then - ossetenv("OSFONTDIR","c:/windows/fonts//") - elseif osname=="macosx" then - ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") - end + local osfontdir=osgetenv("OSFONTDIR") + if osfontdir and osfontdir~="" then + elseif osname=="windows" then + ossetenv("OSFONTDIR","c:/windows/fonts//") + elseif osname=="macosx" then + ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") + end end do - local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' - if not homedir or homedir=="" then - homedir=char(127) - end - homedir=file.collapsepath(homedir) - ossetenv("HOME",homedir) - ossetenv("USERPROFILE",homedir) - environment.homedir=homedir + local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' + if not homedir or homedir=="" then + homedir=char(127) + end + homedir=file.collapsepath(homedir) + ossetenv("HOME",homedir) + ossetenv("USERPROFILE",homedir) + environment.homedir=homedir end do - local args=environment.originalarguments or arg - if not environment.ownmain then - environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" - end - local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" - local ownpath=environment.ownpath or os.selfdir - ownbin=file.collapsepath(ownbin) - ownpath=file.collapsepath(ownpath) - if not ownpath or ownpath=="" or ownpath=="unset" then - ownpath=args[-1] or arg[-1] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - if not ownpath or ownpath=="" then - ownpath=args[-0] or arg[-0] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - end - local binary=ownbin - if not ownpath or ownpath=="" then - ownpath=ownpath and filedirname(binary) - end - if not ownpath or ownpath=="" then - if os.binsuffix~="" then - binary=file.replacesuffix(binary,os.binsuffix) - end - local path=osgetenv("PATH") - if path then - for p in gmatch(path,"[^"..io.pathseparator.."]+") do - local b=filejoin(p,binary) - if lfs.isfile(b) then - local olddir=lfs.currentdir() - if lfs.chdir(p) then - local pp=lfs.currentdir() - if trace_locating and p~=pp then - report_initialization("following symlink %a to %a",p,pp) - end - ownpath=pp - lfs.chdir(olddir) - else - if trace_locating then - report_initialization("unable to check path %a",p) - end - ownpath=p - end - break - end - end + local args=environment.originalarguments or arg + if not environment.ownmain then + environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" + end + local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" + local ownpath=environment.ownpath or os.selfdir + ownbin=file.collapsepath(ownbin) + ownpath=file.collapsepath(ownpath) + if not ownpath or ownpath=="" or ownpath=="unset" then + ownpath=args[-1] or arg[-1] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + if not ownpath or ownpath=="" then + ownpath=args[-0] or arg[-0] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + end + local binary=ownbin + if not ownpath or ownpath=="" then + ownpath=ownpath and filedirname(binary) + end + if not ownpath or ownpath=="" then + if os.binsuffix~="" then + binary=file.replacesuffix(binary,os.binsuffix) + end + local path=osgetenv("PATH") + if path then + for p in gmatch(path,"[^"..io.pathseparator.."]+") do + local b=filejoin(p,binary) + if lfs.isfile(b) then + local olddir=lfs.currentdir() + if lfs.chdir(p) then + local pp=lfs.currentdir() + if trace_locating and p~=pp then + report_initialization("following symlink %a to %a",p,pp) + end + ownpath=pp + lfs.chdir(olddir) + else + if trace_locating then + report_initialization("unable to check path %a",p) + end + ownpath=p end + break + end end - if not ownpath or ownpath=="" then - ownpath="." - report_initialization("forcing fallback to ownpath %a",ownpath) - elseif trace_locating then - report_initialization("using ownpath %a",ownpath) - end + end end - environment.ownbin=ownbin - environment.ownpath=ownpath + if not ownpath or ownpath=="" then + ownpath="." + report_initialization("forcing fallback to ownpath %a",ownpath) + elseif trace_locating then + report_initialization("using ownpath %a",ownpath) + end + end + environment.ownbin=ownbin + environment.ownpath=ownpath end resolvers.ownpath=environment.ownpath function resolvers.getownpath() - return environment.ownpath + return environment.ownpath end do - local ownpath=environment.ownpath or dir.current() - if ownpath then - ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) - ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) - ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) - else - report_initialization("error: unable to locate ownpath") - os.exit() - end -end -local texos=environment.texos or osgetenv("TEXOS") + local ownpath=environment.ownpath or dir.current() + if ownpath then + ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) + ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) + ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) + else + report_initialization("error: unable to locate ownpath") + os.exit() + end +end +local texos=environment.texos or osgetenv("TEXOS") local texmfos=environment.texmfos or osgetenv('SELFAUTODIR') if not texos or texos=="" then - texos=file.basename(texmfos) + texos=file.basename(texmfos) end ossetenv('TEXMFOS',texmfos) -ossetenv('TEXOS',texos) -ossetenv('SELFAUTOSYSTEM',os.platform) +ossetenv('TEXOS',texos) +ossetenv('SELFAUTOSYSTEM',os.platform) environment.texos=texos environment.texmfos=texmfos local texroot=environment.texroot or osgetenv("TEXROOT") if not texroot or texroot=="" then - texroot=osgetenv('SELFAUTOPARENT') - ossetenv('TEXROOT',texroot) + texroot=osgetenv('SELFAUTOPARENT') + ossetenv('TEXROOT',texroot) end environment.texroot=file.collapsepath(texroot) local prefixes=utilities.storage.allocate() @@ -16418,30 +19992,30 @@ local resolved={} local abstract={} local dynamic={} function resolvers.resetresolve(str) - resolved,abstract={},{} + resolved,abstract={},{} end function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" end - return all + end + return all end local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end end function resolvers.unresolve(str) - return abstract[str] or str + return abstract[str] or str end function resolvers.setdynamic(str) - dynamic[str]=true + dynamic[str]=true end local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) local prefix=C(R("az")^2)*P(":") @@ -16450,65 +20024,65 @@ local notarget=(#S(";,")+P(-1))*Cc("") local p_resolve=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) local p_simple=prefix*P(-1) local function resolve(str) - if type(str)=="table" then - local res={} - for i=1,#str do - res[i]=resolve(str[i]) - end - return res - end - local res=resolved[str] - if res then - return res + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) end - local simple=lpegmatch(p_simple,str) - local action=prefixes[simple] - if action then - local res=action(res) - if not dynamic[simple] then - resolved[simple]=res - abstract[res]=simple - end - return res + return res + end + local res=resolved[str] + if res then + return res + end + local simple=lpegmatch(p_simple,str) + local action=prefixes[simple] + if action then + local res=action(res) + if not dynamic[simple] then + resolved[simple]=res + abstract[res]=simple end - res=lpegmatch(p_resolve,str) - resolved[str]=res - abstract[res]=str return res + end + res=lpegmatch(p_resolve,str) + resolved[str]=res + abstract[res]=str + return res end resolvers.resolve=resolve if type(osuname)=="function" then - for k,v in next,osuname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end end + end end if ostype=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - table.setmetatablenewindex(prefixes,makepattern) - function resolvers.repath(str) - return lpegmatch(pattern,str) + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end else - function resolvers.repath(str) - return str - end + function resolvers.repath(str) + return str + end end @@ -16518,14 +20092,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 18105, stripped down to: 11207 +-- original size: 18105, stripped down to: 10389 if not modules then modules={} end modules ['data-exp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } 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 @@ -16535,21 +20109,21 @@ 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 isdir=lfs.isdir local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers local resolveprefix=resolvers.resolve local function f_both(a,b) - local t,n={},0 - for sb in gmatch(b,"[^,]+") do - for sa in gmatch(a,"[^,]+") do - n=n+1;t[n]=sa..sb - end + local t,n={},0 + for sb in gmatch(b,"[^,]+") do + for sa in gmatch(a,"[^,]+") do + n=n+1;t[n]=sa..sb end - return concat(t,",") + end + return concat(t,",") end local comma=P(",") local nocomma=(1-comma)^1 @@ -16559,7 +20133,7 @@ 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 function f_both (a,b) return lpegmatch(both,b,1,a) end local left=P("{") local right=P("}") local var=P((1-S("{}" ))^0) @@ -16572,141 +20146,141 @@ local l_rest=Cs((left*var*(left/"")*var*(right/"")*var*right+other )^0 ) local stripper_1=lpeg.stripper ("{}@") local replacer_1=lpeg.replacer { { ",}",",@}" },{ "{,","{@," },} local function splitpathexpr(str,newlist,validate) - if trace_expansions then - report_expansions("expanding variable %a",str) - end - local t,ok,done=newlist or {},false,false - local n=#t - str=lpegmatch(replacer_1,str) + if trace_expansions then + report_expansions("expanding variable %a",str) + end + local t,ok,done=newlist or {},false,false + local n=#t + str=lpegmatch(replacer_1,str) + repeat + local old=str repeat - local old=str - repeat - local old=str - str=lpegmatch(l_first,str) - until old==str - repeat - local old=str - str=lpegmatch(l_second,str) - until old==str - repeat - local old=str - str=lpegmatch(l_both,str) - until old==str - repeat - local old=str - str=lpegmatch(l_rest,str) - until old==str - until old==str - str=lpegmatch(stripper_1,str) - if validate then - for s in gmatch(str,"[^,]+") do - s=validate(s) - if s then - n=n+1 - t[n]=s - end - end - else - for s in gmatch(str,"[^,]+") do - n=n+1 - t[n]=s - end + local old=str + str=lpegmatch(l_first,str) + until old==str + repeat + local old=str + str=lpegmatch(l_second,str) + until old==str + repeat + local old=str + str=lpegmatch(l_both,str) + until old==str + repeat + local old=str + str=lpegmatch(l_rest,str) + until old==str + until old==str + str=lpegmatch(stripper_1,str) + if validate then + for s in gmatch(str,"[^,]+") do + s=validate(s) + if s then + n=n+1 + t[n]=s + end end - if trace_expansions then - for k=1,#t do - report_expansions("% 4i: %s",k,t[k]) - end + else + for s in gmatch(str,"[^,]+") do + n=n+1 + t[n]=s end - return t + end + if trace_expansions then + for k=1,#t do + report_expansions("% 4i: %s",k,t[k]) + end + end + return t end local function validate(s) - s=collapsepath(s) - return s~="" and not find(s,"^!*unset/*$") and s + s=collapsepath(s) + return s~="" and not find(s,"^!*unset/*$") and s end resolvers.validatedpath=validate function resolvers.expandedpathfromlist(pathlist) - local newlist={} - for k=1,#pathlist do - splitpathexpr(pathlist[k],newlist,validate) - end - return newlist + local newlist={} + for k=1,#pathlist do + splitpathexpr(pathlist[k],newlist,validate) + end + return newlist end local usedhomedir=nil -local donegation=(P("!")/"" )^0 +local donegation=(P("!")/"" )^0 local doslashes=(P("\\")/"/"+1)^0 local function expandedhome() - if not usedhomedir then - usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent path using current path") - end - usedhomedir="." - end + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") + end + usedhomedir="." end - return usedhomedir + end + return usedhomedir end local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 local cleanup=Cs(donegation*dohome*doslashes) resolvers.cleanpath=function(str) - return str and lpegmatch(cleanup,str) or "" + return str and lpegmatch(cleanup,str) or "" end local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" -local dostring=(expandhome+1 )^0 +local dostring=(expandhome+1 )^0 local stripper=Cs( - lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer + lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer ) function resolvers.checkedvariable(str) - return type(str)=="string" and lpegmatch(stripper,str) or str + return type(str)=="string" and lpegmatch(stripper,str) or str end local cache={} local splitter=lpeg.tsplitat(";") local backslashswapper=lpeg.replacer("\\","/") local function splitconfigurationpath(str) - if str then - local found=cache[str] - if not found then - if str=="" then - found={} - else - local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) - found={} - local noffound=0 - for i=1,#split do - local s=split[i] - if not find(s,"^{*unset}*") then - noffound=noffound+1 - found[noffound]=s - end - end - if trace_expansions then - report_expansions("splitting path specification %a",str) - for k=1,noffound do - report_expansions("% 4i: %s",k,found[k]) - end - end - cache[str]=found - end + if str then + local found=cache[str] + if not found then + if str=="" then + found={} + else + local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) + found={} + local noffound=0 + for i=1,#split do + local s=split[i] + if not find(s,"^{*unset}*") then + noffound=noffound+1 + found[noffound]=s + end end - return found + if trace_expansions then + report_expansions("splitting path specification %a",str) + for k=1,noffound do + report_expansions("% 4i: %s",k,found[k]) + end + end + cache[str]=found + end end + return found + end end resolvers.splitconfigurationpath=splitconfigurationpath function resolvers.splitpath(str) - if type(str)=='table' then - return str - else - return splitconfigurationpath(str) - end + if type(str)=='table' then + return str + else + return splitconfigurationpath(str) + end end function resolvers.joinpath(str) - if type(str)=='table' then - return joinpath(str) - else - return str - end + if type(str)=='table' then + return joinpath(str) + else + return str + end end local attributes,directory=lfs.attributes,lfs.dir local weird=P(".")^1+lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) @@ -16719,201 +20293,201 @@ local fullcache={} local nofsharedscans=0 local addcasecraptoo=true local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant) - local full=path=="" and spec or (spec..path..'/') - local dirlist={} - local nofdirs=0 - local pattern=tolerant and lessweird or weird - local filelist={} - local noffiles=0 - for name in directory(full) do - if not lpegmatch(pattern,name) then - local mode=attributes(full..name,"mode") - if mode=="file" then - n=n+1 - noffiles=noffiles+1 - filelist[noffiles]=name - elseif mode=="directory" then - m=m+1 - nofdirs=nofdirs+1 - if path~="" then - dirlist[nofdirs]=path.."/"..name - else - dirlist[nofdirs]=name - end - end + local full=path=="" and spec or (spec..path..'/') + local dirlist={} + local nofdirs=0 + local pattern=tolerant and lessweird or weird + local filelist={} + local noffiles=0 + for name in directory(full) do + if not lpegmatch(pattern,name) then + local mode=attributes(full..name,"mode") + if mode=="file" then + n=n+1 + noffiles=noffiles+1 + filelist[noffiles]=name + elseif mode=="directory" then + m=m+1 + nofdirs=nofdirs+1 + if path~="" then + dirlist[nofdirs]=path.."/"..name + else + dirlist[nofdirs]=name end + end end - if noffiles>0 then - sort(filelist) - for i=1,noffiles do - local name=filelist[i] - local lower=lower(name) - local paths=files[lower] - if paths then - if onlyone then - else - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - if addcasecraptoo then - local paths=files[name] - if not paths then - files[name]=path - elseif type(paths)=="string" then - files[name]={ paths,path } - else - paths[#paths+1]=path - end - end - end - if type(paths)=="string" then - files[lower]={ paths,path } - else - paths[#paths+1]=path - end - end - else - files[lower]=path - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - end + end + if noffiles>0 then + sort(filelist) + for i=1,noffiles do + local name=filelist[i] + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then + else + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + if addcasecraptoo then + local paths=files[name] + if not paths then + files[name]=path + elseif type(paths)=="string" then + files[name]={ paths,path } + else + paths[#paths+1]=path + end end + end + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end end - end - if nofdirs>0 then - sort(dirlist) - for i=1,nofdirs do - files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) + else + files[lower]=path + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end + end + end + end + if nofdirs>0 then + sort(dirlist) + for i=1,nofdirs do + files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) end - scancache[sub(full,1,-2)]=files - return files,remap,n,m,r + end + scancache[sub(full,1,-2)]=files + return files,remap,n,m,r end function resolvers.scanfiles(path,branch,usecache,onlyonce,tolerant) - local realpath=resolveprefix(path) - if usecache then - local content=fullcache[realpath] - if content then - if trace_locating then - report_expansions("using cached scan of path %a, branch %a",path,branch or path) - end - nofsharedscans=nofsharedscans+1 - return content - end - end - statistics.starttiming(timer) + local realpath=resolveprefix(path) + if usecache then + local content=fullcache[realpath] + if content then + if trace_locating then + report_expansions("using cached scan of path %a, branch %a",path,branch or path) + end + nofsharedscans=nofsharedscans+1 + return content + end + end + statistics.starttiming(timer) + if trace_locating then + report_expansions("scanning path %a, branch %a",path,branch or path) + end + local content + if isdir(realpath) then + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) + content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) + report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end - local content - if isdir(realpath) then - local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) - content={ - metadata={ - path=path, - files=n, - directories=m, - remappings=r, - }, - files=files, - remap=remap, - } - if trace_locating then - report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) - end - else - content={ - metadata={ - path=path, - files=0, - directories=0, - remappings=0, - }, - files={}, - remap={}, - } - if trace_locating then - report_expansions("invalid path %a",realpath) - end - end - if usecache then - scanned[#scanned+1]=realpath - fullcache[realpath]=content + else + content={ + metadata={ + path=path, + files=0, + directories=0, + remappings=0, + }, + files={}, + remap={}, + } + if trace_locating then + report_expansions("invalid path %a",realpath) end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return content + end + if usecache then + scanned[#scanned+1]=realpath + fullcache[realpath]=content + end + nofscans=nofscans+1 + statistics.stoptiming(timer) + return content end function resolvers.simplescanfiles(path,branch,usecache) - return resolvers.scanfiles(path,branch,usecache,true,true) + return resolvers.scanfiles(path,branch,usecache,true,true) end function resolvers.scandata() - table.sort(scanned) - return { - n=nofscans, - shared=nofsharedscans, - time=statistics.elapsedtime(timer), - paths=scanned, - } + table.sort(scanned) + return { + n=nofscans, + shared=nofsharedscans, + time=statistics.elapsedtime(timer), + paths=scanned, + } end function resolvers.get_from_content(content,path,name) - if not content then - return - end - local files=content.files - if not files then - return - end - local remap=content.remap - if not remap then - return - end - if name then - local used=lower(name) - return path,remap[used] or used - else - local name=path - local used=lower(name) - local path=files[used] - if path then - return path,remap[used] or used - end - end + if not content then + return + end + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end end local nothing=function() end function resolvers.filtered_from_content(content,pattern) - if content and type(pattern)=="string" then - local pattern=lower(pattern) - local files=content.files - local remap=content.remap - if files and remap then - local f=sortedkeys(files) - local n=#f - local i=0 - local function iterator() - while i<n do - i=i+1 - local k=f[i] - if find(k,pattern) then - return files[k],remap and remap[k] or k - end - end - end - return iterator + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local f=sortedkeys(files) + local n=#f + local i=0 + local function iterator() + while i<n do + i=i+1 + local k=f[i] + if find(k,pattern) then + return files[k],remap and remap[k] or k + end end + end + return iterator end - return nothing + end + return nothing end @@ -16923,14 +20497,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-env"] = package.loaded["data-env"] or true --- original size: 9360, stripped down to: 6903 +-- original size: 9360, stripped down to: 6312 if not modules then modules={} end modules ['data-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local lower,gsub=string.lower,string.gsub local next=next @@ -16950,255 +20524,255 @@ resolvers.suffixmap=suffixmap resolvers.usertypes=usertypes local luasuffixes=utilities.lua.suffixes local relations=allocate { - core={ - ofm={ - names={ "ofm","omega font metric","omega font metrics" }, - variable='OFMFONTS', - suffixes={ 'ofm','tfm' }, - }, - ovf={ - names={ "ovf","omega virtual font","omega virtual fonts" }, - variable='OVFFONTS', - suffixes={ 'ovf','vf' }, - }, - tfm={ - names={ "tfm","tex font metric","tex font metrics" }, - variable='TFMFONTS', - suffixes={ 'tfm' }, - }, - vf={ - names={ "vf","virtual font","virtual fonts" }, - variable='VFFONTS', - suffixes={ 'vf' }, - }, - otf={ - names={ "otf","opentype","opentype font","opentype fonts"}, - variable='OPENTYPEFONTS', - suffixes={ 'otf' }, - }, - ttf={ - names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, - variable='TTFONTS', - suffixes={ 'ttf','ttc','dfont' }, - }, - afm={ - names={ "afm","adobe font metric","adobe font metrics" }, - variable="AFMFONTS", - suffixes={ "afm" }, - }, - pfb={ - names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, - variable='T1FONTS', - suffixes={ 'pfb','pfa' }, - }, - fea={ - names={ "fea","font feature","font features","font feature file","font feature files" }, - variable='FONTFEATURES', - suffixes={ 'fea' }, - }, - cid={ - names={ "cid","cid map","cid maps","cid file","cid files" }, - variable='FONTCIDMAPS', - suffixes={ 'cid','cidmap' }, - }, - fmt={ - names={ "fmt","format","tex format" }, - variable='TEXFORMATS', - suffixes={ 'fmt' }, - }, - mem={ - names={ 'mem',"metapost format" }, - variable='MPMEMS', - suffixes={ 'mem' }, - }, - mp={ - names={ "mp" }, - variable='MPINPUTS', - suffixes={ 'mp','mpvi','mpiv','mpii' }, - usertype=true, - }, - tex={ - names={ "tex" }, - variable='TEXINPUTS', - suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, - usertype=true, - }, - icc={ - names={ "icc","icc profile","icc profiles" }, - variable='ICCPROFILES', - suffixes={ 'icc' }, - }, - texmfscripts={ - names={ "texmfscript","texmfscripts","script","scripts" }, - variable='TEXMFSCRIPTS', - suffixes={ 'lua','rb','pl','py' }, - }, - lua={ - names={ "lua" }, - variable='LUAINPUTS', - suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, - usertype=true, - }, - lib={ - names={ "lib" }, - variable='CLUAINPUTS', - suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, - }, - bib={ - names={ 'bib' }, - variable='BIBINPUTS', - suffixes={ 'bib' }, - usertype=true, - }, - bst={ - names={ 'bst' }, - variable='BSTINPUTS', - suffixes={ 'bst' }, - usertype=true, - }, - fontconfig={ - names={ 'fontconfig','fontconfig file','fontconfig files' }, - variable='FONTCONFIG_PATH', - }, - pk={ - names={ "pk" }, - variable='PKFONTS', - suffixes={ 'pk' }, - }, + core={ + ofm={ + names={ "ofm","omega font metric","omega font metrics" }, + variable='OFMFONTS', + suffixes={ 'ofm','tfm' }, + }, + ovf={ + names={ "ovf","omega virtual font","omega virtual fonts" }, + variable='OVFFONTS', + suffixes={ 'ovf','vf' }, + }, + tfm={ + names={ "tfm","tex font metric","tex font metrics" }, + variable='TFMFONTS', + suffixes={ 'tfm' }, + }, + vf={ + names={ "vf","virtual font","virtual fonts" }, + variable='VFFONTS', + suffixes={ 'vf' }, + }, + otf={ + names={ "otf","opentype","opentype font","opentype fonts"}, + variable='OPENTYPEFONTS', + suffixes={ 'otf' }, + }, + ttf={ + names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, + variable='TTFONTS', + suffixes={ 'ttf','ttc','dfont' }, + }, + afm={ + names={ "afm","adobe font metric","adobe font metrics" }, + variable="AFMFONTS", + suffixes={ "afm" }, + }, + pfb={ + names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, + variable='T1FONTS', + suffixes={ 'pfb','pfa' }, + }, + fea={ + names={ "fea","font feature","font features","font feature file","font feature files" }, + variable='FONTFEATURES', + suffixes={ 'fea' }, + }, + cid={ + names={ "cid","cid map","cid maps","cid file","cid files" }, + variable='FONTCIDMAPS', + suffixes={ 'cid','cidmap' }, + }, + fmt={ + names={ "fmt","format","tex format" }, + variable='TEXFORMATS', + suffixes={ 'fmt' }, + }, + mem={ + names={ 'mem',"metapost format" }, + variable='MPMEMS', + suffixes={ 'mem' }, + }, + mp={ + names={ "mp" }, + variable='MPINPUTS', + suffixes={ 'mp','mpvi','mpiv','mpii' }, + usertype=true, + }, + tex={ + names={ "tex" }, + variable='TEXINPUTS', + suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, + usertype=true, + }, + icc={ + names={ "icc","icc profile","icc profiles" }, + variable='ICCPROFILES', + suffixes={ 'icc' }, + }, + texmfscripts={ + names={ "texmfscript","texmfscripts","script","scripts" }, + variable='TEXMFSCRIPTS', + suffixes={ 'lua','rb','pl','py' }, + }, + lua={ + names={ "lua" }, + variable='LUAINPUTS', + suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, + usertype=true, }, - obsolete={ - enc={ - names={ "enc","enc files","enc file","encoding files","encoding file" }, - variable='ENCFONTS', - suffixes={ 'enc' }, - }, - map={ - names={ "map","map files","map file" }, - variable='TEXFONTMAPS', - suffixes={ 'map' }, - }, - lig={ - names={ "lig files","lig file","ligature file","ligature files" }, - variable='LIGFONTS', - suffixes={ 'lig' }, - }, - opl={ - names={ "opl" }, - variable='OPLFONTS', - suffixes={ 'opl' }, - }, - ovp={ - names={ "ovp" }, - variable='OVPFONTS', - suffixes={ 'ovp' }, - }, + lib={ + names={ "lib" }, + variable='CLUAINPUTS', + suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, }, - kpse={ - base={ - names={ 'base',"metafont format" }, - variable='MFBASES', - suffixes={ 'base','bas' }, - }, - cmap={ - names={ 'cmap','cmap files','cmap file' }, - variable='CMAPFONTS', - suffixes={ 'cmap' }, - }, - cnf={ - names={ 'cnf' }, - suffixes={ 'cnf' }, - }, - web={ - names={ 'web' }, - suffixes={ 'web','ch' } - }, - cweb={ - names={ 'cweb' }, - suffixes={ 'w','web','ch' }, - }, - gf={ - names={ 'gf' }, - suffixes={ '<resolution>gf' }, - }, - mf={ - names={ 'mf' }, - variable='MFINPUTS', - suffixes={ 'mf' }, - }, - mft={ - names={ 'mft' }, - suffixes={ 'mft' }, - }, - pk={ - names={ 'pk' }, - suffixes={ '<resolution>pk' }, - }, + bib={ + names={ 'bib' }, + variable='BIBINPUTS', + suffixes={ 'bib' }, + usertype=true, }, + bst={ + names={ 'bst' }, + variable='BSTINPUTS', + suffixes={ 'bst' }, + usertype=true, + }, + fontconfig={ + names={ 'fontconfig','fontconfig file','fontconfig files' }, + variable='FONTCONFIG_PATH', + }, + pk={ + names={ "pk" }, + variable='PKFONTS', + suffixes={ 'pk' }, + }, + }, + obsolete={ + enc={ + names={ "enc","enc files","enc file","encoding files","encoding file" }, + variable='ENCFONTS', + suffixes={ 'enc' }, + }, + map={ + names={ "map","map files","map file" }, + variable='TEXFONTMAPS', + suffixes={ 'map' }, + }, + lig={ + names={ "lig files","lig file","ligature file","ligature files" }, + variable='LIGFONTS', + suffixes={ 'lig' }, + }, + opl={ + names={ "opl" }, + variable='OPLFONTS', + suffixes={ 'opl' }, + }, + ovp={ + names={ "ovp" }, + variable='OVPFONTS', + suffixes={ 'ovp' }, + }, + }, + kpse={ + base={ + names={ 'base',"metafont format" }, + variable='MFBASES', + suffixes={ 'base','bas' }, + }, + cmap={ + names={ 'cmap','cmap files','cmap file' }, + variable='CMAPFONTS', + suffixes={ 'cmap' }, + }, + cnf={ + names={ 'cnf' }, + suffixes={ 'cnf' }, + }, + web={ + names={ 'web' }, + suffixes={ 'web','ch' } + }, + cweb={ + names={ 'cweb' }, + suffixes={ 'w','web','ch' }, + }, + gf={ + names={ 'gf' }, + suffixes={ '<resolution>gf' }, + }, + mf={ + names={ 'mf' }, + variable='MFINPUTS', + suffixes={ 'mf' }, + }, + mft={ + names={ 'mft' }, + suffixes={ 'mft' }, + }, + pk={ + names={ 'pk' }, + suffixes={ '<resolution>pk' }, + }, + }, } resolvers.relations=relations function resolvers.updaterelations() - for category,categories in next,relations do - for name,relation in next,categories do - local rn=relation.names - local rv=relation.variable - if rn and rv then - local rs=relation.suffixes - local ru=relation.usertype - for i=1,#rn do - local rni=lower(gsub(rn[i]," ","")) - formats[rni]=rv - if rs then - suffixes[rni]=rs - for i=1,#rs do - local rsi=rs[i] - suffixmap[rsi]=rni - end - end - end - if ru then - usertypes[name]=true - end + for category,categories in next,relations do + for name,relation in next,categories do + local rn=relation.names + local rv=relation.variable + if rn and rv then + local rs=relation.suffixes + local ru=relation.usertype + for i=1,#rn do + local rni=lower(gsub(rn[i]," ","")) + formats[rni]=rv + if rs then + suffixes[rni]=rs + for i=1,#rs do + local rsi=rs[i] + suffixmap[rsi]=rni end + end + end + if ru then + usertypes[name]=true end + end end + end end resolvers.updaterelations() local function simplified(t,k) - return k and rawget(t,lower(gsub(k," ",""))) or nil + return k and rawget(t,lower(gsub(k," ",""))) or nil end setmetatableindex(formats,simplified) setmetatableindex(suffixes,simplified) setmetatableindex(suffixmap,simplified) function resolvers.suffixofformat(str) - local s=suffixes[str] - return s and s[1] or "" + local s=suffixes[str] + return s and s[1] or "" end function resolvers.suffixofformat(str) - return suffixes[str] or {} + return suffixes[str] or {} end for name,format in next,formats do - dangerous[name]=true + dangerous[name]=true end dangerous.tex=nil function resolvers.formatofvariable(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.formatofsuffix(str) - return suffixmap[suffixonly(str)] or 'tex' + return suffixmap[suffixonly(str)] or 'tex' end function resolvers.variableofformat(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.variableofformatorsuffix(str) - local v=formats[str] - if v then - return v - end - v=suffixmap[suffixonly(str)] - if v then - return formats[v] - end - return '' + local v=formats[str] + if v then + return v + end + v=suffixmap[suffixonly(str)] + if v then + return formats[v] + end + return '' end @@ -17208,14 +20782,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 16116, stripped down to: 11459 +-- original size: 16116, stripped down to: 10782 if not modules then modules={} end modules ['data-tmp']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,concat=string.format,string.lower,string.gsub,table.concat local concat=table.concat @@ -17223,19 +20797,19 @@ local mkdirs,isdir,isfile=dir.mkdirs,lfs.isdir,lfs.isfile local addsuffix,is_writable,is_readable=file.addsuffix,file.is_writable,file.is_readable local formatters=string.formatters local next,type=next,type -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers local cleanpath=resolvers.cleanpath -local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) -local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) +local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) +local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile function utilities.lua.compile(luafile,lucfile,cleanup,strip) - if cleanup==nil then cleanup=directive_cleanup end - if strip==nil then strip=directive_strip end - return compile(luafile,lucfile,cleanup,strip) + if cleanup==nil then cleanup=directive_cleanup end + if strip==nil then strip=directive_strip end + return compile(luafile,lucfile,cleanup,strip) end caches=caches or {} local caches=caches @@ -17250,324 +20824,324 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - cachepath=file.collapsepath(cachepath) - local valid=isdir(cachepath) - if valid then - if is_readable(cachepath) then - readables[#readables+1]=cachepath - if not writable and is_writable(cachepath) then - writable=cachepath - end - end - elseif not writable and caches.force then - local cacheparent=file.dirname(cachepath) - if is_writable(cacheparent) and true then - if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then - mkdirs(cachepath) - if isdir(cachepath) and is_writable(cachepath) then - report_caches("path %a created",cachepath) - writable=cachepath - readables[#readables+1]=cachepath - end - end - end - end + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + cachepath=file.collapsepath(cachepath) + local valid=isdir(cachepath) + if valid then + if is_readable(cachepath) then + readables[#readables+1]=cachepath + if not writable and is_writable(cachepath) then + writable=cachepath end - end - end - local texmfcaches=caches.defaults - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - cachepath=resolvers.expansion(cachepath) - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - local valid=isdir(cachepath) - if valid and is_readable(cachepath) then - if not writable and is_writable(cachepath) then - readables[#readables+1]=cachepath - writable=cachepath - break - end - end + end + elseif not writable and caches.force then + local cacheparent=file.dirname(cachepath) + if is_writable(cacheparent) and true then + if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then + mkdirs(cachepath) + if isdir(cachepath) and is_writable(cachepath) then + report_caches("path %a created",cachepath) + writable=cachepath + readables[#readables+1]=cachepath + end end + end end + end end - if not writable then - report_caches("fatal error: there is no valid writable cache path defined") - os.exit() - elseif #readables==0 then - report_caches("fatal error: there is no valid readable cache path defined") - os.exit() - end - writable=dir.expandname(resolvers.cleanpath(writable)) - local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() - if tree then - caches.tree=tree - writable=mkdirs(writable,base,more,tree) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more,tree) - end - else - writable=mkdirs(writable,base,more) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more) + end + local texmfcaches=caches.defaults + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + cachepath=resolvers.expansion(cachepath) + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + local valid=isdir(cachepath) + if valid and is_readable(cachepath) then + if not writable and is_writable(cachepath) then + readables[#readables+1]=cachepath + writable=cachepath + break + end end + end end - if trace_cache then - for i=1,#readables do - report_caches("using readable path %a (order %s)",readables[i],i) - end - report_caches("using writable path %a",writable) + end + if not writable then + report_caches("fatal error: there is no valid writable cache path defined") + os.exit() + elseif #readables==0 then + report_caches("fatal error: there is no valid readable cache path defined") + os.exit() + end + writable=dir.expandname(resolvers.cleanpath(writable)) + local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() + if tree then + caches.tree=tree + writable=mkdirs(writable,base,more,tree) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more,tree) end - identify=function() - return writable,readables + else + writable=mkdirs(writable,base,more) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more) end + end + if trace_cache then + for i=1,#readables do + report_caches("using readable path %a (order %s)",readables[i],i) + end + report_caches("using writable path %a",writable) + end + identify=function() return writable,readables + end + return writable,readables end function caches.usedpaths(separator) - local writable,readables=identify() - if #readables>1 then - local result={} - local done={} - for i=1,#readables do - local readable=readables[i] - if readable==writable then - done[readable]=true - result[#result+1]=formatters["readable+writable: %a"](readable) - elseif usedreadables[i] then - done[readable]=true - result[#result+1]=formatters["readable: %a"](readable) - end - end - if not done[writable] then - result[#result+1]=formatters["writable: %a"](writable) - end - return concat(result,separator or " | ") - else - return writable or "?" + local writable,readables=identify() + if #readables>1 then + local result={} + local done={} + for i=1,#readables do + local readable=readables[i] + if readable==writable then + done[readable]=true + result[#result+1]=formatters["readable+writable: %a"](readable) + elseif usedreadables[i] then + done[readable]=true + result[#result+1]=formatters["readable: %a"](readable) + end end + if not done[writable] then + result[#result+1]=formatters["writable: %a"](writable) + end + return concat(result,separator or " | ") + else + return writable or "?" + end end function caches.configfiles() - return concat(resolvers.configurationfiles(),";") + return concat(resolvers.configurationfiles(),";") end function caches.hashed(tree) - tree=gsub(tree,"[\\/]+$","") - tree=lower(tree) - local hash=md5.hex(tree) - if trace_cache or trace_locating then - report_caches("hashing tree %a, hash %a",tree,hash) - end - return hash + tree=gsub(tree,"[\\/]+$","") + tree=lower(tree) + local hash=md5.hex(tree) + if trace_cache or trace_locating then + report_caches("hashing tree %a, hash %a",tree,hash) + end + return hash end function caches.treehash() - local tree=caches.configfiles() - if not tree or tree=="" then - return false - else - return caches.hashed(tree) - end + local tree=caches.configfiles() + if not tree or tree=="" then + return false + else + return caches.hashed(tree) + end end local r_cache,w_cache={},{} local function getreadablepaths(...) - local tags={... } - local hash=concat(tags,"/") - local done=r_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done={} - for i=1,#readables do - done[i]=file.join(readables[i],...) - end - else - done=readables - end - r_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=r_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done={} + for i=1,#readables do + done[i]=file.join(readables[i],...) + end + else + done=readables end - return done + r_cache[hash]=done + end + return done end local function getwritablepath(...) - local tags={... } - local hash=concat(tags,"/") - local done=w_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done=mkdirs(writable,...) - else - done=writable - end - w_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=w_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done=mkdirs(writable,...) + else + done=writable end - return done + w_cache[hash]=done + end + return done end caches.getreadablepaths=getreadablepaths caches.getwritablepath=getwritablepath function caches.getfirstreadablefile(filename,...) - local fullname,path=caches.setfirstwritablefile(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 - 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 + usedreadables[i]=true + return fullname,path end - return fullname,path + end + return fullname,path end function caches.setfirstwritablefile(filename,...) - local wr=getwritablepath(...) - local fullname=file.join(wr,filename) - return fullname,wr + local wr=getwritablepath(...) + local fullname=file.join(wr,filename) + return fullname,wr end function caches.define(category,subcategory) - return function() - return getwritablepath(category,subcategory) - end + return function() + return getwritablepath(category,subcategory) + end end function caches.setluanames(path,name) - return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) + return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) end function caches.loaddata(readables,name,writable) - if type(readables)=="string" then - readables={ readables } + if type(readables)=="string" then + readables={ readables } + end + for i=1,#readables do + local path=readables[i] + local loader=false + local tmaname,tmcname=caches.setluanames(path,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader and isfile(tmaname) then + local tmacrap,tmcname=caches.setluanames(writable,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + utilities.lua.compile(tmaname,tmcname) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader then + loader=loadfile(tmaname) + end end - for i=1,#readables do - local path=readables[i] - local loader=false - local tmaname,tmcname=caches.setluanames(path,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader and isfile(tmaname) then - local tmacrap,tmcname=caches.setluanames(writable,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - utilities.lua.compile(tmaname,tmcname) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader then - loader=loadfile(tmaname) - end - end - if loader then - loader=loader() - collectgarbage("step") - return loader - end + if loader then + loader=loader() + collectgarbage("step") + return loader end - return false + end + return false end function caches.is_writable(filepath,filename) - local tmaname,tmcname=caches.setluanames(filepath,filename) - return is_writable(tmaname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + return is_writable(tmaname) end local saveoptions={ compact=true } function caches.savedata(filepath,filename,data,raw) - local tmaname,tmcname=caches.setluanames(filepath,filename) - data.cache_uuid=os.uuid() - if caches.direct then - file.savedata(tmaname,table.serialize(data,true,saveoptions)) - else - table.tofile(tmaname,data,true,saveoptions) - end - utilities.lua.compile(tmaname,tmcname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + data.cache_uuid=os.uuid() + if caches.direct then + file.savedata(tmaname,table.serialize(data,true,saveoptions)) + else + table.tofile(tmaname,data,true,saveoptions) + end + utilities.lua.compile(tmaname,tmcname) end local content_state={} function caches.contentstate() - return content_state or {} + return content_state or {} end function caches.loadcontent(cachename,dataname,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) - if blob then - local data=blob() - if data and data.content then - if data.type==dataname then - if data.version==resolvers.cacheversion then - content_state[#content_state+1]=data.uuid - if trace_locating then - report_resolvers("loading %a for %a from %a",dataname,cachename,filename) - end - return data.content - else - report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) - end - else - report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) - end - elseif trace_locating then - report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) + if blob then + local data=blob() + if data and data.content then + if data.type==dataname then + if data.version==resolvers.cacheversion then + content_state[#content_state+1]=data.uuid + if trace_locating then + report_resolvers("loading %a for %a from %a",dataname,cachename,filename) + end + return data.content + else + report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) end + else + report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) + end elseif trace_locating then - report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) end + elseif trace_locating then + report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + end end function caches.collapsecontent(content) - for k,v in next,content do - if type(v)=="table" and #v==1 then - content[k]=v[1] - end + for k,v in next,content do + if type(v)=="table" and #v==1 then + content[k]=v[1] end + end end function caches.savecontent(cachename,dataname,content,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local luaname=addsuffix(filename,luasuffixes.lua) - local lucname=addsuffix(filename,luasuffixes.luc) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local luaname=addsuffix(filename,luasuffixes.lua) + local lucname=addsuffix(filename,luasuffixes.luc) + if trace_locating then + report_resolvers("preparing %a for %a",dataname,cachename) + end + local data={ + type=dataname, + root=cachename, + version=resolvers.cacheversion, + date=os.date("%Y-%m-%d"), + time=os.date("%H:%M:%S"), + content=content, + uuid=os.uuid(), + } + local ok=io.savedata(luaname,table.serialize(data,true)) + if ok then if trace_locating then - report_resolvers("preparing %a for %a",dataname,cachename) - end - local data={ - type=dataname, - root=cachename, - version=resolvers.cacheversion, - date=os.date("%Y-%m-%d"), - time=os.date("%H:%M:%S"), - content=content, - uuid=os.uuid(), - } - local ok=io.savedata(luaname,table.serialize(data,true)) - if ok then - if trace_locating then - report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) - end - if utilities.lua.compile(luaname,lucname) then - if trace_locating then - report_resolvers("%a compiled to %a",dataname,lucname) - end - return true - else - if trace_locating then - report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) - end - os.remove(lucname) - end - elseif trace_locating then - report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) + end + if utilities.lua.compile(luaname,lucname) then + if trace_locating then + report_resolvers("%a compiled to %a",dataname,lucname) + end + return true + else + if trace_locating then + report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) + end + os.remove(lucname) end + elseif trace_locating then + report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + end end @@ -17577,14 +21151,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5310, stripped down to: 3980 +-- original size: 5310, stripped down to: 3784 if not modules then modules={} end modules ['data-met']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,format=string.find,string.format local sequenced=table.sequenced @@ -17598,86 +21172,86 @@ local allocate=utilities.storage.allocate local resolvers=resolvers local registered={} local function splitmethod(filename) - if not filename then - return { scheme="unknown",original=filename } - end - if type(filename)=="table" then - return filename - end - filename=file.collapsepath(filename,".") - if not find(filename,"://",1,true) then - return { scheme="file",path=filename,original=filename,filename=filename } - end - local specification=url.hashed(filename) - if not specification.scheme or specification.scheme=="" then - return { scheme="file",path=filename,original=filename,filename=filename } - else - return specification - end + if not filename then + return { scheme="unknown",original=filename } + end + if type(filename)=="table" then + return filename + end + filename=file.collapsepath(filename,".") + if not find(filename,"://",1,true) then + return { scheme="file",path=filename,original=filename,filename=filename } + end + local specification=url.hashed(filename) + if not specification.scheme or specification.scheme=="" then + return { scheme="file",path=filename,original=filename,filename=filename } + else + return specification + end end resolvers.splitmethod=splitmethod local function methodhandler(what,first,...) - local method=registered[what] - if method then - local how,namespace=method.how,method.namespace - if how=="uri" or how=="url" then - local specification=splitmethod(first) - local scheme=specification.scheme - local resolver=namespace and namespace[scheme] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) - end - return resolver(specification,...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) - end - return resolver(specification,...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") - end - end - elseif how=="tag" then - local resolver=namespace and namespace[first] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,first) - end - return resolver(...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"default") - end - return resolver(...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") - end - end + local method=registered[what] + if method then + local how,namespace=method.how,method.namespace + if how=="uri" or how=="url" then + local specification=splitmethod(first) + local scheme=specification.scheme + local resolver=namespace and namespace[scheme] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) + end + return resolver(specification,...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) + end + return resolver(specification,...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") end - else - report_methods("resolving, invalid method %a") + end + elseif how=="tag" then + local resolver=namespace and namespace[first] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,first) + end + return resolver(...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"default") + end + return resolver(...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") + end + end end + else + report_methods("resolving, invalid method %a") + end end resolvers.methodhandler=methodhandler function resolvers.registermethod(name,namespace,how) - registered[name]={ how=how or "tag",namespace=namespace } - namespace["byscheme"]=function(scheme,filename,...) - if scheme=="file" then - return methodhandler(name,filename,...) - else - return methodhandler(name,addurlscheme(filename,scheme),...) - end + registered[name]={ how=how or "tag",namespace=namespace } + namespace["byscheme"]=function(scheme,filename,...) + if scheme=="file" then + return methodhandler(name,filename,...) + else + return methodhandler(name,addurlscheme(filename,scheme),...) end + end end -local concatinators=allocate { notfound=file.join } -local locators=allocate { notfound=function() end } -local hashers=allocate { notfound=function() end } -local generators=allocate { notfound=function() end } +local concatinators=allocate { notfound=file.join } +local locators=allocate { notfound=function() end } +local hashers=allocate { notfound=function() end } +local generators=allocate { notfound=function() end } resolvers.concatinators=concatinators resolvers.locators=locators resolvers.hashers=hashers @@ -17695,17 +21269,17 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 68263, stripped down to: 47789 +-- original size: 68195, stripped down to: 43680 if not modules then modules={} end modules ['data-res']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,remove,sortedkeys,sortedhash=table.concat,table.insert,table.remove,table.sortedkeys,table.sortedhash +local concat,insert,remove=table.concat,table.insert,table.remove local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -17727,11 +21301,11 @@ local isfile=lfs.isfile local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) -local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) +local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) +local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) local report_resolving=logs.reporter("resolvers","resolving") local resolvers=resolvers local expandedpathfromlist=resolvers.expandedpathfromlist @@ -17752,15 +21326,15 @@ resolvers.luacnfname="texmfcnf.lua" resolvers.luacnffallback="contextcnf.lua" resolvers.luacnfstate="unknown" if environment.default_texmfcnf then - resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf + resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf else - resolvers.luacnfspec=concat ({ - "home:texmf/web2c", - "selfautoparent:/texmf-local/web2c", - "selfautoparent:/texmf-context/web2c", - "selfautoparent:/texmf-dist/web2c", - "selfautoparent:/texmf/web2c", - },";") + resolvers.luacnfspec=concat ({ + "home:texmf/web2c", + "selfautoparent:/texmf-local/web2c", + "selfautoparent:/texmf-context/web2c", + "selfautoparent:/texmf-dist/web2c", + "selfautoparent:/texmf/web2c", + },";") end local unset_variable="unset" local formats=resolvers.formats @@ -17771,24 +21345,24 @@ local suffixmap=resolvers.suffixmap resolvers.defaultsuffixes={ "tex" } local instance=nil function resolvers.setenv(key,value,raw) - if instance then - instance.environment[key]=value - ossetenv(key,raw and value or resolveprefix(value)) - end + if instance then + instance.environment[key]=value + ossetenv(key,raw and value or resolveprefix(value)) + end end local function getenv(key) - local value=rawget(instance.environment,key) - if value and value~="" then - return value - else - local e=osgetenv(key) - return e~=nil and e~="" and checkedvariable(e) or "" - end + local value=rawget(instance.environment,key) + if value and value~="" then + return value + else + local e=osgetenv(key) + return e~=nil and e~="" and checkedvariable(e) or "" + end end resolvers.getenv=getenv resolvers.env=getenv local function resolvevariable(k) - return instance.expansions[k] + return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") local inhibitstripper=P("!")^0*Cs(P(1)^0) @@ -17802,1506 +21376,1506 @@ local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) - return lpegmatch(variableexpander,var) or var + return lpegmatch(variableexpander,var) or var end function resolvers.reset() - if trace_locating then - report_resolving("creating instance") - end - local environment={} - local variables={} - local expansions={} - local order={} - instance={ - environment=environment, - variables=variables, - expansions=expansions, - order=order, - files={}, - setups={}, - found={}, - foundintrees={}, - hashes={}, - hashed={}, - pathlists=false, - specification={}, - lists={}, - data={}, - fakepaths={}, - remember=true, - diskcache=true, - renewcache=false, - renewtree=false, - loaderror=false, - savelists=true, - pattern=nil, - force_suffixes=true, - pathstack={}, - } - setmetatableindex(variables,function(t,k) - local v - for i=1,#order do - v=order[i][k] - if v~=nil then - t[k]=v - return v - end - end - if v==nil then - v="" - end - t[k]=v - return v - end) - setmetatableindex(environment,function(t,k) - local v=osgetenv(k) - if v==nil then - v=variables[k] - end - if v~=nil then - v=checkedvariable(v) or "" - end - v=resolvers.repath(v) - t[k]=v - return v - end) - setmetatableindex(expansions,function(t,k) - local v=environment[k] - if type(v)=="string" then - v=lpegmatch(variableresolver,v) - v=lpegmatch(variablecleaner,v) - end + if trace_locating then + report_resolving("creating instance") + end + local environment={} + local variables={} + local expansions={} + local order={} + instance={ + environment=environment, + variables=variables, + expansions=expansions, + order=order, + files={}, + setups={}, + found={}, + foundintrees={}, + hashes={}, + hashed={}, + pathlists=false, + specification={}, + lists={}, + data={}, + fakepaths={}, + remember=true, + diskcache=true, + renewcache=false, + renewtree=false, + loaderror=false, + savelists=true, + pattern=nil, + force_suffixes=true, + pathstack={}, + } + setmetatableindex(variables,function(t,k) + local v + for i=1,#order do + v=order[i][k] + if v~=nil then t[k]=v return v - end) + end + end + if v==nil then + v="" + end + t[k]=v + return v + end) + setmetatableindex(environment,function(t,k) + local v=osgetenv(k) + if v==nil then + v=variables[k] + end + if v~=nil then + v=checkedvariable(v) or "" + end + v=resolvers.repath(v) + t[k]=v + return v + end) + setmetatableindex(expansions,function(t,k) + local v=environment[k] + if type(v)=="string" then + v=lpegmatch(variableresolver,v) + v=lpegmatch(variablecleaner,v) + end + t[k]=v + return v + end) end function resolvers.initialized() - return instance~=nil + return instance~=nil end local function reset_hashes() - instance.lists={} - instance.pathlists=false - instance.found={} + instance.lists={} + instance.pathlists=false + instance.found={} end local function reset_caches() - instance.lists={} - instance.pathlists=false + instance.lists={} + instance.pathlists=false end local slash=P("/") local pathexpressionpattern=Cs ( - Cc("^")*( - Cc("%")*S(".-")+slash^2*P(-1)/"/.*" + Cc("^")*( + Cc("%")*S(".-")+slash^2*P(-1)/"/.*" +slash^2/"/"+(1-slash)*P(-1)*Cc("/")+P(1) - )^1*Cc("$") + )^1*Cc("$") ) local cache={} local function makepathexpression(str) - if str=="." then - return "^%./$" - else - local c=cache[str] - if not c then - c=lpegmatch(pathexpressionpattern,str) - cache[str]=c - end - return c + if str=="." then + return "^%./$" + else + local c=cache[str] + if not c then + c=lpegmatch(pathexpressionpattern,str) + cache[str]=c end + return c + end end local function reportcriticalvariables(cnfspec) - if trace_locating then - for i=1,#resolvers.criticalvars do - local k=resolvers.criticalvars[i] - local v=resolvers.getenv(k) or "unknown" - report_resolving("variable %a set to %a",k,v) - end - report_resolving() - if cnfspec then - report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) - end - report_resolving() + if trace_locating then + for i=1,#resolvers.criticalvars do + local k=resolvers.criticalvars[i] + local v=resolvers.getenv(k) or "unknown" + report_resolving("variable %a set to %a",k,v) + end + report_resolving() + if cnfspec then + report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) end - reportcriticalvariables=function() end + report_resolving() + end + reportcriticalvariables=function() end end local function identify_configuration_files() - local specification=instance.specification - if #specification==0 then - local cnfspec=getenv("TEXMFCNF") - if cnfspec=="" then - cnfspec=resolvers.luacnfspec - resolvers.luacnfstate="default" - else - resolvers.luacnfstate="environment" - end - reportcriticalvariables(cnfspec) - local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) - local function locatecnf(luacnfname,kind) - for i=1,#cnfpaths do - local filepath=cnfpaths[i] - local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolveprefix(filename) - if trace_locating then - local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") - local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) - report_resolving("looking for %s %a on %s path %a from specification %a", - kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) - end - if isfile(realname) then - specification[#specification+1]=filename - if trace_locating then - report_resolving("found %s configuration file %a",kind,realname) - end - end - end - end - locatecnf(resolvers.luacnfname,"regular") - if #specification==0 then - locatecnf(resolvers.luacnffallback,"fallback") - end + local specification=instance.specification + if #specification==0 then + local cnfspec=getenv("TEXMFCNF") + if cnfspec=="" then + cnfspec=resolvers.luacnfspec + resolvers.luacnfstate="default" + else + resolvers.luacnfstate="environment" + end + reportcriticalvariables(cnfspec) + local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) + local function locatecnf(luacnfname,kind) + for i=1,#cnfpaths do + local filepath=cnfpaths[i] + local filename=collapsepath(filejoin(filepath,luacnfname)) + local realname=resolveprefix(filename) if trace_locating then - report_resolving() + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") + local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) + report_resolving("looking for %s %a on %s path %a from specification %a", + kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) + end + if isfile(realname) then + specification[#specification+1]=filename + if trace_locating then + report_resolving("found %s configuration file %a",kind,realname) + end end - elseif trace_locating then - report_resolving("configuration files already identified") + end + end + locatecnf(resolvers.luacnfname,"regular") + if #specification==0 then + locatecnf(resolvers.luacnffallback,"fallback") + end + if trace_locating then + report_resolving() end + elseif trace_locating then + report_resolving("configuration files already identified") + end end local function load_configuration_files() - local specification=instance.specification - if #specification>0 then - local luacnfname=resolvers.luacnfname - for i=1,#specification do - local filename=specification[i] - local pathname=filedirname(filename) - local filename=filejoin(pathname,luacnfname) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local setups=instance.setups - local data=blob() - local parent=data and data.parent - if parent then - local filename=filejoin(pathname,parent) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local parentdata=blob() - if parentdata then - report_resolving("loading configuration file %a",filename) - data=table.merged(parentdata,data) - end - end - end - data=data and data.content - if data then - if trace_locating then - report_resolving("loading configuration file %a",filename) - report_resolving() - end - local variables=data.variables or {} - local warning=false - for k,v in next,data do - local variant=type(v) - if variant=="table" then - initializesetter(filename,k,v) - elseif variables[k]==nil then - if trace_locating and not warning then - report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolveprefix(filename)) - warning=true - end - variables[k]=v - end - end - setups[pathname]=variables - if resolvers.luacnfstate=="default" then - local cnfspec=variables["TEXMFCNF"] - if cnfspec then - if trace_locating then - report_resolving("reloading configuration due to TEXMF redefinition") - end - resolvers.setenv("TEXMFCNF",cnfspec) - instance.specification={} - identify_configuration_files() - load_configuration_files() - resolvers.luacnfstate="configuration" - break - end - end - else - if trace_locating then - report_resolving("skipping configuration file %a (no content)",filename) - end - setups[pathname]={} - instance.loaderror=true - end - elseif trace_locating then - report_resolving("skipping configuration file %a (no valid format)",filename) + local specification=instance.specification + if #specification>0 then + local luacnfname=resolvers.luacnfname + for i=1,#specification do + local filename=specification[i] + local pathname=filedirname(filename) + local filename=filejoin(pathname,luacnfname) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local setups=instance.setups + local data=blob() + local parent=data and data.parent + if parent then + local filename=filejoin(pathname,parent) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local parentdata=blob() + if parentdata then + report_resolving("loading configuration file %a",filename) + data=table.merged(parentdata,data) end - instance.order[#instance.order+1]=instance.setups[pathname] - if instance.loaderror then - break + end + end + data=data and data.content + if data then + if trace_locating then + report_resolving("loading configuration file %a",filename) + report_resolving() + end + local variables=data.variables or {} + local warning=false + for k,v in next,data do + local variant=type(v) + if variant=="table" then + initializesetter(filename,k,v) + elseif variables[k]==nil then + if trace_locating and not warning then + report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", + k,resolveprefix(filename)) + warning=true + end + variables[k]=v + end + end + setups[pathname]=variables + if resolvers.luacnfstate=="default" then + local cnfspec=variables["TEXMFCNF"] + if cnfspec then + if trace_locating then + report_resolving("reloading configuration due to TEXMF redefinition") + end + resolvers.setenv("TEXMFCNF",cnfspec) + instance.specification={} + identify_configuration_files() + load_configuration_files() + resolvers.luacnfstate="configuration" + break end + end + else + if trace_locating then + report_resolving("skipping configuration file %a (no content)",filename) + end + setups[pathname]={} + instance.loaderror=true end - elseif trace_locating then - report_resolving("warning: no lua configuration files found") + elseif trace_locating then + report_resolving("skipping configuration file %a (no valid format)",filename) + end + instance.order[#instance.order+1]=instance.setups[pathname] + if instance.loaderror then + break + end end + elseif trace_locating then + report_resolving("warning: no lua configuration files found") + end end function resolvers.configurationfiles() - return instance.specification or {} + return instance.specification or {} end local function load_file_databases() - instance.loaderror=false - instance.files={} - if not instance.renewcache then - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - resolvers.hashers.byscheme(hash.type,hash.name) - if instance.loaderror then break end - end + instance.loaderror=false + instance.files={} + if not instance.renewcache then + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + resolvers.hashers.byscheme(hash.type,hash.name) + if instance.loaderror then break end end + end end local function locate_file_databases() - local texmfpaths=resolvers.expandedpathlist("TEXMF") - if #texmfpaths>0 then - for i=1,#texmfpaths do - local path=collapsepath(texmfpaths[i]) - path=gsub(path,"/+$","") - local stripped=lpegmatch(inhibitstripper,path) - if stripped~="" then - local runtime=stripped==path - path=cleanpath(path) - local spec=resolvers.splitmethod(stripped) - if runtime and (spec.noscheme or spec.scheme=="file") then - stripped="tree:///"..stripped - elseif spec.scheme=="cache" or spec.scheme=="file" then - stripped=spec.path - end - if trace_locating then - if runtime then - report_resolving("locating list of %a (runtime) (%s)",path,stripped) - else - report_resolving("locating list of %a (cached)",path) - end - end - methodhandler('locators',stripped) - end + local texmfpaths=resolvers.expandedpathlist("TEXMF") + if #texmfpaths>0 then + for i=1,#texmfpaths do + local path=collapsepath(texmfpaths[i]) + path=gsub(path,"/+$","") + local stripped=lpegmatch(inhibitstripper,path) + if stripped~="" then + local runtime=stripped==path + path=cleanpath(path) + local spec=resolvers.splitmethod(stripped) + if runtime and (spec.noscheme or spec.scheme=="file") then + stripped="tree:///"..stripped + elseif spec.scheme=="cache" or spec.scheme=="file" then + stripped=spec.path end if trace_locating then - report_resolving() + if runtime then + report_resolving("locating list of %a (runtime) (%s)",path,stripped) + else + report_resolving("locating list of %a (cached)",path) + end end - elseif trace_locating then - report_resolving("no texmf paths are defined (using TEXMF)") - end -end -local function generate_file_databases() - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - methodhandler('generators',hash.name) + methodhandler('locators',stripped) + end end if trace_locating then - report_resolving() + report_resolving() end + elseif trace_locating then + report_resolving("no texmf paths are defined (using TEXMF)") + end +end +local function generate_file_databases() + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + methodhandler('generators',hash.name) + end + if trace_locating then + report_resolving() + end end local function save_file_databases() - for i=1,#instance.hashes do - local hash=instance.hashes[i] - local cachename=hash.name - if hash.cache then - local content=instance.files[cachename] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",cachename) - end - caches.savecontent(cachename,"files",content) - elseif trace_locating then - report_resolving("not saving runtime tree %a",cachename) - end + for i=1,#instance.hashes do + local hash=instance.hashes[i] + local cachename=hash.name + if hash.cache then + local content=instance.files[cachename] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",cachename) + end + caches.savecontent(cachename,"files",content) + elseif trace_locating then + report_resolving("not saving runtime tree %a",cachename) end + end end function resolvers.renew(hashname) - if hashname and hashname~="" then - local expanded=resolvers.expansion(hashname) or "" - if expanded~="" then - if trace_locating then - report_resolving("identifying tree %a from %a",expanded,hashname) - end - hashname=expanded - else - if trace_locating then - report_resolving("identifying tree %a",hashname) - end - end - local realpath=resolveprefix(hashname) - if isdir(realpath) then - if trace_locating then - report_resolving("using path %a",realpath) - end - methodhandler('generators',hashname) - local content=instance.files[hashname] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",hashname) - end - caches.savecontent(hashname,"files",content) - else - report_resolving("invalid path %a",realpath) - end + if hashname and hashname~="" then + local expanded=resolvers.expansion(hashname) or "" + if expanded~="" then + if trace_locating then + report_resolving("identifying tree %a from %a",expanded,hashname) + end + hashname=expanded + else + if trace_locating then + report_resolving("identifying tree %a",hashname) + end end + local realpath=resolveprefix(hashname) + if isdir(realpath) then + if trace_locating then + report_resolving("using path %a",realpath) + end + methodhandler('generators',hashname) + local content=instance.files[hashname] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",hashname) + end + caches.savecontent(hashname,"files",content) + else + report_resolving("invalid path %a",realpath) + end + end end local function load_databases() - locate_file_databases() - if instance.diskcache and not instance.renewcache then - load_file_databases() - if instance.loaderror then - generate_file_databases() - save_file_databases() - end - else - generate_file_databases() - if instance.renewcache then - save_file_databases() - end + locate_file_databases() + if instance.diskcache and not instance.renewcache then + load_file_databases() + if instance.loaderror then + generate_file_databases() + save_file_databases() + end + else + generate_file_databases() + if instance.renewcache then + save_file_databases() end + end end function resolvers.appendhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a appended",name) - end - insert(instance.hashes,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a appended",name) end + insert(instance.hashes,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.prependhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a prepended",name) - end - insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a prepended",name) end + insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.extendtexmfvariable(specification) - local t=resolvers.splitpath(getenv("TEXMF")) - insert(t,1,specification) - local newspec=concat(t,",") - if instance.environment["TEXMF"] then - instance.environment["TEXMF"]=newspec - elseif instance.variables["TEXMF"] then - instance.variables["TEXMF"]=newspec - else - end - reset_hashes() + local t=resolvers.splitpath(getenv("TEXMF")) + insert(t,1,specification) + local newspec=concat(t,",") + if instance.environment["TEXMF"] then + instance.environment["TEXMF"]=newspec + elseif instance.variables["TEXMF"] then + instance.variables["TEXMF"]=newspec + else + end + reset_hashes() end function resolvers.splitexpansions() - local ie=instance.expansions - for k,v in next,ie do - local t,tn,h,p={},0,{},splitconfigurationpath(v) - for kk=1,#p do - local vv=p[kk] - if vv~="" and not h[vv] then - tn=tn+1 - t[tn]=vv - h[vv]=true - end - end - if #t>1 then - ie[k]=t - else - ie[k]=t[1] - end + local ie=instance.expansions + for k,v in next,ie do + local t,tn,h,p={},0,{},splitconfigurationpath(v) + for kk=1,#p do + local vv=p[kk] + if vv~="" and not h[vv] then + tn=tn+1 + t[tn]=vv + h[vv]=true + end end + if #t>1 then + ie[k]=t + else + ie[k]=t[1] + end + end end function resolvers.datastate() - return caches.contentstate() + return caches.contentstate() end function resolvers.variable(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.variables[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.variables[name] + return result~=nil and result or "" end function resolvers.expansion(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.expansions[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.expansions[name] + return result~=nil and result or "" end function resolvers.unexpandedpathlist(str) - local pth=resolvers.variable(str) - local lst=resolvers.splitpath(pth) - return expandedpathfromlist(lst) + local pth=resolvers.variable(str) + local lst=resolvers.splitpath(pth) + return expandedpathfromlist(lst) end function resolvers.unexpandedpath(str) - return joinpath(resolvers.unexpandedpathlist(str)) + return joinpath(resolvers.unexpandedpathlist(str)) end function resolvers.pushpath(name) - local pathstack=instance.pathstack - local lastpath=pathstack[#pathstack] - local pluspath=filedirname(name) - if lastpath then - lastpath=collapsepath(filejoin(lastpath,pluspath)) - else - lastpath=collapsepath(pluspath) - end - insert(pathstack,lastpath) - if trace_paths then - report_resolving("pushing path %a",lastpath) - end + local pathstack=instance.pathstack + local lastpath=pathstack[#pathstack] + local pluspath=filedirname(name) + if lastpath then + lastpath=collapsepath(filejoin(lastpath,pluspath)) + else + lastpath=collapsepath(pluspath) + end + insert(pathstack,lastpath) + if trace_paths then + report_resolving("pushing path %a",lastpath) + end end function resolvers.poppath() - local pathstack=instance.pathstack - if trace_paths and #pathstack>0 then - report_resolving("popping path %a",pathstack[#pathstack]) - end - remove(pathstack) + local pathstack=instance.pathstack + if trace_paths and #pathstack>0 then + report_resolving("popping path %a",pathstack[#pathstack]) + end + remove(pathstack) end function resolvers.stackpath() - local pathstack=instance.pathstack - local currentpath=pathstack[#pathstack] - return currentpath~="" and currentpath or nil + local pathstack=instance.pathstack + local currentpath=pathstack[#pathstack] + return currentpath~="" and currentpath or nil end local done={} function resolvers.resetextrapaths() - local ep=instance.extra_paths - if not ep then - done={} - instance.extra_paths={} - elseif #ep>0 then - done={} - reset_caches() - end + local ep=instance.extra_paths + if not ep then + done={} + instance.extra_paths={} + elseif #ep>0 then + done={} + reset_caches() + end end function resolvers.getextrapaths() - return instance.extra_paths or {} + return instance.extra_paths or {} end function resolvers.registerextrapath(paths,subpaths) - if not subpaths or subpaths=="" then - if not paths or path=="" then - return - elseif done[paths] then - return - end - end - local paths=settings_to_array(paths) - local subpaths=settings_to_array(subpaths) - local ep=instance.extra_paths or {} - local oldn=#ep - local newn=oldn - local nofpaths=#paths - local nofsubpaths=#subpaths - if nofpaths>0 then - if nofsubpaths>0 then - for i=1,nofpaths do - local p=paths[i] - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=p.."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end - end - else - for i=1,nofpaths do - local p=paths[i] - if not done[p] then - newn=newn+1 - ep[newn]=cleanpath(p) - done[p]=true - end - end + if not subpaths or subpaths=="" then + if not paths or path=="" then + return + elseif done[paths] then + return + end + end + local paths=settings_to_array(paths) + local subpaths=settings_to_array(subpaths) + local ep=instance.extra_paths or {} + local oldn=#ep + local newn=oldn + local nofpaths=#paths + local nofsubpaths=#subpaths + if nofpaths>0 then + if nofsubpaths>0 then + for i=1,nofpaths do + local p=paths[i] + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=p.."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end end - elseif nofsubpaths>0 then - for i=1,oldn do - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=ep[i].."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end + end + else + for i=1,nofpaths do + local p=paths[i] + if not done[p] then + newn=newn+1 + ep[newn]=cleanpath(p) + done[p]=true end + end end - if newn>0 then - instance.extra_paths=ep - end - if newn~=oldn then - reset_caches() + elseif nofsubpaths>0 then + for i=1,oldn do + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=ep[i].."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end + end end + end + if newn>0 then + instance.extra_paths=ep + end + if newn~=oldn then + reset_caches() + end end function resolvers.pushextrapath(path) - local paths=settings_to_array(path) - if instance.extra_stack then - insert(instance.extra_stack,1,paths) - else - instance.extra_stack={ paths } - end - reset_caches() + local paths=settings_to_array(path) + if instance.extra_stack then + insert(instance.extra_stack,1,paths) + else + instance.extra_stack={ paths } + end + reset_caches() end function resolvers.popextrapath() - if instance.extra_stack then - reset_caches() - return remove(instance.extra_stack,1) - end + if instance.extra_stack then + reset_caches() + return remove(instance.extra_stack,1) + end end local function made_list(instance,list,extra_too) - local done={} - local new={} - local newn=0 - local function add(p) - for k=1,#p do - local v=p[k] - if not done[v] then - done[v]=true - newn=newn+1 - new[newn]=v - end - end + local done={} + local new={} + local newn=0 + local function add(p) + for k=1,#p do + local v=p[k] + if not done[v] then + done[v]=true + newn=newn+1 + new[newn]=v + end end - for k=1,#list do - local v=list[k] - if done[v] then - elseif find(v,"^[%.%/]$") then - done[v]=true - newn=newn+1 - new[newn]=v - else - break - end + end + for k=1,#list do + local v=list[k] + if done[v] then + elseif find(v,"^[%.%/]$") then + done[v]=true + newn=newn+1 + new[newn]=v + else + break + end + end + if extra_too then + local es=instance.extra_stack + if es and #es>0 then + for k=1,#es do + add(es[k]) + end end - if extra_too then - local es=instance.extra_stack - if es and #es>0 then - for k=1,#es do - add(es[k]) - end - end - local ep=instance.extra_paths - if ep and #ep>0 then - add(ep) - end + local ep=instance.extra_paths + if ep and #ep>0 then + add(ep) end - add(list) - return new + end + add(list) + return new end function resolvers.cleanpathlist(str) - local t=resolvers.expandedpathlist(str) - if t then - for i=1,#t do - t[i]=collapsepath(cleanpath(t[i])) - end + local t=resolvers.expandedpathlist(str) + if t then + for i=1,#t do + t[i]=collapsepath(cleanpath(t[i])) end - return t + end + return t end function resolvers.expandpath(str) - return joinpath(resolvers.expandedpathlist(str)) + return joinpath(resolvers.expandedpathlist(str)) end function resolvers.expandedpathlist(str,extra_too) - if not str then - return {} - elseif instance.savelists then - str=lpegmatch(dollarstripper,str) - local lists=instance.lists - local lst=lists[str] - if not lst then - local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) - lst=expandedpathfromlist(l) - lists[str]=lst - end - return lst - else - local lst=resolvers.splitpath(resolvers.expansion(str)) - return made_list(instance,expandedpathfromlist(lst),extra_too) + if not str then + return {} + elseif instance.savelists then + str=lpegmatch(dollarstripper,str) + local lists=instance.lists + local lst=lists[str] + if not lst then + local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) + lst=expandedpathfromlist(l) + lists[str]=lst end + return lst + else + local lst=resolvers.splitpath(resolvers.expansion(str)) + return made_list(instance,expandedpathfromlist(lst),extra_too) + end end function resolvers.expandedpathlistfromvariable(str) - str=lpegmatch(dollarstripper,str) - local tmp=resolvers.variableofformatorsuffix(str) - return resolvers.expandedpathlist(tmp~="" and tmp or str) + str=lpegmatch(dollarstripper,str) + local tmp=resolvers.variableofformatorsuffix(str) + return resolvers.expandedpathlist(tmp~="" and tmp or str) end function resolvers.expandpathfromvariable(str) - return joinpath(resolvers.expandedpathlistfromvariable(str)) + return joinpath(resolvers.expandedpathlistfromvariable(str)) end function resolvers.cleanedpathlist(v) - local t=resolvers.expandedpathlist(v) - for i=1,#t do - t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) - end - return t + local t=resolvers.expandedpathlist(v) + for i=1,#t do + t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) + end + return t end function resolvers.expandbraces(str) - local pth=expandedpathfromlist(resolvers.splitpath(str)) - return joinpath(pth) + local pth=expandedpathfromlist(resolvers.splitpath(str)) + return joinpath(pth) end function resolvers.registerfilehash(name,content,someerror) - if content then - instance.files[name]=content - else - instance.files[name]={} - if somerror==true then - instance.loaderror=someerror - end + if content then + instance.files[name]=content + else + instance.files[name]={} + if somerror==true then + instance.loaderror=someerror end + end end function resolvers.getfilehashes() - return instance and instance.files or {} + return instance and instance.files or {} end function resolvers.gethashes() - return instance and instance.hashes or {} + return instance and instance.hashes or {} end function resolvers.renewcache() - if instance then - instance.renewcache=true - end + if instance then + instance.renewcache=true + end end local function isreadable(name) - local readable=isfile(name) - if trace_detail then - if readable then - report_resolving("file %a is readable",name) - else - report_resolving("file %a is not readable",name) - end + local readable=isfile(name) + if trace_detail then + if readable then + report_resolving("file %a is readable",name) + else + report_resolving("file %a is not readable",name) end - return readable + end + return readable end local function collect_files(names) - local filelist={} - local noffiles=0 - local function check(hash,root,pathname,path,basename,name) - if not pathname or find(path,pathname) then - local variant=hash.type - local search=filejoin(root,path,name) - local result=methodhandler('concatinators',variant,root,path,name) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,basename,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } end - for k=1,#names do - local filename=names[k] + end + for k=1,#names do + local filename=names[k] + if trace_detail then + report_resolving("checking name %a",filename) + end + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false + else + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" + end + local hashes=instance.hashes + for h=1,#hashes do + local hash=hashes[h] + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("checking name %a",filename) + report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) end - local basename=filebasename(filename) - local pathname=filedirname(filename) - if pathname=="" or find(pathname,"^%.") then - pathname=false - else - pathname=gsub(pathname,"%*",".*") - pathname="/"..pathname.."$" - end - local hashes=instance.hashes - for h=1,#hashes do - local hash=hashes[h] - local hashname=hash.name - local content=hashname and instance.files[hashname] - if content then - if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) - end - local path,name=lookup(content,basename) - if path then - local metadata=content.metadata - local realroot=metadata and metadata.path or hashname - if type(path)=="string" then - check(hash,realroot,pathname,path,basename,name) - else - for i=1,#path do - check(hash,realroot,pathname,path[i],basename,name) - end - end - end - elseif trace_locating then - report_resolving("no match in %a (%s)",hashname,basename) + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,basename,name) + else + for i=1,#path do + check(hash,realroot,pathname,path[i],basename,name) end + end end + elseif trace_locating then + report_resolving("no match in %a (%s)",hashname,basename) + end end - return noffiles>0 and filelist or nil + end + return noffiles>0 and filelist or nil end local fit={} function resolvers.registerintrees(filename,format,filetype,usedmethod,foundname) - local foundintrees=instance.foundintrees - if usedmethod=="direct" and filename==foundname and fit[foundname] then - else - local collapsed=collapsepath(foundname,true) - local t={ - filename=filename, - format=format~="" and format or nil, - filetype=filetype~="" and filetype or nil, - usedmethod=usedmethod, - foundname=foundname, - fullname=collapsed, - } - fit[foundname]=t - foundintrees[#foundintrees+1]=t - end + local foundintrees=instance.foundintrees + if usedmethod=="direct" and filename==foundname and fit[foundname] then + else + local collapsed=collapsepath(foundname,true) + local t={ + filename=filename, + format=format~="" and format or nil, + filetype=filetype~="" and filetype or nil, + usedmethod=usedmethod, + foundname=foundname, + fullname=collapsed, + } + fit[foundname]=t + foundintrees[#foundintrees+1]=t + end end function resolvers.foundintrees() - return instance.foundintrees or {} + return instance.foundintrees or {} end function resolvers.foundintree(fullname) - local f=fit[fullname] - return f and f.usedmethod=="database" + local f=fit[fullname] + return f and f.usedmethod=="database" end local function can_be_dir(name) - local fakepaths=instance.fakepaths - if not fakepaths[name] then - if isdir(name) then - fakepaths[name]=1 - else - fakepaths[name]=2 - end + local fakepaths=instance.fakepaths + if not fakepaths[name] then + if isdir(name) then + fakepaths[name]=1 + else + fakepaths[name]=2 end - return fakepaths[name]==1 + end + return fakepaths[name]==1 end local preparetreepattern=Cs((P(".")/"%%."+P("-")/"%%-"+P(1))^0*Cc("$")) local collect_instance_files local function find_analyze(filename,askedformat,allresults) - local filetype='' - local filesuffix=suffixonly(filename) - local wantedfiles={} - wantedfiles[#wantedfiles+1]=filename - if askedformat=="" then - if filesuffix=="" or not suffixmap[filesuffix] then - local defaultsuffixes=resolvers.defaultsuffixes - local formatofsuffix=resolvers.formatofsuffix - for i=1,#defaultsuffixes do - local forcedname=filename..'.'..defaultsuffixes[i] - wantedfiles[#wantedfiles+1]=forcedname - filetype=formatofsuffix(forcedname) - if trace_locating then - report_resolving("forcing filetype %a",filetype) - end - end - else - filetype=resolvers.formatofsuffix(filename) - if trace_locating then - report_resolving("using suffix based filetype %a",filetype) - end + local filetype='' + local filesuffix=suffixonly(filename) + local wantedfiles={} + wantedfiles[#wantedfiles+1]=filename + if askedformat=="" then + if filesuffix=="" or not suffixmap[filesuffix] then + local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix + for i=1,#defaultsuffixes do + local forcedname=filename..'.'..defaultsuffixes[i] + wantedfiles[#wantedfiles+1]=forcedname + filetype=formatofsuffix(forcedname) + if trace_locating then + report_resolving("forcing filetype %a",filetype) end + end else - if filesuffix=="" or not suffixmap[filesuffix] then - local format_suffixes=suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] - end - end - end - filetype=askedformat - if trace_locating then - report_resolving("using given filetype %a",filetype) + filetype=resolvers.formatofsuffix(filename) + if trace_locating then + report_resolving("using suffix based filetype %a",filetype) + end + end + else + if filesuffix=="" or not suffixmap[filesuffix] then + local format_suffixes=suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] end + end end - return filetype,wantedfiles + filetype=askedformat + if trace_locating then + report_resolving("using given filetype %a",filetype) + end + end + return filetype,wantedfiles end local function find_direct(filename,allresults) - if not dangerous[askedformat] and isreadable(filename) then - if trace_detail then - report_resolving("file %a found directly",filename) - end - return "direct",{ filename } + if not dangerous[askedformat] and isreadable(filename) then + if trace_detail then + report_resolving("file %a found directly",filename) end + return "direct",{ filename } + end end local function find_wildcard(filename,allresults) - if find(filename,'*',1,true) then - if trace_locating then - report_resolving("checking wildcard %a",filename) - end - local result=resolvers.findwildcardfiles(filename) - if result then - return "wildcard",result - end - end -end -local function find_qualified(filename,allresults,askedformat,alsostripped) - if not is_qualified_path(filename) then - return - end + if find(filename,'*',1,true) then if trace_locating then - report_resolving("checking qualified name %a",filename) + report_resolving("checking wildcard %a",filename) end - if isreadable(filename) then - if trace_detail then - report_resolving("qualified file %a found",filename) - end - return "qualified",{ filename } + local result=resolvers.findwildcardfiles(filename) + if result then + return "wildcard",result end + end +end +local function find_qualified(filename,allresults,askedformat,alsostripped) + if not is_qualified_path(filename) then + return + end + if trace_locating then + report_resolving("checking qualified name %a",filename) + end + if isreadable(filename) then if trace_detail then - report_resolving("locating qualified file %a",filename) - end - local forcedname,suffix="",suffixonly(filename) - if suffix=="" then - local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - local s=format_suffixes[i] - forcedname=filename.."."..s - if isreadable(forcedname) then - if trace_locating then - report_resolving("no suffix, forcing format filetype %a",s) - end - return "qualified",{ forcedname } - end - end + report_resolving("qualified file %a found",filename) + end + return "qualified",{ filename } + end + if trace_detail then + report_resolving("locating qualified file %a",filename) + end + local forcedname,suffix="",suffixonly(filename) + if suffix=="" then + local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + local s=format_suffixes[i] + forcedname=filename.."."..s + if isreadable(forcedname) then + if trace_locating then + report_resolving("no suffix, forcing format filetype %a",s) + end + return "qualified",{ forcedname } end + end end - if alsostripped and suffix and suffix~="" then - local basename=filebasename(filename) - local pattern=lpegmatch(preparetreepattern,filename) - local savedformat=askedformat - local format=savedformat or "" - if format=="" then - askedformat=resolvers.formatofsuffix(suffix) + end + if alsostripped and suffix and suffix~="" then + local basename=filebasename(filename) + local pattern=lpegmatch(preparetreepattern,filename) + local savedformat=askedformat + local format=savedformat or "" + if format=="" then + askedformat=resolvers.formatofsuffix(suffix) + end + if not format then + askedformat="othertextfiles" + end + if basename~=filename then + local resolved=collect_instance_files(basename,askedformat,allresults) + if #resolved==0 then + local lowered=lower(basename) + if filename~=lowered then + resolved=collect_instance_files(lowered,askedformat,allresults) end - if not format then - askedformat="othertextfiles" + end + resolvers.format=savedformat + if #resolved>0 then + local result={} + for r=1,#resolved do + local rr=resolved[r] + if find(rr,pattern) then + result[#result+1]=rr + end end - if basename~=filename then - local resolved=collect_instance_files(basename,askedformat,allresults) - if #resolved==0 then - local lowered=lower(basename) - if filename~=lowered then - resolved=collect_instance_files(lowered,askedformat,allresults) - end - end - resolvers.format=savedformat - if #resolved>0 then - local result={} - for r=1,#resolved do - local rr=resolved[r] - if find(rr,pattern) then - result[#result+1]=rr - end - end - if #result>0 then - return "qualified",result - end - end + if #result>0 then + return "qualified",result end + end end + end end local function check_subpath(fname) - if isreadable(fname) then - if trace_detail then - report_resolving("found %a by deep scanning",fname) - end - return fname + if isreadable(fname) then + if trace_detail then + report_resolving("found %a by deep scanning",fname) end + return fname + end end local function makepathlist(list,filetype) - local typespec=resolvers.variableofformat(filetype) - local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) - local entry={} - if pathlist and #pathlist>0 then - for k=1,#pathlist do - local path=pathlist[k] - local prescanned=find(path,'^!!') - local resursive=find(path,'//$') - local pathname=lpegmatch(inhibitstripper,path) - local expression=makepathexpression(pathname) - local barename=gsub(pathname,"/+$","") - barename=resolveprefix(barename) - local scheme=url.hasscheme(barename) - local schemename=gsub(barename,"%.%*$",'') - entry[k]={ - path=path, - pathname=pathname, - prescanned=prescanned, - recursive=recursive, - expression=expression, - barename=barename, - scheme=scheme, - schemename=schemename, - } - end - entry.typespec=typespec - list[filetype]=entry - else - list[filetype]=false - end - return entry + local typespec=resolvers.variableofformat(filetype) + local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) + local entry={} + if pathlist and #pathlist>0 then + for k=1,#pathlist do + local path=pathlist[k] + local prescanned=find(path,'^!!') + local resursive=find(path,'//$') + local pathname=lpegmatch(inhibitstripper,path) + local expression=makepathexpression(pathname) + local barename=gsub(pathname,"/+$","") + barename=resolveprefix(barename) + local scheme=url.hasscheme(barename) + local schemename=gsub(barename,"%.%*$",'') + entry[k]={ + path=path, + pathname=pathname, + prescanned=prescanned, + recursive=recursive, + expression=expression, + barename=barename, + scheme=scheme, + schemename=schemename, + } + end + entry.typespec=typespec + list[filetype]=entry + else + list[filetype]=false + end + return entry end local function find_intree(filename,filetype,wantedfiles,allresults) - local pathlists=instance.pathlists - if not pathlists then - pathlists=setmetatableindex({},makepathlist) - instance.pathlists=pathlists - end - local pathlist=pathlists[filetype] - if pathlist then - local method="intree" - local filelist=collect_files(wantedfiles) - local dirlist={} - local result={} - if filelist then - for i=1,#filelist do - dirlist[i]=filedirname(filelist[i][3]).."/" + local pathlists=instance.pathlists + if not pathlists then + pathlists=setmetatableindex({},makepathlist) + instance.pathlists=pathlists + end + local pathlist=pathlists[filetype] + if pathlist then + local method="intree" + local filelist=collect_files(wantedfiles) + local dirlist={} + local result={} + if filelist then + for i=1,#filelist do + dirlist[i]=filedirname(filelist[i][3]).."/" + end + end + if trace_detail then + report_resolving("checking filename %a in tree",filename) + end + for k=1,#pathlist do + local entry=pathlist[k] + local path=entry.path + local pathname=entry.pathname + local done=false + if filelist then + local expression=entry.expression + if trace_detail then + report_resolving("using pattern %a for path %a",expression,pathname) + end + for k=1,#filelist do + local fl=filelist[k] + local f=fl[2] + local d=dirlist[k] + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) + done=true + if allresults then + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) + end + else + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) + end + break end + elseif trace_detail then + report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + end end - if trace_detail then - report_resolving("checking filename %a in tree",filename) - end - for k=1,#pathlist do - local entry=pathlist[k] - local path=entry.path - local pathname=entry.pathname - local done=false - if filelist then - local expression=entry.expression + end + if done then + method="database" + else + method="filesystem" + local scheme=entry.scheme + if not scheme or scheme=="file" then + local pname=entry.schemename + if not find(pname,"*",1,true) then + if can_be_dir(pname) then + if not done and not entry.prescanned then if trace_detail then - report_resolving("using pattern %a for path %a",expression,pathname) - end - for k=1,#filelist do - local fl=filelist[k] - local f=fl[2] - local d=dirlist[k] - if find(d,expression) or find(resolveprefix(d),expression) then - result[#result+1]=resolveprefix(fl[3]) - done=true - if allresults then - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) - end - else - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) - end - break - end - elseif trace_detail then - report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + report_resolving("quick root scan for %a",pname) + end + for k=1,#wantedfiles do + local w=wantedfiles[k] + local fname=check_subpath(filejoin(pname,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end - end - end - if done then - method="database" - else - method="filesystem" - local scheme=entry.scheme - if not scheme or scheme=="file" then - local pname=entry.schemename - if not find(pname,"*",1,true) then - if can_be_dir(pname) then - if not done and not entry.prescanned then - if trace_detail then - report_resolving("quick root scan for %a",pname) - end - for k=1,#wantedfiles do - local w=wantedfiles[k] - local fname=check_subpath(filejoin(pname,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - if not done and entry.recursive then - if trace_detail then - report_resolving("scanning filesystem for %a",pname) - end - local files=resolvers.simplescanfiles(pname,false,true) - for k=1,#wantedfiles do - local w=wantedfiles[k] - local subpath=files[w] - if not subpath or subpath=="" then - elseif type(subpath)=="string" then - local fname=check_subpath(filejoin(pname,subpath,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - else - for i=1,#subpath do - local sp=subpath[i] - if sp=="" then - else - local fname=check_subpath(filejoin(pname,sp,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - end - if done and not allresults then - break - end - end - end - end - end + end + end + if not done and entry.recursive then + if trace_detail then + report_resolving("scanning filesystem for %a",pname) + end + local files=resolvers.simplescanfiles(pname,false,true) + for k=1,#wantedfiles do + local w=wantedfiles[k] + local subpath=files[w] + if not subpath or subpath=="" then + elseif type(subpath)=="string" then + local fname=check_subpath(filejoin(pname,subpath,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end + end else - end - else - for k=1,#wantedfiles do - local pname=entry.barename - local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) - if fname then + for i=1,#subpath do + local sp=subpath[i] + if sp=="" then + else + local fname=check_subpath(filejoin(pname,sp,w)) + if fname then result[#result+1]=fname done=true if not allresults then - break + break end + end end + end + if done and not allresults then + break + end end + end end + end end - if done and not allresults then + else + end + else + for k=1,#wantedfiles do + local pname=entry.barename + local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) + if fname then + result[#result+1]=fname + done=true + if not allresults then break + end end + end end - if #result>0 then - return method,result - end + end + if done and not allresults then + break + end + end + if #result>0 then + return method,result end + end end local function find_onpath(filename,filetype,wantedfiles,allresults) - if trace_detail then - report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) - end - local result={} - for k=1,#wantedfiles do - local fname=wantedfiles[k] - if fname and isreadable(fname) then - filename=fname - result[#result+1]=filejoin('.',fname) - if not allresults then - break - end - end - end - if #result>0 then - return "onpath",result + if trace_detail then + report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) + end + local result={} + for k=1,#wantedfiles do + local fname=wantedfiles[k] + if fname and isreadable(fname) then + filename=fname + result[#result+1]=filejoin('.',fname) + if not allresults then + break + end end + end + if #result>0 then + return "onpath",result + end end local function find_otherwise(filename,filetype,wantedfiles,allresults) - local filelist=collect_files(wantedfiles) - local fl=filelist and filelist[1] - if fl then - return "otherwise",{ resolveprefix(fl[3]) } - end + local filelist=collect_files(wantedfiles) + local fl=filelist and filelist[1] + if fl then + return "otherwise",{ resolveprefix(fl[3]) } + end end collect_instance_files=function(filename,askedformat,allresults) - if not filename or filename=="" then - return {} - end - askedformat=askedformat or "" - filename=collapsepath(filename,".") - filename=gsub(filename,"^%./",getcurrentdir().."/") - if allresults then - local filetype,wantedfiles=find_analyze(filename,askedformat) - local results={ - { find_direct (filename,true) }, - { find_wildcard (filename,true) }, - { find_qualified(filename,true,askedformat) }, - { find_intree (filename,filetype,wantedfiles,true) }, - { find_onpath (filename,filetype,wantedfiles,true) }, - { find_otherwise(filename,filetype,wantedfiles,true) }, - } - local result,status,done={},{},{} - for k,r in next,results do - local method,list=r[1],r[2] - if method and list then - for i=1,#list do - local c=collapsepath(list[i]) - if not done[c] then - result[#result+1]=c - done[c]=true - end - status[#status+1]=formatters["%-10s: %s"](method,c) - end - end - end - if trace_detail then - report_resolving("lookup status: %s",table.serialize(status,filename)) + if not filename or filename=="" then + return {} + end + askedformat=askedformat or "" + filename=collapsepath(filename,".") + filename=gsub(filename,"^%./",getcurrentdir().."/") + if allresults then + local filetype,wantedfiles=find_analyze(filename,askedformat) + local results={ + { find_direct (filename,true) }, + { find_wildcard (filename,true) }, + { find_qualified(filename,true,askedformat) }, + { find_intree (filename,filetype,wantedfiles,true) }, + { find_onpath (filename,filetype,wantedfiles,true) }, + { find_otherwise(filename,filetype,wantedfiles,true) }, + } + local result,status,done={},{},{} + for k,r in next,results do + local method,list=r[1],r[2] + if method and list then + for i=1,#list do + local c=collapsepath(list[i]) + if not done[c] then + result[#result+1]=c + done[c]=true + end + status[#status+1]=formatters["%-10s: %s"](method,c) end - return result,status - else - local method,result,stamp,filetype,wantedfiles - if instance.remember then - if askedformat=="" then - stamp=formatters["%s::%s"](suffixonly(filename),filename) - else - stamp=formatters["%s::%s"](askedformat,filename) - end - result=stamp and instance.found[stamp] - if result then - if trace_locating then - report_resolving("remembered file %a",filename) - end - return result - end + end + end + if trace_detail then + report_resolving("lookup status: %s",table.serialize(status,filename)) + end + return result,status + else + local method,result,stamp,filetype,wantedfiles + if instance.remember then + if askedformat=="" then + stamp=formatters["%s::%s"](suffixonly(filename),filename) + else + stamp=formatters["%s::%s"](askedformat,filename) + end + result=stamp and instance.found[stamp] + if result then + if trace_locating then + report_resolving("remembered file %a",filename) end - method,result=find_direct(filename) + return result + end + end + method,result=find_direct(filename) + if not result then + method,result=find_wildcard(filename) + if not result then + method,result=find_qualified(filename,false,askedformat) if not result then - method,result=find_wildcard(filename) - if not result then - method,result=find_qualified(filename,false,askedformat) - if not result then - filetype,wantedfiles=find_analyze(filename,askedformat) - method,result=find_intree(filename,filetype,wantedfiles) - if not result then - method,result=find_onpath(filename,filetype,wantedfiles) - if resolve_otherwise and not result then - method,result=find_otherwise(filename,filetype,wantedfiles) - end - end - end - end - end - if result and #result>0 then - local foundname=collapsepath(result[1]) - resolvers.registerintrees(filename,askedformat,filetype,method,foundname) - result={ foundname } - else - result={} - end - if stamp then - if trace_locating then - report_resolving("remembering file %a using hash %a",filename,stamp) + filetype,wantedfiles=find_analyze(filename,askedformat) + method,result=find_intree(filename,filetype,wantedfiles) + if not result then + method,result=find_onpath(filename,filetype,wantedfiles) + if resolve_otherwise and not result then + method,result=find_otherwise(filename,filetype,wantedfiles) end - instance.found[stamp]=result + end end - return result + end + end + if result and #result>0 then + local foundname=collapsepath(result[1]) + resolvers.registerintrees(filename,askedformat,filetype,method,foundname) + result={ foundname } + else + result={} end + if stamp then + if trace_locating then + report_resolving("remembering file %a using hash %a",filename,stamp) + end + instance.found[stamp]=result + end + return result + end end local function findfiles(filename,filetype,allresults) - if not filename or filename=="" then - return {} - end - local result,status=collect_instance_files(filename,filetype or "",allresults) - if not result or #result==0 then - local lowered=lower(filename) - if filename~=lowered then - result,status=collect_instance_files(lowered,filetype or "",allresults) - end + if not filename or filename=="" then + return {} + end + local result,status=collect_instance_files(filename,filetype or "",allresults) + if not result or #result==0 then + local lowered=lower(filename) + if filename~=lowered then + result,status=collect_instance_files(lowered,filetype or "",allresults) end - return result or {},status + end + return result or {},status end function resolvers.findfiles(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,true) - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,true) + end end function resolvers.findfile(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,false)[1] or "" - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,false)[1] or "" + end end function resolvers.findpath(filename,filetype) - return filedirname(findfiles(filename,filetype,false)[1] or "") + return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local base=filebasename(filename) - local result={} - local hashes=instance.hashes - local function okay(hash,path,name) - local found=methodhandler('concatinators',hash.type,hash.name,path,name) - if found and found~="" then - result[#result+1]=resolveprefix(found) - return not allresults - end - end - for k=1,#hashes do - local hash=hashes[k] - local content=instance.files[hash.name] - if content then - local path,name=lookup(content,base) - if not path then - elseif type(path)=="string" then - if okay(hash,path,name) then - return result - end - else - for i=1,#path do - if okay(hash,path[i],name) then - return result - end - end - end + local base=filebasename(filename) + local result={} + local hashes=instance.hashes + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end + for k=1,#hashes do + local hash=hashes[k] + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result + end + else + for i=1,#path do + if okay(hash,path[i],name) then + return result + end end + end end - return result + end + return result end function resolvers.findgivenfiles(filename) - return findgivenfiles(filename,true) + return findgivenfiles(filename,true) end function resolvers.findgivenfile(filename) - return findgivenfiles(filename,false)[1] or "" + return findgivenfiles(filename,false)[1] or "" end local makewildcard=Cs( - (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 + (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) - return lpegmatch(makewildcard,pattern) or pattern + return lpegmatch(makewildcard,pattern) or pattern end local function findwildcardfiles(filename,allresults,result) - local result=result or {} - local base=filebasename(filename) - local dirn=filedirname(filename) - local path=lower(lpegmatch(makewildcard,dirn) or dirn) - local name=lower(lpegmatch(makewildcard,base) or base) - local files=instance.files - if find(name,"*",1,true) then - local hashes=instance.hashes - local function okay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end - end + local result=result or {} + local base=filebasename(filename) + local dirn=filedirname(filename) + local path=lower(lpegmatch(makewildcard,dirn) or dirn) + local name=lower(lpegmatch(makewildcard,base) or base) + local files=instance.files + if find(name,"*",1,true) then + local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults end - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - for found,base in filtered(files[hashname],name) do - if type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end - end + end + end + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break end - end - else - local function okayokay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end end + end end - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - local found,base=lookup(content,base) - if not found then - elseif type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end + end + end + else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break end + end end + end end - return result + end + return result end function resolvers.findwildcardfiles(filename,result) - return findwildcardfiles(filename,true,result) + return findwildcardfiles(filename,true,result) end function resolvers.findwildcardfile(filename) - return findwildcardfiles(filename,false)[1] or "" + return findwildcardfiles(filename,false)[1] or "" end function resolvers.automount() end function resolvers.starttiming() - statistics.starttiming(instance) + statistics.starttiming(instance) end function resolvers.stoptiming() - statistics.stoptiming(instance) + statistics.stoptiming(instance) end function resolvers.load(option) - resolvers.starttiming() - identify_configuration_files() - load_configuration_files() - if option~="nofiles" then - load_databases() - resolvers.automount() - end - resolvers.stoptiming() - local files=instance.files - return files and next(files) and true + resolvers.starttiming() + identify_configuration_files() + load_configuration_files() + if option~="nofiles" then + load_databases() + resolvers.automount() + end + resolvers.stoptiming() + local files=instance.files + return files and next(files) and true end function resolvers.loadtime() - return statistics.elapsedtime(instance) + return statistics.elapsedtime(instance) end local function report(str) - if trace_locating then - report_resolving(str) - else - print(str) - end + if trace_locating then + report_resolving(str) + else + print(str) + end end function resolvers.dowithfilesandreport(command,files,...) - if files and #files>0 then - if trace_locating then - report('') - end - if type(files)=="string" then - files={ files } - end - for f=1,#files do - local file=files[f] - local result=command(file,...) - if type(result)=='string' then - report(result) - else - for i=1,#result do - report(result[i]) - end - end + if files and #files>0 then + if trace_locating then + report('') + end + if type(files)=="string" then + files={ files } + end + for f=1,#files do + local file=files[f] + local result=command(file,...) + if type(result)=='string' then + report(result) + else + for i=1,#result do + report(result[i]) end + end end + end end -function resolvers.showpath(str) - return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) +function resolvers.showpath(str) + return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) end function resolvers.registerfile(files,name,path) - if files[name] then - if type(files[name])=='string' then - files[name]={ files[name],path } - else - files[name]=path - end + if files[name] then + if type(files[name])=='string' then + files[name]={ files[name],path } else - files[name]=path + files[name]=path end + else + files[name]=path + end end function resolvers.dowithpath(name,func) - local pathlist=resolvers.expandedpathlist(name) - for i=1,#pathlist do - func("^"..cleanpath(pathlist[i])) - end + local pathlist=resolvers.expandedpathlist(name) + for i=1,#pathlist do + func("^"..cleanpath(pathlist[i])) + end end function resolvers.dowithvariable(name,func) - func(expandedvariable(name)) + func(expandedvariable(name)) end function resolvers.locateformat(name) - local engine=environment.ownmain or "luatex" - local barename=removesuffix(name) - local fullname=addsuffix(barename,"fmt") - local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" - if fmtname=="" then - fmtname=resolvers.findfile(fullname) - fmtname=cleanpath(fmtname) - end - if fmtname~="" then - local barename=removesuffix(fmtname) - local luaname=addsuffix(barename,luasuffixes.lua) - local lucname=addsuffix(barename,luasuffixes.luc) - local luiname=addsuffix(barename,luasuffixes.lui) - if isfile(luiname) then - return barename,luiname - elseif isfile(lucname) then - return barename,lucname - elseif isfile(luaname) then - return barename,luaname - end - end - return nil,nil + local engine=environment.ownmain or "luatex" + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") + local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" + if fmtname=="" then + fmtname=resolvers.findfile(fullname) + fmtname=cleanpath(fmtname) + end + if fmtname~="" then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then + return barename,luiname + elseif isfile(lucname) then + return barename,lucname + elseif isfile(luaname) then + return barename,luaname + end + end + return nil,nil end function resolvers.booleanvariable(str,default) - local b=resolvers.expansion(str) - if b=="" then - return default - else - b=toboolean(b) - return (b==nil and default) or b - end + local b=resolvers.expansion(str) + if b=="" then + return default + else + b=toboolean(b) + return (b==nil and default) or b + end end function resolvers.dowithfilesintree(pattern,handle,before,after) - local hashes=instance.hashes - for i=1,#hashes do - local hash=hashes[i] - local blobtype=hash.type - local blobpath=hash.name - if blobtype and blobpath then - local total=0 - local checked=0 - local done=0 - if before then - before(blobtype,blobpath,pattern) - end - for path,name in filtered(instance.files[blobpath],pattern) do - if type(path)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,path,name) then - done=done+1 - end - else - checked=checked+#path - for i=1,#path do - if handle(blobtype,blobpath,path[i],name) then - done=done+1 - end - end - end - end - if after then - after(blobtype,blobpath,pattern,total,checked,done) + local hashes=instance.hashes + for i=1,#hashes do + local hash=hashes[i] + local blobtype=hash.type + local blobpath=hash.name + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 + if before then + before(blobtype,blobpath,pattern) + end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end + end end + end + if after then + after(blobtype,blobpath,pattern,checked,done) + end end + end end local obsolete=resolvers.obsolete or {} resolvers.obsolete=obsolete -resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile -resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles +resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile +resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles function resolvers.knownvariables(pattern) - if instance then - local environment=instance.environment - local variables=instance.variables - local expansions=instance.expansions - local order=instance.order - local pattern=upper(pattern or "") - local result={} - for i=1,#order do - for key in next,order[i] do - if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then - result[key]={ - environment=rawget(environment,key), - variable=key, - expansion=expansions[key], - resolved=resolveprefix(expansions[key]), - } - end - end + if instance then + local environment=instance.environment + local variables=instance.variables + local expansions=instance.expansions + local order=instance.order + local pattern=upper(pattern or "") + local result={} + for i=1,#order do + for key in next,order[i] do + if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then + result[key]={ + environment=rawget(environment,key), + variable=key, + expansion=expansions[key], + resolved=resolveprefix(expansions[key]), + } end - return result - else - return {} + end end + return result + else + return {} + end end @@ -19311,14 +22885,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 4090, stripped down to: 3059 +-- original size: 4854, stripped down to: 2889 if not modules then modules={} end modules ['data-pre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local prefixes=resolvers.prefixes @@ -19331,64 +22905,64 @@ local dirname=file.dirname local joinpath=file.join local isfile=lfs.isfile prefixes.environment=function(str) - return cleanpath(expansion(str)) + return cleanpath(expansion(str)) end local function relative(str,n) - if not isfile(str) then - local pstr="./"..str + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str if isfile(pstr) then - str=pstr + str=pstr + break else - local p="../" - for i=1,n or 2 do - local pstr=p..str - if isfile(pstr) then - str=pstr - break - else - p=p.."../" - end - end + p=p.."../" end + end end - return cleanpath(str) + end + return cleanpath(str) end local function locate(str) - local fullname=findgivenfile(str) or "" - return cleanpath(fullname~="" and fullname or str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) end prefixes.relative=relative prefixes.locate=locate prefixes.auto=function(str) - local fullname=relative(str) - if not isfile(fullname) then - fullname=locate(str) - end - return fullname + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) + end + return fullname end prefixes.filename=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(basename((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(basename((fullname~="" and fullname) or str)) end prefixes.pathname=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(dirname((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(dirname((fullname~="" and fullname) or str)) end prefixes.selfautoloc=function(str) - local pth=getenv('SELFAUTOLOC') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOLOC') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautoparent=function(str) - local pth=getenv('SELFAUTOPARENT') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOPARENT') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautodir=function(str) - local pth=getenv('SELFAUTODIR') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTODIR') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.home=function(str) - local pth=getenv('HOME') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('HOME') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.env=prefixes.environment prefixes.rel=prefixes.relative @@ -19398,24 +22972,24 @@ prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname local function toppath() - local inputstack=resolvers.inputstack - if not inputstack then - return "." - end - local pathname=dirname(inputstack[#inputstack] or "") - if pathname=="" then - return "." - else - return pathname - end + local inputstack=resolvers.inputstack + if not inputstack then + return "." + end + local pathname=dirname(inputstack[#inputstack] or "") + if pathname=="" then + return "." + else + return pathname + end end local function jobpath() - local path=resolvers.stackpath() - if not path or path=="" then - return "." - else - return path - end + local path=resolvers.stackpath() + if not path or path=="" then + return "." + else + return path + end end resolvers.toppath=toppath resolvers.jobpath=jobpath @@ -19423,8 +22997,6 @@ prefixes.toppath=function(str) return cleanpath(joinpath(toppath(),str)) end prefixes.jobpath=function(str) return cleanpath(joinpath(jobpath(),str)) end resolvers.setdynamic("toppath") resolvers.setdynamic("jobpath") -prefixes.jobfile=prefixes.jobpath -resolvers.setdynamic("jobfile") end -- of closure @@ -19433,14 +23005,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-inp"] = package.loaded["data-inp"] or true --- original size: 910, stripped down to: 823 +-- original size: 910, stripped down to: 818 if not modules then modules={} end modules ['data-inp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19463,14 +23035,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-out"] = package.loaded["data-out"] or true --- original size: 530, stripped down to: 475 +-- original size: 530, stripped down to: 470 if not modules then modules={} end modules ['data-out']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19486,16 +23058,16 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3863, stripped down to: 3310 +-- original size: 3863, stripped down to: 3170 if not modules then modules={} end modules ['data-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -19503,88 +23075,88 @@ local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolve local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local filename=specification.filename - local realname=resolveprefix(filename) - if realname and realname~='' and lfs.isdir(realname) then - if trace_locating then - report_files("file locator %a found as %a",filename,realname) - end - resolvers.appendhash('file',filename,true) - elseif trace_locating then - report_files("file locator %a not found",filename) + local filename=specification.filename + local realname=resolveprefix(filename) + if realname and realname~='' and lfs.isdir(realname) then + if trace_locating then + report_files("file locator %a found as %a",filename,realname) end + resolvers.appendhash('file',filename,true) + elseif trace_locating then + report_files("file locator %a not found",filename) + end end function hashers.file(specification) - local pathname=specification.filename - local content=caches.loadcontent(pathname,'files') - resolvers.registerfilehash(pathname,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local pathname=specification.filename - local content=resolvers.scanfiles(pathname,false,true) - resolvers.registerfilehash(pathname,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) - local filename=specification.filename - local foundname=resolvers.findfile(filename,filetype) - if foundname and foundname~="" then - if trace_locating then - report_files("file finder: %a found",filename) - end - return foundname - else - if trace_locating then - report_files("file finder: %a not found",filename) - end - return finders.notfound() + local filename=specification.filename + local foundname=resolvers.findfile(filename,filetype) + if foundname and foundname~="" then + if trace_locating then + report_files("file finder: %a found",filename) + end + return foundname + else + if trace_locating then + report_files("file finder: %a not found",filename) end + return finders.notfound() + end end function openers.helpers.textopener(tag,filename,f) - return { - reader=function() return f:read () end, - close=function() logs.show_close(filename) return f:close() end, - } + return { + reader=function() return f:read () end, + close=function() logs.show_close(filename) return f:close() end, + } end function openers.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"r") - if f then - if trace_locating then - report_files("file opener: %a opened",filename) - end - return openers.helpers.textopener("file",filename,f) - end - end - if trace_locating then - report_files("file opener: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"r") + if f then + if trace_locating then + report_files("file opener: %a opened",filename) + end + return openers.helpers.textopener("file",filename,f) end - return openers.notfound() + end + if trace_locating then + report_files("file opener: %a not found",filename) + end + return openers.notfound() end function loaders.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"rb") - if f then - logs.show_load(filename) - if trace_locating then - report_files("file loader: %a loaded",filename) - end - local s=f:read("*a") - if checkgarbage then - checkgarbage(#s) - end - f:close() - if s then - return true,s,#s - end - end - end - if trace_locating then - report_files("file loader: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"rb") + if f then + logs.show_load(filename) + if trace_locating then + report_files("file loader: %a loaded",filename) + end + local s=f:read("*a") + if checkgarbage then + checkgarbage(#s) + end + f:close() + if s then + return true,s,#s + end end - return loaders.notfound() + end + if trace_locating then + report_files("file loader: %a not found",filename) + end + return loaders.notfound() end @@ -19594,116 +23166,116 @@ do -- create closure to overcome 200 locals limit package.loaded["data-con"] = package.loaded["data-con"] or true --- original size: 5029, stripped down to: 3607 +-- original size: 5029, stripped down to: 3432 if not modules then modules={} end modules ['data-con']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) -local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) -local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) +local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) containers=containers or {} local containers=containers containers.usecache=true local report_containers=logs.reporter("resolvers","containers") local allocated={} local mt={ - __index=function(t,k) - if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } - t.writable=writable - return writable - elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } - t.readables=readables - return readables - end - end, - __storage__=true + __index=function(t,k) + if k=="writable" then + local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + t.writable=writable + return writable + elseif k=="readables" then + local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + t.readables=readables + return readables + end + end, + __storage__=true } function containers.define(category,subcategory,version,enabled) - if category and subcategory then - local c=allocated[category] - if not c then - c={} - allocated[category]=c - end - local s=c[subcategory] - if not s then - s={ - category=category, - subcategory=subcategory, - storage={}, - enabled=enabled, - version=version or math.pi, - trace=false, - } - setmetatable(s,mt) - c[subcategory]=s - end - return s + if category and subcategory then + local c=allocated[category] + if not c then + c={} + allocated[category]=c + end + local s=c[subcategory] + if not s then + s={ + category=category, + subcategory=subcategory, + storage={}, + enabled=enabled, + version=version or math.pi, + trace=false, + } + setmetatable(s,mt) + c[subcategory]=s end + return s + end end function containers.is_usable(container,name) - return container.enabled and caches and caches.is_writable(container.writable,name) + return container.enabled and caches and caches.is_writable(container.writable,name) end function containers.is_valid(container,name) - if name and name~="" then - local storage=container.storage[name] - return storage and storage.cache_version==container.version - else - return false - end + if name and name~="" then + local storage=container.storage[name] + return storage and storage.cache_version==container.version + else + return false + end end function containers.read(container,name) - local storage=container.storage - local stored=storage[name] - if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name,container.writable) - if stored and stored.cache_version==container.version then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","load",container.subcategory,name) - end - else - stored=nil - end - storage[name]=stored - elseif stored then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) - end + local storage=container.storage + local stored=storage[name] + if not stored and container.enabled and caches and containers.usecache then + stored=caches.loaddata(container.readables,name,container.writable) + if stored and stored.cache_version==container.version then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","load",container.subcategory,name) + end + else + stored=nil end - return stored + storage[name]=stored + elseif stored then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) + end + end + return stored end function containers.write(container,name,data) - if data then - data.cache_version=container.version - if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","save",container.subcategory,name) - end - data.unique,data.shared=unique,shared - end - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","store",container.subcategory,name) - end - container.storage[name]=data + if data then + data.cache_version=container.version + if container.enabled and caches then + local unique,shared=data.unique,data.shared + data.unique,data.shared=nil,nil + caches.savedata(container.writable,name,data) + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","save",container.subcategory,name) + end + data.unique,data.shared=unique,shared end - return data + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","store",container.subcategory,name) + end + container.storage[name]=data + end + return data end function containers.content(container,name) - return container.storage[name] + return container.storage[name] end function containers.cleanname(name) - return (gsub(lower(name),"[^%w\128-\255]+","-")) + return (gsub(lower(name),"[^%w\128-\255]+","-")) end @@ -19713,97 +23285,101 @@ do -- create closure to overcome 200 locals limit package.loaded["data-use"] = package.loaded["data-use"] or true --- original size: 4272, stripped down to: 3289 +-- original size: 4434, stripped down to: 3180 if not modules then modules={} end modules ['data-use']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,find=string.format,string.lower,string.gsub,string.find -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_mounts=logs.reporter("resolvers","mounts") local resolvers=resolvers resolvers.automounted=resolvers.automounted or {} function resolvers.automount(usecache) - local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) - if (not mountpaths or #mountpaths==0) and usecache then - mountpaths=caches.getreadablepaths("mount") - end - if mountpaths and #mountpaths>0 then - resolvers.starttiming() - for k=1,#mountpaths do - local root=mountpaths[k] - local f=io.open(root.."/url.tmi") - if f then - for line in f:lines() do - if line then - if find(line,"^[%%#%-]") then - elseif find(line,"^zip://") then - if trace_locating then - report_mounts("mounting %a",line) - end - table.insert(resolvers.automounted,line) - resolvers.usezipfile(line) - end - end - end - f:close() + local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) + if (not mountpaths or #mountpaths==0) and usecache then + mountpaths=caches.getreadablepaths("mount") + end + if mountpaths and #mountpaths>0 then + resolvers.starttiming() + for k=1,#mountpaths do + local root=mountpaths[k] + local f=io.open(root.."/url.tmi") + if f then + for line in f:lines() do + if line then + if find(line,"^[%%#%-]") then + elseif find(line,"^zip://") then + if trace_locating then + report_mounts("mounting %a",line) + end + table.insert(resolvers.automounted,line) + resolvers.usezipfile(line) end + end end - resolvers.stoptiming() + f:close() + end end + resolvers.stoptiming() + end 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,kind,banner) - local enginebanner=status.banner - if formatbanner and enginebanner and sourcefile then - local luvname=file.replacesuffix(texname,"luv") - local luvdata={ - enginebanner=enginebanner, - formatbanner=formatbanner, - sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), - sourcefile=sourcefile, - luaversion=LUAVERSION, - } - io.savedata(luvname,table.serialize(luvdata,true)) - lua.registerfinalizer(function() - logs.report("format banner","%s",banner) - logs.newline() - end) - end + local enginebanner=status.banner + if formatbanner and enginebanner and sourcefile then + local luvname=file.replacesuffix(texname,"luv") + local luvdata={ + enginebanner=enginebanner, + formatbanner=formatbanner, + sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), + sourcefile=sourcefile, + luaversion=LUAVERSION, + } + io.savedata(luvname,table.serialize(luvdata,true)) + lua.registerfinalizer(function() + if jit then + logs.report("format banner","%s lua: %s jit",banner,LUAVERSION) + else + logs.report("format banner","%s lua: %s",banner,LUAVERSION) + end + logs.newline() + end) + end end function statistics.checkfmtstatus(texname) - local enginebanner=status.banner - if enginebanner and texname then - local luvname=file.replacesuffix(texname,"luv") - if lfs.isfile(luvname) then - local luv=dofile(luvname) - if luv and luv.sourcefile then - local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") - local luvbanner=luv.enginebanner or "?" - if luvbanner~=enginebanner then - return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) - end - local luvhash=luv.sourcehash or "?" - if luvhash~=sourcehash then - return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) - end - local luvluaversion=luv.luaversion or 0 - if luvluaversion~=LUAVERSION then - return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) - end - else - return "invalid status file" - end - else - return "missing status file" - end + local enginebanner=status.banner + if enginebanner and texname then + local luvname=file.replacesuffix(texname,"luv") + if lfs.isfile(luvname) then + local luv=dofile(luvname) + if luv and luv.sourcefile then + local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") + local luvbanner=luv.enginebanner or "?" + if luvbanner~=enginebanner then + return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) + end + local luvhash=luv.sourcehash or "?" + if luvhash~=sourcehash then + return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) + end + local luvluaversion=luv.luaversion or 0 + if luvluaversion~=LUAVERSION then + return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) + end + else + return "invalid status file" + end + else + return "missing status file" end - return true + end + return true end @@ -19813,233 +23389,233 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8716, stripped down to: 6795 +-- original size: 8700, stripped down to: 6313 if not modules then modules={} end modules ['data-zip']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,find,match=string.format,string.find,string.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_zip=logs.reporter("resolvers","zip") local resolvers=resolvers zip=zip or {} local zip=zip -zip.archives=zip.archives or {} -local archives=zip.archives -zip.registeredfiles=zip.registeredfiles or {} -local registeredfiles=zip.registeredfiles +local archives=zip.archives or {} +zip.archives=archives +local registeredfiles=zip.registeredfiles or {} +zip.registeredfiles=registeredfiles local function validzip(str) - if not find(str,"^zip://") then - return "zip:///"..str - else - return str - end + if not find(str,"^zip://") then + return "zip:///"..str + else + return str + end end function zip.openarchive(name) - if not name or name=="" then - return nil - else - local arch=archives[name] - if not arch then - local full=resolvers.findfile(name) or "" - arch=full~="" and zip.open(full) or false - archives[name]=arch - end - return arch + if not name or name=="" then + return nil + else + local arch=archives[name] + if not arch then + local full=resolvers.findfile(name) or "" + arch=full~="" and zip.open(full) or false + archives[name]=arch end + return arch + end end function zip.closearchive(name) - if not name or (name=="" and archives[name]) then - zip.close(archives[name]) - archives[name]=nil - end + if not name or (name=="" and archives[name]) then + zip.close(archives[name]) + archives[name]=nil + end end function resolvers.locators.zip(specification) - local archive=specification.filename - local zipfile=archive and archive~="" and zip.openarchive(archive) - if trace_locating then - if zipfile then - report_zip("locator: archive %a found",archive) - else - report_zip("locator: archive %a not found",archive) - end + local archive=specification.filename + local zipfile=archive and archive~="" and zip.openarchive(archive) + if trace_locating then + if zipfile then + report_zip("locator: archive %a found",archive) + else + report_zip("locator: archive %a not found",archive) end + end end function resolvers.hashers.zip(specification) - local archive=specification.filename - if trace_locating then - report_zip("loading file %a",archive) - end - resolvers.usezipfile(specification.original) + local archive=specification.filename + if trace_locating then + report_zip("loading file %a",archive) + end + resolvers.usezipfile(specification.original) end function resolvers.concatinators.zip(zipfile,path,name) - if not path or path=="" then - return format('%s?name=%s',zipfile,name) - else - return format('%s?name=%s/%s',zipfile,path,name) - end + if not path or path=="" then + return format('%s?name=%s',zipfile,name) + else + return format('%s?name=%s/%s',zipfile,path,name) + end end function resolvers.finders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("finder: archive %a found",archive) - end - local dfile=zfile:open(queryname) - if dfile then - dfile=zfile:close() - if trace_locating then - report_zip("finder: file %a found",queryname) - end - return specification.original - elseif trace_locating then - report_zip("finder: file %a not found",queryname) - end - elseif trace_locating then - report_zip("finder: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("finder: archive %a found",archive) end + local dfile=zfile:open(queryname) + if dfile then + dfile:close() + if trace_locating then + report_zip("finder: file %a found",queryname) + end + return specification.original + elseif trace_locating then + report_zip("finder: file %a not found",queryname) + end + elseif trace_locating then + report_zip("finder: unknown archive %a",archive) + end end - if trace_locating then - report_zip("finder: %a not found",original) - end - return resolvers.finders.notfound() + end + if trace_locating then + report_zip("finder: %a not found",original) + end + return resolvers.finders.notfound() end function resolvers.openers.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("opener; archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - if trace_locating then - report_zip("opener: file %a found",queryname) - end - return resolvers.openers.helpers.textopener('zip',original,dfile) - elseif trace_locating then - report_zip("opener: file %a not found",queryname) - end - elseif trace_locating then - report_zip("opener: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("opener; archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + if trace_locating then + report_zip("opener: file %a found",queryname) + end + return resolvers.openers.helpers.textopener('zip',original,dfile) + elseif trace_locating then + report_zip("opener: file %a not found",queryname) + end + elseif trace_locating then + report_zip("opener: unknown archive %a",archive) + end end - if trace_locating then - report_zip("opener: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("opener: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.loaders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("loader: archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - logs.show_load(original) - if trace_locating then - report_zip("loader; file %a loaded",original) - end - local s=dfile:read("*all") - dfile:close() - return true,s,#s - elseif trace_locating then - report_zip("loader: file %a not found",queryname) - end - elseif trace_locating then - report_zip("loader; unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("loader: archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + logs.show_load(original) + if trace_locating then + report_zip("loader; file %a loaded",original) + end + local s=dfile:read("*all") + dfile:close() + return true,s,#s + elseif trace_locating then + report_zip("loader: file %a not found",queryname) + end + elseif trace_locating then + report_zip("loader; unknown archive %a",archive) + end end - if trace_locating then - report_zip("loader: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("loader: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.usezipfile(archive) - local specification=resolvers.splitmethod(archive) - local archive=specification.filename - if archive and not registeredfiles[archive] then - local z=zip.openarchive(archive) - if z then - local tree=url.query(specification.query).tree or "" - if trace_locating then - report_zip("registering: archive %a",archive) - end - resolvers.starttiming() - resolvers.prependhash('zip',archive) - resolvers.extendtexmfvariable(archive) - registeredfiles[archive]=z - resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) - resolvers.stoptiming() - elseif trace_locating then - report_zip("registering: unknown archive %a",archive) - end + local specification=resolvers.splitmethod(archive) + local archive=specification.filename + if archive and not registeredfiles[archive] then + local z=zip.openarchive(archive) + if z then + local tree=url.query(specification.query).tree or "" + if trace_locating then + report_zip("registering: archive %a",archive) + end + resolvers.starttiming() + resolvers.prependhash('zip',archive) + resolvers.extendtexmfvariable(archive) + registeredfiles[archive]=z + resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) + resolvers.stoptiming() elseif trace_locating then - report_zip("registering: archive %a not found",archive) + report_zip("registering: unknown archive %a",archive) end + elseif trace_locating then + report_zip("registering: archive %a not found",archive) + end end function resolvers.registerzipfile(z,tree) - local names={} - local files={} - local remap={} - local n=0 - local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) - local register=resolvers.registerfile - if trace_locating then - report_zip("registering: using filter %a",filter) - end - for i in z:files() do - local filename=i.filename - local path,name=match(filename,filter) - if not path then - n=n+1 - register(names,filename,"") - local usedname=lower(filename) - files[usedname]="" - if usedname~=filename then - remap[usedname]=filename - end - elseif name and name~="" then - n=n+1 - register(names,name,path) - local usedname=lower(name) - files[usedname]=path - if usedname~=name then - remap[usedname]=name - end - else - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile + if trace_locating then + report_zip("registering: using filter %a",filter) + end + for i in z:files() do + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename + end + elseif name and name~="" then + n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end - report_zip("registering: %s files registered",n) - return { - files=files, - remap=remap, - } + end + report_zip("registering: %s files registered",n) + return { + files=files, + remap=remap, + } end @@ -20049,20 +23625,20 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 8479, stripped down to: 5580 +-- original size: 8478, stripped down to: 5223 if not modules then modules={} end modules ['data-tre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,gsub,lower=string.find,string.gsub,string.lower -local basename,dirname,joinname=file.basename,file.dirname,file .join +local basename,dirname,joinname=file.basename,file.dirname,file .join local globdir,isdir,isfile=dir.glob,lfs.isdir,lfs.isfile local P,lpegmatch=lpeg.P,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -20071,165 +23647,167 @@ local lookup=resolvers.get_from_content local collectors={} local found={} function resolvers.finders.tree(specification) - local spec=specification.filename - local okay=found[spec] - if okay==nil then - if spec~="" then - local path=dirname(spec) - local name=basename(spec) - if path=="" then - path="." - end - local names=collectors[path] - if not names then - local pattern=find(path,"/%*+$") and path or (path.."/*") - names=globdir(pattern) - collectors[path]=names - end - local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for i=1,#names do - local fullname=names[i] - if find(fullname,pattern) then - found[spec]=fullname - return fullname - end - end - local pattern=lower(pattern) - for i=1,#names do - local fullname=lower(names[i]) - if find(fullname,pattern) then - if isfile(fullname) then - found[spec]=fullname - return fullname - else - break - end - end - end + local spec=specification.filename + local okay=found[spec] + if okay==nil then + if spec~="" then + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names + end + local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname + end + end + local pattern=lower(pattern) + for i=1,#names do + local fullname=lower(names[i]) + if find(fullname,pattern) then + if isfile(fullname) then + found[spec]=fullname + return fullname + else + break + end end - okay=notfound() - found[spec]=okay + end end - return okay + okay=notfound() + found[spec]=okay + end + return okay end function resolvers.locators.tree(specification) - local name=specification.filename - local realname=resolveprefix(name) - if realname and realname~='' and isdir(realname) then - if trace_locating then - report_trees("locator %a found",realname) - end - resolvers.appendhash('tree',name,false) - elseif trace_locating then - report_trees("locator %a not found",name) + local name=specification.filename + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then + if trace_locating then + report_trees("locator %a found",realname) end + resolvers.appendhash('tree',name,false) + elseif trace_locating then + report_trees("locator %a not found",name) + end end function resolvers.hashers.tree(specification) - local name=specification.filename - report_trees("analyzing %a",name) - resolvers.methodhandler("hashers",name) - resolvers.generators.file(specification) + local name=specification.filename + if trace_locating then + report_trees("analyzing %a",name) + end + resolvers.methodhandler("hashers",name) + resolvers.generators.file(specification) end local collectors={} local splitter=lpeg.splitat("/**/") local stripper=lpeg.replacer { [P("/")*P("*")^1*P(-1)]="" } table.setmetatableindex(collectors,function(t,k) - local rootname=lpegmatch(stripper,k) - local dataname=joinname(rootname,"dirlist") - local content=caches.loadcontent(dataname,"files",dataname) - if not content then - content=resolvers.scanfiles(rootname,nil,nil,false,true) - caches.savecontent(dataname,"files",content,dataname) - end - t[k]=content - return content + local rootname=lpegmatch(stripper,k) + local dataname=joinname(rootname,"dirlist") + local content=caches.loadcontent(dataname,"files",dataname) + if not content then + content=resolvers.scanfiles(rootname,nil,nil,false,true) + caches.savecontent(dataname,"files",content,dataname) + end + t[k]=content + return content end) local function checked(root,p,n) - if p then - if type(p)=="table" then - for i=1,#p do - local fullname=joinname(root,p[i],n) - if isfile(fullname) then - return fullname - end - end - else - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end + if p then + if type(p)=="table" then + for i=1,#p do + local fullname=joinname(root,p[i],n) + if isfile(fullname) then + return fullname end + end + else + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - return notfound() + end + return notfound() end local function resolve(specification) - local filename=specification.filename - if filename~="" then - local root,rest=lpegmatch(splitter,filename) - if root and rest then - local path,name=dirname(rest),basename(rest) - if name~=rest then - local content=collectors[root] - local p,n=lookup(content,name) - if not p then - return notfound() - end - local pattern=".*/"..path.."$" - local istable=type(p)=="table" - if istable then - for i=1,#p do - local pi=p[i] - if pi==path or find(pi,pattern) then - local fullname=joinname(root,pi,n) - if isfile(fullname) then - return fullname - end - end - end - elseif p==path or find(p,pattern) then - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end - end - local queries=specification.queries - if queries and queries.option=="fileonly" then - return checked(root,p,n) - else - return notfound() - end + local filename=specification.filename + if filename~="" then + local root,rest=lpegmatch(splitter,filename) + if root and rest then + local path,name=dirname(rest),basename(rest) + if name~=rest then + local content=collectors[root] + local p,n=lookup(content,name) + if not p then + return notfound() + end + local pattern=".*/"..path.."$" + local istable=type(p)=="table" + if istable then + for i=1,#p do + local pi=p[i] + if pi==path or find(pi,pattern) then + local fullname=joinname(root,pi,n) + if isfile(fullname) then + return fullname + end end + end + elseif p==path or find(p,pattern) then + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - local path,name=dirname(filename),basename(filename) - local root=lpegmatch(stripper,path) - local content=collectors[path] - local p,n=lookup(content,name) - if p then - return checked(root,p,n) + local queries=specification.queries + if queries and queries.option=="fileonly" then + return checked(root,p,n) + else + return notfound() end + end end - return notfound() + local path,name=dirname(filename),basename(filename) + local root=lpegmatch(stripper,path) + local content=collectors[path] + local p,n=lookup(content,name) + if p then + return checked(root,p,n) + end + end + return notfound() end -resolvers.finders .dirlist=resolve -resolvers.locators .dirlist=resolvers.locators .tree -resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.finders .dirlist=resolve +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree resolvers.generators.dirlist=resolvers.generators.file -resolvers.openers .dirlist=resolvers.openers .file -resolvers.loaders .dirlist=resolvers.loaders .file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file function resolvers.finders.dirfile(specification) - local queries=specification.queries - if queries then - queries.option="fileonly" - else - specification.queries={ option="fileonly" } - end - return resolve(specification) -end -resolvers.locators .dirfile=resolvers.locators .dirlist -resolvers.hashers .dirfile=resolvers.hashers .dirlist + local queries=specification.queries + if queries then + queries.option="fileonly" + else + specification.queries={ option="fileonly" } + end + return resolve(specification) +end +resolvers.locators .dirfile=resolvers.locators .dirlist +resolvers.hashers .dirfile=resolvers.hashers .dirlist resolvers.generators.dirfile=resolvers.generators.dirlist -resolvers.openers .dirfile=resolvers.openers .dirlist -resolvers.loaders .dirfile=resolvers.loaders .dirlist +resolvers.openers .dirfile=resolvers.openers .dirlist +resolvers.loaders .dirfile=resolvers.loaders .dirlist end -- of closure @@ -20238,19 +23816,19 @@ do -- create closure to overcome 200 locals limit package.loaded["data-sch"] = package.loaded["data-sch"] or true --- original size: 6753, stripped down to: 5511 +-- original size: 6753, stripped down to: 5268 if not modules then modules={} end modules ['data-sch']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local load,tonumber=load,tonumber local gsub,concat,format=string.gsub,table.concat,string.format local finders,openers,loaders=resolvers.finders,resolvers.openers,resolvers.loaders -local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) +local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) local report_schemes=logs.reporter("resolvers","schemes") local http=require("socket.http") local ltn12=require("ltn12") @@ -20263,27 +23841,27 @@ schemes.cleaners=cleaners local threshold=24*60*60 directives.register("schemes.threshold",function(v) threshold=tonumber(v) or threshold end) function cleaners.none(specification) - return specification.original + return specification.original end function cleaners.strip(specification) - local path,name=file.splitbase(specification.original) - if path=="" then - return (gsub(name,"[^%a%d%.]+","-")) - else - return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) - end + local path,name=file.splitbase(specification.original) + if path=="" then + return (gsub(name,"[^%a%d%.]+","-")) + else + return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) + end end function cleaners.md5(specification) - return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) + return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) end local cleaner=cleaners.strip directives.register("schemes.cleanmethod",function(v) cleaner=cleaners[v] or cleaners.strip end) function resolvers.schemes.cleanname(specification) - local hash=cleaner(specification) - if trace_schemes then - report_schemes("hashing %a to %a",specification.original,hash) - end - return hash + local hash=cleaner(specification) + if trace_schemes then + report_schemes("hashing %a to %a",specification.original,hash) + end + return hash end local cached={} local loaded={} @@ -20291,139 +23869,139 @@ local reused={} local thresholds={} local handlers={} local runner=sandbox.registerrunner { - name="curl resolver", - method="execute", - program="curl", - template="--silent --insecure --create-dirs --output %cachename% %original%", - checkers={ - cachename="cache", - original="url", - } + name="curl resolver", + method="execute", + program="curl", + template="--silent --insecure --create-dirs --output %cachename% %original%", + checkers={ + cachename="cache", + original="url", + } } local function fetch(specification) - local original=specification.original - local scheme=specification.scheme - local cleanname=schemes.cleanname(specification) - local cachename=caches.setfirstwritablefile(cleanname,"schemes") - if not cached[original] then - statistics.starttiming(schemes) - if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then - cached[original]=cachename - local handler=handlers[scheme] - if handler then - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") - end - logs.flush() - handler(specification,cachename) - else - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") - end - logs.flush() - runner { - original=original, - cachename=cachename, - } - end - end - if io.exists(cachename) then - cached[original]=cachename - if trace_schemes then - report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) - end - else - cached[original]="" - if trace_schemes then - report_schemes("using missing %a, protocol %a",original,scheme) - end + local original=specification.original + local scheme=specification.scheme + local cleanname=schemes.cleanname(specification) + local cachename=caches.setfirstwritablefile(cleanname,"schemes") + if not cached[original] then + statistics.starttiming(schemes) + if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then + cached[original]=cachename + local handler=handlers[scheme] + if handler then + if trace_schemes then + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") end - loaded[scheme]=loaded[scheme]+1 - statistics.stoptiming(schemes) - else + logs.flush() + handler(specification,cachename) + else if trace_schemes then - report_schemes("reusing %a, protocol %a",original,scheme) + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") end - reused[scheme]=reused[scheme]+1 + logs.flush() + runner { + original=original, + cachename=cachename, + } + end + end + if io.exists(cachename) then + cached[original]=cachename + if trace_schemes then + report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) + end + else + cached[original]="" + if trace_schemes then + report_schemes("using missing %a, protocol %a",original,scheme) + end end - return cached[original] + loaded[scheme]=loaded[scheme]+1 + statistics.stoptiming(schemes) + else + if trace_schemes then + report_schemes("reusing %a, protocol %a",original,scheme) + end + reused[scheme]=reused[scheme]+1 + end + return cached[original] end local function finder(specification,filetype) - return resolvers.methodhandler("finders",fetch(specification),filetype) + return resolvers.methodhandler("finders",fetch(specification),filetype) end local opener=openers.file local loader=loaders.file local function install(scheme,handler,newthreshold) - handlers [scheme]=handler - loaded [scheme]=0 - reused [scheme]=0 - finders [scheme]=finder - openers [scheme]=opener - loaders [scheme]=loader - thresholds[scheme]=newthreshold or threshold + handlers [scheme]=handler + loaded [scheme]=0 + reused [scheme]=0 + finders [scheme]=finder + openers [scheme]=opener + loaders [scheme]=loader + thresholds[scheme]=newthreshold or threshold end schemes.install=install local function http_handler(specification,cachename) - local tempname=cachename..".tmp" - local f=io.open(tempname,"wb") - local status,message=http.request { - url=specification.original, - sink=ltn12.sink.file(f) - } - if not status then - os.remove(tempname) - else - os.remove(cachename) - os.rename(tempname,cachename) - end - return cachename + local tempname=cachename..".tmp" + local f=io.open(tempname,"wb") + local status,message=http.request { + url=specification.original, + sink=ltn12.sink.file(f) + } + if not status then + os.remove(tempname) + else + os.remove(cachename) + os.rename(tempname,cachename) + end + return cachename end install('http',http_handler) install('https') install('ftp') statistics.register("scheme handling time",function() - local l,r,nl,nr={},{},0,0 - for k,v in table.sortedhash(loaded) do - if v>0 then - nl=nl+1 - l[nl]=k..":"..v - end - end - for k,v in table.sortedhash(reused) do - if v>0 then - nr=nr+1 - r[nr]=k..":"..v - end - end - local n=nl+nr - if n>0 then - l=nl>0 and concat(l) or "none" - r=nr>0 and concat(r) or "none" - return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", - statistics.elapsedtime(schemes),n,threshold,l,r) - else - return nil - end + local l,r,nl,nr={},{},0,0 + for k,v in table.sortedhash(loaded) do + if v>0 then + nl=nl+1 + l[nl]=k..":"..v + end + end + for k,v in table.sortedhash(reused) do + if v>0 then + nr=nr+1 + r[nr]=k..":"..v + end + end + local n=nl+nr + if n>0 then + l=nl>0 and concat(l) or "none" + r=nr>0 and concat(r) or "none" + return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", + statistics.elapsedtime(schemes),n,threshold,l,r) + else + return nil + end end) local httprequest=http.request local toquery=url.toquery local function fetchstring(url,data) - local q=data and toquery(data) - if q then - url=url.."?"..q - end - local reply=httprequest(url) - return reply + local q=data and toquery(data) + if q then + url=url.."?"..q + end + local reply=httprequest(url) + return reply end schemes.fetchstring=fetchstring function schemes.fetchtable(url,data) - local reply=fetchstring(url,data) - if reply then - local s=load("return "..reply) - if s then - return s() - end + local reply=fetchstring(url,data) + if reply then + local s=load("return "..reply) + if s then + return s() end + end end @@ -20433,14 +24011,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4207, stripped down to: 3137 +-- original size: 4207, stripped down to: 3041 if not modules then modules={} end modules ['data-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local package,lpeg=package,lpeg local gsub=string.gsub @@ -20459,20 +24037,20 @@ helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) helpers.sequence={ - "already loaded", - "preload table", - "lua variable format", - "lib variable format", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", + "already loaded", + "preload table", + "lua variable format", + "lib variable format", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolveprefix(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local registerpath=helpers.registerpath @@ -20480,56 +24058,56 @@ local lualibfile=helpers.lualibfile local luaformatpaths local libformatpaths local function getluaformatpaths() - if not luaformatpaths then - luaformatpaths={} - for i=1,#luaformats do - registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) - end + if not luaformatpaths then + luaformatpaths={} + for i=1,#luaformats do + registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) end - return luaformatpaths + end + return luaformatpaths end local function getlibformatpaths() - if not libformatpaths then - libformatpaths={} - for i=1,#libformats do - registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) - end + if not libformatpaths then + libformatpaths={} + for i=1,#libformats do + registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) end - return libformatpaths + end + return libformatpaths end local function loadedbyformat(name,rawname,suffixes,islib,what) - local trace=helpers.trace - local report=helpers.report - for i=1,#suffixes do - local format=suffixes[i] - local resolved=resolvers.findfile(name,format) or "" - if trace then - report("%s format, identifying %a using format %a",what,name,format) - end - if resolved~="" then - if trace then - report("%s format, %a found on %a",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + local report=helpers.report + for i=1,#suffixes do + local format=suffixes[i] + local resolved=resolvers.findfile(name,format) or "" + if trace then + report("%s format, identifying %a using format %a",what,name,format) + end + if resolved~="" then + if trace then + report("%s format, %a found on %a",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + end end helpers.loadedbyformat=loadedbyformat methods["lua variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") + if helpers.trace then + helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") end methods["lib variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") + if helpers.trace then + helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") end resolvers.loadlualib=require @@ -20540,64 +24118,64 @@ do -- create closure to overcome 200 locals limit package.loaded["data-aux"] = package.loaded["data-aux"] or true --- original size: 2438, stripped down to: 2003 +-- original size: 2452, stripped down to: 1877 if not modules then modules={} end modules ['data-aux']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find=string.find local type,next=type,next -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +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="context/lua" - newname=file.addsuffix(newname,"lua") - local oldscript=resolvers.cleanpath(oldname) + local scriptpath="context/lua" + newname=file.addsuffix(newname,"lua") + local oldscript=resolvers.cleanpath(oldname) + if trace_locating then + report_scripts("to be replaced old script %a",oldscript) + end + local newscripts=resolvers.findfiles(newname) or {} + if #newscripts==0 then if trace_locating then - report_scripts("to be replaced old script %a",oldscript) + report_scripts("unable to locate new script") end - local newscripts=resolvers.findfiles(newname) or {} - if #newscripts==0 then + else + for i=1,#newscripts do + local newscript=resolvers.cleanpath(newscripts[i]) + if trace_locating then + report_scripts("checking new script %a",newscript) + end + if oldscript==newscript then if trace_locating then - report_scripts("unable to locate new script") + report_scripts("old and new script are the same") end - else - for i=1,#newscripts do - local newscript=resolvers.cleanpath(newscripts[i]) - if trace_locating then - report_scripts("checking new script %a",newscript) - end - if oldscript==newscript then - if trace_locating then - report_scripts("old and new script are the same") - end - elseif not find(newscript,scriptpath,1,true) then - if trace_locating then - report_scripts("new script should come from %a",scriptpath) - end - elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then - if trace_locating then - report_scripts("invalid new script name") - end - else - local newdata=io.loaddata(newscript) - if newdata then - if trace_locating then - report_scripts("old script content replaced by new content") - end - io.savedata(oldscript,newdata) - break - elseif trace_locating then - report_scripts("unable to load new script") - end - end + elseif not find(newscript,scriptpath,1,true) then + if trace_locating then + report_scripts("new script should come from %a",scriptpath) end + elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then + if trace_locating then + report_scripts("invalid new script name") + end + else + local newdata=io.loaddata(newscript) + if newdata then + if trace_locating then + report_scripts("old script content replaced by new content: %s",oldscript) + end + io.savedata(oldscript,newdata) + break + elseif trace_locating then + report_scripts("unable to load new script") + end + end end + end end @@ -20607,53 +24185,53 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2601, stripped down to: 1627 +-- original size: 2601, stripped down to: 1549 if not modules then modules={} end modules ['data-tmf']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local report_tds=logs.reporter("resolvers","tds") function resolvers.load_tree(tree,resolve) - if type(tree)=="string" and tree~="" then - local getenv,setenv=resolvers.getenv,resolvers.setenv - local texos="texmf-"..os.platform - local oldroot=environment.texroot - local newroot=file.collapsepath(tree) - local newtree=file.join(newroot,texos) - local newpath=file.join(newtree,"bin") - if not lfs.isdir(newtree) then - report_tds("no %a under tree %a",texos,tree) - os.exit() - end - if not lfs.isdir(newpath) then - report_tds("no '%s/bin' under tree %a",texos,tree) - os.exit() - end - local texmfos=newtree - environment.texroot=newroot - environment.texos=texos - environment.texmfos=texmfos - if resolve then - resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) - end - setenv('SELFAUTOPARENT',newroot) - setenv('SELFAUTODIR',newtree) - setenv('SELFAUTOLOC',newpath) - setenv('TEXROOT',newroot) - setenv('TEXOS',texos) - setenv('TEXMFOS',texmfos) - setenv('TEXMFCNF',resolvers.luacnfspec,true) - setenv('PATH',newpath..io.pathseparator..getenv('PATH')) - report_tds("changing from root %a to %a",oldroot,newroot) - report_tds("prepending %a to PATH",newpath) - report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) - report_tds() - end + if type(tree)=="string" and tree~="" then + local getenv,setenv=resolvers.getenv,resolvers.setenv + local texos="texmf-"..os.platform + local oldroot=environment.texroot + local newroot=file.collapsepath(tree) + local newtree=file.join(newroot,texos) + local newpath=file.join(newtree,"bin") + if not lfs.isdir(newtree) then + report_tds("no %a under tree %a",texos,tree) + os.exit() + end + if not lfs.isdir(newpath) then + report_tds("no '%s/bin' under tree %a",texos,tree) + os.exit() + end + local texmfos=newtree + environment.texroot=newroot + environment.texos=texos + environment.texmfos=texmfos + if resolve then + resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) + end + setenv('SELFAUTOPARENT',newroot) + setenv('SELFAUTODIR',newtree) + setenv('SELFAUTOLOC',newpath) + setenv('TEXROOT',newroot) + setenv('TEXOS',texos) + setenv('TEXMFOS',texmfos) + setenv('TEXMFCNF',resolvers.luacnfspec,true) + setenv('PATH',newpath..io.pathseparator..getenv('PATH')) + report_tds("changing from root %a to %a",oldroot,newroot) + report_tds("prepending %a to PATH",newpath) + report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) + report_tds() + end end @@ -20663,14 +24241,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 1823, stripped down to: 1591 +-- original size: 1823, stripped down to: 1542 if not modules then modules={} end modules ['data-lst']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local concat,sortedhash=table.concat,table.sortedhash @@ -20681,37 +24259,37 @@ local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local report_resolved=logs.reporter("system","resolved") local function tabstr(str) - if type(str)=='table' then - return concat(str," | ") - else - return str - end + if type(str)=='table' then + return concat(str," | ") + else + return str + end end function listers.variables(pattern) - local result=resolvers.knownvariables(pattern) - for key,value in sortedhash(result) do - report_lists(key) - report_lists(" env: %s",tabstr(value.environment or "unset")) - report_lists(" var: %s",tabstr(value.variable or "unset")) - report_lists(" exp: %s",tabstr(value.expansion or "unset")) - report_lists(" res: %s",tabstr(value.resolved or "unset")) - end + local result=resolvers.knownvariables(pattern) + for key,value in sortedhash(result) do + report_lists(key) + report_lists(" env: %s",tabstr(value.environment or "unset")) + report_lists(" var: %s",tabstr(value.variable or "unset")) + report_lists(" exp: %s",tabstr(value.expansion or "unset")) + report_lists(" res: %s",tabstr(value.resolved or "unset")) + end end function listers.configurations() - local configurations=resolvers.configurationfiles() - for i=1,#configurations do - report_resolved("file : %s",resolveprefix(configurations[i])) - end - report_resolved("") - local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) - for i=1,#list do - local li=resolveprefix(list[i]) - if lfs.isdir(li) then - report_resolved("path - %s",li) - else - report_resolved("path + %s",li) - end + local configurations=resolvers.configurationfiles() + for i=1,#configurations do + report_resolved("file : %s",resolveprefix(configurations[i])) + end + report_resolved("") + local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) + for i=1,#list do + local li=resolveprefix(list[i]) + if lfs.isdir(li) then + report_resolved("path - %s",li) + else + report_resolved("path + %s",li) end + end end @@ -20721,14 +24299,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lib"] = package.loaded["util-lib"] or true --- original size: 14943, stripped down to: 8305 +-- original size: 16094, stripped down to: 8443 if not modules then modules={} end modules ['util-lib']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local type=type local next=next @@ -20748,256 +24326,291 @@ local qualifiedpath=file.is_qualified_path local isfile=lfs.isfile local done=false local function locate(required,version,trace,report,action) - if type(required)~="string" then - report("provide a proper library name") - return - end - if trace then - report("requiring library %a with version %a",required,version or "any") - end - local found_library=nil - local required_full=gsub(required,"%.","/") - local required_path=pathpart(required_full) - local required_base=nameonly(required_full) - if qualifiedpath(required) then - if isfile(addsuffix(required,os.libsuffix)) then - if trace then - report("qualified name %a found",required) - end - found_library=required - else - if trace then - report("qualified name %a not found",required) - end - end + if type(required)~="string" then + report("provide a proper library name") + return + end + if trace then + report("requiring library %a with version %a",required,version or "any") + end + local found_library=nil + local required_full=gsub(required,"%.","/") + local required_path=pathpart(required_full) + local required_base=nameonly(required_full) + if qualifiedpath(required) then + if isfile(addsuffix(required,os.libsuffix)) then + if trace then + report("qualified name %a found",required) + end + found_library=required else - local required_name=required_base.."."..os.libsuffix - local version=type(version)=="string" and version~="" and version or false - local engine="luatex" - if trace and not done then - local list=expandpaths("lib") - for i=1,#list do - report("tds path %i: %s",i,list[i]) - end + if trace then + report("qualified name %a not found",required) + end + end + else + local required_name=required_base.."."..os.libsuffix + local version=type(version)=="string" and version~="" and version or false + local engine="luatex" + if trace and not done then + local list=expandpaths("lib") + for i=1,#list do + report("tds path %i: %s",i,list[i]) + end + end + local function found(locate,asked_library,how,...) + if trace then + report("checking %s: %a",how,asked_library) + end + return locate(asked_library,...) + end + local function check(locate,...) + local found=nil + if version then + local asked_library=joinfile(required_path,version,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function found(locate,asked_library,how,...) - if trace then - report("checking %s: %a",how,asked_library) - end - return locate(asked_library,...) - end - local function check(locate,...) - local found=nil - if version then - local asked_library=joinfile(required_path,version,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - if not found or found=="" then - local asked_library=joinfile(required_path,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - return found and found~="" and found or false + found=locate(asked_library,...) + end + if not found or found=="" then + local asked_library=joinfile(required_path,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function attempt(checkpattern) - if trace then - report("checking tds lib paths strictly") - end - local found=findfile and check(findfile,"lib") - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - if trace then - report("checking tds lib paths with wildcard") - end - local asked_library=joinfile(required_path,".*",required_name) - if trace then - report("checking %s: %a","latest version",asked_library) - end - local list=findfiles(asked_library,"lib",true) - if list and #list>0 then - sort(list) - local found=list[#list] - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - end - if trace then - report("checking lib paths") - end - package.extralibpath(environment.ownpath) - local paths=package.libpaths() - local pattern="/[^/]+%."..os.libsuffix.."$" - for i=1,#paths do - required_path=gsub(paths[i],pattern,"") - local found=check(lfs.isfound) - if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then - return found - end - end - return false + found=locate(asked_library,...) + end + return found and found~="" and found or false + end + local function attempt(checkpattern) + if trace then + report("checking tds lib paths strictly") + end + local found=findfile and check(findfile,"lib") + if found and (not checkpattern or find(found,checkpattern)) then + return found + end + if trace then + report("checking tds lib paths with wildcard") + end + local asked_library=joinfile(required_path,".*",required_name) + if trace then + report("checking %s: %a","latest version",asked_library) + end + local list=findfiles(asked_library,"lib",true) + if list and #list>0 then + sort(list) + local found=list[#list] + if found and (not checkpattern or find(found,checkpattern)) then + return found end - if engine then - if trace then - report("attemp 1, engine %a",engine) - end - found_library=attempt("/"..engine.."/") - if not found_library then - if trace then - report("attemp 2, no engine",asked_library) - end - found_library=attempt() - end - else - found_library=attempt() + end + if trace then + report("checking lib paths") + end + package.extralibpath(environment.ownpath) + local paths=package.libpaths() + local pattern="/[^/]+%."..os.libsuffix.."$" + for i=1,#paths do + required_path=gsub(paths[i],pattern,"") + local found=check(lfs.isfound) + if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then + return found end + end + return false end - if not found_library then + if engine then + if trace then + report("attemp 1, engine %a",engine) + end + found_library=attempt("/"..engine.."/") + if not found_library then if trace then - report("not found: %a",required) + report("attemp 2, no engine",asked_library) end - library=false + found_library=attempt() + end else - if trace then - report("found: %a",found_library) - end - local result,message=action(found_library,required_base) - if result then - library=result - else - library=false - report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") - end + found_library=attempt() end + end + if not found_library then if trace then - if not library then - report("unknown library: %a",required) - else - report("stored library: %a",required) - end + report("not found: %a",required) end - return library + library=false + else + if trace then + report("found: %a",found_library) + end + local result,message=action(found_library,required_base) + if result then + library=result + else + library=false + report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") + end + end + if trace then + if not library then + report("unknown library: %a",required) + else + report("stored library: %a",required) + end + end + return library or nil end do - local report_swiglib=logs.reporter("swiglib") - local trace_swiglib=false - local savedrequire=require - local loadedlibs={} - local loadlib=package.loadlib - local pushdir=dir.push - local popdir=dir.pop - trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) - function requireswiglib(required,version) - local library=loadedlibs[library] - if library==nil then - local trace_swiglib=trace_swiglib or package.helpers.trace - library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) - pushdir(pathpart(name)) - local opener="luaopen_"..base - if trace_swiglib then - report_swiglib("opening: %a with %a",name,opener) - end - local library,message=loadlib(name,opener) - local libtype=type(library) - if libtype=="function" then - library=library() - else - 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 - popdir() - return library - end) - loadedlibs[required]=library or false + local report_swiglib=logs.reporter("swiglib") + local trace_swiglib=false + local savedrequire=require + local loadedlibs={} + local loadlib=package.loadlib + local pushdir=dir.push + local popdir=dir.pop + trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) + function requireswiglib(required,version) + local library=loadedlibs[library] + if library==nil then + local trace_swiglib=trace_swiglib or package.helpers.trace + library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) + pushdir(pathpart(name)) + local opener="luaopen_"..base + if trace_swiglib then + report_swiglib("opening: %a with %a",name,opener) + end + local library,message=loadlib(name,opener) + local libtype=type(library) + if libtype=="function" then + library=library() + else + 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 + popdir() return library + end) + loadedlibs[required]=library or false end - function require(name,version) - if find(name,"^swiglib%.") then - return requireswiglib(name,version) - else - return savedrequire(name) - end + return library + end + function require(name,version) + if find(name,"^swiglib%.") then + return requireswiglib(name,version) + else + return savedrequire(name) + end + end + local swiglibs={} + local initializer="core" + function swiglib(name,version) + local library=swiglibs[name] + if not library then + statistics.starttiming(swiglibs) + if trace_swiglib then + report_swiglib("loading %a",name) + end + 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 - local swiglibs={} - local initializer="core" - function swiglib(name,version) - local library=swiglibs[name] - if not library then - statistics.starttiming(swiglibs) - if trace_swiglib then - report_swiglib("loading %a",name) - end - 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 - return library + return library + end + statistics.register("used swiglibs",function() + if next(swiglibs) then + return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) end - statistics.register("used swiglibs",function() - if next(swiglibs) then - return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) - end - end) + end) end if FFISUPPORTED and ffi and ffi.load then - local report_ffilib=logs.reporter("ffilib") - local trace_ffilib=false - local savedffiload=ffi.load - trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) - local loaded={} - local function locateindeed(name) - name=removesuffix(name) - local l=loaded[name] - if l==nil then - local message,library=pcall(savedffiload,name) - if type(message)=="userdata" then - l=message - elseif type(library)=="userdata" then - l=library - else - l=false - end - loaded[name]=l - elseif trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l + local report_ffilib=logs.reporter("ffilib") + local trace_ffilib=false + local savedffiload=ffi.load + trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) + local loaded={} + local function locateindeed(name) + name=removesuffix(name) + local l=loaded[name] + if l==nil then + local state,library=pcall(savedffiload,name) + if type(library)=="userdata" then + l=library + elseif type(state)=="userdata" then + l=state + else + l=false + end + loaded[name]=l + elseif trace_ffilib then + report_ffilib("reusing already loaded %a",name) end - function ffilib(name,version) - name=removesuffix(name) - local l=loaded[name] - if l~=nil then - if trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l - elseif version=="system" then - return locateindeed(name) - else - return locate(name,version,trace_ffilib,report_ffilib,locateindeed) + return l + end + local function getlist(required) + local list=directives.value("system.librarynames" ) + if type(list)=="table" then + list=list[required] + if type(list)=="table" then + if trace then + report("using lookup list for library %a: % | t",required,list) end + return list + end end - function ffi.load(name) - local library=ffilib(name) + return { required } + end + function ffilib(name,version) + name=removesuffix(name) + local l=loaded[name] + if l~=nil then + if trace_ffilib then + report_ffilib("reusing already loaded %a",name) + end + return l + end + local list=getlist(name) + if version=="system" then + for i=1,#list do + local library=locateindeed(list[i]) if type(library)=="userdata" then - return library + return library end - if trace_ffilib then - report_ffilib("trying to load %a using normal loader",name) + end + else + for i=1,#list do + local library=locate(list[i],version,trace_ffilib,report_ffilib,locateindeed) + if type(library)=="userdata" then + return library end - return savedffiload(name) + end end + end + function ffi.load(name) + local list=getlist(name) + for i=1,#list do + local library=ffilib(list[i]) + if type(library)=="userdata" then + return library + end + end + if trace_ffilib then + report_ffilib("trying to load %a using normal loader",name) + end + for i=1,#list do + local state,library=pcall(savedffiload,list[i]) + if type(library)=="userdata" then + return library + elseif type(state)=="userdata" then + return library + end + end + end end @@ -21007,13 +24620,13 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-sta"] = package.loaded["luat-sta"] or true --- original size: 5703, stripped down to: 2507 +-- original size: 5703, stripped down to: 2321 if not modules then modules={} end modules ['luat-sta']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gmatch,match=string.gmatch,string.match local type=type @@ -21026,81 +24639,81 @@ local hash=states.hash states.tag=states.tag or "" states.filename=states.filename or "" function states.save(filename,tag) - tag=tag or states.tag - filename=file.addsuffix(filename or states.filename,'lus') - io.savedata(filename, - "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) - ) + tag=tag or states.tag + filename=file.addsuffix(filename or states.filename,'lus') + io.savedata(filename, + "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) + ) end function states.load(filename,tag) - states.filename=filename - states.tag=tag or "whatever" - states.filename=file.addsuffix(states.filename,'lus') - data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} + states.filename=filename + states.tag=tag or "whatever" + states.filename=file.addsuffix(states.filename,'lus') + data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} end local function set_by_tag(tag,key,value,default,persistent) - local d,h=data[tag],hash[tag] - if d then - if type(d)=="table" then - local dkey,hkey=key,key - local pre,post=match(key,"(.+)%.([^%.]+)$") - if pre and post then - for k in gmatch(pre,"[^%.]+") do - local dk=d[k] - if not dk then - dk={} - d[k]=dk - elseif type(dk)=="string" then - break - end - d=dk - end - dkey,hkey=post,key - end - if value==nil then - value=default - elseif value==false then - elseif persistent then - value=value or d[dkey] or default - else - value=value or default - end - d[dkey],h[hkey]=value,value - elseif type(d)=="string" then - data[tag],hash[tag]=value,value + local d,h=data[tag],hash[tag] + if d then + if type(d)=="table" then + local dkey,hkey=key,key + local pre,post=match(key,"(.+)%.([^%.]+)$") + if pre and post then + for k in gmatch(pre,"[^%.]+") do + local dk=d[k] + if not dk then + dk={} + d[k]=dk + elseif type(dk)=="string" then + break + end + d=dk end + dkey,hkey=post,key + end + if value==nil then + value=default + elseif value==false then + elseif persistent then + value=value or d[dkey] or default + else + value=value or default + end + d[dkey],h[hkey]=value,value + elseif type(d)=="string" then + data[tag],hash[tag]=value,value end + end end local function get_by_tag(tag,key,default) - local h=hash[tag] - if h and h[key] then - return h[key] - else - local d=data[tag] - if d then - for k in gmatch(key,"[^%.]+") do - local dk=d[k] - if dk~=nil then - d=dk - else - return default - end - end - if d==false then - return false - else - return d or default - end + local h=hash[tag] + if h and h[key] then + return h[key] + else + local d=data[tag] + if d then + for k in gmatch(key,"[^%.]+") do + local dk=d[k] + if dk~=nil then + d=dk + else + return default end + end + if d==false then + return false + else + return d or default + end end + end end states.set_by_tag=set_by_tag states.get_by_tag=get_by_tag function states.set(key,value,default,persistent) - set_by_tag(states.tag,key,value,default,persistent) + set_by_tag(states.tag,key,value,default,persistent) end function states.get(key,default) - return get_by_tag(states.tag,key,default) + return get_by_tag(states.tag,key,default) end @@ -21110,14 +24723,14 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-fmt"] = package.loaded["luat-fmt"] or true --- original size: 9268, stripped down to: 7401 +-- original size: 9418, stripped down to: 7087 if not modules then modules={} end modules ['luat-fmt']={ - version=1.001, - comment="companion to mtxrun", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to mtxrun", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format=string.format local concat=table.concat @@ -21125,229 +24738,232 @@ local quoted=string.quoted local luasuffixes=utilities.lua.suffixes local report_format=logs.reporter("resolvers","formats") local function primaryflags() - local arguments=environment.arguments - local flags={} - if arguments.silent then - flags[#flags+1]="--interaction=batchmode" - end - if arguments.jit then - flags[#flags+1]="--jiton" - end - return concat(flags," ") + local arguments=environment.arguments + local flags={} + if arguments.silent then + flags[#flags+1]="--interaction=batchmode" + end + return concat(flags," ") end local function secondaryflags() - local arguments=environment.arguments - local trackers=arguments.trackers - local directives=arguments.directives - local flags={} - if trackers and trackers~="" then - flags[#flags+1]="--c:trackers="..quoted(trackers) - end - if directives and directives~="" then - flags[#flags+1]="--c:directives="..quoted(directives) - end - if arguments.silent then - flags[#flags+1]="--c:silent" - end - if arguments.errors then - flags[#flags+1]="--c:errors" - end - if arguments.jit then - flags[#flags+1]="--c:jiton" - end - if arguments.ansi then - flags[#flags+1]="--c:ansi" - end - return concat(flags," ") + local arguments=environment.arguments + local trackers=arguments.trackers + local directives=arguments.directives + local flags={} + if trackers and trackers~="" then + flags[#flags+1]="--c:trackers="..quoted(trackers) + end + if directives and directives~="" then + flags[#flags+1]="--c:directives="..quoted(directives) + end + if arguments.silent then + flags[#flags+1]="--c:silent" + end + if arguments.errors then + flags[#flags+1]="--c:errors" + end + if arguments.jit then + flags[#flags+1]="--c:jiton" + end + if arguments.ansi then + flags[#flags+1]="--c:ansi" + end + if arguments.strip then + flags[#flags+1]="--c:strip" + end + if arguments.lmtx then + flags[#flags+1]="--c:lmtx" + end + return concat(flags," ") end local template=[[--ini %primaryflags% --lua=%luafile% %texfile% %secondaryflags% %dump% %redirect%]] local checkers={ - primaryflags="string", - secondaryflags="string", - luafile="readable", - texfile="readable", - redirect="string", - dump="string", + primaryflags="string", + secondaryflags="string", + luafile="readable", + texfile="readable", + redirect="string", + dump="string", } local runners={ - luatex=sandbox.registerrunner { - name="make luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="make luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="make luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="make luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.make_format(name,arguments) - local engine=environment.ownmain or "luatex" - local silent=environment.arguments.silent - local errors=environment.arguments.errors - local olddir=dir.current() - local path=caches.getwritablepath("formats",engine) or "" - if path~="" then - lfs.chdir(path) - end - report_format("using format path %a",dir.current()) - local texsourcename=file.addsuffix(name,"mkiv") - local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - if fulltexsourcename=="" then - texsourcename=file.addsuffix(name,"tex") - fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - end - if fulltexsourcename=="" then - report_format("no tex source file with name %a (mkiv or tex)",name) - lfs.chdir(olddir) - return - else - report_format("using tex source file %a",fulltexsourcename) - end - local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) - local specificationname=file.replacesuffix(fulltexsourcename,"lus") - local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - if fullspecificationname=="" then - specificationname=file.join(texsourcepath,"context.lus") - fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - end - if fullspecificationname=="" then - report_format("unknown stub specification %a",specificationname) - lfs.chdir(olddir) - return - end - local specificationpath=file.dirname(fullspecificationname) - local usedluastub=nil - local usedlualibs=dofile(fullspecificationname) - if type(usedlualibs)=="string" then - usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) - elseif type(usedlualibs)=="table" then - report_format("using stub specification %a",fullspecificationname) - local texbasename=file.basename(name) - local luastubname=file.addsuffix(texbasename,luasuffixes.lua) - local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) - report_format("creating initialization file %a",luastubname) - utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) - if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then - report_format("using compiled initialization file %a",lucstubname) - usedluastub=lucstubname - else - report_format("using uncompiled initialization file %a",luastubname) - usedluastub=luastubname - end - else - report_format("invalid stub specification %a",fullspecificationname) - lfs.chdir(olddir) - return - end - local specification={ - primaryflags=primaryflags(), - secondaryflags=secondaryflags(), - luafile=quoted(usedluastub), - texfile=quoted(fulltexsourcename), - dump=os.platform=="unix" and "\\\\dump" or "\\dump", - } - local runner=runners[engine] - if not runner then - report_format("format %a cannot be generated, no runner available for engine %a",name,engine) - elseif silent then - statistics.starttiming() - specification.redirect="> temp.log" - local result=runner(specification) - local runtime=statistics.stoptiming() - if result~=0 then - print(format("%s silent make > fatal error when making format %q",engine,name)) - else - print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) - end - os.remove("temp.log") - else - runner(specification) - end - local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" - local mp=dir.glob(pattern) - if mp then - for i=1,#mp do - local name=mp[i] - report_format("removing related mplib format %a",file.basename(name)) - os.remove(name) - end - end + local engine=environment.ownmain or "luatex" + local silent=environment.arguments.silent + local errors=environment.arguments.errors + local olddir=dir.current() + local path=caches.getwritablepath("formats",engine) or "" + if path~="" then + lfs.chdir(path) + end + report_format("using format path %a",dir.current()) + local texsourcename=file.addsuffix(name,"mkiv") + local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + if fulltexsourcename=="" then + texsourcename=file.addsuffix(name,"tex") + fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + end + if fulltexsourcename=="" then + report_format("no tex source file with name %a (mkiv or tex)",name) + lfs.chdir(olddir) + return + else + report_format("using tex source file %a",fulltexsourcename) + end + local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) + local specificationname=file.replacesuffix(fulltexsourcename,"lus") + local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + if fullspecificationname=="" then + specificationname=file.join(texsourcepath,"context.lus") + fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + end + if fullspecificationname=="" then + report_format("unknown stub specification %a",specificationname) + lfs.chdir(olddir) + return + end + local specificationpath=file.dirname(fullspecificationname) + local usedluastub=nil + local usedlualibs=dofile(fullspecificationname) + if type(usedlualibs)=="string" then + usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) + elseif type(usedlualibs)=="table" then + report_format("using stub specification %a",fullspecificationname) + local texbasename=file.basename(name) + local luastubname=file.addsuffix(texbasename,luasuffixes.lua) + local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) + report_format("creating initialization file %a",luastubname) + utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) + if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then + report_format("using compiled initialization file %a",lucstubname) + usedluastub=lucstubname + else + report_format("using uncompiled initialization file %a",luastubname) + usedluastub=luastubname + end + else + report_format("invalid stub specification %a",fullspecificationname) lfs.chdir(olddir) + return + end + local specification={ + primaryflags=primaryflags(), + secondaryflags=secondaryflags(), + luafile=quoted(usedluastub), + texfile=quoted(fulltexsourcename), + dump=os.platform=="unix" and "\\\\dump" or "\\dump", + } + local runner=runners[engine] + if not runner then + report_format("format %a cannot be generated, no runner available for engine %a",name,engine) + elseif silent then + statistics.starttiming() + specification.redirect="> temp.log" + local result=runner(specification) + local runtime=statistics.stoptiming() + if result~=0 then + print(format("%s silent make > fatal error when making format %q",engine,name)) + else + print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) + end + os.remove("temp.log") + else + runner(specification) + end + local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" + local mp=dir.glob(pattern) + if mp then + for i=1,#mp do + local name=mp[i] + report_format("removing related mplib format %a",file.basename(name)) + os.remove(name) + end + end + lfs.chdir(olddir) end local template=[[%flags% --fmt=%fmtfile% --lua=%luafile% %texfile% %more%]] local checkers={ - flags="string", - more="string", - fmtfile="readable", - luafile="readable", - texfile="readable", + flags="string", + more="string", + fmtfile="readable", + luafile="readable", + texfile="readable", } local runners={ - luatex=sandbox.registerrunner { - name="run luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="run luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="run luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="run luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.run_format(name,data,more) - if name and name~="" then - local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) - if fmtname=="" then - fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" - end - fmtname=resolvers.cleanpath(fmtname) - if fmtname=="" then - report_format("no format with name %a",name) + if name and name~="" then + local engine=environment.ownmain or "luatex" + local barename=file.removesuffix(name) + local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) + if fmtname=="" then + fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" + end + fmtname=resolvers.cleanpath(fmtname) + if fmtname=="" then + report_format("no format with name %a",name) + else + local barename=file.removesuffix(name) + local luaname=file.addsuffix(barename,"luc") + if not lfs.isfile(luaname) then + luaname=file.addsuffix(barename,"lua") + end + if not lfs.isfile(luaname) then + report_format("using format name %a",fmtname) + report_format("no luc/lua file with name %a",barename) + else + local runner=runners[engine] + if not runner then + report_format("format %a cannot be run, no runner available for engine %a",name,engine) else - local barename=file.removesuffix(name) - local luaname=file.addsuffix(barename,"luc") - if not lfs.isfile(luaname) then - luaname=file.addsuffix(barename,"lua") - end - if not lfs.isfile(luaname) then - report_format("using format name %a",fmtname) - report_format("no luc/lua file with name %a",barename) - else - local runner=runners[engine] - if not runner then - report_format("format %a cannot be run, no runner available for engine %a",name,engine) - else - runner { - flags=primaryflags(), - fmtfile=quoted(barename), - luafile=quoted(luaname), - texfile=quoted(data), - more=more, - } - end - end + runner { + flags=primaryflags(), + fmtfile=quoted(barename), + luafile=quoted(luaname), + texfile=quoted(data), + more=more, + } end + end end + end end end -- of closure --- used libraries : l-lua.lua l-macro.lua l-sandbox.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-fil.lua util-sac.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-tpl.lua util-sbx.lua util-mrg.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 +-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.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-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.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 : 877962 --- stripped bytes : 317771 +-- original bytes : 994864 +-- stripped bytes : 395007 -- end library merge @@ -21370,6 +24986,7 @@ local owntree = environment and environment.ownpath or ownpath local ownlibs = { -- order can be made better + 'l-bit32.lua', 'l-lua.lua', 'l-macro.lua', 'l-sandbox.lua', @@ -21385,6 +25002,7 @@ local ownlibs = { -- order can be made better 'l-file.lua', 'l-gzip.lua', 'l-md5.lua', + 'l-sha.lua', 'l-url.lua', 'l-dir.lua', 'l-boolean.lua', @@ -21399,6 +25017,19 @@ local ownlibs = { -- order can be made better 'util-prs.lua', 'util-fmt.lua', + 'util-soc-imp-reset.lua', + 'util-soc-imp-socket.lua', + 'util-soc-imp-copas.lua', + 'util-soc-imp-ltn12.lua', + -- 'util-soc-imp-mbox.lua', + 'util-soc-imp-mime.lua', + 'util-soc-imp-url.lua', + 'util-soc-imp-headers.lua', + 'util-soc-imp-tp.lua', + 'util-soc-imp-http.lua', + 'util-soc-imp-ftp.lua', + 'util-soc-imp-smtp.lua', + 'trac-set.lua', 'trac-log.lua', 'trac-inf.lua', -- was before trac-set @@ -21601,9 +25232,7 @@ local helpinfo = [[ <flag name="locate"><short>locate given filename in database (default) or system (<ref name="first"/> <ref name="all"/> <ref name="detail"/>)</short></flag> </subcategory> <subcategory> - <flag name="autotree"><short>use texmf tree cf. env texmfstart_tree or texmfstarttree</short></flag> <flag name="tree" value="pathtotree"><short>use given texmf tree (default file: setuptex.tmf)</short></flag> - <flag name="environment" value="name"><short>use given (tmf) environment file</short></flag> <flag name="path" value="runpath"><short>go to given path before execution</short></flag> <flag name="ifchanged" value="filename"><short>only execute when given file has changed (md checksum)</short></flag> <flag name="iftouched" value="old,new"><short>only execute when given file has changed (time stamp)</short></flag> @@ -21623,7 +25252,7 @@ local helpinfo = [[ </subcategory> <subcategory> <flag name="edit"><short>launch editor with found file</short></flag> - <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>)</short></flag> + <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>,<ref name="list"/>)</short></flag> </subcategory> <subcategory> <flag name="timedrun"><short>run a script and time its run</short></flag> @@ -22022,9 +25651,9 @@ function resolvers.launch(str) end function runners.launch_file(filename) - trackers.enable("resolvers.locating") local allresults = environment.arguments["all"] - local pattern = environment.arguments["pattern"] + local pattern = environment.arguments["pattern"] + local listonly = environment.arguments["list"] if not pattern or pattern == "" then pattern = filename end @@ -22039,14 +25668,32 @@ function runners.launch_file(filename) t = resolvers.findfiles("*/" .. pattern .. "*",nil,allresults) end if t and #t > 0 then - if allresults then - for _, v in pairs(t) do - report("launching %s", v) - resolvers.launch(v) + for i=1,#t do + local name = t[i] + if listonly then + report("% 3i: %-30s %s",i,file.basename(name),file.dirname(name)) + else + report("launching: %s",name) + resolvers.launch(name) + if not allresults then + break + end + end + end + if listonly then + io.write("\n") + io.write("\n[select number]\n\n>> ") + local answer = tonumber(io.read()) + if answer then + io.write("\n") + local name = t[answer] + if name then + report("launching: %s",name) + resolvers.launch(name) + else + report("invalid number") + end end - else - report("launching %s", t[1]) - resolvers.launch(t[1]) end else report("no match for %s", pattern) @@ -22166,12 +25813,9 @@ function runners.execute_ctx_script(filename,...) dofile(fullname) local savename = environment.arguments['save'] if savename then - local save_list = runners.save_list - if save_list and next(save_list) then - if type(savename) ~= "string" then savename = file.basename(fullname) end - savename = file.replacesuffix(savename,"cfg") - runners.save_script_session(savename,save_list) - end + if type(savename) ~= "string" then savename = file.basename(fullname) end + savename = file.replacesuffix(savename,"cfg") + runners.save_script_session(savename,save_list) end return true end @@ -22188,22 +25832,22 @@ function runners.execute_ctx_script(filename,...) local scriptbase = match(scriptname,".*mtx%-([^%-]-)%.lua") if scriptbase then local data = io.loaddata(scriptname) -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 + 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 @@ -22243,7 +25887,7 @@ function runners.timedrun(filename) -- just for me end function runners.timed(action) - statistics.timed(action) + statistics.timed(action,true) end function runners.associate(filename) diff --git a/scripts/context/stubs/win64/metatex.exe b/scripts/context/stubs/win64/metatex.exe Binary files differdeleted file mode 100644 index 93290a6e0..000000000 --- a/scripts/context/stubs/win64/metatex.exe +++ /dev/null diff --git a/scripts/context/stubs/win64/mtxrun.lua b/scripts/context/stubs/win64/mtxrun.lua index 0f4767d91..569a7f2e1 100644 --- a/scripts/context/stubs/win64/mtxrun.lua +++ b/scripts/context/stubs/win64/mtxrun.lua @@ -1,16 +1,5 @@ #!/usr/bin/env texlua --- for k, v in next, _G.string do --- local tv = type(v) --- if tv == "table" then --- for kk, vv in next, v do --- print(k,kk,vv) --- end --- else --- print(tv,k,v) --- end --- end - if not modules then modules = { } end modules ['mtxrun'] = { version = 1.001, comment = "runner, lua replacement for texmfstart.rb", @@ -20,25 +9,43 @@ if not modules then modules = { } end modules ['mtxrun'] = { } -- one can make a stub: + +-- mtxrun : -- -- #!/bin/sh -- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@" +-- mtxrun.cmd : +-- +-- @luatex --luaonly %~d0%~p0mtxrun.lua %* + -- filename : mtxrun.lua -- comment : companion to context.tex -- author : Hans Hagen, PRAGMA-ADE, Hasselt NL -- copyright: PRAGMA ADE / ConTeXt Development Team -- license : see context related readme files --- This script is based on texmfstart.rb but does not use kpsewhich to --- locate files. Although kpse is a library it never came to opening up --- its interface to other programs (esp scripting languages) and so we --- do it ourselves. The lua variant evolved out of an experimental ruby --- one. Interesting is that using a scripting language instead of c does --- not have a speed penalty. Actually the lua variant is more efficient, --- especially when multiple calls to kpsewhich are involved. The lua +-- This script is based on texmfstart.rb but does not use kpsewhich to locate files. +-- Although kpse is a library it never came to opening up its interface to other +-- programs (esp scripting languages) and so we do it ourselves. The lua variant +-- evolved out of an experimental ruby one. Interesting is that using a scripting +-- language instead of c does not have a speed penalty. Actually the lua variant is +-- more efficient, especially when multiple calls to kpsewhich are involved. The lua -- library also gives way more control. +-- When libraries used here are updates you can run +-- +-- mtxrun --selfmerge +-- +-- to update the embedded code. After that you might need to run +-- +-- mtxrun --selfupdate +-- +-- to copy the new script (from scripts/context/lua) to location where +-- binaries are expected. If you want to remove the embedded code you can run +-- +-- mtxxun --selfclean + -- to be done / considered -- -- support for --exec or make it default @@ -54,16 +61,147 @@ if not modules then modules = { } end modules ['mtxrun'] = { do -- create closure to overcome 200 locals limit +package.loaded["l-bit32"] = package.loaded["l-bit32"] or true + +-- original size: 3607, stripped down to: 3009 + +if not modules then modules={} end modules ['l-bit32']={ + version=1.001, + license="the same as regular Lua", + source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto", + comment="drop-in for bit32, adapted a bit by Hans Hagen", +} +if bit32 then +elseif utf8 then + load ([[ +local select = select -- instead of: arg = { ... } +bit32 = { + bnot = function (a) + return ~a & 0xFFFFFFFF + end, + band = function (x, y, z, ...) + if not z then + return ((x or -1) & (y or -1)) & 0xFFFFFFFF + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bor = function (x, y, z, ...) + if not z then + return ((x or 0) | (y or 0)) & 0xFFFFFFFF + else + local res = x | y | z + for i=1,select("#",...) do + res = res | select(i,...) + end + return res & 0xFFFFFFFF + end + end, + bxor = function (x, y, z, ...) + if not z then + return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF + else + local res = x ~ y ~ z + for i=1,select("#",...) do + res = res ~ select(i,...) + end + return res & 0xFFFFFFFF + end + end, + btest = function (x, y, z, ...) + if not z then + return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0 + else + local res = x & y & z + for i=1,select("#",...) do + res = res & select(i,...) + end + return (res & 0xFFFFFFFF) ~= 0 + end + end, + lshift = function (a, b) + return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF + end, + rshift = function (a, b) + return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF + end, + arshift = function (a, b) + a = a & 0xFFFFFFFF + if b <= 0 or (a & 0x80000000) == 0 then + return (a >> b) & 0xFFFFFFFF + else + return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF + end + end, + lrotate = function (a ,b) + b = b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + rrotate = function (a, b) + b = -b & 31 + a = a & 0xFFFFFFFF + a = (a << b) | (a >> (32 - b)) + return a & 0xFFFFFFFF + end, + extract = function (a, f, w) + return (a >> f) & ~(-1 << (w or 1)) + end, + replace = function (a, v, f, w) + local mask = ~(-1 << (w or 1)) + return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF + end, +} + ]] ) () +elseif bit then + load ([[ +local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift +bit32 = { + arshift = bit.arshift, + band = band, + bnot = bnot, + bor = bit.bor, + bxor = bit.bxor, + btest = function(...) + return band(...) ~= 0 + end, + extract = function(a,f,w) + return band(rshift(a,f),2^(w or 1)-1) + end, + lrotate = bit.rol, + lshift = lshift, + replace = function(a,v,f,w) + local mask = 2^(w or 1)-1 + return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f) + end, + rrotate = bit.ror, + rshift = rshift, +} + ]] ) () +else + xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end) +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + package.loaded["l-lua"] = package.loaded["l-lua"] or true --- original size: 6230, stripped down to: 3662 +-- original size: 6281, stripped down to: 2863 if not modules then modules={} end modules ['l-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,tonumber=next,type,tonumber LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$") @@ -71,122 +209,111 @@ LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5 LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1 LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10 if LUAVERSION<5.2 and jit then - MINORVERSION=2 - LUAVERSION=5.2 + MINORVERSION=2 + LUAVERSION=5.2 end -_LUAVERSION=LUAVERSION if not lpeg then - lpeg=require("lpeg") + lpeg=require("lpeg") end if loadstring then - local loadnormal=load - function load(first,...) - if type(first)=="string" then - return loadstring(first,...) - else - return loadnormal(first,...) - end + local loadnormal=load + function load(first,...) + if type(first)=="string" then + return loadstring(first,...) + else + return loadnormal(first,...) end + end else - loadstring=load + loadstring=load end if not ipairs then - local function iterate(a,i) - i=i+1 - local v=a[i] - if v~=nil then - return i,v - end - end - function ipairs(a) - return iterate,a,0 + local function iterate(a,i) + i=i+1 + local v=a[i] + if v~=nil then + return i,v end + end + function ipairs(a) + return iterate,a,0 + end end if not pairs then - function pairs(t) - return next,t - end + function pairs(t) + return next,t + end end if not table.unpack then - table.unpack=_G.unpack + table.unpack=_G.unpack elseif not unpack then - _G.unpack=table.unpack + _G.unpack=table.unpack end if not package.loaders then - package.loaders=package.searchers + package.loaders=package.searchers end local print,select,tostring=print,select,tostring local inspectors={} function setinspector(kind,inspector) - inspectors[kind]=inspector + inspectors[kind]=inspector end function inspect(...) - for s=1,select("#",...) do - local value=select(s,...) - if value==nil then - print("nil") - else - local done=false - local kind=type(value) - local inspector=inspectors[kind] - if inspector then - done=inspector(value) - if done then - break - end - end - for kind,inspector in next,inspectors do - done=inspector(value) - if done then - break - end - end - if not done then - print(tostring(value)) - end + for s=1,select("#",...) do + local value=select(s,...) + if value==nil then + print("nil") + else + local done=false + local kind=type(value) + local inspector=inspectors[kind] + if inspector then + done=inspector(value) + if done then + break + end + end + for kind,inspector in next,inspectors do + done=inspector(value) + if done then + break end + end + if not done then + print(tostring(value)) + end end + end end local dummy=function() end function optionalrequire(...) - local ok,result=xpcall(require,dummy,...) - if ok then - return result - end + local ok,result=xpcall(require,dummy,...) + if ok then + return result + end end if lua then - lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" + lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" end local flush=io.flush if flush then - local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end - local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end - local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end - local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end + local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end + local exec=os.exec if exec then function os.exec (...) flush() return exec (...) end end + local spawn=os.spawn if spawn then function os.spawn (...) flush() return spawn (...) end end + local popen=io.popen if popen then function io.popen (...) flush() return popen (...) end end end FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load if not FFISUPPORTED then - local okay;okay,ffi=pcall(require,"ffi") - FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load + local okay;okay,ffi=pcall(require,"ffi") + FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load end if not FFISUPPORTED then - ffi=nil + ffi=nil elseif not ffi.number then - ffi.number=tonumber + ffi.number=tonumber end -if not bit32 then - bit32=require("l-bit32") +if LUAVERSION>5.3 then + collectgarbage("generational") end -local loaded=package.loaded -if not loaded["socket"] then loaded["socket"]=loaded["socket.core"] end -if not loaded["mime"] then loaded["mime"]=loaded["mime.core"] end -if not socket.mime then socket.mime=package.loaded["mime"] end -if not loaded["socket.mime"] then loaded["socket.mime"]=socket.mime end -if not loaded["socket.http"] then loaded["socket.http"]=socket.http end -if not loaded["socket.ftp"] then loaded["socket.ftp"]=socket.ftp end -if not loaded["socket.smtp"] then loaded["socket.smtp"]=socket.smtp end -if not loaded["socket.tp"] then loaded["socket.tp"]=socket.tp end -if not loaded["socket.url"] then loaded["socket.url"]=socket.url end end -- of closure @@ -195,25 +322,27 @@ do -- create closure to overcome 200 locals limit package.loaded["l-macro"] = package.loaded["l-macro"] or true --- original size: 8260, stripped down to: 5213 +-- original size: 10131, stripped down to: 5991 if not modules then modules={} end modules ['l-macros']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg local lpegmatch=lpeg.match local concat=table.concat -local format,sub=string.format,string.sub +local format,sub,match=string.format,string.sub,string.match local next,load,type=next,load,type local newline=S("\n\r")^1 local continue=P("\\")*newline +local whitespace=S(" \t\n\r") local spaces=S(" \t")+continue -local name=R("az","AZ","__","09")^1 -local body=((1+continue/"")-newline)^1 +local nametoken=R("az","AZ","__","09") +local name=nametoken^1 +local body=((continue/""+1)-newline)^1 local lparent=P("(") local rparent=P(")") local noparent=1-(lparent+rparent) @@ -230,172 +359,214 @@ local definitions={} local resolve local subparser local report_lua=function(...) - if logs and logs.reporter then - report_lua=logs.reporter("system","lua") - report_lua(...) - else - print(format(...)) - end -end -resolve=C(C(name)*arguments^-1)/function(raw,s,a) - local d=definitions[s] - if d then - if a then - local n=#a - local p=patterns[s][n] - if p then - local d=d[n] - for i=1,n do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return lpegmatch(p,d,1,a) or d - else - return raw - end - else - return d[0] or raw - end - elseif a then - for i=1,#a do - a[i]=lpegmatch(subparser,a[i]) or a[i] - end - return s.."("..concat(a,",")..")" - else - return raw - end -end -subparser=Cs((resolve+P(1))^1) -local enddefine=P("#enddefine")/"" -local beginregister=(C(name)*spaces^0*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) - local n=0 + if logs and logs.reporter then + report_lua=logs.reporter("system","lua") + report_lua(...) + else + print(format(...)) + end +end +local safeguard=P("local")*whitespace^1*name*(whitespace+P("=")) +resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a) + local d=definitions[s] + if d then if a then - n=#a - local pattern=P(false) + local n=#a + local p=patterns[s][n] + if p then + local d=d[n] for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p + a[i]=lpegmatch(subparser,a[i]) or a[i] end - p[n]=pattern + return lpegmatch(p,d,1,a) or d + else + return raw + end + else + return d[0] or raw end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d + elseif a then + for i=1,#a do + a[i]=lpegmatch(subparser,a[i]) or a[i] end - d[n]=lpegmatch(subparser,v) or v - return "" + return s.."("..concat(a,",")..")" + else + return raw + end end -local register=(C(name)*spaces^0*(arguments+Cc(false))*spaces^0*C(body))/function(k,a,v) - local n=0 - if a then - n=#a - local pattern=P(false) - for i=1,n do - pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end - end - pattern=Cs((pattern+P(1))^1) - local p=patterns[k] - if not p then - p={ [0]=false,false,false,false,false,false,false,false,false } - patterns[k]=p - end - p[n]=pattern - end - local d=definitions[k] - if not d then - d={ [0]=false,false,false,false,false,false,false,false,false } - definitions[k]=d - end - d[n]=lpegmatch(subparser,v) or v - return "" +subparser=Cs((resolve+P(1))^1) +local enddefine=P("#enddefine")/"" +local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" +end +local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v) + local n=0 + if a then + n=#a + local pattern=P(false) + for i=1,n do + pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end + end + pattern=Cs((pattern+P(1))^1) + local p=patterns[k] + if not p then + p={ [0]=false,false,false,false,false,false,false,false,false } + patterns[k]=p + end + p[n]=pattern + end + local d=definitions[k] + if not d then + d={ a=a,[0]=false,false,false,false,false,false,false,false,false } + definitions[k]=d + end + d[n]=lpegmatch(subparser,v) or v + return "" end local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a) - local n=0 - if a then - n=#a - local p=patterns[k] - if p then - p[n]=false - end - end - local d=definitions[k] - if d then - d[n]=false + local n=0 + if a then + n=#a + local p=patterns[k] + if p then + p[n]=false end - return "" + end + local d=definitions[k] + if d then + d[n]=false + end + return "" end local begindefine=(P("begindefine")*spaces^0/"")*beginregister -local define=(P("define" )*spaces^0/"")*register -local undefine=(P("undefine" )*spaces^0/"")*unregister +local define=(P("define" )*spaces^0/"")*register +local undefine=(P("undefine" )*spaces^0/"")*unregister local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 ) function macros.reset() - definitions={} - patterns={} + definitions={} + patterns={} +end +function macros.showdefinitions() + for name,list in table.sortedhash(definitions) do + local arguments=list.a + if arguments then + arguments="("..concat(arguments,",")..")" + else + arguments="" + end + print("macro: "..name..arguments) + for i=0,#list do + local l=list[i] + if l then + print(" "..l) + end + end + end end function macros.resolvestring(str) - return lpegmatch(parser,str) or str + return lpegmatch(parser,str) or str end function macros.resolving() - return next(patterns) -end -local function loaded(name,trace,detail) - local f=io.open(name,"rb") - if not f then - return false,format("file '%s' not found",name) - end - local c=f:read("*a") - if not c then - return false,format("file '%s' is invalid",name) - end + return next(patterns) +end +local function reload(path,name,data) + local only=match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only + local f=io.open(name,"wb") + f:write(data) f:close() - local n=lpegmatch(parser,c) - if trace then - if #n~=#c then - report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) - if detail then - report_lua() - report_lua(n) - report_lua() - end - elseif detail then - report_lua("no macros expanded in '%s'",name) - end + local f=loadfile(name) + os.remove(name) + return f + end +end +local function reload(path,name,data) + if path and path~="" then + local only=string.match(name,".-([^/]+)%.lua") + if only and only~="" then + local name=path.."/"..only.."-macro.lua" + local f=io.open(name,"wb") + if f then + f:write(data) + f:close() + local l=loadfile(name) + os.remove(name) + return l + end end - if #name>30 then - n="--[["..sub(name,-30).."]] "..n - else - n="--[["..name.."]] "..n + end + return load(data,name) +end +local function loaded(name,trace,detail) + local f=io.open(name,"rb") + if not f then + return false,format("file '%s' not found",name) + end + local c=f:read("*a") + if not c then + return false,format("file '%s' is invalid",name) + end + f:close() + local n=lpegmatch(parser,c) + if trace then + if #n~=#c then + report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n) + if detail then + report_lua() + report_lua(n) + report_lua() + end + elseif detail then + report_lua("no macros expanded in '%s'",name) end - return load(n) + end + return reload(lfs and lfs.currentdir(),name,n) end macros.loaded=loaded function required(name,trace) - local filename=file.addsuffix(name,"lua") - local fullname=resolvers and resolvers.find_file(filename) or filename - if not fullname or fullname=="" then - return false - end - local codeblob=package.loaded[fullname] - if codeblob then - return codeblob - end - local code,message=loaded(fullname,macros,trace,trace) - if type(code)=="function" then - code=code() - else - report_lua("error when loading '%s'",fullname) - return false,message - end - if code==nil then - code=false - end - package.loaded[fullname]=code - return code + local filename=file.addsuffix(name,"lua") + local fullname=resolvers and resolvers.find_file(filename) or filename + if not fullname or fullname=="" then + return false + end + local codeblob=package.loaded[fullname] + if codeblob then + return codeblob + end + local code,message=loaded(fullname,macros,trace,trace) + if type(code)=="function" then + code=code() + else + report_lua("error when loading '%s'",fullname) + return false,message + end + if code==nil then + code=false + end + package.loaded[fullname]=code + return code end macros.required=required @@ -406,14 +577,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true --- original size: 9678, stripped down to: 6688 +-- original size: 9747, stripped down to: 6313 if not modules then modules={} end modules ['l-sandbox']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local global=_G local next=next @@ -439,231 +610,234 @@ local trace=false local logger=false local blocked={} local function report(...) - tprint("sandbox ! "..format(...)) + tprint("sandbox ! "..format(...)) end sandbox.report=report function sandbox.setreporter(r) - report=r - sandbox.report=r + report=r + sandbox.report=r end function sandbox.settrace(v) - trace=v + trace=v end function sandbox.setlogger(l) - logger=type(l)=="function" and l or false + logger=type(l)=="function" and l or false end local function register(func,overload,comment) - if type(func)=="function" then - if type(overload)=="string" then - comment=overload - overload=nil - end - local function f(...) - if sandboxed then - local overload=overloads[f] - if overload then - if logger then - local result={ overload(func,...) } - logger { - comment=comments[f] or tostring(f), - arguments={... }, - result=result[1] and true or false, - } - return unpack(result) - else - return overload(func,...) - end - else - end - else - return func(...) - end - end - if comment then - comments[f]=comment - if trace then - report("registering function: %s",comment) - end + if type(func)=="function" then + if type(overload)=="string" then + comment=overload + overload=nil + end + local function f(...) + if sandboxed then + local overload=overloads[f] + if overload then + if logger then + local result={ overload(func,...) } + logger { + comment=comments[f] or tostring(f), + arguments={... }, + result=result[1] and true or false, + } + return unpack(result) + else + return overload(func,...) + end + else end - overloads[f]=overload or false - originals[f]=func - return f + else + return func(...) + end end + if comment then + comments[f]=comment + if trace then + report("registering function: %s",comment) + end + end + overloads[f]=overload or false + originals[f]=func + return f + end end local function redefine(func,comment) - if type(func)=="function" then - skiploads[func]=comment or comments[func] or "unknown" - if overloads[func]==false then - overloads[func]=nil - end + if type(func)=="function" then + skiploads[func]=comment or comments[func] or "unknown" + if overloads[func]==false then + overloads[func]=nil end + end end sandbox.register=register sandbox.redefine=redefine function sandbox.original(func) - return originals and originals[func] or func + return originals and originals[func] or func end function sandbox.overload(func,overload,comment) - comment=comment or comments[func] or "?" - if type(func)~="function" then - if trace then - report("overloading unknown function: %s",comment) - end - elseif type(overload)~="function" then - if trace then - report("overloading function with bad overload: %s",comment) - end - elseif overloads[func]==nil then - if trace then - report("function is not registered: %s",comment) - end - elseif skiploads[func] then - if trace then - report("function is not skipped: %s",comment) - end - else - if trace then - report("overloading function: %s",comment) - end - overloads[func]=overload + comment=comment or comments[func] or "?" + if type(func)~="function" then + if trace then + report("overloading unknown function: %s",comment) + end + elseif type(overload)~="function" then + if trace then + report("overloading function with bad overload: %s",comment) + end + elseif overloads[func]==nil then + if trace then + report("function is not registered: %s",comment) + end + elseif skiploads[func] then + if trace then + report("function is not skipped: %s",comment) end - return func + else + if trace then + report("overloading function: %s",comment) + end + overloads[func]=overload + end + return func end local function whatever(specification,what,target) - if type(specification)~="table" then - report("%s needs a specification",what) - elseif type(specification.category)~="string" or type(specification.action)~="function" then - report("%s needs a category and action",what) - elseif not sandboxed then - target[#target+1]=specification - elseif trace then - report("already enabled, discarding %s",what) - end + if type(specification)~="table" then + report("%s needs a specification",what) + elseif type(specification.category)~="string" or type(specification.action)~="function" then + report("%s needs a category and action",what) + elseif not sandboxed then + target[#target+1]=specification + elseif trace then + report("already enabled, discarding %s",what) + end end function sandbox.initializer(specification) - whatever(specification,"initializer",initializers) + whatever(specification,"initializer",initializers) end function sandbox.finalizer(specification) - whatever(specification,"finalizer",finalizers) + whatever(specification,"finalizer",finalizers) end function require(name) - local n=gsub(name,"^.*[\\/]","") - local n=gsub(n,"[%.].*$","") - local b=blocked[n] - if b==false then - return nil - elseif b then - if trace then - report("using blocked: %s",n) - end - return b - else - if trace then - report("requiring: %s",name) - end - return requiem(name) + local n=gsub(name,"^.*[\\/]","") + local n=gsub(n,"[%.].*$","") + local b=blocked[n] + if b==false then + return nil + elseif b then + if trace then + report("using blocked: %s",n) end -end -function blockrequire(name,lib) + return b + else if trace then - report("preventing reload of: %s",name) + report("requiring: %s",name) end - blocked[name]=lib or _G[name] or false + return requiem(name) + end +end +function blockrequire(name,lib) + if trace then + report("preventing reload of: %s",name) + end + blocked[name]=lib or _G[name] or false end function sandbox.enable() - if not sandboxed then - for i=1,#initializers do - initializers[i].action() - end - for i=1,#finalizers do - finalizers[i].action() - end - local nnot=0 - local nyes=0 - local cnot={} - local cyes={} - local skip={} - for k,v in next,overloads do - local c=comments[k] - if v then - if c then - cyes[#cyes+1]=c - else - nyes=nyes+1 - end - else - if c then - cnot[#cnot+1]=c - else - nnot=nnot+1 - end - end - end - for k,v in next,skiploads do - skip[#skip+1]=v - end - if #cyes>0 then - sort(cyes) - report("overloaded known: %s",concat(cyes," | ")) - end - if nyes>0 then - report("overloaded unknown: %s",nyes) - end - if #cnot>0 then - sort(cnot) - report("not overloaded known: %s",concat(cnot," | ")) - end - if nnot>0 then - report("not overloaded unknown: %s",nnot) + if not sandboxed then + debug={ + traceback=debug.traceback, + } + for i=1,#initializers do + initializers[i].action() + end + for i=1,#finalizers do + finalizers[i].action() + end + local nnot=0 + local nyes=0 + local cnot={} + local cyes={} + local skip={} + for k,v in next,overloads do + local c=comments[k] + if v then + if c then + cyes[#cyes+1]=c + else + nyes=nyes+1 end - if #skip>0 then - sort(skip) - report("not overloaded redefined: %s",concat(skip," | ")) + else + if c then + cnot[#cnot+1]=c + else + nnot=nnot+1 end - initializers=nil - finalizers=nil - originals=nil - sandboxed=true + end + end + for k,v in next,skiploads do + skip[#skip+1]=v + end + if #cyes>0 then + sort(cyes) + report("overloaded known: %s",concat(cyes," | ")) + end + if nyes>0 then + report("overloaded unknown: %s",nyes) end + if #cnot>0 then + sort(cnot) + report("not overloaded known: %s",concat(cnot," | ")) + end + if nnot>0 then + report("not overloaded unknown: %s",nnot) + end + if #skip>0 then + sort(skip) + report("not overloaded redefined: %s",concat(skip," | ")) + end + initializers=nil + finalizers=nil + originals=nil + sandboxed=true + end end blockrequire("lfs",lfs) blockrequire("io",io) blockrequire("os",os) blockrequire("ffi",ffi) local function supported(library) - local l=_G[library] - return l + local l=_G[library] + return l end loadfile=register(loadfile,"loadfile") if supported("io") then - io.open=register(io.open,"io.open") - io.popen=register(io.popen,"io.popen") - io.lines=register(io.lines,"io.lines") - io.output=register(io.output,"io.output") - io.input=register(io.input,"io.input") + io.open=register(io.open,"io.open") + io.popen=register(io.popen,"io.popen") + io.lines=register(io.lines,"io.lines") + io.output=register(io.output,"io.output") + io.input=register(io.input,"io.input") end if supported("os") then - os.execute=register(os.execute,"os.execute") - os.spawn=register(os.spawn,"os.spawn") - os.exec=register(os.exec,"os.exec") - os.rename=register(os.rename,"os.rename") - os.remove=register(os.remove,"os.remove") + os.execute=register(os.execute,"os.execute") + os.spawn=register(os.spawn,"os.spawn") + os.exec=register(os.exec,"os.exec") + os.rename=register(os.rename,"os.rename") + os.remove=register(os.remove,"os.remove") end if supported("lfs") then - lfs.chdir=register(lfs.chdir,"lfs.chdir") - lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") - lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") - lfs.isfile=register(lfs.isfile,"lfs.isfile") - lfs.isdir=register(lfs.isdir,"lfs.isdir") - lfs.attributes=register(lfs.attributes,"lfs.attributes") - lfs.dir=register(lfs.dir,"lfs.dir") - lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") - lfs.touch=register(lfs.touch,"lfs.touch") - lfs.link=register(lfs.link,"lfs.link") - lfs.setmode=register(lfs.setmode,"lfs.setmode") - lfs.readlink=register(lfs.readlink,"lfs.readlink") - lfs.shortname=register(lfs.shortname,"lfs.shortname") - lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") + lfs.chdir=register(lfs.chdir,"lfs.chdir") + lfs.mkdir=register(lfs.mkdir,"lfs.mkdir") + lfs.rmdir=register(lfs.rmdir,"lfs.rmdir") + lfs.isfile=register(lfs.isfile,"lfs.isfile") + lfs.isdir=register(lfs.isdir,"lfs.isdir") + lfs.attributes=register(lfs.attributes,"lfs.attributes") + lfs.dir=register(lfs.dir,"lfs.dir") + lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir") + lfs.touch=register(lfs.touch,"lfs.touch") + lfs.link=register(lfs.link,"lfs.link") + lfs.setmode=register(lfs.setmode,"lfs.setmode") + lfs.readlink=register(lfs.readlink,"lfs.readlink") + lfs.shortname=register(lfs.shortname,"lfs.shortname") + lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes") end @@ -673,14 +847,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-package"] = package.loaded["l-package"] or true --- original size: 11562, stripped down to: 8625 +-- original size: 11605, stripped down to: 8299 if not modules then modules={} end modules ['l-package']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local gsub,format,find=string.gsub,string.format,string.find @@ -688,40 +862,40 @@ local insert,remove=table.insert,table.remove local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match local package=package local searchers=package.searchers or package.loaders -local filejoin=file and file.join or function(path,name) return path.."/"..name end -local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end -local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end +local filejoin=file and file.join or function(path,name) return path.."/"..name end +local isreadable=file and file.is_readable or function(name) local f=io.open(name) if f then f:close() return true end end +local addsuffix=file and file.addsuffix or function(name,suffix) return name.."."..suffix end local function cleanpath(path) - return path + return path end local pattern=Cs((((1-S("\\/"))^0*(S("\\/")^1/"/"))^0*(P(".")^1/"/"+P(1))^1)*-1) local function lualibfile(name) - return lpegmatch(pattern,name) or name + return lpegmatch(pattern,name) or name end local offset=luarocks and 1 or 0 local helpers=package.helpers or { - cleanpath=cleanpath, - lualibfile=lualibfile, - trace=false, - report=function(...) print(format(...)) end, - builtin={ - ["preload table"]=searchers[1+offset], - ["path specification"]=searchers[2+offset], - ["cpath specification"]=searchers[3+offset], - ["all in one fallback"]=searchers[4+offset], - }, - methods={}, - sequence={ - "already loaded", - "preload table", - "qualified path", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", - } + cleanpath=cleanpath, + lualibfile=lualibfile, + trace=false, + report=function(...) print(format(...)) end, + builtin={ + ["preload table"]=searchers[1+offset], + ["path specification"]=searchers[2+offset], + ["cpath specification"]=searchers[3+offset], + ["all in one fallback"]=searchers[4+offset], + }, + methods={}, + sequence={ + "already loaded", + "preload table", + "qualified path", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", + } } package.helpers=helpers local methods=helpers.methods @@ -737,253 +911,256 @@ local nofextralib=-1 local nofpathlua=-1 local nofpathlib=-1 local function listpaths(what,paths) - local nofpaths=#paths - if nofpaths>0 then - for i=1,nofpaths do - helpers.report("using %s path %i: %s",what,i,paths[i]) - end - else - helpers.report("no %s paths defined",what) + local nofpaths=#paths + if nofpaths>0 then + for i=1,nofpaths do + helpers.report("using %s path %i: %s",what,i,paths[i]) end - return nofpaths + else + helpers.report("no %s paths defined",what) + end + return nofpaths end local function getextraluapaths() - if helpers.trace and #extraluapaths~=nofextralua then - nofextralua=listpaths("extra lua",extraluapaths) - end - return extraluapaths + if helpers.trace and #extraluapaths~=nofextralua then + nofextralua=listpaths("extra lua",extraluapaths) + end + return extraluapaths end local function getextralibpaths() - if helpers.trace and #extralibpaths~=nofextralib then - nofextralib=listpaths("extra lib",extralibpaths) - end - return extralibpaths + if helpers.trace and #extralibpaths~=nofextralib then + nofextralib=listpaths("extra lib",extralibpaths) + end + return extralibpaths end local function getluapaths() - local luapath=package.path or "" - if oldluapath~=luapath then - luapaths=file.splitpath(luapath,";") - oldluapath=luapath - nofpathlua=-1 - end - if helpers.trace and #luapaths~=nofpathlua then - nofpathlua=listpaths("builtin lua",luapaths) - end - return luapaths + local luapath=package.path or "" + if oldluapath~=luapath then + luapaths=file.splitpath(luapath,";") + oldluapath=luapath + nofpathlua=-1 + end + if helpers.trace and #luapaths~=nofpathlua then + nofpathlua=listpaths("builtin lua",luapaths) + end + return luapaths end local function getlibpaths() - local libpath=package.cpath or "" - if oldlibpath~=libpath then - libpaths=file.splitpath(libpath,";") - oldlibpath=libpath - nofpathlib=-1 - end - if helpers.trace and #libpaths~=nofpathlib then - nofpathlib=listpaths("builtin lib",libpaths) - end - return libpaths + local libpath=package.cpath or "" + if oldlibpath~=libpath then + libpaths=file.splitpath(libpath,";") + oldlibpath=libpath + nofpathlib=-1 + end + if helpers.trace and #libpaths~=nofpathlib then + nofpathlib=listpaths("builtin lib",libpaths) + end + return libpaths end package.luapaths=getluapaths package.libpaths=getlibpaths package.extraluapaths=getextraluapaths package.extralibpaths=getextralibpaths local hashes={ - lua={}, - lib={}, + lua={}, + lib={}, } local function registerpath(tag,what,target,...) - local pathlist={... } - local cleanpath=helpers.cleanpath - local trace=helpers.trace - local report=helpers.report - local hash=hashes[what] - local function add(path) - local path=cleanpath(path) - if not hash[path] then - target[#target+1]=path - hash[path]=true - if trace then - report("registered %s path %s: %s",tag,#target,path) - end - else - if trace then - report("duplicate %s path: %s",tag,path) - end - end + local pathlist={... } + local cleanpath=helpers.cleanpath + local trace=helpers.trace + local report=helpers.report + local hash=hashes[what] + local function add(path) + local path=cleanpath(path) + if not hash[path] then + target[#target+1]=path + hash[path]=true + if trace then + report("registered %s path %s: %s",tag,#target,path) + end + else + if trace then + report("duplicate %s path: %s",tag,path) + end end - for p=1,#pathlist do - local path=pathlist[p] - if type(path)=="table" then - for i=1,#path do - add(path[i]) - end - else - add(path) - end + end + for p=1,#pathlist do + local path=pathlist[p] + if type(path)=="table" then + for i=1,#path do + add(path[i]) + end + else + add(path) end + end end local function pushpath(tag,what,target,path) - local path=helpers.cleanpath(path) - insert(target,1,path) - if helpers.trace then - helpers.report("pushing %s path in front: %s",tag,path) - end + local path=helpers.cleanpath(path) + insert(target,1,path) + if helpers.trace then + helpers.report("pushing %s path in front: %s",tag,path) + end end local function poppath(tag,what,target) - local path=remove(target,1) - if helpers.trace then - if path then - helpers.report("popping %s path from front: %s",tag,path) - else - helpers.report("no %s path to pop",tag) - end + local path=remove(target,1) + if helpers.trace then + if path then + helpers.report("popping %s path from front: %s",tag,path) + else + helpers.report("no %s path to pop",tag) end + end end helpers.registerpath=registerpath function package.extraluapath(...) - registerpath("extra lua","lua",extraluapaths,...) + registerpath("extra lua","lua",extraluapaths,...) end function package.pushluapath(path) - pushpath("extra lua","lua",extraluapaths,path) + pushpath("extra lua","lua",extraluapaths,path) end function package.popluapath() - poppath("extra lua","lua",extraluapaths) + poppath("extra lua","lua",extraluapaths) end function package.extralibpath(...) - registerpath("extra lib","lib",extralibpaths,...) + registerpath("extra lib","lib",extralibpaths,...) end function package.pushlibpath(path) - pushpath("extra lib","lib",extralibpaths,path) + pushpath("extra lib","lib",extralibpaths,path) end function package.poplibpath() - poppath("extra lib","lua",extralibpaths) + poppath("extra lib","lua",extralibpaths) end local function loadedaslib(resolved,rawname) - local base=gsub(rawname,"%.","_") - local init="luaopen_"..gsub(base,"%.","_") - if helpers.trace then - helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) - end - return package.loadlib(resolved,init) + local base=gsub(rawname,"%.","_") + local init="luaopen_"..gsub(base,"%.","_") + if helpers.trace then + helpers.report("calling loadlib with '%s' with init '%s'",resolved,init) + end + return package.loadlib(resolved,init) end helpers.loadedaslib=loadedaslib local function loadedbypath(name,rawname,paths,islib,what) - local trace=helpers.trace - for p=1,#paths do - local path=paths[p] - local resolved=filejoin(path,name) - if trace then - helpers.report("%s path, identifying '%s' on '%s'",what,name,path) - end - if isreadable(resolved) then - if trace then - helpers.report("%s path, '%s' found on '%s'",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + for p=1,#paths do + local path=paths[p] + local resolved=filejoin(path,name) + if trace then + helpers.report("%s path, identifying '%s' on '%s'",what,name,path) + end + if isreadable(resolved) then + if trace then + helpers.report("%s path, '%s' found on '%s'",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + 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 + 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] + return package.loaded[name] end methods["preload table"]=function(name) - return builtin["preload table"](name) + return builtin["preload table"](name) end methods["qualified path"]=function(name) - return loadedbyname(addsuffix(lualibfile(name),"lua"),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") + return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib") end methods["path specification"]=function(name) - getluapaths() - return builtin["path specification"](name) + getluapaths() + return builtin["path specification"](name) end methods["cpath specification"]=function(name) - getlibpaths() - return builtin["cpath specification"](name) + getlibpaths() + return builtin["cpath specification"](name) end methods["all in one fallback"]=function(name) - return builtin["all in one fallback"](name) + return builtin["all in one fallback"](name) end methods["not loaded"]=function(name) - if helpers.trace then - helpers.report("unable to locate '%s'",name or "?") - end - return nil + if helpers.trace then + helpers.report("unable to locate '%s'",name or "?") + end + return nil end local level=0 local used={} helpers.traceused=false function helpers.loaded(name) - local sequence=helpers.sequence - level=level+1 - for i=1,#sequence do - local method=sequence[i] - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) - end - local result,rest=methods[method](name) - if type(result)=="function" then - if helpers.trace then - helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) - end - if helpers.traceused then - used[#used+1]={ level=level,name=name } - end - level=level-1 - return result,rest - end + local sequence=helpers.sequence + level=level+1 + for i=1,#sequence do + local method=sequence[i] + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name) end - level=level-1 - return nil + local result,rest=methods[method](name) + if type(result)=="function" then + if helpers.trace then + helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name) + end + if helpers.traceused then + used[#used+1]={ level=level,name=name } + end + level=level-1 + return result,rest + end + end + level=level-1 + return nil end function helpers.showused() - local n=#used - if n>0 then - helpers.report("%s libraries loaded:",n) - helpers.report() - for i=1,n do - local u=used[i] - helpers.report("%i %a",u.level,u.name) - end - helpers.report() - end + local n=#used + if n>0 then + helpers.report("%s libraries loaded:",n) + helpers.report() + for i=1,n do + local u=used[i] + helpers.report("%i %a",u.level,u.name) + end + helpers.report() + end end function helpers.unload(name) - if helpers.trace then - if package.loaded[name] then - helpers.report("unloading, name '%s', %s",name,"done") - else - helpers.report("unloading, name '%s', %s",name,"not loaded") - end + if helpers.trace then + if package.loaded[name] then + helpers.report("unloading, name '%s', %s",name,"done") + else + helpers.report("unloading, name '%s', %s",name,"not loaded") end - package.loaded[name]=nil + end + package.loaded[name]=nil end table.insert(searchers,1,helpers.loaded) +if context then + package.path="" +end end -- of closure @@ -992,14 +1169,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true --- original size: 38582, stripped down to: 20518 +-- original size: 38434, stripped down to: 19310 if not modules then modules={} end modules ['l-lpeg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } lpeg=require("lpeg") local lpeg=lpeg @@ -1010,7 +1187,7 @@ 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 if setinspector then - setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) + setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns @@ -1033,7 +1210,7 @@ local underscore=P("_") local hexdigit=digit+lowercase+uppercase local hexdigits=hexdigit^1 local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") -local newline=P("\r")*(P("\n")+P(true))+P("\n") +local newline=P("\r")*(P("\n")+P(true))+P("\n") local escaped=P("\\")*anything local squote=P("'") local dquote=P('"') @@ -1042,9 +1219,9 @@ 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_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") @@ -1076,7 +1253,7 @@ patterns.utf8character=utf8character patterns.validutf8=validutf8char patterns.validutf8char=validutf8char local eol=S("\n\r") -local spacer=S(" \t\f\v") +local spacer=S(" \t\f\v") local whitespace=eol+spacer local nonspacer=1-spacer local nonwhitespace=1-whitespace @@ -1085,15 +1262,15 @@ 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)) local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0) local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0) -local e_collapser=Cs((whitespace^1*P(-1)/""+nonwhitespace^1+whitespace^1/" ")^0) +local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0) local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0) local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0) -local e_stripper=Cs((spacer^1*P(-1)/""+nonspacer^1+spacer^1/" ")^0) +local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0) local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0) patterns.stripper=stripper patterns.fullstripper=fullstripper @@ -1150,7 +1327,7 @@ patterns.cpfloat=sign^-1*patterns.cpunsigned patterns.number=patterns.float+patterns.integer patterns.cnumber=patterns.cfloat+patterns.integer patterns.cpnumber=patterns.cpfloat+patterns.integer -patterns.oct=zero*octdigits +patterns.oct=zero*octdigits patterns.octal=patterns.oct patterns.HEX=zero*P("X")*(digit+uppercase)^1 patterns.hex=zero*P("x")*(digit+lowercase)^1 @@ -1160,76 +1337,84 @@ patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)* 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/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) -local function anywhere(pattern) - return P { P(pattern)+1*V(1) } +patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0)) +function anywhere(pattern) + return (1-P(pattern))^0*P(pattern) end lpeg.anywhere=anywhere function lpeg.instringchecker(p) - p=anywhere(p) - return function(str) - return lpegmatch(p,str) and true or false - end + p=anywhere(p) + return function(str) + return lpegmatch(p,str) and true or false + end end function lpeg.splitter(pattern,action) + if action then return (((1-P(pattern))^1)/action+1)^0 + else + return (Cs((1-P(pattern))^1)+1)^0 + end end function lpeg.tsplitter(pattern,action) + if action then return Ct((((1-P(pattern))^1)/action+1)^0) + else + return Ct((Cs((1-P(pattern))^1)+1)^0) + end end local splitters_s,splitters_m,splitters_t={},{},{} local function splitat(separator,single) - local splitter=(single and splitters_s[separator]) or splitters_m[separator] - if not splitter then - separator=P(separator) - local other=C((1-separator)^0) - if single then - local any=anything - splitter=other*(separator*C(any^0)+"") - splitters_s[separator]=splitter - else - splitter=other*(separator*other)^0 - splitters_m[separator]=splitter - end + local splitter=(single and splitters_s[separator]) or splitters_m[separator] + if not splitter then + separator=P(separator) + local other=C((1-separator)^0) + if single then + local any=anything + splitter=other*(separator*C(any^0)+"") + splitters_s[separator]=splitter + else + splitter=other*(separator*other)^0 + splitters_m[separator]=splitter end - return splitter + end + return splitter end local function tsplitat(separator) - local splitter=splitters_t[separator] - if not splitter then - splitter=Ct(splitat(separator)) - splitters_t[separator]=splitter - end - return splitter + local splitter=splitters_t[separator] + if not splitter then + splitter=Ct(splitat(separator)) + splitters_t[separator]=splitter + end + return splitter end lpeg.splitat=splitat lpeg.tsplitat=tsplitat function string.splitup(str,separator) - if not separator then - separator="," - end - return lpegmatch(splitters_m[separator] or splitat(separator),str) + if not separator then + separator="," + end + return lpegmatch(splitters_m[separator] or splitat(separator),str) end local cache={} function lpeg.split(separator,str) + local c=cache[separator] + if not c then + c=tsplitat(separator) + cache[separator]=c + end + return lpegmatch(c,str) +end +function string.split(str,separator) + if separator then local c=cache[separator] if not c then - c=tsplitat(separator) - cache[separator]=c + c=tsplitat(separator) + cache[separator]=c end return lpegmatch(c,str) -end -function string.split(str,separator) - if separator then - local c=cache[separator] - if not c then - c=tsplitat(separator) - cache[separator]=c - end - return lpegmatch(c,str) - else - return { str } - end + else + return { str } + end end local spacing=patterns.spacer^0*newline local empty=spacing*Cc("") @@ -1239,505 +1424,463 @@ patterns.textline=content local linesplitter=tsplitat(newline) patterns.linesplitter=linesplitter function string.splitlines(str) - return lpegmatch(linesplitter,str) + return lpegmatch(linesplitter,str) end local cache={} function lpeg.checkedsplit(separator,str) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) end function string.checkedsplit(str,separator) - local c=cache[separator] - if not c then - separator=P(separator) - local other=C((1-separator)^1) - c=Ct(separator^0*other*(separator^1*other)^0) - cache[separator]=c - end - return lpegmatch(c,str) -end -local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end -local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end + local c=cache[separator] + if not c then + separator=P(separator) + local other=C((1-separator)^1) + c=Ct(separator^0*other*(separator^1*other)^0) + cache[separator]=c + end + return lpegmatch(c,str) +end +local function f2(s) local c1,c2=byte(s,1,2) return c1*64+c2-12416 end +local function f3(s) local c1,c2,c3=byte(s,1,3) return (c1*64+c2)*64+c3-925824 end local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4 patterns.utf8byte=utf8byte local cache={} function lpeg.stripper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs(((S(str)^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs(((str^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs(((S(str)^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs(((str^1)/""+1)^0) + end end local cache={} function lpeg.keeper(str) - if type(str)=="string" then - local s=cache[str] - if not s then - s=Cs((((1-S(str))^1)/""+1)^0) - cache[str]=s - end - return s - else - return Cs((((1-str)^1)/""+1)^0) + if type(str)=="string" then + local s=cache[str] + if not s then + s=Cs((((1-S(str))^1)/""+1)^0) + cache[str]=s end + return s + else + return Cs((((1-str)^1)/""+1)^0) + end end function lpeg.frontstripper(str) - return (P(str)+P(true))*Cs(anything^0) + return (P(str)+P(true))*Cs(anything^0) end function lpeg.endstripper(str) - return Cs((1-P(str)*endofstring)^0) + return Cs((1-P(str)*endofstring)^0) end function lpeg.replacer(one,two,makefunction,isutf) - local pattern - local u=isutf and utf8char or 1 - if type(one)=="table" then - local no=#one - local p=P(false) - if no==0 then - for k,v in next,one do - p=p+P(k)/v - end - pattern=Cs((p+u)^0) - elseif no==1 then - local o=one[1] - one,two=P(o[1]),o[2] - pattern=Cs((one/two+u)^0) - else - for i=1,no do - local o=one[i] - p=p+P(o[1])/o[2] - end - pattern=Cs((p+u)^0) - end - else - pattern=Cs((P(one)/(two or "")+u)^0) + local pattern + local u=isutf and utf8char or 1 + if type(one)=="table" then + local no=#one + local p=P(false) + if no==0 then + for k,v in next,one do + p=p+P(k)/v + end + pattern=Cs((p+u)^0) + elseif no==1 then + local o=one[1] + one,two=P(o[1]),o[2] + pattern=Cs((one/two+u)^0) + else + for i=1,no do + local o=one[i] + p=p+P(o[1])/o[2] + end + pattern=Cs((p+u)^0) end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=Cs((P(one)/(two or "")+u)^0) + end + if makefunction then + return function(str) + return lpegmatch(pattern,str) end + else + return pattern + end end function lpeg.finder(lst,makefunction,isutf) - local pattern - if type(lst)=="table" then - pattern=P(false) - if #lst==0 then - for k,v in next,lst do - pattern=pattern+P(k) - end - else - for i=1,#lst do - pattern=pattern+P(lst[i]) - end - end - else - pattern=P(lst) - end - if isutf then - pattern=((utf8char or 1)-pattern)^0*pattern + local pattern + if type(lst)=="table" then + pattern=P(false) + if #lst==0 then + for k,v in next,lst do + pattern=pattern+P(k) + end else - pattern=(1-pattern)^0*pattern + for i=1,#lst do + pattern=pattern+P(lst[i]) + end end - if makefunction then - return function(str) - return lpegmatch(pattern,str) - end - else - return pattern + else + pattern=P(lst) + end + 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) end + else + return pattern + end end local splitters_f,splitters_s={},{} function lpeg.firstofsplit(separator) - local splitter=splitters_f[separator] - if not splitter then - local pattern=P(separator) - splitter=C((1-pattern)^0) - splitters_f[separator]=splitter - end - return splitter + local splitter=splitters_f[separator] + if not splitter then + local pattern=P(separator) + splitter=C((1-pattern)^0) + splitters_f[separator]=splitter + end + return splitter end function lpeg.secondofsplit(separator) - local splitter=splitters_s[separator] - if not splitter then - local pattern=P(separator) - splitter=(1-pattern)^0*pattern*C(anything^0) - splitters_s[separator]=splitter - end - return splitter + local splitter=splitters_s[separator] + if not splitter then + 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 + 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 + 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 } + left,right=P(left),P(right) + return P { left*((1-left-right)+V(1))^0*right } end function lpeg.counter(pattern,action) - local n=0 - local pattern=(P(pattern)/function() n=n+1 end+anything)^0 - if action then - return function(str) n=0;lpegmatch(pattern,str);action(n) end - else - return function(str) n=0;lpegmatch(pattern,str);return n end - end -end -utf=utf or (unicode and unicode.utf8) or {} -local utfcharacters=utf and utf.characters or string.utfcharacters -local utfgmatch=utf and utf.gmatch -local utfchar=utf and utf.char -lpeg.UP=lpeg.P -if utfcharacters then - function lpeg.US(str) - local p=P(false) - for uc in utfcharacters(str) do - p=p+P(uc) - end - return p - end -elseif utfgmatch then - function lpeg.US(str) - local p=P(false) - for uc in utfgmatch(str,".") do - p=p+P(uc) - end - return p - end -else - function lpeg.US(str) - local p=P(false) - local f=function(uc) - p=p+P(uc) - end - lpegmatch((utf8char/f)^0,str) - return p - end -end -local range=utf8byte*utf8byte+Cc(false) -function lpeg.UR(str,more) - local first,last - if type(str)=="number" then - first=str - last=more or first - else - first,last=lpegmatch(range,str) - if not last then - return P(str) - end - end - if first==last then - return P(str) - elseif utfchar and (last-first<8) then - local p=P(false) - for i=first,last do - p=p+P(utfchar(i)) - end - return p - else - local f=function(b) - return b>=first and b<=last - end - return utf8byte/f - end + local n=0 + local pattern=(P(pattern)/function() n=n+1 end+anything)^0 + if action then + return function(str) n=0;lpegmatch(pattern,str);action(n) end + else + return function(str) n=0;lpegmatch(pattern,str);return n end + end end function lpeg.is_lpeg(p) - return p and lpegtype(p)=="pattern" + return p and lpegtype(p)=="pattern" end function lpeg.oneof(list,...) - if type(list)~="table" then - list={ list,... } - end - local p=P(list[1]) - for l=2,#list do - p=p+P(list[l]) - end - return p + if type(list)~="table" then + list={ list,... } + end + local p=P(list[1]) + for l=2,#list do + p=p+P(list[l]) + end + return p end local sort=table.sort local function copyindexed(old) - local new={} - for i=1,#old do - new[i]=old - end - return new + local new={} + for i=1,#old do + new[i]=old + end + return new end local function sortedkeys(tab) - local keys,s={},0 - for key,_ in next,tab do - s=s+1 - keys[s]=key - end - sort(keys) - return keys + local keys,s={},0 + for key,_ in next,tab do + s=s+1 + keys[s]=key + end + sort(keys) + return keys end function lpeg.append(list,pp,delayed,checked) - local p=pp - if #list>0 then - local keys=copyindexed(list) - sort(keys) - for i=#keys,1,-1 do - local k=keys[i] - if p then - p=P(k)+p - else - p=P(k) - end - end - elseif delayed then - local keys=sortedkeys(list) + local p=pp + if #list>0 then + local keys=copyindexed(list) + sort(keys) + for i=#keys,1,-1 do + local k=keys[i] + if p then + p=P(k)+p + else + p=P(k) + end + end + elseif delayed then + local keys=sortedkeys(list) + if p then + for i=1,#keys,1 do + local k=keys[i] + local v=list[k] + p=P(k)/list+p + end + else + for i=1,#keys do + local k=keys[i] + local v=list[k] if p then - for i=1,#keys,1 do - local k=keys[i] - local v=list[k] - p=P(k)/list+p - end + p=P(k)+p else - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)+p - else - p=P(k) - end - end - if p then - p=p/list - end + p=P(k) end - elseif checked then - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - if k==v then - p=P(k)+p - else - p=P(k)/v+p - end - else - if k==v then - p=P(k) - else - p=P(k)/v - end - end + end + if p then + p=p/list + end + end + elseif checked then + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + if k==v then + p=P(k)+p + else + p=P(k)/v+p end - else - local keys=sortedkeys(list) - for i=1,#keys do - local k=keys[i] - local v=list[k] - if p then - p=P(k)/v+p - else - p=P(k)/v - end + else + if k==v then + p=P(k) + else + p=P(k)/v end + end end - return p + else + local keys=sortedkeys(list) + for i=1,#keys do + local k=keys[i] + local v=list[k] + if p then + p=P(k)/v+p + else + p=P(k)/v + end + end + end + return p end local p_false=P(false) local p_true=P(true) local lower=utf and utf.lower or string.lower local upper=utf and utf.upper or string.upper function lpeg.setutfcasers(l,u) - lower=l or lower - upper=u or upper + lower=l or lower + upper=u or upper end local function make1(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+P(k)*p_true - elseif v==false then - else - p=p+P(k)*make1(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+P(k)*p_true + elseif v==false then + else + p=p+P(k)*make1(v,v[""]) + end end - return p + end + if rest then + p=p+p_true + end + return p end local function make2(t,rest) - local p=p_false - local keys=sortedkeys(t) - for i=1,#keys do - local k=keys[i] - if k~="" then - local v=t[k] - if v==true then - p=p+(P(lower(k))+P(upper(k)))*p_true - elseif v==false then - else - p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) - end - end - end - if rest then - p=p+p_true + local p=p_false + local keys=sortedkeys(t) + for i=1,#keys do + local k=keys[i] + if k~="" then + local v=t[k] + if v==true then + p=p+(P(lower(k))+P(upper(k)))*p_true + elseif v==false then + else + p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""]) + end end - return p -end -function lpeg.utfchartabletopattern(list,insensitive) - local tree={} - local n=#list - if n==0 then - for s in next,list do - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + end + if rest then + p=p+p_true + end + return p +end +local function utfchartabletopattern(list,insensitive) + local tree={} + local n=#list + if n==0 then + for s in next,list do + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end - else - for i=1,n do - local s=list[i] - local t=tree - local p,pk - for c in gmatch(s,".") do - if t==true then - t={ [c]=true,[""]=true } - p[pk]=t - p=t - t=false - elseif t==false then - t={ [c]=false } - p[pk]=t - p=t - t=false - else - local tc=t[c] - if not tc then - tc=false - t[c]=false - end - p=t - t=tc - end - pk=c - end - if t==false then - p[pk]=true - elseif t==true then - else - t[""]=true - end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end + end + else + for i=1,n do + local s=list[i] + local t=tree + local p,pk + for c in gmatch(s,".") do + if t==true then + t={ [c]=true,[""]=true } + p[pk]=t + p=t + t=false + elseif t==false then + t={ [c]=false } + p[pk]=t + p=t + t=false + else + local tc=t[c] + if not tc then + tc=false + t[c]=false + end + p=t + t=tc end + pk=c + end + if t==false then + p[pk]=true + elseif t==true then + else + t[""]=true + end end - return (insensitive and make2 or make1)(tree) + end + return (insensitive and make2 or make1)(tree) +end +lpeg.utfchartabletopattern=utfchartabletopattern +function lpeg.utfreplacer(list,insensitive) + local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0) + return function(str) + return lpegmatch(pattern,str) or str + end end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) - local m=n%step - local d=floor(n/step) - if d>0 then - local v=V(tostring(step)) - local s=result.start - for i=1,d do - if s then - s=v*s - else - s=v - end - end - result.start=s - end - if step>1 and result.start then - local v=V(tostring(step/2)) - result[tostring(step)]=v*v - end - if step>0 then - return nextstep(m,step/2,result) - else - return result + local m=n%step + local d=floor(n/step) + if d>0 then + local v=V(tostring(step)) + local s=result.start + for i=1,d do + if s then + s=v*s + else + s=v + end end + result.start=s + end + if step>1 and result.start then + local v=V(tostring(step/2)) + result[tostring(step)]=v*v + end + if step>0 then + return nextstep(m,step/2,result) + else + return result + end end function lpeg.times(pattern,n) - return P(nextstep(n,2^16,{ "start",["1"]=pattern })) -end -local trailingzeros=zero^0*-digit -local case_1=period*trailingzeros/"" -local case_2=period*(digit-trailingzeros)^1*(trailingzeros/"") -local number=digits*(case_1+case_2) -local stripper=Cs((number+1)^0) -lpeg.patterns.stripzeros=stripper + return P(nextstep(n,2^16,{ "start",["1"]=pattern })) +end +do + local trailingzeros=zero^0*-digit + local stripper=Cs(( + digits*( + period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"") + )+1 + )^0) + lpeg.patterns.stripzeros=stripper + local nonzero=digit-zero + local trailingzeros=zero^1*endofstring + local stripper=Cs((1-period)^0*( + period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring + )) + lpeg.patterns.stripzero=stripper +end local byte_to_HEX={} local byte_to_hex={} local byte_to_dec={} local hex_to_byte={} for i=0,255 do - local H=format("%02X",i) - local h=format("%02x",i) - local d=format("%03i",i) - local c=char(i) - byte_to_HEX[c]=H - byte_to_hex[c]=h - byte_to_dec[c]=d - hex_to_byte[h]=c - hex_to_byte[H]=c + local H=format("%02X",i) + local h=format("%02x",i) + local d=format("%03i",i) + local c=char(i) + byte_to_HEX[c]=H + byte_to_hex[c]=h + byte_to_dec[c]=d + hex_to_byte[h]=c + hex_to_byte[H]=c end local hextobyte=P(2)/hex_to_byte local bytetoHEX=P(1)/byte_to_HEX @@ -1756,32 +1899,47 @@ patterns.bytestoHEX=bytestoHEX patterns.bytestohex=bytestohex patterns.bytestodec=bytestodec function string.toHEX(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestoHEX,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestoHEX,s) + end end function string.tohex(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestohex,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestohex,s) + end end function string.todec(s) - if not s or s=="" then - return s - else - return lpegmatch(bytestodec,s) - end + if not s or s=="" then + return s + else + return lpegmatch(bytestodec,s) + end end function string.tobytes(s) - if not s or s=="" then - return s - else - return lpegmatch(hextobytes,s) - end + if not s or s=="" then + return s + else + return lpegmatch(hextobytes,s) + end +end +local patterns={} +local function containsws(what) + local p=patterns[what] + if not p then + local p1=P(what)*(whitespace+endofstring)*Cc(true) + local p2=whitespace*P(p1) + p=P(p1)+P(1-p2)^0*p2+Cc(false) + patterns[what]=p + end + return p +end +lpeg.containsws=containsws +function string.containsws(str,what) + return lpegmatch(patterns[what] or containsws(what),str) end @@ -1791,14 +1949,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-function"] = package.loaded["l-function"] or true --- original size: 361, stripped down to: 322 +-- original size: 361, stripped down to: 317 if not modules then modules={} end modules ['l-functions']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } functions=functions or {} function functions.dummy() end @@ -1810,14 +1968,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-string"] = package.loaded["l-string"] or true --- original size: 6461, stripped down to: 3341 +-- original size: 6461, stripped down to: 3255 if not modules then modules={} end modules ['l-string']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local string=string local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower @@ -1825,25 +1983,25 @@ local lpegmatch,patterns=lpeg.match,lpeg.patterns local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote function string.unquoted(str) - return lpegmatch(unquoted,str) or str + return lpegmatch(unquoted,str) or str end function string.quoted(str) - return format("%q",str) + return format("%q",str) end function string.count(str,pattern) - local n=0 - for _ in gmatch(str,pattern) do - n=n+1 - end - return n + local n=0 + for _ in gmatch(str,pattern) do + n=n+1 + end + return n end function string.limit(str,n,sentinel) - if #str>n then - sentinel=sentinel or "..." - return sub(str,1,(n-#sentinel))..sentinel - else - return str - end + if #str>n then + sentinel=sentinel or "..." + return sub(str,1,(n-#sentinel))..sentinel + else + return str + end end local stripper=patterns.stripper local fullstripper=patterns.fullstripper @@ -1851,81 +2009,81 @@ local collapser=patterns.collapser local nospacer=patterns.nospacer local longtostring=patterns.longtostring function string.strip(str) - return str and lpegmatch(stripper,str) or "" + return str and lpegmatch(stripper,str) or "" end function string.fullstrip(str) - return str and lpegmatch(fullstripper,str) or "" + return str and lpegmatch(fullstripper,str) or "" end function string.collapsespaces(str) - return str and lpegmatch(collapser,str) or "" + return str and lpegmatch(collapser,str) or "" end function string.nospaces(str) - return str and lpegmatch(nospacer,str) or "" + return str and lpegmatch(nospacer,str) or "" end function string.longtostring(str) - return str and lpegmatch(longtostring,str) or "" + return str and lpegmatch(longtostring,str) or "" end local pattern=P(" ")^0*P(-1) function string.is_empty(str) - if not str or str=="" then - return true - else - return lpegmatch(pattern,str) and true or false - end + if not str or str=="" then + return true + else + return lpegmatch(pattern,str) and true or false + end end local anything=patterns.anything local allescapes=Cc("%")*S(".-+%?()[]*") -local someescapes=Cc("%")*S(".-+%()[]") -local matchescapes=Cc(".")*S("*?") +local someescapes=Cc("%")*S(".-+%()[]") +local matchescapes=Cc(".")*S("*?") local pattern_a=Cs ((allescapes+anything )^0 ) local pattern_b=Cs ((someescapes+matchescapes+anything )^0 ) local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") ) function string.escapedpattern(str,simple) - return lpegmatch(simple and pattern_b or pattern_a,str) + return lpegmatch(simple and pattern_b or pattern_a,str) end function string.topattern(str,lowercase,strict) - if str=="" or type(str)~="string" then - return ".*" - elseif strict then - str=lpegmatch(pattern_c,str) - else - str=lpegmatch(pattern_b,str) - end - if lowercase then - return lower(str) - else - return str - end + if str=="" or type(str)~="string" then + return ".*" + elseif strict then + str=lpegmatch(pattern_c,str) + else + str=lpegmatch(pattern_b,str) + end + if lowercase then + return lower(str) + else + return str + end end function string.valid(str,default) - return (type(str)=="string" and str~="" and str) or default or nil + return (type(str)=="string" and str~="" and str) or default or nil end string.itself=function(s) return s end local pattern_c=Ct(C(1)^0) local pattern_b=Ct((C(1)/byte)^0) function string.totable(str,bytes) - return lpegmatch(bytes and pattern_b or pattern_c,str) + return lpegmatch(bytes and pattern_b or pattern_c,str) end local replacer=lpeg.replacer("@","%%") function string.tformat(fmt,...) - return format(lpegmatch(replacer,fmt),...) + return format(lpegmatch(replacer,fmt),...) end string.quote=string.quoted string.unquote=string.unquoted if not string.bytetable then - local limit=5000 - function string.bytetable(str) - local n=#str - if n>limit then - local t={ byte(str,1,limit) } - for i=limit+1,n do - t[i]=byte(str,i) - end - return t - else - return { byte(str,1,n) } - end + local limit=5000 + function string.bytetable(str) + local n=#str + if n>limit then + local t={ byte(str,1,limit) } + for i=limit+1,n do + t[i]=byte(str,i) + end + return t + else + return { byte(str,1,n) } end + end end @@ -1935,166 +2093,172 @@ do -- create closure to overcome 200 locals limit package.loaded["l-table"] = package.loaded["l-table"] or true --- original size: 40197, stripped down to: 23561 +-- original size: 41298, stripped down to: 21498 if not modules then modules={} end modules ['l-table']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select local table,string=table,string -local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove +local concat,sort=table.concat,table.sort local format,lower,dump=string.format,string.lower,string.dump local getmetatable,setmetatable=getmetatable,setmetatable -local getinfo=debug.getinfo local lpegmatch,patterns=lpeg.match,lpeg.patterns local floor=math.floor local stripper=patterns.stripper function table.getn(t) - return t and #t + return t and #t end function table.strip(tab) - local lst,l={},0 - for i=1,#tab do - local s=lpegmatch(stripper,tab[i]) or "" - if s=="" then - else - l=l+1 - lst[l]=s - end + local lst={} + local l=0 + for i=1,#tab do + local s=lpegmatch(stripper,tab[i]) or "" + if s=="" then + else + l=l+1 + lst[l]=s end - return lst + end + return lst end function table.keys(t) - if t then - local keys,k={},0 - for key in next,t do - k=k+1 - keys[k]=key - end - return keys - else - return {} + if t then + local keys={} + local k=0 + for key in next,t do + k=k+1 + keys[k]=key end + return keys + else + return {} + end end local function compare(a,b) - local ta=type(a) - if ta=="number" then - local tb=type(b) - if ta==tb then - return a<b - elseif tb=="string" then - return tostring(a)<b - end - elseif ta=="string" then - local tb=type(b) - if ta==tb then - return a<b - else - return a<tostring(b) - end + local ta=type(a) + if ta=="number" then + local tb=type(b) + if ta==tb then + return a<b + elseif tb=="string" then + return tostring(a)<b end - return tostring(a)<tostring(b) + elseif ta=="string" then + local tb=type(b) + if ta==tb then + return a<b + else + return a<tostring(b) + end + end + return tostring(a)<tostring(b) end local function sortedkeys(tab) - if tab then - local srt,category,s={},0,0 - for key in next,tab do - s=s+1 - srt[s]=key - if category==3 then - elseif category==1 then - if type(key)~="string" then - category=3 - end - elseif category==2 then - if type(key)~="number" then - category=3 - end - else - local tkey=type(key) - if tkey=="string" then - category=1 - elseif tkey=="number" then - category=2 - else - category=3 - end - end - end - if s<2 then - elseif category==3 then - sort(srt,compare) + if tab then + local srt={} + local category=0 + local s=0 + for key in next,tab do + s=s+1 + srt[s]=key + if category==3 then + elseif category==1 then + if type(key)~="string" then + category=3 + end + elseif category==2 then + if type(key)~="number" then + category=3 + end + else + local tkey=type(key) + if tkey=="string" then + category=1 + elseif tkey=="number" then + category=2 else - sort(srt) + category=3 end - return srt + end + end + if s<2 then + elseif category==3 then + sort(srt,compare) else - return {} + sort(srt) end + return srt + else + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="string" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + 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 - if s>1 then - sort(srt) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if type(key)=="number" then + s=s+1 + srt[s]=key + end end + if s>1 then + sort(srt) + end + return srt + else + return {} + end end local function sortedhashkeys(tab,cmp) - if tab then - local srt,s={},0 - for key in next,tab do - if key then - s=s+1 - srt[s]=key - end - end - if s>1 then - sort(srt,cmp) - end - return srt - else - return {} + if tab then + local srt={} + local s=0 + for key in next,tab do + if key then + s=s+1 + srt[s]=key + end + end + if s>1 then + sort(srt,cmp) end + return srt + else + return {} + end end function table.allkeys(t) - local keys={} - for k,v in next,t do - for k in next,v do - keys[k]=true - end + local keys={} + for k,v in next,t do + for k in next,v do + keys[k]=true end - return sortedkeys(keys) + end + return sortedkeys(keys) end table.sortedkeys=sortedkeys table.sortedhashonly=sortedhashonly @@ -2102,907 +2266,944 @@ table.sortedindexonly=sortedindexonly table.sortedhashkeys=sortedhashkeys local function nothing() end local function sortedhash(t,cmp) - if t then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local m=#s - if m==1 then - return next,t - elseif m>0 then - local n=0 - return function() - if n<m then - n=n+1 - local k=s[n] - return k,t[k] - end - end + if t then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local m=#s + if m==1 then + return next,t + elseif m>0 then + local n=0 + return function() + if n<m then + n=n+1 + local k=s[n] + return k,t[k] end + end end - return nothing + end + return nothing end table.sortedhash=sortedhash table.sortedpairs=sortedhash function table.append(t,list) - local n=#t - for i=1,#list do - n=n+1 - t[n]=list[i] - end - return t + local n=#t + for i=1,#list do + n=n+1 + t[n]=list[i] + end + return t end function table.prepend(t,list) - local nl=#list - local nt=nl+#t - for i=#t,1,-1 do - t[nt]=t[i] - nt=nt-1 - end - for i=1,#list do - t[i]=list[i] - end - return t + local nl=#list + local nt=nl+#t + for i=#t,1,-1 do + t[nt]=t[i] + nt=nt-1 + end + for i=1,#list do + t[i]=list[i] + end + return t end function table.merge(t,...) - t=t or {} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + if not t then + t={} + end + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.merged(...) - local t={} - for i=1,select("#",...) do - for k,v in next,(select(i,...)) do - t[k]=v - end + local t={} + for i=1,select("#",...) do + for k,v in next,(select(i,...)) do + t[k]=v end - return t + end + return t end function table.imerge(t,...) - local nt=#t - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - nt=nt+1 - t[nt]=nst[j] - end + local nt=#t + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + nt=nt+1 + t[nt]=nst[j] end - return t + end + return t end function table.imerged(...) - local tmp,ntmp={},0 - for i=1,select("#",...) do - local nst=select(i,...) - for j=1,#nst do - ntmp=ntmp+1 - tmp[ntmp]=nst[j] - end + local tmp={} + local ntmp=0 + for i=1,select("#",...) do + local nst=select(i,...) + for j=1,#nst do + ntmp=ntmp+1 + tmp[ntmp]=nst[j] end - return tmp + end + return tmp end local function fastcopy(old,metatabletoo) - if old then - local new={} - for k,v in next,old do - if type(v)=="table" then - new[k]=fastcopy(v,metatabletoo) - else - new[k]=v - end - end - if metatabletoo then - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + if type(v)=="table" then + new[k]=fastcopy(v,metatabletoo) + else + new[k]=v + end + end + if metatabletoo then + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end end + return new + else + return {} + end end local function copy(t,tables) - tables=tables or {} - local tcopy={} - if not tables[t] then - tables[t]=tcopy - end - for i,v in next,t do - if type(i)=="table" then - if tables[i] then - i=tables[i] - else - i=copy(i,tables) - end - end - if type(v)~="table" then - tcopy[i]=v - elseif tables[v] then - tcopy[i]=tables[v] - else - tcopy[i]=copy(v,tables) - end + if not tables then + tables={} + end + local tcopy={} + if not tables[t] then + tables[t]=tcopy + end + for i,v in next,t do + if type(i)=="table" then + if tables[i] then + i=tables[i] + else + i=copy(i,tables) + end end - local mt=getmetatable(t) - if mt then - setmetatable(tcopy,mt) + if type(v)~="table" then + tcopy[i]=v + elseif tables[v] then + tcopy[i]=tables[v] + else + tcopy[i]=copy(v,tables) end - return tcopy + end + local mt=getmetatable(t) + if mt then + setmetatable(tcopy,mt) + end + return tcopy end table.fastcopy=fastcopy table.copy=copy function table.derive(parent) - local child={} - if parent then - setmetatable(child,{ __index=parent }) - end - return child + local child={} + if parent then + setmetatable(child,{ __index=parent }) + end + return child end function table.tohash(t,value) - local h={} - if t then - if value==nil then value=true end - for _,v in next,t do - h[v]=value - end + local h={} + if t then + if value==nil then value=true end + for _,v in next,t do + h[v]=value end - return h + end + return h end function table.fromhash(t) - local hsh,h={},0 - for k,v in next,t do - if v then - h=h+1 - hsh[h]=k - end + local hsh={} + local h=0 + for k,v in next,t do + if v then + h=h+1 + hsh[h]=k end - return hsh + end + return hsh end local noquotes,hexify,handle,compact,inline,functions,metacheck 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', + '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 is_simple_table(t,hexify) - local nt=#t - if nt>0 then - local n=0 - for _,v in next,t do - n=n+1 - if type(v)=="table" then - return nil - end + local nt=#t + if nt>0 then + local n=0 + for _,v in next,t do + n=n+1 + if type(v)=="table" then + return nil + end + end + local haszero=rawget(t,0) + if n==nt then + local tt={} + for i=1,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i]=format("0x%X",v) + else + tt[i]=v + end + elseif tv=="string" then + tt[i]=format("%q",v) + elseif tv=="boolean" then + tt[i]=v and "true" or "false" + else + return nil end - local haszero=rawget(t,0) - if n==nt then - local tt={} - for i=1,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i]=format("0x%X",v) - else - tt[i]=v - end - elseif tv=="string" then - tt[i]=format("%q",v) - elseif tv=="boolean" then - tt[i]=v and "true" or "false" - else - return nil - end - end - return tt - elseif haszero and (n==nt+1) then - local tt={} - for i=0,nt do - local v=t[i] - local tv=type(v) - if tv=="number" then - if hexify then - tt[i+1]=format("0x%X",v) - else - tt[i+1]=v - end - elseif tv=="string" then - tt[i+1]=format("%q",v) - elseif tv=="boolean" then - tt[i+1]=v and "true" or "false" - else - return nil - end - end - tt[1]="[0] = "..tt[1] - return tt + end + return tt + elseif haszero and (n==nt+1) then + local tt={} + for i=0,nt do + local v=t[i] + local tv=type(v) + if tv=="number" then + if hexify then + tt[i+1]=format("0x%X",v) + else + tt[i+1]=v + end + elseif tv=="string" then + tt[i+1]=format("%q",v) + elseif tv=="boolean" then + tt[i+1]=v and "true" or "false" + else + return nil end + end + tt[1]="[0] = "..tt[1] + return tt end - return nil + end + return nil end table.is_simple_table=is_simple_table local propername=patterns.propername local function dummy() end local function do_serialize(root,name,depth,level,indexed) - if level>0 then - depth=depth.." " - if indexed then - handle(format("%s{",depth)) + if level>0 then + depth=depth.." " + if indexed then + handle(format("%s{",depth)) + else + local tn=type(name) + if tn=="number" then + if hexify then + handle(format("%s[0x%X]={",depth,name)) else - local tn=type(name) - if tn=="number" then - if hexify then - handle(format("%s[0x%X]={",depth,name)) - else - handle(format("%s[%s]={",depth,name)) - end - elseif tn=="string" then - if noquotes and not reserved[name] and lpegmatch(propername,name) then - handle(format("%s%s={",depth,name)) - else - handle(format("%s[%q]={",depth,name)) - end - elseif tn=="boolean" then - handle(format("%s[%s]={",depth,name and "true" or "false")) - else - handle(format("%s{",depth)) - end + handle(format("%s[%s]={",depth,name)) end + elseif tn=="string" then + if noquotes and not reserved[name] and lpegmatch(propername,name) then + handle(format("%s%s={",depth,name)) + else + handle(format("%s[%q]={",depth,name)) + end + elseif tn=="boolean" then + handle(format("%s[%s]={",depth,name and "true" or "false")) + else + handle(format("%s{",depth)) + end end - if root and next(root)~=nil then - local first,last=nil,0 - if compact then - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end - end - if last>0 then - first=1 - end + end + if root and next(root)~=nil then + local first=nil + local last=0 + if compact then + last=#root + for k=1,last do + if rawget(root,k)==nil then + last=k-1 + break 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 compact and first and tk=="number" and k>=first and k<=last then - if tv=="number" then - if hexify then - handle(format("%s 0x%X,",depth,v)) - else - handle(format("%s %s,",depth,v)) - end - elseif tv=="string" then - handle(format("%s %q,",depth,v)) - elseif tv=="table" then - if next(v)==nil then - handle(format("%s {},",depth)) - elseif inline then - local st=is_simple_table(v,hexify) - if st then - handle(format("%s { %s },",depth,concat(st,", "))) - else - do_serialize(v,k,depth,level+1,true) - end - else - do_serialize(v,k,depth,level+1,true) - end - 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))) - else - handle(format('%s "function",',depth)) - end - else - handle(format("%s %q,",depth,tostring(v))) - end - elseif k=="__p__" then - if false then - handle(format("%s __p__=nil,",depth)) - end - elseif tv=="number" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=0x%X,",depth,k,v)) - else - handle(format("%s [%s]=%s,",depth,k,v)) - end - elseif tk=="boolean" then - if hexify then - handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) - else - handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) - end - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - if hexify then - handle(format("%s %s=0x%X,",depth,k,v)) - else - handle(format("%s %s=%s,",depth,k,v)) - end - else - if hexify then - handle(format("%s [%q]=0x%X,",depth,k,v)) - else - handle(format("%s [%q]=%s,",depth,k,v)) - end - end - elseif tv=="string" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,v)) - else - handle(format("%s [%s]=%q,",depth,k,v)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) - elseif tk~="string" then - 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 - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={},",depth,k)) - else - handle(format("%s [%s]={},",depth,k)) - end - elseif tk=="boolean" then - handle(format("%s [%s]={},",depth,k and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={},",depth,k)) - else - handle(format("%s [%q]={},",depth,k)) - end - elseif inline then - local st=is_simple_table(v,hexify) - if st then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) - end - elseif tk=="boolean" then - handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s={ %s },",depth,k,concat(st,", "))) - else - handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) - end - else - do_serialize(v,k,depth,level+1) - end - else - do_serialize(v,k,depth,level+1) - end - elseif tv=="boolean" then - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) - else - 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),v and "true" or "false")) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%s,",depth,k,v and "true" or "false")) - else - handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) - end - elseif tv=="function" then - if functions then - local f=getinfo(v).what=="C" and dump(dummy) or dump(v) - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=load(%q),",depth,k,f)) - else - handle(format("%s [%s]=load(%q),",depth,k,f)) - end - elseif tk=="boolean" then - handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=load(%q),",depth,k,f)) - else - handle(format("%s [%q]=load(%q),",depth,k,f)) - end - end + end + if last>0 then + first=1 + end + 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 compact and first and tk=="number" and k>=first and k<=last then + if tv=="number" then + if hexify then + handle(format("%s 0x%X,",depth,v)) + else + handle(format("%s %s,",depth,v)) + end + elseif tv=="string" then + handle(format("%s %q,",depth,v)) + elseif tv=="table" then + if next(v)==nil then + handle(format("%s {},",depth)) + elseif inline then + local st=is_simple_table(v,hexify) + if st then + handle(format("%s { %s },",depth,concat(st,", "))) else - if tk=="number" then - if hexify then - handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) - else - handle(format("%s [%s]=%q,",depth,k,tostring(v))) - end - elseif tk=="boolean" then - handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) - elseif tk~="string" then - elseif noquotes and not reserved[k] and lpegmatch(propername,k) then - handle(format("%s %s=%q,",depth,k,tostring(v))) - else - handle(format("%s [%q]=%q,",depth,k,tostring(v))) - end + do_serialize(v,k,depth,level+1,true) end + else + do_serialize(v,k,depth,level+1,true) + end + 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))) + else + handle(format('%s "function",',depth)) + end + else + handle(format("%s %q,",depth,tostring(v))) end - end - if level>0 then - handle(format("%s},",depth)) - end -end -local function serialize(_handle,root,name,specification) - local tname=type(name) - if type(specification)=="table" then - noquotes=specification.noquotes - hexify=specification.hexify - handle=_handle or specification.handle or print - functions=specification.functions - compact=specification.compact - inline=specification.inline and compact - metacheck=specification.metacheck - if functions==nil then - functions=true - end - if compact==nil then - compact=true - end - if inline==nil then - inline=compact - end - if metacheck==nil then - metacheck=true + elseif k=="__p__" then + if false then + handle(format("%s __p__=nil,",depth)) end - else - noquotes=false - hexify=false - handle=_handle or print - compact=true - inline=true - functions=true - metacheck=true - end - if tname=="string" then - if name=="return" then - handle("return {") + elseif tv=="number" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=0x%X,",depth,k,v)) + else + handle(format("%s [%s]=%s,",depth,k,v)) + end + elseif tk=="boolean" then + if hexify then + handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) + else + handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) + end + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + if hexify then + handle(format("%s %s=0x%X,",depth,k,v)) + else + handle(format("%s %s=%s,",depth,k,v)) + end + else + if hexify then + handle(format("%s [%q]=0x%X,",depth,k,v)) + else + handle(format("%s [%q]=%s,",depth,k,v)) + end + end + elseif tv=="string" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,v)) + else + handle(format("%s [%s]=%q,",depth,k,v)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,v)) else - handle(name.."={") + handle(format("%s [%q]=%q,",depth,k,v)) end - elseif tname=="number" then - if hexify then - handle(format("[0x%X]={",name)) + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={},",depth,k)) + else + handle(format("%s [%s]={},",depth,k)) + end + elseif tk=="boolean" then + handle(format("%s [%s]={},",depth,k and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={},",depth,k)) + else + handle(format("%s [%q]={},",depth,k)) + end + elseif inline then + local st=is_simple_table(v,hexify) + if st then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) + end + elseif tk=="boolean" then + handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s={ %s },",depth,k,concat(st,", "))) + else + handle(format("%s [%q]={ %s },",depth,k,concat(st,", "))) + end + else + do_serialize(v,k,depth,level+1) + end else - handle("["..name.."]={") + do_serialize(v,k,depth,level+1) end - elseif tname=="boolean" then - if name then - handle("return {") + elseif tv=="boolean" then + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) + else + 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),v and "true" or "false")) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else - handle("{") + handle(format("%s [%q]=%s,",depth,k,v and "true" or "false")) end - else - handle("t={") - end - if root then - if metacheck and getmetatable(root) then - local dummy=root._w_h_a_t_e_v_e_r_ - root._w_h_a_t_e_v_e_r_=nil + elseif tv=="function" then + if functions then + local getinfo=debug and debug.getinfo + if getinfo then + local f=getinfo(v).what=="C" and dump(dummy) or dump(v) + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=load(%q),",depth,k,f)) + else + handle(format("%s [%s]=load(%q),",depth,k,f)) + end + elseif tk=="boolean" then + handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=load(%q),",depth,k,f)) + else + handle(format("%s [%q]=load(%q),",depth,k,f)) + end + end end - if next(root)~=nil then - do_serialize(root,name,"",0) + else + if tk=="number" then + if hexify then + handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) + else + handle(format("%s [%s]=%q,",depth,k,tostring(v))) + end + elseif tk=="boolean" then + handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) + elseif tk~="string" then + elseif noquotes and not reserved[k] and lpegmatch(propername,k) then + handle(format("%s %s=%q,",depth,k,tostring(v))) + else + handle(format("%s [%q]=%q,",depth,k,tostring(v))) end + end end - handle("}") + end + if level>0 then + handle(format("%s},",depth)) + end end -function table.serialize(root,name,specification) - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s +local function serialize(_handle,root,name,specification) + local tname=type(name) + if type(specification)=="table" then + noquotes=specification.noquotes + hexify=specification.hexify + handle=_handle or specification.handle or print + functions=specification.functions + compact=specification.compact + inline=specification.inline and compact + metacheck=specification.metacheck + if functions==nil then + functions=true + end + if compact==nil then + compact=true + end + if inline==nil then + inline=compact + end + if metacheck==nil then + metacheck=true + end + else + noquotes=false + hexify=false + handle=_handle or print + compact=true + inline=true + functions=true + metacheck=true + end + if tname=="string" then + if name=="return" then + handle("return {") + else + handle(name.."={") + end + elseif tname=="number" then + if hexify then + handle(format("[0x%X]={",name)) + else + handle("["..name.."]={") + end + elseif tname=="boolean" then + if name then + handle("return {") + else + handle("{") + end + else + handle("t={") + end + if root then + if metacheck and 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)~=nil then + do_serialize(root,name,"",0) end - serialize(flush,root,name,specification) - return concat(t,"\n") + end + handle("}") +end +function table.serialize(root,name,specification) + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + end + serialize(flush,root,name,specification) + return concat(t,"\n") end table.tohandle=serialize local maxtab=2*1024 function table.tofile(filename,root,name,specification) - local f=io.open(filename,'w') - if f then - if maxtab>1 then - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s - if n>maxtab then - f:write(concat(t,"\n"),"\n") - t,n={},0 - end - end - serialize(flush,root,name,specification) - f:write(concat(t,"\n"),"\n") - else - local function flush(s) - f:write(s,"\n") - end - serialize(flush,root,name,specification) + local f=io.open(filename,'w') + if f then + if maxtab>1 then + local t={} + local n=0 + local function flush(s) + n=n+1 + t[n]=s + if n>maxtab then + f:write(concat(t,"\n"),"\n") + t={} + n=0 end - f:close() - io.flush() + end + serialize(flush,root,name,specification) + f:write(concat(t,"\n"),"\n") + else + local function flush(s) + f:write(s,"\n") + end + serialize(flush,root,name,specification) end + f:close() + io.flush() + end end local function flattened(t,f,depth) - if f==nil then - f={} - depth=0xFFFF - elseif tonumber(f) then - depth=f - f={} - elseif not depth then - depth=0xFFFF - end - for k,v in next,t do - if type(k)~="number" then - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end - end + if f==nil then + f={} + depth=0xFFFF + elseif tonumber(f) then + depth=f + f={} + elseif not depth then + depth=0xFFFF + end + for k,v in next,t do + if type(k)~="number" then + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v + end end - for k=1,#t do - local v=t[k] - if depth>0 and type(v)=="table" then - flattened(v,f,depth-1) - else - f[#f+1]=v - end + end + for k=1,#t do + local v=t[k] + if depth>0 and type(v)=="table" then + flattened(v,f,depth-1) + else + f[#f+1]=v end - return f + end + return f end table.flattened=flattened local function collapsed(t,f,h) - if f==nil then - f={} - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsed(v,f,h) - elseif not h[v] then - f[#f+1]=v - h[v]=true - end + if f==nil then + f={} + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsed(v,f,h) + elseif not h[v] then + f[#f+1]=v + h[v]=true end - return f + end + return f end local function collapsedhash(t,h) - if h==nil then - h={} - end - for k=1,#t do - local v=t[k] - if type(v)=="table" then - collapsedhash(v,h) - else - h[v]=true - end + if h==nil then + h={} + end + for k=1,#t do + local v=t[k] + if type(v)=="table" then + collapsedhash(v,h) + else + h[v]=true end - return h + end + return h end -table.collapsed=collapsed +table.collapsed=collapsed table.collapsedhash=collapsedhash local function unnest(t,f) - if not f then - f={} - end - for i=1,#t do - local v=t[i] - if type(v)=="table" then - if type(v[1])=="table" then - unnest(v,f) - else - f[#f+1]=v - end - else - f[#f+1]=v - end + if not f then + f={} + end + for i=1,#t do + local v=t[i] + if type(v)=="table" then + if type(v[1])=="table" then + unnest(v,f) + else + f[#f+1]=v + end + else + f[#f+1]=v end - return f + end + return f end function table.unnest(t) - return unnest(t) + return unnest(t) end local function are_equal(a,b,n,m) - if a==b then - return true - elseif a and b and #a==#b then - n=n or 1 - m=m or #a - for i=n,m do - local ai,bi=a[i],b[i] - if ai==bi then - elseif type(ai)=="table" and type(bi)=="table" then - if not are_equal(ai,bi) then - return false - end - else - return false - end + if a==b then + return true + elseif a and b and #a==#b then + if not n then + n=1 + end + if not m then + m=#a + end + for i=n,m do + local ai,bi=a[i],b[i] + if ai==bi then + elseif type(ai)=="table" and type(bi)=="table" then + if not are_equal(ai,bi) then + return false end - return true - else + else return false + end end + return true + else + return false + end end local function identical(a,b) - if a~=b then - for ka,va in next,a do - local vb=b[ka] - if va==vb then - elseif type(va)=="table" and type(vb)=="table" then - if not identical(va,vb) then - return false - end - else - return false - end - end + if a~=b then + for ka,va in next,a do + local vb=b[ka] + if va==vb then + elseif type(va)=="table" and type(vb)=="table" then + if not identical(va,vb) then + return false + end + else + return false + end end - return true + end + return true end table.identical=identical table.are_equal=are_equal local function sparse(old,nest,keeptables) - local new={} - for k,v in next,old do - if not (v=="" or v==false) then - if nest and type(v)=="table" then - v=sparse(v,nest) - if keeptables or next(v)~=nil then - new[k]=v - end - else - new[k]=v - end - end + local new={} + for k,v in next,old do + if not (v=="" or v==false) then + if nest and type(v)=="table" then + v=sparse(v,nest) + if keeptables or next(v)~=nil then + new[k]=v + end + else + new[k]=v + end end - return new + end + return new end table.sparse=sparse function table.compact(t) - return sparse(t,true,true) + return sparse(t,true,true) end function table.contains(t,v) - if t then - for i=1,#t do - if t[i]==v then - return i - end - end + if t then + for i=1,#t do + if t[i]==v then + return i + end end - return false + end + return false end function table.count(t) - local n=0 - for k,v in next,t do - n=n+1 - end - return n + local n=0 + for k,v in next,t do + n=n+1 + end + return n end function table.swapped(t,s) - local n={} - if s then - for k,v in next,s do - n[k]=v - end + local n={} + if s then + for k,v in next,s do + n[k]=v end - for k,v in next,t do - n[v]=k - end - return n + end + for k,v in next,t do + n[v]=k + end + return n end function table.hashed(t) - for i=1,#t do - t[t[i]]=i - end - return t + for i=1,#t do + t[t[i]]=i + end + return t end function table.mirrored(t) - local n={} - for k,v in next,t do - n[v]=k - n[k]=v - end - return n + local n={} + for k,v in next,t do + n[v]=k + n[k]=v + end + return n end function table.reversed(t) - if t then - local tt,tn={},#t - if tn>0 then - local ttn=0 - for i=tn,1,-1 do - ttn=ttn+1 - tt[ttn]=t[i] - end - end - return tt + if t then + local tt={} + local tn=#t + if tn>0 then + local ttn=0 + for i=tn,1,-1 do + ttn=ttn+1 + tt[ttn]=t[i] + end end + return tt + end end function table.reverse(t) - if t then - local n=#t - for i=1,floor(n/2) do - local j=n-i+1 - t[i],t[j]=t[j],t[i] - end - return t + if t then + local n=#t + local m=n+1 + for i=1,floor(n/2) do + local j=m-i + t[i],t[j]=t[j],t[i] end + return t + end end -function table.sequenced(t,sep,simple) - if not t then - return "" +local function sequenced(t,sep,simple) + if not t then + return "" + elseif type(t)=="string" then + return t + end + local n=#t + local s={} + if n>0 then + for i=1,n do + local v=t[i] + if type(v)=="table" then + s[i]="{"..sequenced(v,sep,simple).."}" + else + s[i]=tostring(t[i]) + end end - local n=#t - local s={} - if n>0 then - for i=1,n do - s[i]=tostring(t[i]) + else + n=0 + for k,v in sortedhash(t) do + if simple then + if v==true then + n=n+1 + s[n]=k + elseif v and v~="" then + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) + end end - else - n=0 - for k,v in sortedhash(t) do - if simple then - if v==true then - n=n+1 - s[n]=k - elseif v and v~="" then - n=n+1 - s[n]=k.."="..tostring(v) - end - else - n=n+1 - s[n]=k.."="..tostring(v) - end + else + n=n+1 + if type(v)=="table" then + s[n]=k.."={"..sequenced(v,sep,simple).."}" + else + s[n]=k.."="..tostring(v) end + end end - return concat(s,sep or " | ") + end + return concat(s,sep or " | ") end +table.sequenced=sequenced function table.print(t,...) - if type(t)~="table" then - print(tostring(t)) - else - serialize(print,t,...) - end + if type(t)~="table" then + print(tostring(t)) + else + serialize(print,t,...) + end end if setinspector then - setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) + setinspector("table",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) } + return { unpack(t,i,j) } end function table.is_empty(t) - return not t or next(t)==nil + return not t or next(t)==nil end function table.has_one_entry(t) - return t and next(t,next(t))==nil + return t and next(t,next(t))==nil end function table.loweredkeys(t) - local l={} - for k,v in next,t do - l[lower(k)]=v - end - return l + local l={} + for k,v in next,t do + l[lower(k)]=v + end + return l end function table.unique(old) - local hash={} - local new={} - local n=0 - for i=1,#old do - local oi=old[i] - if not hash[oi] then - n=n+1 - new[n]=oi - hash[oi]=true - end - end - return new + local hash={} + local new={} + local n=0 + for i=1,#old do + local oi=old[i] + if not hash[oi] then + n=n+1 + new[n]=oi + hash[oi]=true + end + end + return new end function table.sorted(t,...) - sort(t,...) - return 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 {} + if t then + local values={} + local keys={} + local 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 function table.filtered(t,pattern,sort,cmp) - if t and type(pattern)=="string" then - if sort then - local s - if cmp then - s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) - else - s=sortedkeys(t) - end - local n=0 - local m=#s - local function kv(s) - while n<m do - n=n+1 - local k=s[n] - if find(k,pattern) then - return k,t[k] - end - end - end - return kv,s - else - local n=next(t) - local function iterator() - while n~=nil do - local k=n - n=next(t,k) - if find(k,pattern) then - return k,t[k] - end - end - end - return iterator,t + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end end - else - return nothing + end + return kv,s + else + local n=next(t) + local function iterator() + while n~=nil do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t end + else + return nothing + end end if not table.move then - function table.move(a1,f,e,t,a2) - if a2 and a1~=a2 then - for i=f,e do - a2[t]=a1[i] - t=t+1 - end - return a2 - else - t=t+e-f - for i=e,f,-1 do - a1[t]=a1[i] - t=t-1 - end - return a1 - end + function table.move(a1,f,e,t,a2) + if a2 and a1~=a2 then + for i=f,e do + a2[t]=a1[i] + t=t+1 + end + return a2 + else + t=t+e-f + for i=e,f,-1 do + a1[t]=a1[i] + t=t-1 + end + return a1 end + end end @@ -3012,14 +3213,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-io"] = package.loaded["l-io"] or true --- original size: 11823, stripped down to: 6945 +-- original size: 11823, stripped down to: 6325 if not modules then modules={} end modules ['l-io']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local io=io local open,flush,write,read=io.open,io.flush,io.write,io.read @@ -3027,334 +3228,334 @@ local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local type=type if string.find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator="\\",";" + io.fileseparator,io.pathseparator="\\",";" else - io.fileseparator,io.pathseparator="/",":" + io.fileseparator,io.pathseparator="/",":" end local large=0x01000000 local medium=0x00100000 local small=0x00020000 local function readall(f) - local size=f:seek("end") - if size>0 then - f:seek("set",0) - return f:read(size) - else - return "" - end + local size=f:seek("end") + if size>0 then + f:seek("set",0) + return f:read(size) + else + return "" + end end io.readall=readall function io.loaddata(filename,textmode) - local f=open(filename,(textmode and 'r') or 'rb') - if f then - local size=f:seek("end") - local data=nil - if size>0 then - f:seek("set",0) - data=f:read(size) - end - f:close() - return data + local f=open(filename,(textmode and 'r') or 'rb') + if f then + local size=f:seek("end") + local data=nil + if size>0 then + f:seek("set",0) + data=f:read(size) end + f:close() + return data + end end function io.copydata(source,target,action) - local f=open(source,"rb") - if f then - local g=open(target,"wb") - if g then - local size=f:seek("end") - if size>0 then - f:seek("set",0) - local data=f:read(size) - if action then - data=action(data) - end - if data then - g:write(data) - end - end - g:close() + local f=open(source,"rb") + if f then + local g=open(target,"wb") + if g then + local size=f:seek("end") + if size>0 then + f:seek("set",0) + local data=f:read(size) + if action then + data=action(data) end - f:close() - flush() + if data then + g:write(data) + end + end + g:close() end + f:close() + flush() + end end function io.savedata(filename,data,joiner) - local f=open(filename,"wb") - if f then - if type(data)=="table" then - f:write(concat(data,joiner or "")) - elseif type(data)=="function" then - data(f) - else - f:write(data or "") - end - f:close() - flush() - return true + local f=open(filename,"wb") + if f then + if type(data)=="table" then + f:write(concat(data,joiner or "")) + elseif type(data)=="function" then + data(f) else - return false + f:write(data or "") end + f:close() + flush() + return true + else + return false + end end if fio and fio.readline then - local readline=fio.readline - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=readline(f) - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + local readline=fio.readline + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=readline(f) + if line then + lines[i]=line else - local line=readline(f) - f:close() - if line and #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=readline(f) + f:close() + if line and #line>0 then + return line + end end + end else - function io.loadlines(filename,n) - local f=open(filename,'r') - if not f then - elseif n then - local lines={} - for i=1,n do - local line=f:read("*lines") - if line then - lines[i]=line - else - break - end - end - f:close() - lines=concat(lines,"\n") - if #lines>0 then - return lines - end + function io.loadlines(filename,n) + local f=open(filename,'r') + if not f then + elseif n then + local lines={} + for i=1,n do + local line=f:read("*lines") + if line then + lines[i]=line else - local line=f:read("*line") or "" - f:close() - if #line>0 then - return line - end + break end + end + f:close() + lines=concat(lines,"\n") + if #lines>0 then + return lines + end + else + local line=f:read("*line") or "" + f:close() + if #line>0 then + return line + end end + end end function io.loadchunk(filename,n) - local f=open(filename,'rb') - if f then - local data=f:read(n or 1024) - f:close() - if #data>0 then - return data - end + local f=open(filename,'rb') + if f then + local data=f:read(n or 1024) + f:close() + if #data>0 then + return data end + end end function io.exists(filename) - local f=open(filename) - if f==nil then - return false - else - f:close() - return true - end + local f=open(filename) + if f==nil then + return false + else + f:close() + return true + end end function io.size(filename) - local f=open(filename) - if f==nil then - return 0 - else - local s=f:seek("end") - f:close() - return s - end + local f=open(filename) + if f==nil then + return 0 + else + local s=f:seek("end") + f:close() + return s + end end local function noflines(f) - if type(f)=="string" then - local f=open(filename) - if f then - local n=f and noflines(f) or 0 - f:close() - return n - else - return 0 - end + if type(f)=="string" then + local f=open(filename) + if f then + local n=f and noflines(f) or 0 + f:close() + return n else - local n=0 - for _ in f:lines() do - n=n+1 - end - f:seek('set',0) - return n + return 0 + end + else + local n=0 + for _ in f:lines() do + n=n+1 end + f:seek('set',0) + return n + end end io.noflines=noflines local nextchar={ - [ 4]=function(f) - return f:read(1,1,1,1) - end, - [ 2]=function(f) - return f:read(1,1) - end, - [ 1]=function(f) - return f:read(1) - end, - [-2]=function(f) - local a,b=f:read(1,1) - return b,a - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - return d,c,b,a - end + [ 4]=function(f) + return f:read(1,1,1,1) + end, + [ 2]=function(f) + return f:read(1,1) + end, + [ 1]=function(f) + return f:read(1) + end, + [-2]=function(f) + local a,b=f:read(1,1) + return b,a + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + return d,c,b,a + end } function io.characters(f,n) - if f then - return nextchar[n or 1],f - end + if f then + return nextchar[n or 1],f + end end local nextbyte={ - [4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(a),byte(b),byte(c),byte(d) - end - end, - [3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(a),byte(b),byte(c) - end - end, - [2]=function(f) - local a,b=f:read(1,1) - if b then - return byte(a),byte(b) - end - end, - [1]=function (f) - local a=f:read(1) - if a then - return byte(a) - end - end, - [-2]=function (f) - local a,b=f:read(1,1) - if b then - return byte(b),byte(a) - end - end, - [-3]=function(f) - local a,b,c=f:read(1,1,1) - if b then - return byte(c),byte(b),byte(a) - end - end, - [-4]=function(f) - local a,b,c,d=f:read(1,1,1,1) - if d then - return byte(d),byte(c),byte(b),byte(a) - end + [4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(a),byte(b),byte(c),byte(d) + end + end, + [3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(a),byte(b),byte(c) + end + end, + [2]=function(f) + local a,b=f:read(1,1) + if b then + return byte(a),byte(b) + end + end, + [1]=function (f) + local a=f:read(1) + if a then + return byte(a) + end + end, + [-2]=function (f) + local a,b=f:read(1,1) + if b then + return byte(b),byte(a) + end + end, + [-3]=function(f) + local a,b,c=f:read(1,1,1) + if b then + return byte(c),byte(b),byte(a) + end + end, + [-4]=function(f) + local a,b,c,d=f:read(1,1,1,1) + if d then + return byte(d),byte(c),byte(b),byte(a) end + end } function io.bytes(f,n) - if f then - return nextbyte[n or 1],f - else - return nil,nil - end + if f then + return nextbyte[n or 1],f + else + return nil,nil + end end function io.ask(question,default,options) - while true do - write(question) - if options then - write(format(" [%s]",concat(options,"|"))) - end - if default then - write(format(" [%s]",default)) - end - write(format(" ")) - flush() - local answer=read() - answer=gsub(answer,"^%s*(.*)%s*$","%1") - if answer=="" and default then - return default - elseif not options then - return answer - else - for k=1,#options do - if options[k]==answer then - return answer - end - end - local pattern="^"..answer - for k=1,#options do - local v=options[k] - if find(v,pattern) then - return v - end - end + while true do + write(question) + if options then + write(format(" [%s]",concat(options,"|"))) + end + if default then + write(format(" [%s]",default)) + end + write(format(" ")) + flush() + local answer=read() + answer=gsub(answer,"^%s*(.*)%s*$","%1") + if answer=="" and default then + return default + elseif not options then + return answer + else + for k=1,#options do + if options[k]==answer then + return answer end + end + local pattern="^"..answer + for k=1,#options do + local v=options[k] + if find(v,pattern) then + return v + end + end end + end end local function readnumber(f,n,m) - if m then - f:seek("set",n) - n=m - end - if n==1 then - return byte(f:read(1)) - elseif n==2 then - local a,b=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==3 then - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==4 then - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==8 then - local a,b=readnumber(f,4),readnumber(f,4) - return 0x100*a+b - elseif n==12 then - local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) - return 0x10000*a+0x100*b+c - elseif n==-2 then - local b,a=byte(f:read(2),1,2) - return 0x100*a+b - elseif n==-3 then - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c - elseif n==-4 then - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d - elseif n==-8 then - local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) - return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h - else - return 0 - end + if m then + f:seek("set",n) + n=m + end + if n==1 then + return byte(f:read(1)) + elseif n==2 then + local a,b=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==3 then + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==4 then + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==8 then + local a,b=readnumber(f,4),readnumber(f,4) + return 0x100*a+b + elseif n==12 then + local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4) + return 0x10000*a+0x100*b+c + elseif n==-2 then + local b,a=byte(f:read(2),1,2) + return 0x100*a+b + elseif n==-3 then + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c + elseif n==-4 then + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d + elseif n==-8 then + local h,g,f,e,d,c,b,a=byte(f:read(8),1,8) + return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h + else + return 0 + end end io.readnumber=readnumber function io.readstring(f,n,m) - if m then - f:seek("set",n) - n=m - end - local str=gsub(f:read(n),"\000","") - return str + if m then + f:seek("set",n) + n=m + end + local str=gsub(f:read(n),"\000","") + return str end @@ -3364,14 +3565,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-number"] = package.loaded["l-number"] or true --- original size: 5645, stripped down to: 2253 +-- original size: 5720, stripped down to: 2176 if not modules then modules={} end modules ['l-number']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tostring,tonumber=tostring,tonumber local format,floor,match,rep=string.format,math.floor,string.match,string.rep @@ -3381,99 +3582,107 @@ local floor=math.floor number=number or {} local number=number if bit32 then - local bextract=bit32.extract - local t={ - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - "0","0","0","0","0","0","0","0", - } - function number.tobitstring(b,m) - local n=32 - for i=0,31 do - local v=bextract(b,i) - local k=32-i - if v==1 then - n=k - t[k]="1" - else - t[k]="0" - end - end - if m then - m=33-m*8 - if m<1 then - m=1 - end - return concat(t,"",m) - elseif n<8 then - return concat(t) - elseif n<16 then - return concat(t,"",9) - elseif n<24 then - return concat(t,"",17) - else - return concat(t,"",25) - end + local bextract=bit32.extract + local t={ + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + "0","0","0","0","0","0","0","0", + } + function number.tobitstring(b,m,w) + if not w then + w=32 + end + local n=w + for i=0,w-1 do + local v=bextract(b,i) + local k=w-i + if v==1 then + n=k + t[k]="1" + else + t[k]="0" + end + end + if w then + return concat(t,"",1,w) + elseif m then + m=33-m*8 + if m<1 then + m=1 + end + return concat(t,"",1,m) + elseif n<8 then + return concat(t) + elseif n<16 then + return concat(t,"",9) + elseif n<24 then + return concat(t,"",17) + else + return concat(t,"",25) end + end else - function number.tobitstring(n,m) - if n>0 then - local t={} - while n>0 do - insert(t,1,n%2>0 and 1 or 0) - n=floor(n/2) - end - local nn=8-#t%8 - if nn>0 and nn<8 then - for i=1,nn do - insert(t,1,0) - end - end - if m then - m=m*8-#t - if m>0 then - insert(t,1,rep("0",m)) - end - end - return concat(t) - elseif m then - rep("00000000",m) - else - return "00000000" + function number.tobitstring(n,m) + if n>0 then + local t={} + while n>0 do + insert(t,1,n%2>0 and 1 or 0) + n=floor(n/2) + end + local nn=8-#t%8 + if nn>0 and nn<8 then + for i=1,nn do + insert(t,1,0) + end + end + if m then + m=m*8-#t + if m>0 then + insert(t,1,rep("0",m)) end + end + return concat(t) + elseif m then + rep("00000000",m) + else + return "00000000" end + end end function number.valid(str,default) - return tonumber(str) or default or nil + return tonumber(str) or default or nil end function number.toevenhex(n) - local s=format("%X",n) - if #s%2==0 then - return s - else - return "0"..s - end + local s=format("%X",n) + if #s%2==0 then + return s + else + return "0"..s + end end function number.bytetodecimal(b) - local d=floor(b*100/255+0.5) - if d>100 then - return 100 - elseif d<-100 then - return -100 - else - return d - end + local d=floor(b*100/255+0.5) + if d>100 then + return 100 + elseif d<-100 then + return -100 + else + return d + end end function number.decimaltobyte(d) - local b=floor(d*255/100+0.5) - if b>255 then - return 255 - elseif b<-255 then - return -255 - else - return b - end + local b=floor(d*255/100+0.5) + if b>255 then + return 255 + elseif b<-255 then + return -255 + else + return b + end +end +function number.idiv(i,d) + return floor(i/d) end @@ -3483,14 +3692,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-set"] = package.loaded["l-set"] or true --- original size: 1923, stripped down to: 1133 +-- original size: 1923, stripped down to: 1044 if not modules then modules={} end modules ['l-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } set=set or {} local nums={} @@ -3499,54 +3708,54 @@ local concat=table.concat local next,type=next,type set.create=table.tohash function set.tonumber(t) - if next(t) then - local s="" - for k,v in next,t do - if v then - s=s.." "..k - end - end - local n=nums[s] - if not n then - n=#tabs+1 - tabs[n]=t - nums[s]=n - end - return n - else - return 0 + if next(t) then + local s="" + for k,v in next,t do + if v then + s=s.." "..k + end end + local n=nums[s] + if not n then + n=#tabs+1 + tabs[n]=t + nums[s]=n + end + return n + else + return 0 + end end function set.totable(n) - if n==0 then - return {} - else - return tabs[n] or {} - end + if n==0 then + return {} + else + return tabs[n] or {} + end end function set.tolist(n) - if n==0 or not tabs[n] then - return "" - else - local t,n={},0 - for k,v in next,tabs[n] do - if v then - n=n+1 - t[n]=k - end - end - return concat(t," ") + if n==0 or not tabs[n] then + return "" + else + local t,n={},0 + for k,v in next,tabs[n] do + if v then + n=n+1 + t[n]=k + end end + return concat(t," ") + end end function set.contains(n,s) - if type(n)=="table" then - return n[s] - elseif n==0 then - return false - else - local t=tabs[n] - return t and t[s] - end + if type(n)=="table" then + return n[s] + elseif n==0 then + return false + else + local t=tabs[n] + return t and t[s] + end end @@ -3556,14 +3765,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-os"] = package.loaded["l-os"] or true --- original size: 16268, stripped down to: 9246 +-- original size: 19347, stripped down to: 10258 if not modules then modules={} end modules ['l-os']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local os=os local date,time=os.date,os.time @@ -3571,357 +3780,434 @@ local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string local concat=table.concat local random,ceil,randomseed=math.random,math.ceil,math.randomseed local rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring=rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring -math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) -randomseed(math.initialseed) -if not os.__getenv__ then - os.__getenv__=os.getenv - os.__setenv__=os.setenv - if os.env then - local osgetenv=os.getenv - local ossetenv=os.setenv - local osenv=os.env local _=osenv.PATH - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - if type(v)=="table" then - v=concat(v,";") - end - ossetenv(K,v) - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v - end +do + local selfdir=os.selfdir + if selfdir=="" then + selfdir=nil + end + if not selfdir then + if arg then + for i=1,#arg do + local a=arg[i] + if find(a,"^%-%-[c:]*texmfbinpath=") then + selfdir=gsub(a,"^.-=","") + break end - else - local ossetenv=os.setenv - local osgetenv=os.getenv - local osenv={} - function os.setenv(k,v) - if v==nil then - v="" - end - local K=upper(k) - osenv[K]=v - end - function os.getenv(k) - local K=upper(k) - local v=osenv[K] or osgetenv(K) or osgetenv(k) - if v=="" then - return nil - else - return v + end + end + if not selfdir then + selfdir=os.selfbin or "luatex" + if find(selfdir,"[/\\]") then + selfdir=gsub(selfdir,"[/\\][^/\\]*$","") + elseif os.getenv then + local path=os.getenv("PATH") + local name=gsub(selfdir,"^.*[/\\][^/\\]","") + local patt="[^:]+" + if os.type=="windows" then + patt="[^;]+" + name=name..".exe" + end + local isfile + if lfs then + local attributes=lfs.attributes + isfile=function(name) + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil + end + else + local open=io.open + isfile=function(name) + local f=open(name) + if f then + f:close() + return true end + end end - local function __index(t,k) - return os.getenv(k) - end - local function __newindex(t,k,v) - os.setenv(k,v) + for p in gmatch(path,patt) do + if isfile(p.."/"..name) then + selfdir=p + break + end end - os.env={} - setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end + os.selfdir=selfdir or "." + end +end +math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6)) +randomseed(math.initialseed) +if not os.__getenv__ then + os.__getenv__=os.getenv + os.__setenv__=os.setenv + if os.env then + local osgetenv=os.getenv + local ossetenv=os.setenv + local osenv=os.env local _=osenv.PATH + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + if type(v)=="table" then + v=concat(v,";") + end + ossetenv(K,v) + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + else + local ossetenv=os.setenv + local osgetenv=os.getenv + local osenv={} + function os.setenv(k,v) + if v==nil then + v="" + end + local K=upper(k) + osenv[K]=v + end + function os.getenv(k) + local K=upper(k) + local v=osenv[K] or osgetenv(K) or osgetenv(k) + if v=="" then + return nil + else + return v + end + end + local function __index(t,k) + return os.getenv(k) + end + local function __newindex(t,k,v) + os.setenv(k,v) + end + os.env={} + setmetatable(os.env,{ __index=__index,__newindex=__newindex } ) + end end local execute=os.execute local iopopen=io.popen local function resultof(command) - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - else - return "" - end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + else + return "" + end end os.resultof=resultof function os.pipeto(command) - return iopopen(command,"w") + return iopopen(command,"w") end if not io.fileseparator then - if find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" - else - io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" - end + if find(os.getenv("PATH"),";",1,true) then + io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows" + else + io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix" + end end os.type=os.type or (io.pathseparator==";" and "windows") or "unix" -os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" +os.name=os.name or (os.type=="windows" and "mswin" ) or "linux" if os.type=="windows" then - os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } + os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' } else - os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } + os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' } end local launchers={ - windows="start %s", - macosx="open %s", - unix="$BROWSER %s &> /dev/null &", + windows="start %s", + macosx="open %s", + unix="xdg-open %s &> /dev/null &", } function os.launch(str) - execute(format(launchers[os.name] or launchers.unix,str)) + execute(format(launchers[os.name] or launchers.unix,str)) end if not os.times then - function os.times() - return { - utime=os.gettimeofday(), - stime=0, - cutime=0, - cstime=0, - } - end + function os.times() + return { + utime=os.gettimeofday(), + stime=0, + cutime=0, + cstime=0, + } + end end local gettimeofday=os.gettimeofday or os.clock os.gettimeofday=gettimeofday local startuptime=gettimeofday() function os.runtime() - return gettimeofday()-startuptime + return gettimeofday()-startuptime end 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 + local r=resolvers[k] + return r and r(t,k) or nil end }) local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or "" if platform~="" then - os.platform=platform + os.platform=platform elseif os.type=="windows" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or "" - if find(architecture,"AMD64",1,true) then - platform="win64" - else - platform="mswin" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("PROCESSOR_ARCHITECTURE") or "" + local platform="" + if find(architecture,"AMD64",1,true) then + platform="win64" + else + platform="mswin" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="linux" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="linux-64" - elseif find(architecture,"ppc",1,true) then - platform="linux-ppc" - else - platform="linux" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform=os.getenv("MTX_PLATFORM") or "" + local musl=find(os.selfdir or "","linuxmusl") + if platform~="" then + elseif find(architecture,"x86_64",1,true) then + platform=musl and "linuxmusl" or "linux-64" + elseif find(architecture,"ppc",1,true) then + platform="linux-ppc" + else + platform=musl and "linuxmusl" or "linux" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="macosx" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("echo $HOSTTYPE") or "" - if architecture=="" then - platform="osx-intel" - elseif find(architecture,"i386",1,true) then - platform="osx-intel" - elseif find(architecture,"x86_64",1,true) then - platform="osx-64" - else - platform="osx-ppc" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local architecture=resultof("echo $HOSTTYPE") or "" + local platform="" + if architecture=="" then + platform="osx-intel" + elseif find(architecture,"i386",1,true) then + platform="osx-intel" + elseif find(architecture,"x86_64",1,true) then + platform="osx-64" + else + platform="osx-ppc" + end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="sunos" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"sparc",1,true) then - platform="solaris-sparc" - else - platform="solaris-intel" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"sparc",1,true) then + platform="solaris-sparc" + else + platform="solaris-intel" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="freebsd" then - function resolvers.platform(t,k) - local platform,architecture="",resultof("uname -m") or "" - if find(architecture,"amd64",1,true) then - platform="freebsd-amd64" - else - platform="freebsd" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=resultof("uname -m") or "" + local platform="" + if find(architecture,"amd64",1,true) then + platform="freebsd-amd64" + else + platform="freebsd" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end elseif name=="kfreebsd" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="kfreebsd-amd64" - else - platform="kfreebsd-i386" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform + function resolvers.platform(t,k) + local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or "" + local platform="" + if find(architecture,"x86_64",1,true) then + platform="kfreebsd-amd64" + else + platform="kfreebsd-i386" end + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end else - function resolvers.platform(t,k) - local platform="linux" - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end + function resolvers.platform(t,k) + local platform="linux" + os.setenv("MTX_PLATFORM",platform) + os.platform=platform + return platform + end end os.newline=name=="windows" and "\013\010" or "\010" function resolvers.bits(t,k) - local bits=find(os.platform,"64",1,true) and 64 or 32 - os.bits=bits - return bits + 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", - random(0xFFFF),random(0xFFFF), - random(0x0FFF), - t[ceil(random(4))] or 8,random(0x0FFF), - random(0xFFFF), - random(0xFFFF),random(0xFFFF),random(0xFFFF) - ) + return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x", + random(0xFFFF),random(0xFFFF), + random(0x0FFF), + t[ceil(random(4))] or 8,random(0x0FFF), + random(0xFFFF), + random(0xFFFF),random(0xFFFF),random(0xFFFF) + ) end local d function os.timezone(delta) - d=d or tonumber(tonumber(date("%H")-date("!%H"))) - if delta then - if d>0 then - return format("+%02i:00",d) - else - return format("-%02i:00",-d) - end + d=d or tonumber(tonumber(date("%H")-date("!%H"))) + if delta then + if d>0 then + return format("+%02i:00",d) else - return 1 + return format("-%02i:00",-d) end + else + return 1 + end 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=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=format(timeformat,date(dateformat)) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=format(timeformat,date(dateformat)) + end + return lastdate end local dateformat="%Y-%m-%d %H:%M:%S" local lasttime=nil local lastdate=nil function os.localtime(t,default) - t=t and tonumber(t) or 0 - if t>0 then - elseif default then - return default - else - t=time() - end - if t~=lasttime then - lasttime=t - lastdate=date(dateformat,t) - end - return lastdate + t=t and tonumber(t) or 0 + if t>0 then + elseif default then + return default + else + t=time() + end + if t~=lasttime then + lasttime=t + lastdate=date(dateformat,t) + end + return lastdate end function os.converttime(t,default) - local t=tonumber(t) - if t and t>0 then - return date(dateformat,t) - else - return default or "-" - end + local t=tonumber(t) + if t and t>0 then + return date(dateformat,t) + else + return default or "-" + end end local memory={} local function which(filename) - local fullname=memory[filename] - if fullname==nil then - local suffix=file.suffix(filename) - local suffixes=suffix=="" and os.binsuffixes or { suffix } - for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do - local df=file.join(directory,filename) - for i=1,#suffixes do - local dfs=file.addsuffix(df,suffixes[i]) - if io.exists(dfs) then - fullname=dfs - break - end - end - end - if not fullname then - fullname=false + local fullname=memory[filename] + if fullname==nil then + local suffix=file.suffix(filename) + local suffixes=suffix=="" and os.binsuffixes or { suffix } + for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do + local df=file.join(directory,filename) + for i=1,#suffixes do + local dfs=file.addsuffix(df,suffixes[i]) + if io.exists(dfs) then + fullname=dfs + break end - memory[filename]=fullname + end end - return fullname + if not fullname then + fullname=false + end + memory[filename]=fullname + end + return fullname end os.which=which os.where=which function os.today() - return date("!*t") + return date("!*t") end function os.now() - return date("!%Y-%m-%d %H:%M:%S") + return date("!%Y-%m-%d %H:%M:%S") end if not os.sleep then - local socket=socket - function os.sleep(n) - if not socket then - socket=require("socket") - end - socket.sleep(n) + local socket=socket + function os.sleep(n) + if not socket then + socket=require("socket") end + socket.sleep(n) + end end local function isleapyear(year) - return (year%4==0) and (year%100~=0 or year%400==0) + return (year%4==0) and (year%100~=0 or year%400==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 + 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 + 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 + 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 +local osexit=os.exit +local exitcode=nil +function os.setexitcode(code) + exitcode=code +end +function os.exit(c) + if exitcode~=nil then + return osexit(exitcode) + end + if c~=nil then + return osexit(c) + end + return osexit() end @@ -3931,19 +4217,19 @@ do -- create closure to overcome 200 locals limit package.loaded["l-file"] = package.loaded["l-file"] or true --- original size: 21616, stripped down to: 10359 +-- original size: 21804, stripped down to: 9980 if not modules then modules={} end modules ['l-file']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } file=file or {} local file=file if not lfs then - lfs=optionalrequire("lfs") + lfs=optionalrequire("lfs") end local insert,concat=table.insert,table.concat local match,find,gmatch=string.match,string.find,string.gmatch @@ -3951,24 +4237,22 @@ local lpegmatch=lpeg.match local getcurrentdir,attributes=lfs.currentdir,lfs.attributes local checkedsplit=string.checkedsplit local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct -local tricky=S("/\\")*P(-1) local attributes=lfs.attributes -if sandbox then - sandbox.redefine(lfs.isfile,"lfs.isfile") - sandbox.redefine(lfs.isdir,"lfs.isdir") -end function lfs.isdir(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end + return attributes(name,"mode")=="directory" end function lfs.isfile(name) - return attributes(name,"mode")=="file" + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil end function lfs.isfound(name) - return attributes(name,"mode")=="file" and name or nil + local a=attributes(name,"mode") + return (a=="file" or a=="link") and name or nil +end +if sandbox then + sandbox.redefine(lfs.isfile,"lfs.isfile") + sandbox.redefine(lfs.isdir,"lfs.isdir") + sandbox.redefine(lfs.isfound,"lfs.isfound") end local colon=P(":") local period=P(".") @@ -3982,27 +4266,27 @@ local name=noperiod^1 local suffix=period/""*(1-period-slashes)^1*-1 local pattern=C((1-(slashes^1*noslashes^1*-1))^1)*P(1) local function pathpart(name,default) - return name and lpegmatch(pattern,name) or default or "" + return name and lpegmatch(pattern,name) or default or "" end local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1 local function basename(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes^1)^0*Cs((1-suffix)^1)*suffix^0 local function nameonly(name) - return name and lpegmatch(pattern,name) or name + return name and lpegmatch(pattern,name) or name end local pattern=(noslashes^0*slashes)^0*(noperiod^1*period)^1*C(noperiod^1)*-1 local function suffixonly(name) - return name and lpegmatch(pattern,name) or "" + return name and lpegmatch(pattern,name) or "" end local pattern=(noslashes^0*slashes)^0*noperiod^1*((period*C(noperiod^1))^1)*-1+Cc("") local function suffixesonly(name) - if name then - return lpegmatch(pattern,name) - else - return "" - end + if name then + return lpegmatch(pattern,name) + else + return "" + end end file.pathpart=pathpart file.basename=basename @@ -4011,7 +4295,7 @@ file.suffixonly=suffixonly file.suffix=suffixonly file.suffixesonly=suffixesonly file.suffixes=suffixesonly -file.dirname=pathpart +file.dirname=pathpart file.extname=suffixonly local drive=C(R("az","AZ"))*colon local path=C((noslashes^0*slashes)^0) @@ -4027,142 +4311,142 @@ local pattern_b=path*base*suffix local pattern_c=C(drive*path)*C(base*suffix) local pattern_d=path*rest function file.splitname(str,splitdrive) - if not str then - elseif splitdrive then - return lpegmatch(pattern_a,str) - else - return lpegmatch(pattern_b,str) - end + if not str then + elseif splitdrive then + return lpegmatch(pattern_a,str) + else + return lpegmatch(pattern_b,str) + end end function file.splitbase(str) - if str then - return lpegmatch(pattern_d,str) - else - return "",str - end + if str then + return lpegmatch(pattern_d,str) + else + return "",str + end end function file.nametotable(str,splitdrive) - if str then - local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) - if splitdrive then - return { - path=path, - drive=drive, - subpath=subpath, - name=name, - base=base, - suffix=suffix, - } - else - return { - path=path, - name=name, - base=base, - suffix=suffix, - } - end + if str then + local path,drive,subpath,name,base,suffix=lpegmatch(pattern_c,str) + if splitdrive then + return { + path=path, + drive=drive, + subpath=subpath, + name=name, + base=base, + suffix=suffix, + } + else + return { + path=path, + name=name, + base=base, + suffix=suffix, + } end + end end local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1) function file.removesuffix(name) - return name and lpegmatch(pattern,name) + return name and lpegmatch(pattern,name) end local suffix=period/""*(1-period-slashes)^1*-1 local pattern=Cs((noslashes^0*slashes^1)^0*((1-suffix)^1))*Cs(suffix) function file.addsuffix(filename,suffix,criterium) - if not filename or not suffix or suffix=="" then - return filename - elseif criterium==true then - return filename.."."..suffix - elseif not criterium then - local n,s=lpegmatch(pattern,filename) - if not s or s=="" then - return filename.."."..suffix - else + if not filename or not suffix or suffix=="" then + return filename + elseif criterium==true then + return filename.."."..suffix + elseif not criterium then + local n,s=lpegmatch(pattern,filename) + if not s or s=="" then + return filename.."."..suffix + else + return filename + end + else + local n,s=lpegmatch(pattern,filename) + if s and s~="" then + local t=type(criterium) + if t=="table" then + for i=1,#criterium do + if s==criterium[i] then return filename + end end - else - local n,s=lpegmatch(pattern,filename) - if s and s~="" then - local t=type(criterium) - if t=="table" then - for i=1,#criterium do - if s==criterium[i] then - return filename - end - end - elseif t=="string" then - if s==criterium then - return filename - end - end + elseif t=="string" then + if s==criterium then + return filename end - return (n or filename).."."..suffix + end end + return (n or filename).."."..suffix + end end local suffix=period*(1-period-slashes)^1*-1 local pattern=Cs((1-suffix)^0) function file.replacesuffix(name,suffix) - if name and suffix and suffix~="" then - return lpegmatch(pattern,name).."."..suffix - else - return name - end + if name and suffix and suffix~="" then + return lpegmatch(pattern,name).."."..suffix + else + return name + end end local reslasher=lpeg.replacer(P("\\"),"/") function file.reslash(str) - return str and lpegmatch(reslasher,str) + return str and lpegmatch(reslasher,str) end function file.is_writable(name) - if not name then - elseif lfs.isdir(name) then - name=name.."/m_t_x_t_e_s_t.tmp" - local f=io.open(name,"wb") - if f then - f:close() - os.remove(name) - return true - end - elseif lfs.isfile(name) then - local f=io.open(name,"ab") - if f then - f:close() - return true - end - else - local f=io.open(name,"ab") - if f then - f:close() - os.remove(name) - return true - end + if not name then + elseif lfs.isdir(name) then + name=name.."/m_t_x_t_e_s_t.tmp" + local f=io.open(name,"wb") + if f then + f:close() + os.remove(name) + return true end - return false + elseif lfs.isfile(name) then + local f=io.open(name,"ab") + if f then + f:close() + return true + end + else + local f=io.open(name,"ab") + if f then + f:close() + os.remove(name) + return true + end + end + return false end local readable=P("r")*Cc(true) function file.is_readable(name) - if name then - local a=attributes(name) - return a and lpegmatch(readable,a.permissions) or false - else - return false - end + if name then + local a=attributes(name) + return a and lpegmatch(readable,a.permissions) or false + else + return false + end end file.isreadable=file.is_readable file.iswritable=file.is_writable function file.size(name) - if name then - local a=attributes(name) - return a and a.size or 0 - else - return 0 - end + if name then + local a=attributes(name) + return a and a.size or 0 + else + return 0 + end end function file.splitpath(str,separator) - return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) + return str and checkedsplit(lpegmatch(reslasher,str),separator or io.pathseparator) end function file.joinpath(tab,separator) - return tab and concat(tab,separator or io.pathseparator) + return tab and concat(tab,separator or io.pathseparator) end local someslash=S("\\/") local stripper=Cs(P(fwslash)^0/""*reslasher) @@ -4172,30 +4456,30 @@ local hasroot=fwslash^1 local reslasher=lpeg.replacer(S("\\/"),"/") local deslasher=lpeg.replacer(S("\\/")^1,"/") function file.join(one,two,three,...) - if not two then - return one=="" and one or lpegmatch(reslasher,one) - end - if one=="" then - return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) - end - if lpegmatch(isnetwork,one) then - local one=lpegmatch(reslasher,one) - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return one..two - else - return one.."/"..two - end - elseif lpegmatch(isroot,one) then - local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) - if lpegmatch(hasroot,two) then - return two - else - return "/"..two - end - else - return lpegmatch(deslasher,concat({ one,two,three,... },"/")) - end + if not two then + return one=="" and one or lpegmatch(reslasher,one) + end + if one=="" then + return lpegmatch(stripper,three and concat({ two,three,... },"/") or two) + end + if lpegmatch(isnetwork,one) then + local one=lpegmatch(reslasher,one) + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return one..two + else + return one.."/"..two + end + elseif lpegmatch(isroot,one) then + local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two) + if lpegmatch(hasroot,two) then + return two + else + return "/"..two + end + else + return lpegmatch(deslasher,concat({ one,two,three,... },"/")) + end end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec @@ -4205,56 +4489,56 @@ 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 - return - end - if anchor==true and not lpegmatch(anchors,str) then - str=getcurrentdir().."/"..str - end - if str=="" or str=="." then - return "." - elseif lpegmatch(untouched,str) then - return lpegmatch(reslasher,str) - end - local starter,oldelements=lpegmatch(splitstarter,str) - local newelements={} - local i=#oldelements - while i>0 do - local element=oldelements[i] - if element=='.' then - elseif element=='..' then - local n=i-1 - while n>0 do - local element=oldelements[n] - if element~='..' and element~='.' then - oldelements[n]='.' - break - else - n=n-1 - end - end - if n<1 then - insert(newelements,1,'..') - end - elseif element~="" then - insert(newelements,1,element) - end - i=i-1 - end - if #newelements==0 then - return starter or "." - elseif starter then - return starter..concat(newelements,'/') - elseif lpegmatch(absolute,str) then - return "/"..concat(newelements,'/') - else - newelements=concat(newelements,'/') - if anchor=="." and find(str,"^%./") then - return "./"..newelements + if not str then + return + end + if anchor==true and not lpegmatch(anchors,str) then + str=getcurrentdir().."/"..str + end + if str=="" or str=="." then + return "." + elseif lpegmatch(untouched,str) then + return lpegmatch(reslasher,str) + end + local starter,oldelements=lpegmatch(splitstarter,str) + local newelements={} + local i=#oldelements + while i>0 do + local element=oldelements[i] + if element=='.' then + elseif element=='..' then + local n=i-1 + while n>0 do + local element=oldelements[n] + if element~='..' and element~='.' then + oldelements[n]='.' + break else - return newelements + n=n-1 end - end + end + if n<1 then + insert(newelements,1,'..') + end + elseif element~="" then + insert(newelements,1,element) + end + i=i-1 + end + if #newelements==0 then + return starter or "." + elseif starter then + return starter..concat(newelements,'/') + elseif lpegmatch(absolute,str) then + return "/"..concat(newelements,'/') + else + newelements=concat(newelements,'/') + if anchor=="." and find(str,"^%./") then + return "./"..newelements + else + return newelements + end + end end local validchars=R("az","09","AZ","--","..") local pattern_a=lpeg.replacer(1-validchars) @@ -4262,26 +4546,26 @@ local pattern_a=Cs((validchars+P(1)/"-")^1) local whatever=P("-")^0/"" local pattern_b=Cs(whatever*(1-whatever*-1)^1) function file.robustname(str,strict) - if str then - str=lpegmatch(pattern_a,str) or str - if strict then - return lpegmatch(pattern_b,str) or str - else - return str - end + if str then + str=lpegmatch(pattern_a,str) or str + if strict then + return lpegmatch(pattern_b,str) or str + else + return str end + end end local loaddata=io.loaddata local savedata=io.savedata file.readdata=loaddata file.savedata=savedata function file.copy(oldname,newname) - if oldname and newname then - local data=loaddata(oldname) - if data and data~="" then - savedata(newname,data) - end + if oldname and newname then + local data=loaddata(oldname) + if data and data~="" then + savedata(newname,data) end + end end local letter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4290,40 +4574,44 @@ local rootbased=fwslash+letter*colon lpeg.patterns.qualified=qualified lpeg.patterns.rootbased=rootbased function file.is_qualified_path(filename) - return filename and lpegmatch(qualified,filename)~=nil + return filename and lpegmatch(qualified,filename)~=nil end function file.is_rootbased_path(filename) - return filename and lpegmatch(rootbased,filename)~=nil + return filename and lpegmatch(rootbased,filename)~=nil end function file.strip(name,dir) - if name then - local b,a=match(name,"^(.-)"..dir.."(.*)$") - return a~="" and a or name - end + if name then + local b,a=match(name,"^(.-)"..dir.."(.*)$") + return a~="" and a or name + end end function lfs.mkdirs(path) - local full="" - for sub in gmatch(path,"(/*[^\\/]+)") do - full=full..sub - lfs.mkdir(full) - end + local full="" + for sub in gmatch(path,"(/*[^\\/]+)") do + full=full..sub + lfs.mkdir(full) + end end function file.withinbase(path) - local l=0 - if not find(path,"^/") then - path="/"..path + local l=0 + if not find(path,"^/") then + path="/"..path + end + for dir in gmatch(path,"/([^/]+)") do + if dir==".." then + l=l-1 + elseif dir~="." then + l=l+1 end - for dir in gmatch(path,"/([^/]+)") do - if dir==".." then - l=l-1 - elseif dir~="." then - l=l+1 - end - if l<0 then - return false - end + if l<0 then + return false end - return true + end + return true +end +local symlinkattributes=lfs.symlinkattributes +function lfs.readlink(name) + return symlinkattributes(name,"target") or nil end @@ -4333,51 +4621,51 @@ do -- create closure to overcome 200 locals limit package.loaded["l-gzip"] = package.loaded["l-gzip"] or true --- original size: 1211, stripped down to: 1002 +-- original size: 1211, stripped down to: 951 if not modules then modules={} end modules ['l-gzip']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not gzip then - return + return end local suffix,suffixes=file.suffix,file.suffixes function gzip.load(filename) - local f=io.open(filename,"rb") - if not f then - elseif suffix(filename)=="gz" then - f:close() - local g=gzip.open(filename,"rb") - if g then - local str=g:read("*all") - g:close() - return str - end - else - local str=f:read("*all") - f:close() - return str - end + local f=io.open(filename,"rb") + if not f then + elseif suffix(filename)=="gz" then + f:close() + local g=gzip.open(filename,"rb") + if g then + local str=g:read("*all") + g:close() + return str + end + else + local str=f:read("*all") + f:close() + return str + end end function gzip.save(filename,data) - if suffix(filename)~="gz" then - filename=filename..".gz" - end - local f=io.open(filename,"wb") - if f then - local s=zlib.compress(data or "",9,nil,15+16) - f:write(s) - f:close() - return #s - end + if suffix(filename)~="gz" then + filename=filename..".gz" + end + local f=io.open(filename,"wb") + if f then + local s=zlib.compress(data or "",9,nil,15+16) + f:write(s) + f:close() + return #s + end end function gzip.suffix(filename) - local suffix,extra=suffixes(filename) - local gzipped=extra=="gz" - return suffix,gzipped + local suffix,extra=suffixes(filename) + local gzipped=extra=="gz" + return suffix,gzipped end @@ -4387,87 +4675,119 @@ do -- create closure to overcome 200 locals limit package.loaded["l-md5"] = package.loaded["l-md5"] or true --- original size: 3309, stripped down to: 2314 +-- original size: 3309, stripped down to: 2218 if not modules then modules={} end modules ['l-md5']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not md5 then - md5=optionalrequire("md5") + md5=optionalrequire("md5") end if not md5 then - md5={ - sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, - sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, - } + md5={ + sum=function(str) print("error: md5 is not loaded (sum ignored)") return str end, + sumhexa=function(str) print("error: md5 is not loaded (sumhexa ignored)") return str end, + } end local md5,file=md5,file local gsub=string.gsub do - local patterns=lpeg and lpeg.patterns - if patterns then - local bytestoHEX=patterns.bytestoHEX - local bytestohex=patterns.bytestohex - local bytestodec=patterns.bytestodec - local lpegmatch=lpeg.match - local md5sum=md5.sum - if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end - if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end - if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end - md5.sumhexa=md5.hex - md5.sumHEXA=md5.HEX - end + local patterns=lpeg and lpeg.patterns + if patterns then + local bytestoHEX=patterns.bytestoHEX + local bytestohex=patterns.bytestohex + local bytestodec=patterns.bytestodec + local lpegmatch=lpeg.match + local md5sum=md5.sum + if not md5.HEX then function md5.HEX(str) if str then return lpegmatch(bytestoHEX,md5sum(str)) end end end + if not md5.hex then function md5.hex(str) if str then return lpegmatch(bytestohex,md5sum(str)) end end end + if not md5.dec then function md5.dec(str) if str then return lpegmatch(bytestodec,md5sum(str)) end end end + md5.sumhexa=md5.hex + md5.sumHEXA=md5.HEX + end end function file.needsupdating(oldname,newname,threshold) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime then - local newtime=lfs.attributes(newname,"modification") - if not newtime then - return true - elseif newtime>=oldtime then - return false - elseif oldtime-newtime<(threshold or 1) then - return false - else - return true - end - else - return false - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime then + local newtime=lfs.attributes(newname,"modification") + if not newtime then + return true + elseif newtime>=oldtime then + return false + elseif oldtime-newtime<(threshold or 1) then + return false + else + return true + end + else + return false + end end file.needs_updating=file.needsupdating function file.syncmtimes(oldname,newname) - local oldtime=lfs.attributes(oldname,"modification") - if oldtime and lfs.isfile(newname) then - lfs.touch(newname,oldtime,oldtime) - end + local oldtime=lfs.attributes(oldname,"modification") + if oldtime and lfs.isfile(newname) then + lfs.touch(newname,oldtime,oldtime) + end end function file.checksum(name) - if md5 then - local data=io.loaddata(name) - if data then - return md5.HEX(data) - end + if md5 then + local data=io.loaddata(name) + if data then + return md5.HEX(data) end - return nil + end + return nil end function file.loadchecksum(name) - if md5 then - local data=io.loaddata(name..".md5") - return data and (gsub(data,"%s","")) - end - return nil + if md5 then + local data=io.loaddata(name..".md5") + return data and (gsub(data,"%s","")) + end + return nil end function file.savechecksum(name,checksum) - if not checksum then checksum=file.checksum(name) end - if checksum then - io.savedata(name..".md5",checksum) - return checksum - end - return nil + if not checksum then checksum=file.checksum(name) end + if checksum then + io.savedata(name..".md5",checksum) + return checksum + end + return nil +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["l-sha"] = package.loaded["l-sha"] or true + +-- original size: 1085, stripped down to: 969 + +if not modules then modules={} end modules ['l-sha']={ + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" +} +if sha2 then + local lpegmatch=lpeg.match + local lpegpatterns=lpeg.patterns + local bytestohex=lpegpatterns.bytestohex + local bytestoHEX=lpegpatterns.bytestoHEX + local digest256=sha2.digest256 + local digest384=sha2.digest384 + local digest512=sha2.digest512 + sha2.hash256=function(str) return lpegmatch(bytestohex,digest256(str)) end + sha2.hash384=function(str) return lpegmatch(bytestohex,digest384(str)) end + sha2.hash512=function(str) return lpegmatch(bytestohex,digest512(str)) end + sha2.HASH256=function(str) return lpegmatch(bytestoHEX,digest256(str)) end + sha2.HASH384=function(str) return lpegmatch(bytestoHEX,digest384(str)) end + sha2.HASH512=function(str) return lpegmatch(bytestoHEX,digest512(str)) end end @@ -4477,14 +4797,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-url"] = package.loaded["l-url"] or true --- original size: 14755, stripped down to: 7236 +-- original size: 14755, stripped down to: 6981 if not modules then modules={} end modules ['l-url']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local char,format,byte=string.char,string.format,string.byte local concat=table.concat @@ -4497,14 +4817,14 @@ local url=url local unescapes={} local escapes={} setmetatable(unescapes,{ __index=function(t,k) - local v=char(tonumber(k,16)) - t[k]=v - return v + local v=char(tonumber(k,16)) + t[k]=v + return v end }) setmetatable(escapes,{ __index=function(t,k) - local v=format("%%%02X",byte(k)) - t[k]=v - return v + local v=format("%%%02X",byte(k)) + t[k]=v + return v end }) local colon=P(":") local qmark=P("?") @@ -4523,21 +4843,21 @@ local escaped=(plus/" ")+escapedchar local noslash=P("/")/"" local plustospace=P("+")/" " local decoder=Cs(( - plustospace+escapedchar+P("\r\n")/"\n"+P(1) - )^0 ) + plustospace+escapedchar+P("\r\n")/"\n"+P(1) + )^0 ) local encoder=Cs(( - R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar - )^0 ) + R("09","AZ","az")^1+S("-./_")^1+P(" ")/"+"+P("\n")/"\r\n"+unescapedchar + )^0 ) lpegpatterns.urldecoder=decoder lpegpatterns.urlencoder=encoder -function url.decode (str) return str and lpegmatch(decoder,str) or str end -function url.encode (str) return str and lpegmatch(encoder,str) or str end +function url.decode (str) return str and lpegmatch(decoder,str) or str end +function url.encode (str) return str and lpegmatch(encoder,str) or str end function url.unescape(str) return str and lpegmatch(unescaper,str) or str end local schemestr=Cs((escaped+(1-colon-slash-qmark-hash))^2) local authoritystr=Cs((escaped+(1- slash-qmark-hash))^0) -local pathstr=Cs((escaped+(1- qmark-hash))^0) -local querystr=Cs(((1- hash))^0) -local fragmentstr=Cs((escaped+(1- endofstring))^0) +local pathstr=Cs((escaped+(1- qmark-hash))^0) +local querystr=Cs(((1- hash))^0) +local fragmentstr=Cs((escaped+(1- endofstring))^0) local scheme=schemestr*colon+nothing local authority=slash*slash*authoritystr+nothing local path=slash*pathstr+nothing @@ -4555,19 +4875,19 @@ lpegpatterns.urlescaper=escaper lpegpatterns.urlunescaper=unescaper lpegpatterns.urlgetcleaner=getcleaner function url.unescapeget(str) - return lpegmatch(getcleaner,str) + return lpegmatch(getcleaner,str) end local function split(str) - return (type(str)=="string" and lpegmatch(parser,str)) or str + return (type(str)=="string" and lpegmatch(parser,str)) or str end local isscheme=schemestr*colon*slash*slash local function hasscheme(str) - if str then - local scheme=lpegmatch(isscheme,str) - return scheme~="" and scheme or false - else - return false - end + if str then + local scheme=lpegmatch(isscheme,str) + return scheme~="" and scheme or false + else + return false + end end local rootletter=R("az","AZ")+S("_-+") local separator=P("://") @@ -4577,161 +4897,161 @@ local barswapper=replacer("|",":") local backslashswapper=replacer("\\","/") local equal=P("=") local amp=P("&") -local key=Cs(((plustospace+escapedchar+1)-equal )^0) +local key=Cs(((plustospace+escapedchar+1)-equal )^0) local value=Cs(((plustospace+escapedchar+1)-amp-endofstring)^0) local splitquery=Cf (Ct("")*P { "sequence", - sequence=V("pair")*(amp*V("pair"))^0, - pair=Cg(key*equal*value), + sequence=V("pair")*(amp*V("pair"))^0, + pair=Cg(key*equal*value), },rawset) local userpart=(1-atsign-colon)^1 local serverpart=(1-colon)^1 local splitauthority=((Cs(userpart)*colon*Cs(userpart)+Cs(userpart)*Cc(nil))*atsign+Cc(nil)*Cc(nil))*Cs(serverpart)*(colon*(serverpart/tonumber)+Cc(nil)) local function hashed(str) - if not str or str=="" then - return { - scheme="invalid", - original=str, - } - end - local detailed=split(str) - local rawscheme="" - local rawquery="" - local somescheme=false - local somequery=false - if detailed then - rawscheme=detailed[1] - rawquery=detailed[4] - somescheme=rawscheme~="" - somequery=rawquery~="" - end - if not somescheme and not somequery then - return { - scheme="file", - authority="", - path=str, - query="", - fragment="", - original=str, - noscheme=true, - filename=str, - } - end - local authority=detailed[2] - local path=detailed[3] - local filename - local username - local password - local host - local port - if authority~="" then - username,password,host,port=lpegmatch(splitauthority,authority) - end - if authority=="" then - filename=path - elseif path=="" then - filename="" - else - filename=authority.."/"..path - end + if not str or str=="" then return { - scheme=rawscheme, - authority=authority, - path=path, - query=lpegmatch(unescaper,rawquery), - queries=lpegmatch(splitquery,rawquery), - fragment=detailed[5], - original=str, - noscheme=false, - filename=filename, - host=host, - port=port, + scheme="invalid", + original=str, } + end + local detailed=split(str) + local rawscheme="" + local rawquery="" + local somescheme=false + local somequery=false + if detailed then + rawscheme=detailed[1] + rawquery=detailed[4] + somescheme=rawscheme~="" + somequery=rawquery~="" + end + if not somescheme and not somequery then + return { + scheme="file", + authority="", + path=str, + query="", + fragment="", + original=str, + noscheme=true, + filename=str, + } + end + local authority=detailed[2] + local path=detailed[3] + local filename + local username + local password + local host + local port + if authority~="" then + username,password,host,port=lpegmatch(splitauthority,authority) + end + if authority=="" then + filename=path + elseif path=="" then + filename="" + else + filename=authority.."/"..path + end + return { + scheme=rawscheme, + authority=authority, + path=path, + query=lpegmatch(unescaper,rawquery), + queries=lpegmatch(splitquery,rawquery), + fragment=detailed[5], + original=str, + noscheme=false, + filename=filename, + host=host, + port=port, + } end url.split=split url.hasscheme=hasscheme url.hashed=hashed function url.addscheme(str,scheme) - if hasscheme(str) then - return str - elseif not scheme then - return "file:///"..str - else - return scheme..":///"..str - end + if hasscheme(str) then + return str + elseif not scheme then + return "file:///"..str + else + return scheme..":///"..str + end end function url.construct(hash) - local result,r={},0 - local scheme=hash.scheme - local authority=hash.authority - local path=hash.path - local queries=hash.queries - local fragment=hash.fragment - if scheme and scheme~="" then - r=r+1;result[r]=lpegmatch(escaper,scheme) - r=r+1;result[r]="://" - end - if authority and authority~="" then - r=r+1;result[r]=lpegmatch(escaper,authority) - end - if path and path~="" then - r=r+1;result[r]="/" - r=r+1;result[r]=lpegmatch(escaper,path) - end - if queries then - local done=false - for k,v in sortedhash(queries) do - r=r+1;result[r]=done and "&" or "?" - r=r+1;result[r]=lpegmatch(escaper,k) - r=r+1;result[r]="=" - r=r+1;result[r]=lpegmatch(escaper,v) - done=true - end - end - if fragment and fragment~="" then - r=r+1;result[r]="#" - r=r+1;result[r]=lpegmatch(escaper,fragment) - end - return concat(result) + local result,r={},0 + local scheme=hash.scheme + local authority=hash.authority + local path=hash.path + local queries=hash.queries + local fragment=hash.fragment + if scheme and scheme~="" then + r=r+1;result[r]=lpegmatch(escaper,scheme) + r=r+1;result[r]="://" + end + if authority and authority~="" then + r=r+1;result[r]=lpegmatch(escaper,authority) + end + if path and path~="" then + r=r+1;result[r]="/" + r=r+1;result[r]=lpegmatch(escaper,path) + end + if queries then + local done=false + for k,v in sortedhash(queries) do + r=r+1;result[r]=done and "&" or "?" + r=r+1;result[r]=lpegmatch(escaper,k) + r=r+1;result[r]="=" + r=r+1;result[r]=lpegmatch(escaper,v) + done=true + end + end + if fragment and fragment~="" then + r=r+1;result[r]="#" + r=r+1;result[r]=lpegmatch(escaper,fragment) + end + return concat(result) end local pattern=Cs(slash^-1/""*R("az","AZ")*((S(":|")/":")+P(":"))*slash*P(1)^0) function url.filename(filename) - local spec=hashed(filename) - local path=spec.path - return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename + local spec=hashed(filename) + local path=spec.path + return (spec.scheme=="file" and path and lpegmatch(pattern,path)) or filename end local function escapestring(str) - return lpegmatch(escaper,str) + return lpegmatch(escaper,str) end url.escape=escapestring function url.query(str) - if type(str)=="string" then - return lpegmatch(splitquery,str) or "" - else - return str - end + if type(str)=="string" then + return lpegmatch(splitquery,str) or "" + else + return str + end end function url.toquery(data) - local td=type(data) - if td=="string" then - return #str and escape(data) or nil - elseif td=="table" then - if next(data) then - local t={} - for k,v in next,data do - t[#t+1]=format("%s=%s",k,escapestring(v)) - end - return concat(t,"&") - end - else + local td=type(data) + if td=="string" then + return #str and escape(data) or nil + elseif td=="table" then + if next(data) then + local t={} + for k,v in next,data do + t[#t+1]=format("%s=%s",k,escapestring(v)) + end + return concat(t,"&") end + else + end end local pattern=Cs(noslash^0*(1-noslash*P(-1))^0) function url.barepath(path) - if not path or path=="" then - return "" - else - return lpegmatch(pattern,path) - end + if not path or path=="" then + return "" + else + return lpegmatch(pattern,path) + end end @@ -4741,14 +5061,14 @@ do -- create closure to overcome 200 locals limit package.loaded["l-dir"] = package.loaded["l-dir"] or true --- original size: 17703, stripped down to: 11691 +-- original size: 18002, stripped down to: 10681 if not modules then modules={} end modules ['l-dir']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,select=type,select local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub @@ -4760,471 +5080,478 @@ local dir=dir local lfs=lfs local attributes=lfs.attributes local walkdir=lfs.dir -local isdir=lfs.isdir +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 onwindows then - local tricky=S("/\\")*P(-1) - isdir=function(name) - if lpegmatch(tricky,name) then - return attributes(name,"mode")=="directory" - else - return attributes(name.."/.","mode")=="directory" - end - end - isfile=function(name) - return attributes(name,"mode")=="file" + local tricky=S("/\\")*P(-1) + isdir=function(name) + if lpegmatch(tricky,name) then + return attributes(name,"mode")=="directory" + else + return attributes(name.."/.","mode")=="directory" end - lfs.isdir=isdir - lfs.isfile=isfile + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile else - isdir=function(name) - return attributes(name,"mode")=="directory" - end - isfile=function(name) - return attributes(name,"mode")=="file" - end - lfs.isdir=isdir - lfs.isfile=isfile + isdir=function(name) + return attributes(name,"mode")=="directory" + end + isfile=function(name) + return attributes(name,"mode")=="file" + end + lfs.isdir=isdir + lfs.isfile=isfile end function dir.current() - return (gsub(currentdir(),"\\","/")) + return (gsub(currentdir(),"\\","/")) end local function glob_pattern_function(path,patt,recurse,action) - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - action(full) - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end - if dirs then - for i=1,#dirs do - glob_pattern_function(dirs[i],patt,recurse,action) - end + if isdir(path) then + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + for name in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + action(full) + end + elseif recurse and mode=="directory" then + if dirs then + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } + end end + end + end + if dirs then + for i=1,nofdirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end end + end end local function glob_pattern_table(path,patt,recurse,result) - if not result then - result={} - end - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - result[#result+1]=full - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end + if not result then + result={} + end + local usedpath + if path=="/" then + usedpath="/." + elseif not find(path,"/$") then + usedpath=path.."/." + path=path.."/" + else + usedpath=path + end + local dirs + local nofdirs=0 + local noffiles=#result + for name,a in walkdir(usedpath) do + if name~="." and name~=".." then + local full=path..name + local mode=attributes(full,'mode') + if mode=='file' then + if not patt or find(full,patt) then + noffiles=noffiles+1 + result[noffiles]=full + end + elseif recurse and mode=="directory" then if dirs then - for i=1,#dirs do - glob_pattern_table(dirs[i],patt,recurse,result) - end + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } end + end end - return result + end + if dirs then + for i=1,nofdirs do + glob_pattern_table(dirs[i],patt,recurse,result) + end + end + return result end local function globpattern(path,patt,recurse,method) - local kind=type(method) - if patt and sub(patt,1,-3)==path then - patt=false - end - if kind=="function" then - return glob_pattern_function(path,patt,recurse,method) - elseif kind=="table" then - return glob_pattern_table(path,patt,recurse,method) - else - return glob_pattern_table(path,patt,recurse,{}) - end + local kind=type(method) + if patt and sub(patt,1,-3)==path then + patt=false + end + local okay=isdir(path) + if kind=="function" then + return okay and glob_pattern_function(path,patt,recurse,method) or {} + elseif kind=="table" then + return okay and glob_pattern_table(path,patt,recurse,method) or method + else + return okay and glob_pattern_table(path,patt,recurse,{}) or {} + end end dir.globpattern=globpattern local function collectpattern(path,patt,recurse,result) - local ok,scanner - result=result or {} - if path=="/" then - ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) - else - ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) - end - if ok and type(scanner)=="function" then - if not find(path,"/$") then - path=path..'/' - end - for name in scanner,first do - if name=="." then - elseif name==".." then - else - local full=path..name - local attr=attributes(full) - local mode=attr.mode - if mode=='file' then - if find(full,patt) then - result[name]=attr - end - elseif recurse and mode=="directory" then - attr.list=collectpattern(full,patt,recurse) - result[name]=attr - end - end + local ok,scanner + result=result or {} + if path=="/" then + ok,scanner,first=xpcall(function() return walkdir(path..".") end,function() end) + else + ok,scanner,first=xpcall(function() return walkdir(path) end,function() end) + end + if ok and type(scanner)=="function" then + if not find(path,"/$") then + path=path..'/' + end + for name in scanner,first do + if name=="." then + elseif name==".." then + else + local full=path..name + local attr=attributes(full) + local mode=attr.mode + if mode=='file' then + if find(full,patt) then + result[name]=attr + end + elseif recurse and mode=="directory" then + attr.list=collectpattern(full,patt,recurse) + result[name]=attr end + end end - return result + end + return result end dir.collectpattern=collectpattern local separator,pattern if onwindows then - local slash=S("/\\")/"/" - pattern={ - [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) - } + local slash=S("/\\")/"/" + pattern={ + [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={ - [1]=(C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3), - [2]=C(((1-S("*?/"))^0*P("/"))^0), - [3]=C(P(1)^0) - } + pattern={ + [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) + P("**")/".*"+P("*")/"[^/]*"+P("?")/"[^/]"+P(".")/"%%."+P("+")/"%%+"+P("-")/"%%-"+P(1) )^0 ) local function glob(str,t) - if type(t)=="function" then - if type(str)=="table" then - for s=1,#str do - glob(str[s],t) - end - elseif isfile(str) then - t(str) - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - globpattern(start,result,recurse,t) - end - end + if type(t)=="function" then + if type(str)=="table" then + for s=1,#str do + glob(str[s],t) + end + elseif isfile(str) then + t(str) + else + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + globpattern(start,result,recurse,t) + end + end + else + if type(str)=="table" then + local t=t or {} + for s=1,#str do + glob(str[s],t) + end + return t + elseif isfile(str) then + if t then + t[#t+1]=str + return t + else + return { str } + end else - if type(str)=="table" then - local t=t or {} - for s=1,#str do - glob(str[s],t) - end - return t - elseif isfile(str) then - if t then - t[#t+1]=str - return t - else - return { str } - end - else - local root,path,base=lpegmatch(pattern,str) - if root and path and base then - local recurse=find(base,"**",1,true) - local start=root..path - local result=lpegmatch(filter,start..base) - return globpattern(start,result,recurse,t) - else - return {} - end - end + local root,path,base=lpegmatch(pattern,str) + if root and path and base then + local recurse=find(base,"**",1,true) + local start=root..path + local result=lpegmatch(filter,start..base) + return globpattern(start,result,recurse,t) + else + return {} + end end + end end dir.glob=glob local function globfiles(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if recurse then - globfiles(path.."/"..name,recurse,func,files) - end - elseif mode=="file" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if recurse then + globfiles(path.."/"..name,recurse,func,files) + end + elseif mode=="file" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name end + end end - return files + end + return files end dir.globfiles=globfiles local function globdirs(path,recurse,func,files) - if type(func)=="string" then - local s=func - func=function(name) return find(name,s) end - end - files=files or {} - local noffiles=#files - for name in walkdir(path) do - if find(name,"^%.") then - else - local mode=attributes(name,'mode') - if mode=="directory" then - if not func or func(name) then - noffiles=noffiles+1 - files[noffiles]=path.."/"..name - if recurse then - globdirs(path.."/"..name,recurse,func,files) - end - end - end + if type(func)=="string" then + local s=func + func=function(name) return find(name,s) end + end + files=files or {} + local noffiles=#files + for name in walkdir(path) do + if find(name,"^%.") then + else + local mode=attributes(name,'mode') + if mode=="directory" then + if not func or func(name) then + noffiles=noffiles+1 + files[noffiles]=path.."/"..name + if recurse then + globdirs(path.."/"..name,recurse,func,files) + end end + end end - return files + end + return files end dir.globdirs=globdirs function dir.ls(pattern) - return concat(glob(pattern),"\n") + return concat(glob(pattern),"\n") end local make_indeed=true if onwindows then - function dir.mkdirs(...) - local n=select("#",...) - local str - if n==1 then - str=select(1,...) - if isdir(str) then - return str,true - end + function dir.mkdirs(...) + 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="" - for i=1,n do - local s=select(i,...) - if s=="" then - elseif str=="" then - str=s - else - str=str.."/"..s - end - end + str=str.."/"..s end - local pth="" - local drive=false - local first,middle,last=match(str,"^(//)(//*)(.*)$") - if first then + end + end + local pth="" + local drive=false + local first,middle,last=match(str,"^(//)(//*)(.*)$") + if first then + else + first,last=match(str,"^(//)/*(.-)$") + if first then + middle,last=match(str,"([^/]+)/+(.-)$") + if middle then + pth="//"..middle else - first,last=match(str,"^(//)/*(.-)$") - if first then - middle,last=match(str,"([^/]+)/+(.-)$") - if middle then - pth="//"..middle - else - pth="//"..last - last="" - end - else - first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") - if first then - pth,drive=first..middle,true - else - middle,last=match(str,"^(/*)(.-)$") - if not middle then - last=str - end - end - end + pth="//"..last + last="" end - for s in gmatch(last,"[^/]+") do - if pth=="" then - pth=s - elseif drive then - pth,drive=pth..s,false - else - pth=pth.."/"..s - end - if make_indeed and not isdir(pth) then - mkdir(pth) - end + else + first,middle,last=match(str,"^([a-zA-Z]:)(/*)(.-)$") + if first then + pth,drive=first..middle,true + else + middle,last=match(str,"^(/*)(.-)$") + if not middle then + last=str + end end - return pth,(isdir(pth)==true) + end end + for s in gmatch(last,"[^/]+") do + if pth=="" then + pth=s + elseif drive then + pth,drive=pth..s,false + else + pth=pth.."/"..s + end + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end + return pth,(isdir(pth)==true) + end else - function dir.mkdirs(...) - 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 + function dir.mkdirs(...) + 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 - str=gsub(str,"/+","/") - if find(str,"^/") then - pth="/" - for s in gmatch(str,"[^/]+") do - local first=(pth=="/") - if first then - pth=pth..s - else - pth=pth.."/"..s - end - if make_indeed and not first and not isdir(pth) then - mkdir(pth) - end - end + end + end + str=gsub(str,"/+","/") + if find(str,"^/") then + pth="/" + for s in gmatch(str,"[^/]+") do + local first=(pth=="/") + if first then + pth=pth..s else - pth="." - for s in gmatch(str,"[^/]+") do - pth=pth.."/"..s - if make_indeed and not isdir(pth) then - mkdir(pth) - end - end + pth=pth.."/"..s end - return pth,(isdir(pth)==true) + if make_indeed and not first and not isdir(pth) then + mkdir(pth) + end + end + else + pth="." + for s in gmatch(str,"[^/]+") do + pth=pth.."/"..s + if make_indeed and not isdir(pth) then + mkdir(pth) + end + end end + return pth,(isdir(pth)==true) + end end dir.makedirs=dir.mkdirs do - local chdir=sandbox and sandbox.original(chdir) or chdir - if onwindows then - local xcurrentdir=dir.current - function dir.expandname(str) - local first,nothing,last=match(str,"^(//)(//*)(.*)$") - if first then - first=xcurrentdir().."/" - end - if not first then - first,last=match(str,"^(//)/*(.*)$") - end - if not first then - first,last=match(str,"^([a-zA-Z]:)(.*)$") - if first and not find(last,"^/") then - local d=currentdir() - if chdir(first) then - first=xcurrentdir() - end - chdir(d) - end - end - if not first then - first,last=xcurrentdir(),str - end - last=gsub(last,"//","/") - last=gsub(last,"/%./","/") - last=gsub(last,"^/*","") - first=gsub(first,"/*$","") - if last=="" or last=="." then - return first - else - return first.."/"..last - end - end - else - function dir.expandname(str) - if not find(str,"^/") then - str=currentdir().."/"..str - end - str=gsub(str,"//","/") - str=gsub(str,"/%./","/") - str=gsub(str,"(.)/%.$","%1") - return str + local chdir=sandbox and sandbox.original(chdir) or chdir + if onwindows then + local xcurrentdir=dir.current + function dir.expandname(str) + local first,nothing,last=match(str,"^(//)(//*)(.*)$") + if first then + first=xcurrentdir().."/" + end + if not first then + first,last=match(str,"^(//)/*(.*)$") + end + if not first then + first,last=match(str,"^([a-zA-Z]:)(.*)$") + if first and not find(last,"^/") then + local d=currentdir() + if chdir(first) then + first=xcurrentdir() + end + chdir(d) end + end + if not first then + first,last=xcurrentdir(),str + end + last=gsub(last,"//","/") + last=gsub(last,"/%./","/") + last=gsub(last,"^/*","") + first=gsub(first,"/*$","") + if last=="" or last=="." then + return first + else + return first.."/"..last + end end + else + function dir.expandname(str) + if not find(str,"^/") then + str=currentdir().."/"..str + end + str=gsub(str,"//","/") + str=gsub(str,"/%./","/") + str=gsub(str,"(.)/%.$","%1") + return str + end + end end file.expandname=dir.expandname local stack={} function dir.push(newdir) - local curdir=currentdir() - insert(stack,curdir) - if newdir and newdir~="" then - chdir(newdir) - return newdir - else - return curdir - end + local curdir=currentdir() + insert(stack,curdir) + if newdir and newdir~="" then + chdir(newdir) + return newdir + else + return curdir + end end function dir.pop() - local d=remove(stack) - if d then - chdir(d) - end - return d + local d=remove(stack) + if d then + chdir(d) + end + return d end local function found(...) - for i=1,select("#",...) do - local path=select(i,...) - local kind=type(path) - if kind=="string" then - if isdir(path) then - return path - end - elseif kind=="table" then - local path=found(unpack(path)) - if path then - return path - end - end + for i=1,select("#",...) do + local path=select(i,...) + local kind=type(path) + if kind=="string" then + if isdir(path) then + return path + end + elseif kind=="table" then + local path=found(unpack(path)) + if path then + return path + end end + end end dir.found=found @@ -5235,69 +5562,69 @@ do -- create closure to overcome 200 locals limit package.loaded["l-boolean"] = package.loaded["l-boolean"] or true --- original size: 1850, stripped down to: 1568 +-- original size: 1850, stripped down to: 1498 if not modules then modules={} end modules ['l-boolean']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber=type,tonumber boolean=boolean or {} local boolean=boolean function boolean.tonumber(b) - if b then return 1 else return 0 end + if b then return 1 else return 0 end end function toboolean(str,tolerant) - if str==nil then - return false - elseif str==false then - return false - elseif str==true then - return true - elseif str=="true" then - return true - elseif str=="false" then - return false - elseif not tolerant then - return false - elseif str==0 then - return false - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str==nil then + return false + elseif str==false then + return false + elseif str==true then + return true + elseif str=="true" then + return true + elseif str=="false" then + return false + elseif not tolerant then + return false + elseif str==0 then + return false + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end string.toboolean=toboolean function string.booleanstring(str) - if str=="0" then - return false - elseif str=="1" then - return true - elseif str=="" then - return false - elseif str=="false" then - return false - elseif str=="true" then - return true - elseif (tonumber(str) or 0)>0 then - return true - else - return str=="yes" or str=="on" or str=="t" - end + if str=="0" then + return false + elseif str=="1" then + return true + elseif str=="" then + return false + elseif str=="false" then + return false + elseif str=="true" then + return true + elseif (tonumber(str) or 0)>0 then + return true + else + return str=="yes" or str=="on" or str=="t" + end end function string.is_boolean(str,default,strict) - if type(str)=="string" then - if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then - return true - elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then - return false - end + if type(str)=="string" then + if str=="true" or str=="yes" or str=="on" or str=="t" or (not strict and str=="1") then + return true + elseif str=="false" or str=="no" or str=="off" or str=="f" or (not strict and str=="0") then + return false end - return default + end + return default end @@ -5307,18 +5634,24 @@ do -- create closure to overcome 200 locals limit package.loaded["l-unicode"] = package.loaded["l-unicode"] or true --- original size: 40036, stripped down to: 17837 +-- original size: 41047, stripped down to: 17171 if not modules then modules={} end modules ['l-unicode']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -utf=utf or (unicode and unicode.utf8) or {} -utf.characters=utf.characters or string.utfcharacters -utf.values=utf.values or string.utfvalues +utf=utf or {} +unicode=nil +if not string.utfcharacters then + local gmatch=string.gmatch + function string.characters(str) + return gmatch(str,".[\128-\191]*") + end +end +utf.characters=string.utfcharacters local type=type local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch local concat=table.concat @@ -5329,345 +5662,340 @@ local tabletopattern=lpeg.utfchartabletopattern local bytepairs=string.bytepairs local finder=lpeg.finder 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.utf8character +local p_utf8character=patterns.utf8character +local p_utf8char=patterns.utf8char local p_utf8byte=patterns.utf8byte local p_utfbom=patterns.utfbom local p_newline=patterns.newline local p_whitespace=patterns.whitespace -if not unicode then - unicode={ utf=utf } -end if not utf.char then - utf.char=string.utfcharacter or (utf8 and utf8.char) - if not utf.char then - local char=string.char - if bit32 then - local rshift=bit32.rshift - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+rshift(n,6), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+rshift(n,12), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+rshift(n,18), - 0x80+(rshift(n,12)%0x40), - 0x80+(rshift(n,6)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + utf.char=string.utfcharacter or (utf8 and utf8.char) + if not utf.char then + local char=string.char + if bit32 then + local rshift=bit32.rshift + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+rshift(n,6), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+rshift(n,12), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+rshift(n,18), + 0x80+(rshift(n,12)%0x40), + 0x80+(rshift(n,6)%0x40), + 0x80+(n%0x40) + ) else - local floor=math.floor - function utf.char(n) - if n<0x80 then - return char(n) - elseif n<0x800 then - return char( - 0xC0+floor(n/0x40), - 0x80+(n%0x40) - ) - elseif n<0x10000 then - return char( - 0xE0+floor(n/0x1000), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - elseif n<0x200000 then - return char( - 0xF0+floor(n/0x40000), - 0x80+(floor(n/0x1000)%0x40), - 0x80+(floor(n/0x40)%0x40), - 0x80+(n%0x40) - ) - else - return "" - end - end + return "" end + end + else + local floor=math.floor + function utf.char(n) + if n<0x80 then + return char(n) + elseif n<0x800 then + return char( + 0xC0+floor(n/0x40), + 0x80+(n%0x40) + ) + elseif n<0x10000 then + return char( + 0xE0+floor(n/0x1000), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + elseif n<0x200000 then + return char( + 0xF0+floor(n/0x40000), + 0x80+(floor(n/0x1000)%0x40), + 0x80+(floor(n/0x40)%0x40), + 0x80+(n%0x40) + ) + else + return "" + end + end end + end end if not utf.byte then - utf.byte=string.utfvalue or (utf8 and utf8.codepoint) - if not utf.byte then - local utf8byte=patterns.utf8byte - function utf.byte(c) - return lpegmatch(utf8byte,c) - end + utf.byte=string.utfvalue or (utf8 and utf8.codepoint) + if not utf.byte then + function utf.byte(c) + return lpegmatch(p_utf8byte,c) end + end end local utfchar,utfbyte=utf.char,utf.byte function utf.filetype(data) - return data and lpegmatch(p_utftype,data) or "unknown" + return data and lpegmatch(p_utftype,data) or "unknown" end local toentities=Cs ( - ( - patterns.utf8one+( - patterns.utf8two+patterns.utf8three+patterns.utf8four - )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end - )^0 + ( + patterns.utf8one+( + patterns.utf8two+patterns.utf8three+patterns.utf8four + )/function(s) local b=utfbyte(s) if b<127 then return s else return format("&#%X;",b) end end + )^0 ) patterns.toentities=toentities function utf.toentities(str) - return lpegmatch(toentities,str) + return lpegmatch(toentities,str) end local one=P(1) local two=C(1)*C(1) local four=C(R(utfchar(0xD8),utfchar(0xFF)))*C(1)*C(1)*C(1) local pattern=P("\254\255")*Cs(( - four/function(a,b,c,d) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(a,b) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 )+P("\255\254")*Cs(( - four/function(b,a,d,c) - local ab=0xFF*byte(a)+byte(b) - local cd=0xFF*byte(c)+byte(d) - return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) - end+two/function(b,a) - return utfchar(byte(a)*256+byte(b)) - end+one - )^1 ) + four/function(a,b,c,d) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(a,b) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 )+P("\255\254")*Cs(( + four/function(b,a,d,c) + local ab=0xFF*byte(a)+byte(b) + local cd=0xFF*byte(c)+byte(d) + return utfchar((ab-0xD800)*0x400+(cd-0xDC00)+0x10000) + end+two/function(b,a) + return utfchar(byte(a)*256+byte(b)) + end+one + )^1 ) function string.toutf(s) - return lpegmatch(pattern,s) or s + return lpegmatch(pattern,s) or s end local validatedutf=Cs ( - ( - patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" - )^0 + ( + patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four+P(1)/"�" + )^0 ) patterns.validatedutf=validatedutf function utf.is_valid(str) - return type(str)=="string" and lpegmatch(validatedutf,str) or false + return type(str)=="string" and lpegmatch(validatedutf,str) or false end if not utf.len then - utf.len=string.utflength or (utf8 and utf8.len) - if not utf.len then - local n,f=0,1 - local utfcharcounter=patterns.utfbom^-1*Cmt ( - Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, - function(_,t,d) - n=n+(t-f)/d - f=t - return true - end - )^0 - function utf.len(str) - n,f=0,1 - lpegmatch(utfcharcounter,str or "") - return n - end + utf.len=string.utflength or (utf8 and utf8.len) + if not utf.len then + local n,f=0,1 + local utfcharcounter=patterns.utfbom^-1*Cmt ( + Cc(1)*patterns.utf8one^1+Cc(2)*patterns.utf8two^1+Cc(3)*patterns.utf8three^1+Cc(4)*patterns.utf8four^1, + function(_,t,d) + n=n+(t-f)/d + f=t + return true + end + )^0 + function utf.len(str) + n,f=0,1 + lpegmatch(utfcharcounter,str or "") + return n end + end end utf.length=utf.len if not utf.sub then - local utflength=utf.length - local b,e,n,first,last=0,0,0,0,0 - local function slide_zero(s,p) - n=n+1 - if n>=last then - e=p-1 - else - return p - end + local utflength=utf.length + local b,e,n,first,last=0,0,0,0,0 + local function slide_zero(s,p) + n=n+1 + if n>=last then + e=p-1 + else + return p end - local function slide_one(s,p) - n=n+1 - if n==first then - b=p - end - if n>=last then - e=p-1 - else - return p - end + end + local function slide_one(s,p) + n=n+1 + if n==first then + b=p end - local function slide_two(s,p) - n=n+1 - if n==first then - b=p - else - return true - end + if n>=last then + e=p-1 + else + return p end - local pattern_zero=Cmt(p_utf8char,slide_zero)^0 - local pattern_one=Cmt(p_utf8char,slide_one )^0 - local pattern_two=Cmt(p_utf8char,slide_two )^0 - local pattern_first=C(patterns.utf8character) - function utf.sub(str,start,stop) - if not start then - return str - end - if start==0 then - start=1 - end - if not stop then - if start<0 then - local l=utflength(str) - start=l+start - else - start=start-1 - end - b,n,first=0,0,start - lpegmatch(pattern_two,str) - if n>=first then - return sub(str,b) - else - return "" - end - end - if start<0 or stop<0 then - local l=utf.length(str) - if start<0 then - start=l+start - if start<=0 then - start=1 - else - start=start+1 - end - end - if stop<0 then - stop=l+stop - if stop==0 then - stop=1 - else - stop=stop+1 - end - end + end + local function slide_two(s,p) + n=n+1 + if n==first then + b=p + else + return true + end + end + local pattern_zero=Cmt(p_utf8character,slide_zero)^0 + local pattern_one=Cmt(p_utf8character,slide_one )^0 + local pattern_two=Cmt(p_utf8character,slide_two )^0 + local pattern_first=C(p_utf8character) + function utf.sub(str,start,stop) + if not start then + return str + end + if start==0 then + start=1 + end + if not stop then + if start<0 then + local l=utflength(str) + start=l+start + else + start=start-1 + end + b,n,first=0,0,start + lpegmatch(pattern_two,str) + if n>=first then + return sub(str,b) + else + return "" + end + end + if start<0 or stop<0 then + local l=utf.length(str) + if start<0 then + start=l+start + if start<=0 then + start=1 + else + start=start+1 end - if start==1 and stop==1 then - return lpegmatch(pattern_first,str) or "" - elseif start>stop then - return "" - elseif start>1 then - b,e,n,first,last=0,0,0,start-1,stop - lpegmatch(pattern_one,str) - if n>=first and e==0 then - e=#str - end - return sub(str,b,e) + end + if stop<0 then + stop=l+stop + if stop==0 then + stop=1 else - b,e,n,last=1,0,0,stop - lpegmatch(pattern_zero,str) - if e==0 then - e=#str - end - return sub(str,b,e) + stop=stop+1 end + end end + if start==1 and stop==1 then + return lpegmatch(pattern_first,str) or "" + elseif start>stop then + return "" + elseif start>1 then + b,e,n,first,last=0,0,0,start-1,stop + lpegmatch(pattern_one,str) + if n>=first and e==0 then + e=#str + end + return sub(str,b,e) + else + b,e,n,last=1,0,0,stop + lpegmatch(pattern_zero,str) + if e==0 then + e=#str + end + return sub(str,b,e) + end + end end function utf.remapper(mapping,option,action) - local variant=type(mapping) - if variant=="table" then - action=action or mapping - if option=="dynamic" then - local pattern=false - table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) - return function(str) - if not str or str=="" then - return "" - else - if not pattern then - pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - end - return lpegmatch(pattern,str) - end - end - elseif option=="pattern" then - return Cs((tabletopattern(mapping)/action+p_utf8char)^0) + local variant=type(mapping) + if variant=="table" then + action=action or mapping + if option=="dynamic" then + local pattern=false + table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + if not pattern then + pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + end + return lpegmatch(pattern,str) end - elseif variant=="function" then - if option=="pattern" then - return Cs((p_utf8char/mapping+p_utf8char)^0) + end + elseif option=="pattern" then + return Cs((tabletopattern(mapping)/action+p_utf8character)^0) + else + local pattern=Cs((tabletopattern(mapping)/action+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" else - local pattern=Cs((p_utf8char/mapping+p_utf8char)^0) - return function(str) - if not str or str=="" then - return "" - else - return lpegmatch(pattern,str) - end - end,pattern + return lpegmatch(pattern,str) end + end,pattern + end + elseif variant=="function" then + if option=="pattern" then + return Cs((p_utf8character/mapping+p_utf8character)^0) else - return function(str) - return str or "" + local pattern=Cs((p_utf8character/mapping+p_utf8character)^0) + return function(str) + if not str or str=="" then + return "" + else + return lpegmatch(pattern,str) end + end,pattern end -end -function utf.replacer(t) - local r=replacer(t,false,false,true) + else return function(str) - return lpegmatch(r,str) + return str or "" end + end +end +function utf.replacer(t) + local r=replacer(t,false,false,true) + return function(str) + return lpegmatch(r,str) + end end function utf.subtituter(t) - local f=finder (t) - local r=replacer(t,false,false,true) - return function(str) - local i=lpegmatch(f,str) - if not i then - return str - elseif i>#str then - return str - else - return lpegmatch(r,str) - end + local f=finder (t) + local r=replacer(t,false,false,true) + return function(str) + local i=lpegmatch(f,str) + if not i then + return str + elseif i>#str then + return str + else + return lpegmatch(r,str) end + end end local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline) -local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0) -local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0) -local utfcharsplitter_raw=Ct(C(p_utf8char)^0) +local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8character)^0) +local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8character))^0) +local utfcharsplitter_raw=Ct(C(p_utf8character)^0) patterns.utflinesplitter=utflinesplitter function utf.splitlines(str) - return lpegmatch(utflinesplitter,str or "") + return lpegmatch(utflinesplitter,str or "") end function utf.split(str,ignorewhitespace) - if ignorewhitespace then - return lpegmatch(utfcharsplitter_iws,str or "") - else - return lpegmatch(utfcharsplitter_ows,str or "") - end + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end end function utf.totable(str) - return lpegmatch(utfcharsplitter_raw,str) + return lpegmatch(utfcharsplitter_raw,str) end function utf.magic(f) - local str=f:read(4) or "" - local off=lpegmatch(p_utfoffset,str) - if off<4 then - f:seek('set',off) - end - return lpegmatch(p_utftype,str) + local str=f:read(4) or "" + local off=lpegmatch(p_utfoffset,str) + if off<4 then + f:seek('set',off) + end + return lpegmatch(p_utftype,str) end local utf16_to_utf8_be,utf16_to_utf8_le local utf32_to_utf8_be,utf32_to_utf8_le @@ -5681,36 +6009,36 @@ local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_n local utf_32_le_linesplitter=utf_32_le_getbom*lpeg.tsplitat(patterns.utf_32_le_nl) local more=0 local p_utf16_to_utf8_be=C(1)*C(1)/function(left,right) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf16_to_utf8_le=C(1)*C(1)/function(right,left) - local now=256*byte(left)+byte(right) - if more>0 then - now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 - more=0 - return utfchar(now) - elseif now>=0xD800 and now<=0xDBFF then - more=now - return "" - else - return utfchar(now) - end + local now=256*byte(left)+byte(right) + if more>0 then + now=(more-0xD800)*0x400+(now-0xDC00)+0x10000 + more=0 + return utfchar(now) + elseif now>=0xD800 and now<=0xDBFF then + more=now + return "" + else + return utfchar(now) + end end local p_utf32_to_utf8_be=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) + return utfchar(256*256*256*byte(a)+256*256*byte(b)+256*byte(c)+byte(d)) end local p_utf32_to_utf8_le=C(1)*C(1)*C(1)*C(1)/function(a,b,c,d) - return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) + return utfchar(256*256*256*byte(d)+256*256*byte(c)+256*byte(b)+byte(a)) end p_utf16_to_utf8_be=P(true)/function() more=0 end*utf_16_be_getbom*Cs(p_utf16_to_utf8_be^0) p_utf16_to_utf8_le=P(true)/function() more=0 end*utf_16_le_getbom*Cs(p_utf16_to_utf8_le^0) @@ -5721,88 +6049,88 @@ patterns.utf16_to_utf8_le=p_utf16_to_utf8_le patterns.utf32_to_utf8_be=p_utf32_to_utf8_be patterns.utf32_to_utf8_le=p_utf32_to_utf8_le utf16_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_be,s) + else + return s + end end local utf16_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_be,s) end - return t + end + return t end utf16_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf16_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf16_to_utf8_le,s) + else + return s + end end local utf16_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_16_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf16_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_16_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf16_to_utf8_le,s) end - return t + end + return t end utf32_to_utf8_be=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_be,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_be,s) + else + return s + end end local utf32_to_utf8_be_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_be_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_be,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_be_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_be,s) end - return t + end + return t end utf32_to_utf8_le=function(s) - if s and s~="" then - return lpegmatch(p_utf32_to_utf8_le,s) - else - return s - end + if s and s~="" then + return lpegmatch(p_utf32_to_utf8_le,s) + else + return s + end end local utf32_to_utf8_le_t=function(t) - if not t then - return nil - elseif type(t)=="string" then - t=lpegmatch(utf_32_le_linesplitter,t) - end - for i=1,#t do - local s=t[i] - if s~="" then - t[i]=lpegmatch(p_utf32_to_utf8_le,s) - end + if not t then + return nil + elseif type(t)=="string" then + t=lpegmatch(utf_32_le_linesplitter,t) + end + for i=1,#t do + local s=t[i] + if s~="" then + t[i]=lpegmatch(p_utf32_to_utf8_le,s) end - return t + end + return t end utf.utf16_to_utf8_le_t=utf16_to_utf8_le_t utf.utf16_to_utf8_be_t=utf16_to_utf8_be_t @@ -5813,189 +6141,225 @@ 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(t) - return type(t)=="string" and lpegmatch(utflinesplitter,t) or t + return type(t)=="string" and lpegmatch(utflinesplitter,t) or t end function utf.utf16_to_utf8_t(t,endian) - return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t + return endian and utf16_to_utf8_be_t(t) or utf16_to_utf8_le_t(t) or t end function utf.utf32_to_utf8_t(t,endian) - return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t + return endian and utf32_to_utf8_be_t(t) or utf32_to_utf8_le_t(t) or t end local function little(b) - if b<0x10000 then - return char(b%256,rshift(b,8)) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) - end + if b<0x10000 then + return char(b%256,rshift(b,8)) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(b1%256,rshift(b1,8),b2%256,rshift(b2,8)) + end end local function big(b) - if b<0x10000 then - return char(rshift(b,8),b%256) - else - b=b-0x10000 - local b1=rshift(b,10)+0xD800 - local b2=b%1024+0xDC00 - return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) - end + if b<0x10000 then + return char(rshift(b,8),b%256) + else + b=b-0x10000 + local b1=rshift(b,10)+0xD800 + local b2=b%1024+0xDC00 + return char(rshift(b1,8),b1%256,rshift(b2,8),b2%256) + end end local l_remap=Cs((p_utf8byte/little+P(1)/"")^0) local b_remap=Cs((p_utf8byte/big+P(1)/"")^0) local function utf8_to_utf16_be(str,nobom) - if nobom then - return lpegmatch(b_remap,str) - else - return char(254,255)..lpegmatch(b_remap,str) - end + if nobom then + return lpegmatch(b_remap,str) + else + return char(254,255)..lpegmatch(b_remap,str) + end end local function utf8_to_utf16_le(str,nobom) - if nobom then - return lpegmatch(l_remap,str) - else - return char(255,254)..lpegmatch(l_remap,str) - end + if nobom then + return lpegmatch(l_remap,str) + else + return char(255,254)..lpegmatch(l_remap,str) + end end utf.utf8_to_utf16_be=utf8_to_utf16_be utf.utf8_to_utf16_le=utf8_to_utf16_le function utf.utf8_to_utf16(str,littleendian,nobom) - if littleendian then - return utf8_to_utf16_le(str,nobom) - else - return utf8_to_utf16_be(str,nobom) - end + if littleendian then + return utf8_to_utf16_le(str,nobom) + else + return 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 + (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 ) function utf.tocodes(str,separator) - return lpegmatch(pattern,str,1,separator or " ") + return lpegmatch(pattern,str,1,separator or " ") end function utf.ustring(s) - return format("U+%05X",type(s)=="number" and s or utfbyte(s)) + return format("U+%05X",type(s)=="number" and s or utfbyte(s)) end function utf.xstring(s) - return format("0x%05X",type(s)=="number" and s or utfbyte(s)) + return format("0x%05X",type(s)=="number" and s or utfbyte(s)) end function utf.toeight(str) - if not str or str=="" then - return nil - end - local utftype=lpegmatch(p_utfstricttype,str) - if utftype=="utf-8" then - return sub(str,4) - elseif utftype=="utf-16-be" then - return utf16_to_utf8_be(str) - elseif utftype=="utf-16-le" then - return utf16_to_utf8_le(str) - else - return str - end -end -local p_nany=p_utf8char/"" -if utfgmatch then - function utf.count(str,what) - if type(what)=="string" then - local n=0 - for _ in utfgmatch(str,what) do - n=n+1 - end - return n - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end -else - local cache={} - function utf.count(str,what) - if type(what)=="string" then - local p=cache[what] - if not p then - p=Cs((P(what)/" "+p_nany)^0) - cache[p]=p - end - return #lpegmatch(p,str) - else - return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) - end - end + if not str or str=="" then + return nil + end + local utftype=lpegmatch(p_utfstricttype,str) + if utftype=="utf-8" then + return sub(str,4) + elseif utftype=="utf-16-be" then + return utf16_to_utf8_be(str) + elseif utftype=="utf-16-le" then + return utf16_to_utf8_le(str) + else + return str + end end -if not utf.characters then - function utf.characters(str) - return gmatch(str,".[\128-\191]*") +do + local p_nany=p_utf8character/"" + local cache={} + function utf.count(str,what) + if type(what)=="string" then + local p=cache[what] + if not p then + p=Cs((P(what)/" "+p_nany)^0) + cache[p]=p + end + return #lpegmatch(p,str) + else + return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str) end - string.utfcharacters=utf.characters + end end -if not utf.values then - local find=string.find - local dummy=function() - end - function utf.values(str) - local n=#str - if n==0 then - return dummy - elseif n==1 then - return function() return utfbyte(str) end - else - local p=1 - return function() - local b,e=find(str,".[\128-\191]*",p) - if b then - p=e+1 - return utfbyte(sub(str,b,e)) - end - end - end +if not string.utfvalues then + local find=string.find + local dummy=function() + end + function string.utfvalues(str) + local n=#str + if n==0 then + return dummy + elseif n==1 then + return function() return utfbyte(str) end + else + local p=1 + return function() + local b,e=find(str,".[\128-\191]*",p) + if b then + p=e+1 + return utfbyte(sub(str,b,e)) + end + end end - string.utfvalues=utf.values + end end +utf.values=string.utfvalues 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 + 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 if bit32 then - local extract=bit32.extract - local char=string.char - function unicode.toutf32string(n) - if n<=0xFF then - return - char(n).."\000\000\000" - elseif n<=0xFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" - elseif n<=0xFFFFFF then - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" - else - return - char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) - end - end + local extract=bit32.extract + local char=string.char + function utf.toutf32string(n) + if n<=0xFF then + return + char(n).."\000\000\000" + elseif n<=0xFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8)).."\000\000" + elseif n<=0xFFFFFF then + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000" + else + return + char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8)) + end + end end local len=utf.len local rep=rep function string.utfpadd(s,n) - if n and n~=0 then - local l=len(s) - if n>0 then - local d=n-l - if d>0 then - return rep(c or " ",d)..s - end - else - local d=- n-l - if d>0 then - return s..rep(c or " ",d) - end - end + if n and n~=0 then + local l=len(s) + if n>0 then + local d=n-l + if d>0 then + return rep(c or " ",d)..s + end + else + local d=- n-l + if d>0 then + return s..rep(c or " ",d) + end end - return s + end + return s +end +do + local utfcharacters=utf.characters or string.utfcharacters + local utfchar=utf.char or string.utfcharacter + lpeg.UP=P + if utfcharacters then + function lpeg.US(str) + local p=P(false) + for uc in utfcharacters(str) do + p=p+P(uc) + end + return p + end + else + function lpeg.US(str) + local p=P(false) + local f=function(uc) + p=p+P(uc) + end + lpegmatch((p_utf8char/f)^0,str) + return p + end + end + local range=p_utf8byte*p_utf8byte+Cc(false) + function lpeg.UR(str,more) + local first,last + if type(str)=="number" then + first=str + last=more or first + else + first,last=lpegmatch(range,str) + if not last then + return P(str) + end + end + if first==last then + return P(str) + end + if not utfchar then + utfchar=utf.char + end + if utfchar and (last-first<8) then + local p=P(false) + for i=first,last do + p=p+P(utfchar(i)) + end + return p + else + local f=function(b) + return b>=first and b<=last + end + return p_utf8byte/f + end + end end @@ -6005,93 +6369,93 @@ do -- create closure to overcome 200 locals limit package.loaded["l-math"] = package.loaded["l-math"] or true --- original size: 2555, stripped down to: 1900 +-- original size: 2555, stripped down to: 1831 if not modules then modules={} end modules ['l-math']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not math.ceiling then - math.ceiling=math.ceil + math.ceiling=math.ceil end if not math.round then - local floor=math.floor - function math.round(x) return floor(x+0.5) end + local floor=math.floor + function math.round(x) return floor(x+0.5) end end if not math.div then - local floor=math.floor - function math.div(n,m) return floor(n/m) end + local floor=math.floor + function math.div(n,m) return floor(n/m) end end if not math.mod then - function math.mod(n,m) return n%m end + function math.mod(n,m) return n%m end end if not math.sind then - local sin,cos,tan=math.sin,math.cos,math.tan - local pipi=2*math.pi/360 - function math.sind(d) return sin(d*pipi) end - function math.cosd(d) return cos(d*pipi) end - function math.tand(d) return tan(d*pipi) end + local sin,cos,tan=math.sin,math.cos,math.tan + local pipi=2*math.pi/360 + function math.sind(d) return sin(d*pipi) end + function math.cosd(d) return cos(d*pipi) end + function math.tand(d) return tan(d*pipi) end end if not math.odd then - function math.odd (n) return n%2~=0 end - function math.even(n) return n%2==0 end + function math.odd (n) return n%2~=0 end + function math.even(n) return n%2==0 end end if not math.cosh then - local exp=math.exp - function math.cosh(x) - local xx=exp(x) - return (xx+1/xx)/2 - end - function math.sinh(x) - local xx=exp(x) - return (xx-1/xx)/2 - end - function math.tanh(x) - local xx=exp(x) - return (xx-1/xx)/(xx+1/xx) - end + local exp=math.exp + function math.cosh(x) + local xx=exp(x) + return (xx+1/xx)/2 + end + function math.sinh(x) + local xx=exp(x) + return (xx-1/xx)/2 + end + function math.tanh(x) + local xx=exp(x) + return (xx-1/xx)/(xx+1/xx) + end end if not math.pow then - function math.pow(x,y) - return x^y - end + function math.pow(x,y) + return x^y + end end if not math.atan2 then - math.atan2=math.atan + math.atan2=math.atan end if not math.ldexp then - function math.ldexp(x,e) - return x*2.0^e - end + function math.ldexp(x,e) + return x*2.0^e + end end if not math.log10 then - local log=math.log - function math.log10(x) - return log(x,10) - end + local log=math.log + function math.log10(x) + return log(x,10) + end end if not math.type then - function math.type() - return "float" - end + function math.type() + return "float" + end end if not math.tointeger then - math.mininteger=-0x4FFFFFFFFFFF - math.maxinteger=0x4FFFFFFFFFFF - local floor=math.floor - function math.tointeger(n) - local f=floor(n) - return f==n and f or nil - end + math.mininteger=-0x4FFFFFFFFFFF + math.maxinteger=0x4FFFFFFFFFFF + local floor=math.floor + function math.tointeger(n) + local f=floor(n) + return f==n and f or nil + end end if not math.ult then - local floor=math.floor - function math.tointeger(m,n) - return floor(m)<floor(n) - end + local floor=math.floor + function math.tointeger(m,n) + return floor(m)<floor(n) + end end @@ -6101,14 +6465,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-str"] = package.loaded["util-str"] or true --- original size: 38734, stripped down to: 22142 +-- original size: 43539, stripped down to: 21641 if not modules then modules={} end modules ['util-str']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.strings=utilities.strings or {} @@ -6121,624 +6485,657 @@ 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,utflen=utf.char,utf.byte,utf.len -local loadstripped=nil -local oldfashioned=LUAVERSION<5.2 -if oldfashioned 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 +local 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 if not number then number={} end -local stripper=patterns.stripzeros +local stripzero=patterns.stripzero +local stripzeros=patterns.stripzeros local newline=patterns.newline local endofstring=patterns.endofstring +local anything=patterns.anything local whitespace=patterns.whitespace +local space=patterns.space local spacer=patterns.spacer local spaceortab=patterns.spaceortab +local digit=patterns.digit +local sign=patterns.sign +local period=patterns.period +local ptf=1/65536 +local bpf=(7200/7227)/65536 local function points(n) - n=tonumber(n) - return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*ptf + if n%1==0 then + return format("%ipt",n) + end + return lpegmatch(stripzeros,format("%.5fpt",n)) 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)) + if n==0 then + return "0pt" + end + n=tonumber(n) + if not n or n==0 then + return "0pt" + end + n=n*bpf + if n%1==0 then + return format("%ibp",n) + end + return lpegmatch(stripzeros,format("%.5fbp",n)) end number.points=points number.basepoints=basepoints local rubish=spaceortab^0*newline local anyrubish=spaceortab+newline -local anything=patterns.anything local stripped=(spaceortab^1/"")*newline local leading=rubish^0/"" local trailing=(anyrubish^1*endofstring)/"" local redundant=rubish^3/"\n" local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) function strings.collapsecrlf(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local repeaters={} function strings.newrepeater(str,offset) - offset=offset or 0 - local s=repeaters[str] - if not s then - s={} - repeaters[str]=s - end - local t=s[offset] - if t then - return t - end - t={} - setmetatable(t,{ __index=function(t,k) - if not k then - return "" - end - local n=k+offset - local s=n>0 and rep(str,n) or "" - t[k]=s - return s - end }) - s[offset]=t + offset=offset or 0 + local s=repeaters[str] + if not s then + s={} + repeaters[str]=s + end + local t=s[offset] + if t then return t + end + t={} + setmetatable(t,{ __index=function(t,k) + if not k then + return "" + end + local n=k+offset + local s=n>0 and rep(str,n) or "" + t[k]=s + return s + end }) + s[offset]=t + return t end local extra,tab,start=0,0,4,0 local nspaces=strings.newrepeater(" ") string.nspaces=nspaces local pattern=Carg(1)/function(t) - extra,tab,start=0,t or 7,1 - end*Cs(( + extra,tab,start=0,t or 7,1 + end*Cs(( Cp()*patterns.tab/function(position) - local current=(position-start+1)+extra - local spaces=tab-(current-1)%tab - if spaces>0 then - extra=extra+spaces-1 - return nspaces[spaces] - else - return "" - end + local current=(position-start+1)+extra + local spaces=tab-(current-1)%tab + if spaces>0 then + extra=extra+spaces-1 + return nspaces[spaces] + else + return "" + end end+newline*Cp()/function(position) - extra,start=0,position - end+patterns.anything - )^1) + extra,start=0,position + end+anything + )^1) function strings.tabtospace(str,tab) - return lpegmatch(pattern,str,1,tab or 7) + return lpegmatch(pattern,str,1,tab or 7) end function string.utfpadding(s,n) - if not n or n==0 then - return "" - end - local l=utflen(s) - if n>0 then - return nspaces[n-l] - else - return nspaces[-n-l] - end -end -local space=spacer^0 -local nospace=space/"" + if not n or n==0 then + return "" + end + local l=utflen(s) + if n>0 then + return nspaces[n-l] + else + return nspaces[-n-l] + end +end +local optionalspace=spacer^0 +local nospace=optionalspace/"" local endofline=nospace*newline local stripend=(whitespace^1*endofstring)/"" -local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) +local normalline=(nospace*((1-optionalspace*(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 intospace=whitespace^1/" " +local noleading=whitespace^1/"" +local notrailing=noleading*endofstring 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_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^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, - ["collapse"]=patterns.collapser, + ["prune"]=p_prune_normal, + ["prune and collapse"]=p_prune_collapse, + ["prune and no empty"]=p_prune_noempty, + ["prune and to space"]=p_prune_intospace, + ["retain"]=p_retain_normal, + ["retain and collapse"]=p_retain_collapse, + ["retain and no empty"]=p_retain_noempty, + ["collapse"]=patterns.collapser, } setmetatable(striplinepatterns,{ __index=function(t,k) return p_prune_collapse end }) strings.striplinepatterns=striplinepatterns function strings.striplines(str,how) - return str and lpegmatch(striplinepatterns[how],str) or str + return str and lpegmatch(striplinepatterns[how],str) or str +end +function strings.collapse(str) + return str and lpegmatch(p_prune_intospace,str) or str end strings.striplong=strings.striplines function strings.nice(str) - str=gsub(str,"[:%-+_]+"," ") - return str + str=gsub(str,"[:%-+_]+"," ") + return str end local n=0 local sequenced=table.sequenced function string.autodouble(s,sep) - if s==nil then - return '""' - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ('"'..sequenced(s,sep or ",")..'"') - end - return ('"'..tostring(s)..'"') + if s==nil then + return '""' + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ('"'..sequenced(s,sep or ",")..'"') + end + return ('"'..tostring(s)..'"') end function string.autosingle(s,sep) - if s==nil then - return "''" - end - local t=type(s) - if t=="number" then - return tostring(s) - end - if t=="table" then - return ("'"..sequenced(s,sep or ",").."'") - end - return ("'"..tostring(s).."'") + if s==nil then + return "''" + end + local t=type(s) + if t=="number" then + return tostring(s) + end + if t=="table" then + return ("'"..sequenced(s,sep or ",").."'") + end + return ("'"..tostring(s).."'") end local tracedchars={ [0]= - "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", - "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", - "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", - "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", - "[space]", + "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", + "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", + "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", + "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", + "[space]", } string.tracedchars=tracedchars strings.tracers=tracedchars function string.tracedchar(b) - if type(b)=="number" then - return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") - else - local c=utfbyte(b) - return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") - end + if type(b)=="number" then + return tracedchars[b] or (utfchar(b).." (U+"..format("%05X",b)..")") + else + local c=utfbyte(b) + return tracedchars[c] or (b.." (U+"..(c and format("%05X",c) or "?????")..")") + end end function number.signed(i) - if i>0 then - return "+",i - else - return "-",-i - end -end -local digit=patterns.digit -local period=patterns.period -local three=digit*digit*digit + if i>0 then + return "+",i + else + return "-",-i + end +end +local two=digit*digit +local three=two*digit +local prefix=(Carg(1)*three)^1 local splitter=Cs ( - (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2) + (((1-(three^1*period))^1+C(three))*prefix+C((1-period)^1))*(anything/""*Carg(2))*C(2) +) +local splitter3=Cs ( + three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit ) patterns.formattednumber=splitter function number.formatted(n,sep1,sep2) - local s=type(s)=="string" and n or format("%0.2f",n) + if sep1==false then + if type(n)=="number" then + n=tostring(n) + end + return lpegmatch(splitter3,n,1,sep2 or ".") + else + if type(n)=="number" then + n=format("%0.2f",n) + end if sep1==true then - return lpegmatch(splitter,s,1,".",",") + return lpegmatch(splitter,n,1,".",",") elseif sep1=="." then - return lpegmatch(splitter,s,1,sep1,sep2 or ",") + return lpegmatch(splitter,n,1,sep1,sep2 or ",") elseif sep1=="," then - return lpegmatch(splitter,s,1,sep1,sep2 or ".") + return lpegmatch(splitter,n,1,sep1,sep2 or ".") else - return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") + return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".") end + end end local p=Cs( - P("-")^0*(P("0")^1/"")^0*(1-P("."))^0*(P(".")*P("0")^1*P(-1)/""+P(".")^0)*P(1-P("0")^1*P(-1))^0 - ) + P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^0 + ) function number.compactfloat(n,fmt) - if n==0 then - return "0" - elseif n==1 then - return "1" - end - n=lpegmatch(p,format(fmt or "%0.3f",n)) - if n=="." or n=="" or n=="-" then - return "0" - end - return n + if n==0 then + return "0" + elseif n==1 then + return "1" + end + n=lpegmatch(p,format(fmt or "%0.3f",n)) + if n=="." or n=="" or n=="-" then + return "0" + end + return n end local zero=P("0")^1/"" local plus=P("+")/"" local minus=P("-") -local separator=S(".") -local digit=R("09") +local separator=period 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 exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1)) local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) -local pattern_b=Cs((exponent+P(1))^0) +local pattern_b=Cs((exponent+anything)^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)) + 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 - return tostring(n) + 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 hf={} local hs={} setmetatable(hf,{ __index=function(t,k) - local v="%."..k.."f" - t[k]=v - return v + local v="%."..k.."f" + t[k]=v + return v end } ) setmetatable(hs,{ __index=function(t,k) - local v="%"..k.."s" - t[k]=v - return v + local v="%"..k.."s" + t[k]=v + return v end } ) function number.formattedfloat(n,b,a) - local s=format(hf[a],n) - local l=(b or 0)+(a or 0)+1 - if #s<l then - return format(hs[l],s) - else - return s - end + local s=format(hf[a],n) + local l=(b or 0)+(a or 0)+1 + if #s<l then + return format(hs[l],s) + else + return s + end end local template=[[ %s %s return function(%s) return %s end ]] -local preamble,environment="",{} -if oldfashioned 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 utfpadding=string.utfpadding -local tracedchar=string.tracedchar -local autosingle=string.autosingle -local autodouble=string.autodouble -local sequenced=table.sequenced -local formattednumber=number.formatted -local sparseexponent=number.sparseexponent -local formattedfloat=number.formattedfloat - ]] -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, - utfpadding=string.utfpadding, - tracedchar=string.tracedchar, - autosingle=string.autosingle, - autodouble=string.autodouble, - sequenced=table.sequenced, - formattednumber=number.formatted, - sparseexponent=number.sparseexponent, - formattedfloat=number.formattedfloat, - } -end +local preamble="" +local 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, + utfpadding=string.utfpadding, + tracedchar=string.tracedchar, + autosingle=string.autosingle, + autodouble=string.autodouble, + sequenced=table.sequenced, + formattednumber=number.formatted, + sparseexponent=number.sparseexponent, + formattedfloat=number.formattedfloat, + stripzero=lpeg.patterns.stripzero, + stripzeros=lpeg.patterns.stripzeros, + FORMAT=string.f9, +} local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) - local v=t[k-1]..",a"..k - t[k]=v - return v - end + local v=t[k-1]..",a"..k + t[k]=v + return v + end }) -local prefix_any=C((S("+- .")+R("09"))^0) -local prefix_sub=(C((S("+-")+R("09"))^0)+Cc(0))*P(".")*(C((S("+-")+R("09"))^0)+Cc(0)) +local prefix_any=C((sign+space+period+digit)^0) +local prefix_sub=(C((sign+digit)^0)+Cc(0))*period*(C((sign+digit)^0)+Cc(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 - return format("format('%%%ss',a%s)",f,n) - else - return format("(a%s or '')",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',a%s)",f,n) + else + return format("(a%s or '')",n) + end end local format_S=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%ss',tostring(a%s))",f,n) - else - return format("tostring(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%ss',tostring(a%s))",f,n) + else + return format("tostring(a%s)",n) + end end local format_right=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - elseif f>0 then - return format("utfpadding(a%s,%i)..a%s",n,f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + elseif f>0 then + return format("utfpadding(a%s,%i)..a%s",n,f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,f) + end end local format_left=function(f) - n=n+1 - f=tonumber(f) - if not f or f==0 then - return format("(a%s or '')",n) - end - if f<0 then - return format("utfpadding(a%s,%i)..a%s",n,-f,n) - else - return format("a%s..utfpadding(a%s,%i)",n,n,-f) - end + n=n+1 + f=tonumber(f) + if not f or f==0 then + return format("(a%s or '')",n) + end + if f<0 then + return format("utfpadding(a%s,%i)..a%s",n,-f,n) + else + return format("a%s..utfpadding(a%s,%i)",n,n,-f) + end end local format_q=function() - n=n+1 - return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) + n=n+1 + return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n) end local format_Q=function() - n=n+1 - return format("format('%%q',tostring(a%s))",n) + n=n+1 + return format("format('%%q',tostring(a%s))",n) end local format_i=function(f) - n=n+1 - if f and f~="" then - return format("format('%%%si',a%s)",f,n) - else - return format("format('%%i',a%s)",n) - end + n=n+1 + if f and f~="" then + return format("format('%%%si',a%s)",f,n) + else + return format("format('%%i',a%s)",n) + end end local format_d=format_i local format_I=function(f) - n=n+1 - return format("format('%%s%%%si',signed(a%s))",f,n) + n=n+1 + return format("format('%%s%%%si',signed(a%s))",f,n) end local format_f=function(f) - n=n+1 - return format("format('%%%sf',a%s)",f,n) + n=n+1 + return format("format('%%%sf',a%s)",f,n) end local format_F=function(f) - n=n+1 - if not f or f=="" then - return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) - else - return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) - end + n=n+1 + if not f or f=="" then + return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) + else + return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) + end end local format_k=function(b,a) - n=n+1 - return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) + n=n+1 + return format("formattedfloat(a%s,%i,%i)",n,b or 0,a or 0) end local format_g=function(f) - n=n+1 - return format("format('%%%sg',a%s)",f,n) + n=n+1 + return format("format('%%%sg',a%s)",f,n) end local format_G=function(f) - n=n+1 - return format("format('%%%sG',a%s)",f,n) + n=n+1 + return format("format('%%%sG',a%s)",f,n) end local format_e=function(f) - n=n+1 - return format("format('%%%se',a%s)",f,n) + n=n+1 + return format("format('%%%se',a%s)",f,n) end local format_E=function(f) - n=n+1 - return format("format('%%%sE',a%s)",f,n) + 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) + 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) + 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) + n=n+1 + return format("format('%%%sx',a%s)",f,n) end local format_X=function(f) - n=n+1 - return format("format('%%%sX',a%s)",f,n) + n=n+1 + return format("format('%%%sX',a%s)",f,n) end local format_o=function(f) - n=n+1 - return format("format('%%%so',a%s)",f,n) + n=n+1 + return format("format('%%%so',a%s)",f,n) end local format_c=function() - n=n+1 - return format("utfchar(a%s)",n) + n=n+1 + return format("utfchar(a%s)",n) end local format_C=function() - n=n+1 - return format("tracedchar(a%s)",n) + n=n+1 + return format("tracedchar(a%s)",n) end local format_r=function(f) - n=n+1 - return format("format('%%%s.0f',a%s)",f,n) + n=n+1 + return format("format('%%%s.0f',a%s)",f,n) end local format_h=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_H=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('0x%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_u=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('u+%%%sx',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_U=function(f) - n=n+1 - if f=="-" then - f=sub(f,2) - return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - else - return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) - end + n=n+1 + if f=="-" then + f=sub(f,2) + return format("format('%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + else + return format("format('U+%%%sX',type(a%s) == 'number' and a%s or utfbyte(a%s))",f=="" and "05" or f,n,n,n) + end end local format_p=function() - n=n+1 - return format("points(a%s)",n) + n=n+1 + return format("points(a%s)",n) end local format_b=function() - n=n+1 - return format("basepoints(a%s)",n) + n=n+1 + return format("basepoints(a%s)",n) end local format_t=function(f) - n=n+1 - if f and f~="" then - return format("concat(a%s,%q)",n,f) - else - return format("concat(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("concat(a%s,%q)",n,f) + else + return format("concat(a%s)",n) + end end local format_T=function(f) - n=n+1 - if f and f~="" then - return format("sequenced(a%s,%q)",n,f) - else - return format("sequenced(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("sequenced(a%s,%q)",n,f) + else + return format("sequenced(a%s)",n) + end end local format_l=function() - n=n+1 - return format("(a%s and 'true' or 'false')",n) + n=n+1 + return format("(a%s and 'true' or 'false')",n) end local format_L=function() - n=n+1 - return format("(a%s and 'TRUE' or 'FALSE')",n) + n=n+1 + return format("(a%s and 'TRUE' or 'FALSE')",n) end -local format_N=function() - n=n+1 - return format("tostring(tonumber(a%s) or a%s)",n,n) +local format_n=function() + n=n+1 + return format("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n) +end +local format_N=function(f) + n=n+1 + if not f or f=="" then + f=".9" + end + return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n) end local format_a=function(f) - n=n+1 - if f and f~="" then - return format("autosingle(a%s,%q)",n,f) - else - return format("autosingle(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autosingle(a%s,%q)",n,f) + else + return format("autosingle(a%s)",n) + end end local format_A=function(f) - n=n+1 - if f and f~="" then - return format("autodouble(a%s,%q)",n,f) - else - return format("autodouble(a%s)",n) - end + n=n+1 + if f and f~="" then + return format("autodouble(a%s,%q)",n,f) + else + return format("autodouble(a%s)",n) + end end local format_w=function(f) - n=n+1 - f=tonumber(f) - if f then - return format("nspaces[%s+a%s]",f,n) - else - return format("nspaces[a%s]",n) - end + n=n+1 + f=tonumber(f) + if f then + return format("nspaces[%s+a%s]",f,n) + else + return format("nspaces[a%s]",n) + end end local format_W=function(f) - return format("nspaces[%s]",tonumber(f) or 0) + return format("nspaces[%s]",tonumber(f) or 0) end local format_m=function(f) - n=n+1 - if not f or f=="" then - f="," - end + n=n+1 + if not f or f=="" then + f="," + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,".")]],n,f) + end end local format_M=function(f) - n=n+1 - if not f or f=="" then - f="." - end + n=n+1 + if not f or f=="" then + f="." + end + if f=="0" then + return format([[formattednumber(a%s,false)]],n) + else return format([[formattednumber(a%s,%q,",")]],n,f) + end end local format_z=function(f) - n=n+(tonumber(f) or 1) - return "''" + n=n+(tonumber(f) or 1) + return "''" end local format_rest=function(s) - return format("%q",s) + return format("%q",s) end local format_extension=function(extensions,f,name) - local extension=extensions[name] or "tostring(%s)" - local f=tonumber(f) or 1 - local w=find(extension,"%.%.%.") + local extension=extensions[name] or "tostring(%s)" + local f=tonumber(f) or 1 + local w=find(extension,"%.%.%.") + if w then if f==0 then - if w then - extension=gsub(extension,"%.%.%.","") - end - return extension + extension=gsub(extension,"%.%.%.","") + return extension elseif f==1 then - if w then - extension=gsub(extension,"%.%.%.","%%s") - end - n=n+1 - local a="a"..n - return format(extension,a,a) + extension=gsub(extension,"%.%.%.","%%s") + n=n+1 + local a="a"..n + return format(extension,a,a) elseif f<0 then - local a="a"..(n+f+1) - return format(extension,a,a) + local a="a"..(n+f+1) + return format(extension,a,a) else - if w then - extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") - end - local t={} - for i=1,f do - n=n+1 - t[i]="a"..n - end - return format(extension,unpack(t)) + extension=gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + local t={} + for i=1,f do + n=n+1 + t[i]="a"..n + end + return format(extension,unpack(t)) end + else + extension=gsub(extension,"%%s",function() + n=n+1 + return "a"..n + end) + return extension + end end local builder=Cs { "start", - start=( - ( - P("%")/""*( - V("!") + start=( + ( + P("%")/""*( + V("!") +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("N") +V("k") +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") @@ -6750,160 +7147,156 @@ local builder=Cs { "start", +V("z") +V(">") +V("<") - )+V("*") - )*(P(-1)+Carg(1)) - )^0, - ["s"]=(prefix_any*P("s"))/format_s, - ["q"]=(prefix_any*P("q"))/format_q, - ["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, - ["E"]=(prefix_any*P("E"))/format_E, - ["x"]=(prefix_any*P("x"))/format_x, - ["X"]=(prefix_any*P("X"))/format_X, - ["o"]=(prefix_any*P("o"))/format_o, - ["S"]=(prefix_any*P("S"))/format_S, - ["Q"]=(prefix_any*P("Q"))/format_Q, - ["N"]=(prefix_any*P("N"))/format_N, - ["k"]=(prefix_sub*P("k"))/format_k, - ["c"]=(prefix_any*P("c"))/format_c, - ["C"]=(prefix_any*P("C"))/format_C, - ["r"]=(prefix_any*P("r"))/format_r, - ["h"]=(prefix_any*P("h"))/format_h, - ["H"]=(prefix_any*P("H"))/format_H, - ["u"]=(prefix_any*P("u"))/format_u, - ["U"]=(prefix_any*P("U"))/format_U, - ["p"]=(prefix_any*P("p"))/format_p, - ["b"]=(prefix_any*P("b"))/format_b, - ["t"]=(prefix_tab*P("t"))/format_t, - ["T"]=(prefix_tab*P("T"))/format_T, - ["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, - ["<"]=(prefix_any*P("<"))/format_left, - [">"]=(prefix_any*P(">"))/format_right, - ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, - ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, - ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, + )+V("*") + )*(endofstring+Carg(1)) + )^0, + ["s"]=(prefix_any*P("s"))/format_s, + ["q"]=(prefix_any*P("q"))/format_q, + ["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, + ["E"]=(prefix_any*P("E"))/format_E, + ["x"]=(prefix_any*P("x"))/format_x, + ["X"]=(prefix_any*P("X"))/format_X, + ["o"]=(prefix_any*P("o"))/format_o, + ["S"]=(prefix_any*P("S"))/format_S, + ["Q"]=(prefix_any*P("Q"))/format_Q, + ["n"]=(prefix_any*P("n"))/format_n, + ["N"]=(prefix_any*P("N"))/format_N, + ["k"]=(prefix_sub*P("k"))/format_k, + ["c"]=(prefix_any*P("c"))/format_c, + ["C"]=(prefix_any*P("C"))/format_C, + ["r"]=(prefix_any*P("r"))/format_r, + ["h"]=(prefix_any*P("h"))/format_h, + ["H"]=(prefix_any*P("H"))/format_H, + ["u"]=(prefix_any*P("u"))/format_u, + ["U"]=(prefix_any*P("U"))/format_U, + ["p"]=(prefix_any*P("p"))/format_p, + ["b"]=(prefix_any*P("b"))/format_b, + ["t"]=(prefix_tab*P("t"))/format_t, + ["T"]=(prefix_tab*P("T"))/format_T, + ["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_any*P("m"))/format_m, + ["M"]=(prefix_any*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, + ["<"]=(prefix_any*P("<"))/format_left, + [">"]=(prefix_any*P(">"))/format_right, + ["*"]=Cs(((1-P("%"))^1+P("%%")/"%%")^1)/format_rest, + ["?"]=Cs(((1-P("%"))^1 )^1)/format_rest, + ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } local xx=setmetatable({},{ __index=function(t,k) local v=format("%02x",k) t[k]=v return v end }) local XX=setmetatable({},{ __index=function(t,k) local v=format("%02X",k) t[k]=v return v end }) local preset={ - ["%02x"]=function(n) return xx[n] end, - ["%02X"]=function(n) return XX[n] end, + ["%02x"]=function(n) return xx[n] end, + ["%02X"]=function(n) return XX[n] end, } -local direct=P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] +local direct=P("%")*(sign+space+period+digit)^0*S("sqidfgGeExXo")*endofstring/[[local format = string.format return function(str) return format("%0",str) end]] local function make(t,str) - local f=preset[str] - if f then - return f - end - local p=lpegmatch(direct,str) - if p then - f=loadstripped(p)() + local f=preset[str] + if f then + return f + end + local p=lpegmatch(direct,str) + if p then + f=loadstripped(p)() + else + n=0 + 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,t._environment_)() else - n=0 - 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,t._environment_)() - else - f=function() return str end - end + f=function() return str end end - t[str]=f - return f + end + t[str]=f + return f end local function use(t,fmt,...) - return t[fmt](...) + return t[fmt](...) end strings.formatters={} -if oldfashioned 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 +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 local formatters=strings.formatters.new() string.formatters=formatters 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 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 + if type(t)=="table" and t._type_=="formatter" then + t._extensions_[name]=template or "%s" + 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 -patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) -patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) +patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+anything)^0) +patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+anything)^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 oldfashioned 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 +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 }) local dquote=patterns.dquote local equote=patterns.escaped+dquote/'\\"'+1 -local space=patterns.space local cquote=Cc('"') -local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) +Cs(cquote*(equote-space)^0*space*equote^0*cquote) function string.optionalquoted(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local pattern=Cs((newline/(os.newline or "\r")+1)^0) function string.replacenewlines(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function strings.newcollector() - local result,r={},0 - return - function(fmt,str,...) - r=r+1 - result[r]=str==nil and fmt or formatters[fmt](str,...) - end, - function(connector) - if result then - local str=concat(result,connector) - result,r={},0 - return str - end - end + local result,r={},0 + return + function(fmt,str,...) + r=r+1 + result[r]=str==nil and fmt or formatters[fmt](str,...) + end, + function(connector) + if result then + local str=concat(result,connector) + result,r={},0 + return str + end + end +end +local f_16_16=formatters["%0.5N"] +function number.to16dot16(n) + return f_16_16(n/65536.0) end @@ -6913,14 +7306,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tab"] = package.loaded["util-tab"] or true --- original size: 27741, stripped down to: 17085 +-- original size: 28772, stripped down to: 16111 if not modules then modules={} end modules ['util-tab']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.tables=utilities.tables or {} @@ -6935,219 +7328,220 @@ local formatters=string.formatters local utftoeight=utf.toeight local splitter=lpeg.tsplitat(".") 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=composed.."."..name - t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) - else - composed=name - if not nofirst then - t[#t+1]=formatters["%s = %s or { }"](composed,composed) - end - end - end + local composed=nil + local t={} + local snippets=lpegmatch(splitter,target) + for i=1,#snippets-(nolast and 1 or 0) do + local name=snippets[i] if composed then - if nolast then - composed=composed.."."..snippets[#snippets] - end - return concat(t,"\n"),composed + composed=composed.."."..name + t[#t+1]=formatters["if not %s then %s = { } end"](composed,composed) else - return "",target + composed=name + if not nofirst then + t[#t+1]=formatters["%s = %s or { }"](composed,composed) + end + end + end + if composed then + if nolast then + composed=composed.."."..snippets[#snippets] end + return concat(t,"\n"),composed + else + return "",target + end end function tables.definedtable(...) - local t=_G - for i=1,select("#",...) do - local li=select(i,...) - local tl=t[li] - if not tl then - tl={} - t[li]=tl - end - t=tl - end - return t + local t=_G + for i=1,select("#",...) do + local li=select(i,...) + local tl=t[li] + if not tl then + tl={} + t[li]=tl + end + t=tl + end + return t end function tables.accesstable(target,root) - local t=root or _G - for name in gmatch(target,"([^%.]+)") do - t=t[name] - if not t then - return - end + local t=root or _G + for name in gmatch(target,"([^%.]+)") do + t=t[name] + if not t then + return end - return t + end + return t end function tables.migratetable(target,v,root) - local t=root or _G - local names=lpegmatch(splitter,target) - for i=1,#names-1 do - local name=names[i] - t[name]=t[name] or {} - t=t[name] - if not t then - return - end + local t=root or _G + local names=lpegmatch(splitter,target) + for i=1,#names-1 do + local name=names[i] + t[name]=t[name] or {} + t=t[name] + if not t then + return end - t[names[#names]]=v + end + t[names[#names]]=v end function tables.removevalue(t,value) - if value then - for i=1,#t do - if t[i]==value then - remove(t,i) - end - end + if value then + for i=1,#t do + if t[i]==value then + remove(t,i) + end end + end end function tables.replacevalue(t,oldvalue,newvalue) - if oldvalue and newvalue then - for i=1,#t do - if t[i]==oldvalue then - t[i]=newvalue - end - end + if oldvalue and newvalue then + for i=1,#t do + if t[i]==oldvalue then + t[i]=newvalue + end end + end end function tables.insertbeforevalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i,extra) + return end - insert(t,1,extra) + end + insert(t,1,extra) end function tables.insertaftervalue(t,value,extra) - for i=1,#t do - if t[i]==extra then - remove(t,i) - end + for i=1,#t do + if t[i]==extra then + remove(t,i) end - for i=1,#t do - if t[i]==value then - insert(t,i+1,extra) - return - end + end + for i=1,#t do + if t[i]==value then + insert(t,i+1,extra) + return end - insert(t,#t+1,extra) + end + insert(t,#t+1,extra) end local escape=Cs(Cc('"')*((P('"')/'""'+P(1))^0)*Cc('"')) function table.tocsv(t,specification) - if t and #t>0 then - local result={} - local r={} - specification=specification or {} - local fields=specification.fields - if type(fields)~="string" then - fields=sortedkeys(t[1]) - end - local separator=specification.separator or "," - local noffields=#fields - if specification.preamble==true then - for f=1,noffields do - r[f]=lpegmatch(escape,tostring(fields[f])) - end - result[1]=concat(r,separator) - end - for i=1,#t do - local ti=t[i] - for f=1,noffields do - local field=ti[fields[f]] - if type(field)=="string" then - r[f]=lpegmatch(escape,field) - else - r[f]=tostring(field) - end - end - result[i+1]=concat(r,separator) + if t and #t>0 then + local result={} + local r={} + specification=specification or {} + local fields=specification.fields + if type(fields)~="string" then + fields=sortedkeys(t[1]) + end + local separator=specification.separator or "," + local noffields=#fields + if specification.preamble==true then + for f=1,noffields do + r[f]=lpegmatch(escape,tostring(fields[f])) + end + result[1]=concat(r,separator) + end + for i=1,#t do + local ti=t[i] + for f=1,noffields do + local field=ti[fields[f]] + if type(field)=="string" then + r[f]=lpegmatch(escape,field) + else + r[f]=tostring(field) end - return concat(result,"\n") - else - return "" + end + result[i+1]=concat(r,separator) end + return concat(result,"\n") + else + return "" + end end local nspaces=utilities.strings.newrepeater(" ") local function toxml(t,d,result,step) - local r=#result - for k,v in sortedpairs(t) do - local s=nspaces[d] - local tk=type(k) - local tv=type(v) - if tv=="table" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</entry>"](s,k) - else - r=r+1 result[r]=formatters["%s<%s>"](s,k) - toxml(v,d+step,result,step) - r=r+1 result[r]=formatters["%s</%s>"](s,k) - end - elseif tv=="string" then - if tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) - end - elseif tk=="number" then - r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) - else - r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) - end + local r=#result + for k,v in sortedpairs(t) do + local s=nspaces[d] + local tk=type(k) + local tv=type(v) + if tv=="table" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</entry>"](s,k) + else + r=r+1 result[r]=formatters["%s<%s>"](s,k) + toxml(v,d+step,result,step) + r=r+1 result[r]=formatters["%s</%s>"](s,k) + end + elseif tv=="string" then + if tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%!xml!</%s>"](s,k,v,k) + end + elseif tk=="number" then + r=r+1 result[r]=formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k) + else + r=r+1 result[r]=formatters["%s<%s>%S</%s>"](s,k,v,k) end + end end function table.toxml(t,specification) - specification=specification or {} - local name=specification.name - local noroot=name==false - local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } - local indent=specification.indent or 0 - local spaces=specification.spaces or 1 - if noroot then - toxml(t,indent,result,spaces) - else - toxml({ [name or "data"]=t },indent,result,spaces) - end - return concat(result,"\n") + specification=specification or {} + local name=specification.name + local noroot=name==false + local result=(specification.nobanner or noroot) and {} or { "<?xml version='1.0' standalone='yes' ?>" } + local indent=specification.indent or 0 + local spaces=specification.spaces or 1 + if noroot then + toxml(t,indent,result,spaces) + else + toxml({ [name or "data"]=t },indent,result,spaces) + end + return concat(result,"\n") end function tables.encapsulate(core,capsule,protect) - if type(capsule)~="table" then - protect=true - capsule={} - end + if type(capsule)~="table" then + protect=true + capsule={} + end + for key,value in next,core do + if capsule[key] then + print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) + os.exit() + else + capsule[key]=value + end + end + if protect then for key,value in next,core do + core[key]=nil + end + setmetatable(core,{ + __index=capsule, + __newindex=function(t,key,value) if capsule[key] then - print(formatters["\ninvalid %s %a in %a"]("inheritance",key,core)) - os.exit() + print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) + os.exit() else - capsule[key]=value + rawset(t,key,value) end - end - if protect then - for key,value in next,core do - core[key]=nil - end - setmetatable(core,{ - __index=capsule, - __newindex=function(t,key,value) - if capsule[key] then - print(formatters["\ninvalid %s %a' in %a"]("overload",key,core)) - os.exit() - else - rawset(t,key,value) - end - end - } ) - end + end + } ) + end end local f_hashed_string=formatters["[%q]=%q,"] local f_hashed_number=formatters["[%q]=%s,"] @@ -7161,157 +7555,157 @@ 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 + 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 - for k,v in next,t do - 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 + end + for k,v in next,t do + 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 - m=m+1 - if outer then - r[m]="}" - else - r[m]="}," + 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 - return r + end end - return concat(fastserialize(t,true)) + m=m+1 + if outer then + r[m]="}" + else + r[m]="}," + end + return r + end + return concat(fastserialize(t,true)) end function table.deserialize(str) - if not str or str=="" then - return - end - local code=load(str) - if not code then - return - end - code=code() - if not code then - return - end - return code + if not str or str=="" then + return + end + local code=load(str) + if not code then + return + end + code=code() + if not code then + return + end + return code end 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() - if type(t)=="table" then - return t - end - end + 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() + if type(t)=="table" then + return t end + end end + end end function table.save(filename,t,n,...) - io.savedata(filename,table.serialize(t,n==nil and true or n,...)) + io.savedata(filename,table.serialize(t,n==nil and true or n,...)) end 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 - local ti=t[i] - local j=0 - for k,v in next,ti do - j=j+1 - l[j]=f_key_value(k,v) - end - r[i]=f_add_table(l) - end - return f_return_table(r) + local r={} + local l={} + for i=1,#t do + local ti=t[i] + local j=0 + for k,v in next,ti do + j=j+1 + l[j]=f_key_value(k,v) + end + r[i]=f_add_table(l) + end + 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] - m=m+1 r[m]=" {" - for k,v in next,ti do - m=m+1 r[m]=f_key_value(k,v) - end - m=m+1 r[m]="},\n" - end - m=m+1 - r[m]="}" - return concat(r) + local r={ "return {\n" } + local m=1 + for i=1,#t do + local ti=t[i] + m=m+1 r[m]=" {" + for k,v in next,ti do + m=m+1 r[m]=f_key_value(k,v) + end + m=m+1 r[m]="},\n" + end + m=m+1 + r[m]="}" + return concat(r) end function table.drop(t,slow) - if #t==0 then - return "return { }" - elseif slow==true then - return slowdrop(t) - else - return fastdrop(t) - end + if #t==0 then + return "return { }" + elseif slow==true then + return slowdrop(t) + else + return fastdrop(t) + end end local selfmapper={ __index=function(t,k) t[k]=k return k end } -function table.twowaymapper(t) - if not t then - t={} - else - local zero=rawget(t,0) - for i=zero and 0 or 1,#t do - local ti=t[i] - if ti then - local i=tostring(i) - t[i]=ti - t[ti]=i - end - end +function table.twowaymapper(t) + if not t then + t={} + else + local zero=rawget(t,0) + for i=zero and 0 or 1,#t do + local ti=t[i] + if ti then + local i=tostring(i) + t[i]=ti + t[ti]=i + end end - setmetatable(t,selfmapper) - return t + end + setmetatable(t,selfmapper) + return t end local f_start_key_idx=formatters["%w{"] local f_start_key_num=formatters["%w[%s]={"] @@ -7349,187 +7743,223 @@ local spaces=utilities.strings.newrepeater(" ") local original_serialize=table.serialize local is_simple_table=table.is_simple_table local function serialize(root,name,specification) - if type(specification)=="table" then - return original_serialize(root,name,specification) - end - local t - local n=1 - local unknown=false - 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) + if type(specification)=="table" then + return original_serialize(root,name,specification) + end + local t + local n=1 + local unknown=false + 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)~=nil then + local first=nil + local last=0 + last=#root + for k=1,last do + if rawget(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<=last and k>=first 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 next(v)==nil then + n=n+1 t[n]=f_val_not(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)~=nil then - local first=nil - local last=0 - last=#root - for k=1,last do - if rawget(root,k)==nil then - last=k-1 - break - end + local st=is_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 - if last>0 then - first=1 + elseif tv=="boolean" then + n=n+1 t[n]=f_val_boo(depth,v) + elseif unknown then + n=n+1 t[n]=f_val_str(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) + end + elseif tv=="table" then + if next(v)==nil then + if tk=="number" then + n=n+1 t[n]=f_key_num_value_not(depth,k) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_not(depth,k) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_not(depth,k) + elseif unknown then + n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) 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<=last and k>=first 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 next(v)==nil then - n=n+1 t[n]=f_val_not(depth) - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_val_str(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_num(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),v) - end - elseif tv=="table" then - if next(v)==nil then - if tk=="number" then - n=n+1 t[n]=f_key_num_value_not(depth,k) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_not(depth,k) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_not(depth,k) - elseif unknown then - n=n+1 t[n]=f_key_str_value_not(depth,tostring(k)) - end - else - local st=is_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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_seq(depth,tostring(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) - elseif unknown then - n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) - end - else - if tk=="number" then - n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) - elseif tk=="string" then - n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) - elseif tk=="boolean" then - n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) - elseif unknown then - n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(v)) - end - end + else + local st=is_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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_seq(depth,tostring(k),st) 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() } + 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) + elseif unknown then + n=n+1 t[n]=f_key_str_value_boo(depth,tostring(k),v) + end else - t={ f_table_direct() } + if tk=="number" then + n=n+1 t[n]=f_key_num_value_str(depth,k,tostring(v)) + elseif tk=="string" then + n=n+1 t[n]=f_key_str_value_str(depth,k,tostring(v)) + elseif tk=="boolean" then + n=n+1 t[n]=f_key_boo_value_str(depth,k,tostring(v)) + elseif unknown then + n=n+1 t[n]=f_key_str_value_str(depth,tostring(k),tostring(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("t") } + t={ f_table_name(name) } 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)~=nil then - local st=is_simple_table(root) - if st then - return t[1]..f_fin_seq(st) - else - do_serialize(root,name,1,0) - end - 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)~=nil then + local st=is_simple_table(root) + if st then + return t[1]..f_fin_seq(st) + else + do_serialize(root,name,1,0) + end end - n=n+1 - t[n]=f_table_finish() - return concat(t,"\n") + end + n=n+1 + t[n]=f_table_finish() + return concat(t,"\n") end table.serialize=serialize if setinspector then - setinspector("table",function(v) - if type(v)=="table" then - print(serialize(v,"table",{ metacheck=false })) - return true - end - end) + setinspector("table",function(v) + if type(v)=="table" then + print(serialize(v,"table",{ metacheck=false })) + return true + end + end) +end +local mt={ + __newindex=function(t,k,v) + local n=t.last+1 + t.last=n + t.list[n]=k + t.hash[k]=v + end, + __index=function(t,k) + return t.hash[k] + end, + __len=function(t) + return t.last + end, +} +function table.orderedhash() + return setmetatable({ list={},hash={},last=0 },mt) +end +function table.ordered(t) + local n=t.last + if n>0 then + local l=t.list + local i=1 + local h=t.hash + local f=function() + if i<=n then + local k=i + local v=h[l[k]] + i=i+1 + return k,v + end + end + return f,1,h[l[1]] + else + return function() end + end end @@ -7539,15 +7969,16 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fil"] = package.loaded["util-fil"] or true --- original size: 7787, stripped down to: 5858 +-- original size: 8607, stripped down to: 6727 if not modules then modules={} end modules ['util-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } +local tonumber=tonumber local byte=string.byte local char=string.char utilities=utilities or {} @@ -7555,251 +7986,280 @@ local files={} utilities.files=files local zerobased={} function files.open(filename,zb) - local f=io.open(filename,"rb") - if f then - zerobased[f]=zb or false - end - return f + local f=io.open(filename,"rb") + if f then + zerobased[f]=zb or false + end + return f end function files.close(f) - zerobased[f]=nil - f:close() + zerobased[f]=nil + f:close() end function files.size(f) - local current=f:seek() - local size=f:seek("end") - f:seek("set",current) - return size + local current=f:seek() + local size=f:seek("end") + f:seek("set",current) + return size end files.getsize=files.size function files.setposition(f,n) - if zerobased[f] then - f:seek("set",n) - else - f:seek("set",n-1) - end + if zerobased[f] then + f:seek("set",n) + else + f:seek("set",n-1) + end end function files.getposition(f) - if zerobased[f] then - return f:seek() - else - return f:seek()+1 - end + if zerobased[f] then + return f:seek() + else + return f:seek()+1 + end end function files.look(f,n,chars) - local p=f:seek() - local s=f:read(n) - f:seek("set",p) - if chars then - return s - else - return byte(s,1,#s) - end + local p=f:seek() + local s=f:read(n) + f:seek("set",p) + if chars then + return s + else + return byte(s,1,#s) + end end function files.skip(f,n) - if n==1 then - f:read(n) - else - f:seek("set",f:seek()+n) - end + if n==1 then + f:read(n) + else + f:seek("set",f:seek()+n) + end end function files.readbyte(f) - return byte(f:read(1)) + return byte(f:read(1)) end function files.readbytes(f,n) - return byte(f:read(n),1,n) + return byte(f:read(n),1,n) end function files.readbytetable(f,n) - local s=f:read(n or 1) - return { byte(s,1,#s) } + local s=f:read(n or 1) + return { byte(s,1,#s) } end function files.readchar(f) - return f:read(1) + return f:read(1) end function files.readstring(f,n) - return f:read(n or 1) + return f:read(n or 1) end -function files.readinteger1(f) - local n=byte(f:read(1)) - if n>=0x80 then - return n-0x100 - else - return n - end +function files.readinteger1(f) + local n=byte(f:read(1)) + if n>=0x80 then + return n-0x100 + else + return n + end end -files.readcardinal1=files.readbyte +files.readcardinal1=files.readbyte files.readcardinal=files.readcardinal1 files.readinteger=files.readinteger1 files.readsignedbyte=files.readinteger1 function files.readcardinal2(f) - local a,b=byte(f:read(2),1,2) - return 0x100*a+b + local a,b=byte(f:read(2),1,2) + return 0x100*a+b end function files.readcardinal2le(f) - local b,a=byte(f:read(2),1,2) - return 0x100*a+b + local b,a=byte(f:read(2),1,2) + return 0x100*a+b end function files.readinteger2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readinteger2le(f) - local b,a=byte(f:read(2),1,2) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local b,a=byte(f:read(2),1,2) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function files.readcardinal3(f) - local a,b,c=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local a,b,c=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readcardinal3le(f) - local c,b,a=byte(f:read(3),1,3) - return 0x10000*a+0x100*b+c + local c,b,a=byte(f:read(3),1,3) + return 0x10000*a+0x100*b+c end function files.readinteger3(f) - local a,b,c=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local a,b,c=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readinteger3le(f) - local c,b,a=byte(f:read(3),1,3) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local c,b,a=byte(f:read(3),1,3) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function files.readcardinal4(f) - local a,b,c,d=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local a,b,c,d=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readcardinal4le(f) - local d,c,b,a=byte(f:read(4),1,4) - return 0x1000000*a+0x10000*b+0x100*c+d + local d,c,b,a=byte(f:read(4),1,4) + return 0x1000000*a+0x10000*b+0x100*c+d end function files.readinteger4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readinteger4le(f) - local d,c,b,a=byte(f:read(4),1,4) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local d,c,b,a=byte(f:read(4),1,4) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function files.readfixed2(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - return (a-0x100)+b/0x100 - else - return (a )+b/0x100 - end + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function files.readfixed4(f) - local a,b,c,d=byte(f:read(4),1,4) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local a,b,c,d=byte(f:read(4),1,4) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end if bit32 then - local extract=bit32.extract - local band=bit32.band - function files.read2dot14(f) - local a,b=byte(f:read(2),1,2) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local extract=bit32.extract + local band=bit32.band + function files.read2dot14(f) + local a,b=byte(f:read(2),1,2) + if a>=0x80 then + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) + else + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function files.skipshort(f,n) - f:read(2*(n or 1)) + f:read(2*(n or 1)) end function files.skiplong(f,n) - f:read(4*(n or 1)) + f:read(4*(n or 1)) end if bit32 then - local rshift=bit32.rshift - function files.writecardinal2(f,n) - local a=char(n%256) - n=rshift(n,8) - local b=char(n%256) - f:write(b,a) - end -else - local floor=math.floor - function files.writecardinal2(f,n) - local a=char(n%256) - n=floor(n/256) - local b=char(n%256) - f:write(b,a) - end -end -function files.writecardinal4(f,n) + local rshift=bit32.rshift + function files.writecardinal2(f,n) local a=char(n%256) n=rshift(n,8) local b=char(n%256) - n=rshift(n,8) - local c=char(n%256) - n=rshift(n,8) - local d=char(n%256) - f:write(d,c,b,a) + f:write(b,a) + end +else + local floor=math.floor + function files.writecardinal2(f,n) + local a=char(n%256) + n=floor(n/256) + local b=char(n%256) + f:write(b,a) + end +end +function files.writecardinal4(f,n) + local a=char(n%256) + n=rshift(n,8) + local b=char(n%256) + n=rshift(n,8) + local c=char(n%256) + n=rshift(n,8) + local d=char(n%256) + f:write(d,c,b,a) end function files.writestring(f,s) - f:write(char(byte(s,1,#s))) + f:write(char(byte(s,1,#s))) end function files.writebyte(f,b) - f:write(char(b)) + f:write(char(b)) end if fio and fio.readcardinal1 then - files.readcardinal1=fio.readcardinal1 - files.readcardinal2=fio.readcardinal2 - files.readcardinal3=fio.readcardinal3 - files.readcardinal4=fio.readcardinal4 - files.readinteger1=fio.readinteger1 - files.readinteger2=fio.readinteger2 - files.readinteger3=fio.readinteger3 - files.readinteger4=fio.readinteger4 - files.readfixed2=fio.readfixed2 - files.readfixed4=fio.readfixed4 - files.read2dot14=fio.read2dot14 - files.setposition=fio.setposition - files.getposition=fio.getposition - files.readbyte=files.readcardinal1 - files.readsignedbyte=files.readinteger1 - files.readcardinal=files.readcardinal1 - files.readinteger=files.readinteger1 - local skipposition=fio.skipposition - files.skipposition=skipposition - files.readbytes=fio.readbytes - files.readbytetable=fio.readbytetable - function files.skipshort(f,n) - skipposition(f,2*(n or 1)) - end - function files.skiplong(f,n) - skipposition(f,4*(n or 1)) - end + files.readcardinal1=fio.readcardinal1 + files.readcardinal2=fio.readcardinal2 + files.readcardinal3=fio.readcardinal3 + files.readcardinal4=fio.readcardinal4 + files.readinteger1=fio.readinteger1 + files.readinteger2=fio.readinteger2 + files.readinteger3=fio.readinteger3 + files.readinteger4=fio.readinteger4 + files.readfixed2=fio.readfixed2 + files.readfixed4=fio.readfixed4 + files.read2dot14=fio.read2dot14 + files.setposition=fio.setposition + files.getposition=fio.getposition + files.readbyte=files.readcardinal1 + files.readsignedbyte=files.readinteger1 + files.readcardinal=files.readcardinal1 + files.readinteger=files.readinteger1 + local skipposition=fio.skipposition + files.skipposition=skipposition + files.readbytes=fio.readbytes + files.readbytetable=fio.readbytetable + function files.skipshort(f,n) + skipposition(f,2*(n or 1)) + end + function files.skiplong(f,n) + skipposition(f,4*(n or 1)) + end +end +if fio and fio.readcardinaltable then + files.readcardinaltable=fio.readcardinaltable + files.readintegertable=fio.readintegertable +else + local readcardinal1=files.readcardinal1 + local readcardinal2=files.readcardinal2 + local readcardinal3=files.readcardinal3 + local readcardinal4=files.readcardinal4 + function files.readcardinaltable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end + return t + end + local readinteger1=files.readinteger1 + local readinteger2=files.readinteger2 + local readinteger3=files.readinteger3 + local readinteger4=files.readinteger4 + function files.readintegertable(f,n,b) + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end + return t + end end @@ -7809,338 +8269,412 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sac"] = package.loaded["util-sac"] or true --- original size: 8716, stripped down to: 6754 +-- original size: 11065, stripped down to: 8209 if not modules then modules={} end modules ['util-sac']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local byte,sub=string.byte,string.sub -local extract=bit32 and bit32.extract +local tonumber=tonumber utilities=utilities or {} local streams={} utilities.streams=streams function streams.open(filename,zerobased) - local f=io.loaddata(filename) + local f=filename and io.loaddata(filename) + if f then return { f,1,#f,zerobased or false } + end +end +function streams.openstring(f,zerobased) + if f then + return { f,1,#f,zerobased or false } + end end function streams.close() end function streams.size(f) - return f and f[3] or 0 + return f and f[3] or 0 end function streams.setposition(f,i) - if f[4] then - if i<=0 then - f[2]=1 - else - f[2]=i+1 - end + if f[4] then + if i<=0 then + f[2]=1 else - if i<=1 then - f[2]=1 - else - f[2]=i - end + f[2]=i+1 end -end -function streams.getposition(f) - if f[4] then - return f[2]-1 + else + if i<=1 then + f[2]=1 else - return f[2] + f[2]=i end + end +end +function streams.getposition(f) + if f[4] then + return f[2]-1 + else + return f[2] + end end function streams.look(f,n,chars) - local b=f[2] - local e=b+n-1 - if chars then - return sub(f[1],b,e) - else - return byte(f[1],b,e) - end + local b=f[2] + local e=b+n-1 + if chars then + return sub(f[1],b,e) + else + return byte(f[1],b,e) + end end function streams.skip(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readbyte(f) - local i=f[2] - f[2]=i+1 - return byte(f[1],i) + local i=f[2] + f[2]=i+1 + return byte(f[1],i) end function streams.readbytes(f,n) - local i=f[2] - local j=i+n - f[2]=j - return byte(f[1],i,j-1) + local i=f[2] + local j=i+n + f[2]=j + return byte(f[1],i,j-1) end function streams.readbytetable(f,n) - local i=f[2] - local j=i+n - f[2]=j - return { byte(f[1],i,j-1) } + local i=f[2] + local j=i+n + f[2]=j + return { byte(f[1],i,j-1) } end function streams.skipbytes(f,n) - f[2]=f[2]+n + f[2]=f[2]+n end function streams.readchar(f) - local i=f[2] - f[2]=i+1 - return sub(f[1],i,i) + local i=f[2] + f[2]=i+1 + return sub(f[1],i,i) end function streams.readstring(f,n) - local i=f[2] - local j=i+n - f[2]=j - return sub(f[1],i,j-1) -end -function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - local n=byte(f[1],i) - if n>=0x80 then - return n-0x100 - else - return n - end + local i=f[2] + local j=i+n + f[2]=j + return sub(f[1],i,j-1) +end +function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + local n=byte(f[1],i) + if n>=0x80 then + return n-0x100 + else + return n + end end -streams.readcardinal1=streams.readbyte +streams.readcardinal1=streams.readbyte streams.readcardinal=streams.readcardinal1 streams.readinteger=streams.readinteger1 function streams.readcardinal2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + return 0x100*a+b end function streams.readcardinal2LE(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - return 0x100*a+b + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + return 0x100*a+b end function streams.readinteger2(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readinteger2le(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x100*a+b-0x10000 - else - return 0x100*a+b - end + local i=f[2] + local j=i+1 + f[2]=j+1 + local b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x100*a+b-0x10000 + else + return 0x100*a+b + end end function streams.readcardinal3(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readcardinal3le(f) - local i=f[2] - local j=i+2 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - return 0x10000*a+0x100*b+c + local i=f[2] + local j=i+2 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + return 0x10000*a+0x100*b+c end function streams.readinteger3(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readinteger3le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x10000*a+0x100*b+c-0x1000000 - else - return 0x10000*a+0x100*b+c - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x10000*a+0x100*b+c-0x1000000 + else + return 0x10000*a+0x100*b+c + end end function streams.readcardinal4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - return 0x1000000*a+0x10000*b+0x100*c+d + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + return 0x1000000*a+0x10000*b+0x100*c+d end function streams.readinteger4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end end function streams.readinteger4le(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local d,c,b,a=byte(f[1],i,j) - if a>=0x80 then - return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 - else - return 0x1000000*a+0x10000*b+0x100*c+d - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local d,c,b,a=byte(f[1],i,j) + if a>=0x80 then + return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000 + else + return 0x1000000*a+0x10000*b+0x100*c+d + end +end +function streams.readfixed2(f) + local i=f[2] + local j=i+1 + f[2]=j+1 + local a,b=byte(f[1],i,j) + if a>=0x80 then + tonumber((a-0x100).."."..b) + else + tonumber((a ).."."..b) + end end function streams.readfixed4(f) - local i=f[2] - local j=i+3 - f[2]=j+1 - local a,b,c,d=byte(f[1],i,j) - if a>=0x80 then - return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 - else - return (0x100*a+b )+(0x100*c+d)/0x10000 - end + local i=f[2] + local j=i+3 + f[2]=j+1 + local a,b,c,d=byte(f[1],i,j) + if a>=0x80 then + tonumber((0x100*a+b-0x10000).."."..(0x100*c+d)) + else + tonumber((0x100*a+b ).."."..(0x100*c+d)) + end end -function streams.readfixed2(f) +if bit32 then + local extract=bit32.extract + local band=bit32.band + function streams.read2dot14(f) local i=f[2] local j=i+1 f[2]=j+1 local a,b=byte(f[1],i,j) if a>=0x80 then - return (a-0x100)+b/0x100 + local n=-(0x100*a+b) + return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) else - return (a )+b/0x100 - end -end -if extract then - local extract=bit32.extract - local band=bit32.band - function streams.read2dot14(f) - local i=f[2] - local j=i+1 - f[2]=j+1 - local a,b=byte(f[1],i,j) - if a>=0x80 then - local n=-(0x100*a+b) - return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - else - local n=0x100*a+b - return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) - end + local n=0x100*a+b + return (extract(n,14,2)+(band(n,0x3FFF)/16384.0)) end + end end function streams.skipshort(f,n) - f[2]=f[2]+2*(n or 1) + f[2]=f[2]+2*(n or 1) end function streams.skiplong(f,n) - f[2]=f[2]+4*(n or 1) + f[2]=f[2]+4*(n or 1) end if sio and sio.readcardinal2 then - local readcardinal1=sio.readcardinal1 - local readcardinal2=sio.readcardinal2 - local readcardinal3=sio.readcardinal3 - local readcardinal4=sio.readcardinal4 - local readinteger1=sio.readinteger1 - local readinteger2=sio.readinteger2 - local readinteger3=sio.readinteger3 - local readinteger4=sio.readinteger4 - local readfixed2=sio.readfixed2 - local readfixed4=sio.readfixed4 - local read2dot14=sio.read2dot14 - local readbytes=sio.readbytes - local readbytetable=sio.readbytetable - function streams.readcardinal1(f) - local i=f[2] - f[2]=i+1 - return readcardinal1(f[1],i) - end - function streams.readcardinal2(f) - local i=f[2] - f[2]=i+2 - return readcardinal2(f[1],i) - end - function streams.readcardinal3(f) - local i=f[2] - f[2]=i+3 - return readcardinal3(f[1],i) - end - function streams.readcardinal4(f) - local i=f[2] - f[2]=i+4 - return readcardinal4(f[1],i) - end - function streams.readinteger1(f) - local i=f[2] - f[2]=i+1 - return readinteger1(f[1],i) - end - function streams.readinteger2(f) - local i=f[2] - f[2]=i+2 - return readinteger2(f[1],i) - end - function streams.readinteger3(f) - local i=f[2] - f[2]=i+3 - return readinteger3(f[1],i) - end - function streams.readinteger4(f) - local i=f[2] - f[2]=i+4 - return readinteger4(f[1],i) - end - function streams.read2dot4(f) - local i=f[2] - f[2]=i+2 - return read2dot4(f[1],i) - end - function streams.readbytes(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytes(f[1],i,n) + local readcardinal1=sio.readcardinal1 + local readcardinal2=sio.readcardinal2 + local readcardinal3=sio.readcardinal3 + local readcardinal4=sio.readcardinal4 + local readinteger1=sio.readinteger1 + local readinteger2=sio.readinteger2 + local readinteger3=sio.readinteger3 + local readinteger4=sio.readinteger4 + local readfixed2=sio.readfixed2 + local readfixed4=sio.readfixed4 + local read2dot14=sio.read2dot14 + local readbytes=sio.readbytes + local readbytetable=sio.readbytetable + function streams.readcardinal1(f) + local i=f[2] + f[2]=i+1 + return readcardinal1(f[1],i) + end + function streams.readcardinal2(f) + local i=f[2] + f[2]=i+2 + return readcardinal2(f[1],i) + end + function streams.readcardinal3(f) + local i=f[2] + f[2]=i+3 + return readcardinal3(f[1],i) + end + function streams.readcardinal4(f) + local i=f[2] + f[2]=i+4 + return readcardinal4(f[1],i) + end + function streams.readinteger1(f) + local i=f[2] + f[2]=i+1 + return readinteger1(f[1],i) + end + function streams.readinteger2(f) + local i=f[2] + f[2]=i+2 + return readinteger2(f[1],i) + end + function streams.readinteger3(f) + local i=f[2] + f[2]=i+3 + return readinteger3(f[1],i) + end + function streams.readinteger4(f) + local i=f[2] + f[2]=i+4 + return readinteger4(f[1],i) + end + function streams.read2dot4(f) + local i=f[2] + f[2]=i+2 + return read2dot4(f[1],i) + end + function streams.readbytes(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p end - function streams.readbytetable(f,n) - local i=f[2] - local s=f[3] - local p=i+n - if p>s then - f[2]=s+1 - else - f[2]=p - end - return readbytetable(f[1],i,n) + return readbytes(f[1],i,n) + end + function streams.readbytetable(f,n) + local i=f[2] + local s=f[3] + local p=i+n + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readbytetable(f[1],i,n) + end + streams.readbyte=streams.readcardinal1 + streams.readsignedbyte=streams.readinteger1 + streams.readcardinal=streams.readcardinal1 + streams.readinteger=streams.readinteger1 +end +if sio and sio.readcardinaltable then + local readcardinaltable=sio.readcardinaltable + local readintegertable=sio.readintegertable + function utilities.streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readcardinaltable(f[1],i,n,b) + end + function utilities.streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + return readintegertable(f[1],i,n,b) + end +else + local readcardinal1=streams.readcardinal1 + local readcardinal2=streams.readcardinal2 + local readcardinal3=streams.readcardinal3 + local readcardinal4=streams.readcardinal4 + function streams.readcardinaltable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p end - streams.readbyte=streams.readcardinal1 - streams.readsignedbyte=streams.readinteger1 - streams.readcardinal=streams.readcardinal1 - streams.readinteger=streams.readinteger1 + local t={} + if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end + return t + end + local readinteger1=streams.readinteger1 + local readinteger2=streams.readinteger2 + local readinteger3=streams.readinteger3 + local readinteger4=streams.readinteger4 + function streams.readintegertable(f,n,b) + local i=f[2] + local s=f[3] + local p=i+n*b + if p>s then + f[2]=s+1 + else + f[2]=p + end + local t={} + if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end + elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end + elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end + elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end + return t + end end @@ -8150,156 +8684,168 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sto"] = package.loaded["util-sto"] or true --- original size: 6449, stripped down to: 3069 +-- original size: 6661, stripped down to: 3074 if not modules then modules={} end modules ['util-sto']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local setmetatable,getmetatable,rawset,type=setmetatable,getmetatable,rawset,type utilities=utilities or {} utilities.storage=utilities.storage or {} local storage=utilities.storage function storage.mark(t) - if not t then - print("\nfatal error: storage cannot be marked\n") - os.exit() - return - end - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + if not t then + print("\nfatal error: storage cannot be marked\n") + os.exit() + return + end + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.allocate(t) - t=t or {} - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m.__storage__=true - return t + t=t or {} + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m.__storage__=true + return t end function storage.marked(t) - local m=getmetatable(t) - return m and m.__storage__ + local m=getmetatable(t) + return m and m.__storage__ end function storage.checked(t) - if not t then - report("\nfatal error: storage has not been allocated\n") - os.exit() - return - end - return t + if not t then + report("\nfatal error: storage has not been allocated\n") + os.exit() + return + end + return t end function storage.setinitializer(data,initialize) - local m=getmetatable(data) or {} - m.__index=function(data,k) - m.__index=nil - initialize() - return data[k] - end - setmetatable(data,m) + local m=getmetatable(data) or {} + m.__index=function(data,k) + m.__index=nil + initialize() + return data[k] + end + setmetatable(data,m) end local keyisvalue={ __index=function(t,k) - t[k]=k - return k + t[k]=k + return k end } function storage.sparse(t) - t=t or {} - setmetatable(t,keyisvalue) - return t -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 + t=t or {} + setmetatable(t,keyisvalue) + return t +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 f_index={ - ["empty"]=f_empty, - ["self"]=f_self, - ["table"]=f_table, - ["number"]=f_number, + ["empty"]=f_empty, + ["self"]=f_self, + ["table"]=f_table, + ["number"]=f_number, } function table.setmetatableindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - else - setmetatable(t,{ __index=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + else + setmetatable(t,{ __index=i }) + end + return t end local f_index={ - ["ignore"]=f_ignore, + ["ignore"]=f_ignore, } function table.setmetatablenewindex(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__newindex=i - else - setmetatable(t,{ __newindex=i }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__newindex=i + else + setmetatable(t,{ __newindex=i }) + end + return t end function table.setmetatablecall(t,f) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - if m then - m.__call=f - else - setmetatable(t,{ __call=f }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + if m then + m.__call=f + else + setmetatable(t,{ __call=f }) + end + return t end function table.setmetatableindices(t,f,n,c) - if type(t)~="table" then - f,t=t,{} - end - local m=getmetatable(t) - local i=f_index[f] or f - if m then - m.__index=i - m.__newindex=n - m.__call=c - else - setmetatable(t,{ - __index=i, - __newindex=n, - __call=c, - }) - end - return t + if type(t)~="table" then + f,t=t,{} + end + local m=getmetatable(t) + local i=f_index[f] or f + if m then + m.__index=i + m.__newindex=n + m.__call=c + else + setmetatable(t,{ + __index=i, + __newindex=n, + __call=c, + }) + end + return t end function table.setmetatablekey(t,key,value) - local m=getmetatable(t) - if not m then - m={} - setmetatable(t,m) - end - m[key]=value - return t + local m=getmetatable(t) + if not m then + m={} + setmetatable(t,m) + end + m[key]=value + return t end function table.getmetatablekey(t,key,value) - local m=getmetatable(t) - return m and m[key] + local m=getmetatable(t) + return m and m[key] +end +function table.makeweak(t) + if not t then + t={} + end + local m=getmetatable(t) + if m then + m.__mode="v" + else + setmetatable(t,{ __mode="v" }) + end + return t end @@ -8309,14 +8855,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-prs"] = package.loaded["util-prs"] or true --- original size: 22956, stripped down to: 16106 +-- original size: 23460, stripped down to: 15834 if not modules then modules={} end modules ['util-prs']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } 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 @@ -8338,6 +8884,7 @@ utilities.parsers.hashes=hashes local digit=R("09") local space=P(' ') local equal=P("=") +local colon=P(":") local comma=P(",") local lbrace=P("{") local rbrace=P("}") @@ -8357,8 +8904,8 @@ local noparent=1-(lparent+rparent) local nobracket=1-(lbracket+rbracket) local escape,left,right=P("\\"),P('{'),P('}') lpegpatterns.balanced=P { - [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, - [2]=left*V(1)*right + [1]=((escape*(left+right))+(1-(left+right))+V(2))^0, + [2]=left*V(1)*right } local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace } local nestedparents=P { lparent*(noparent+V(1))^0*rparent } @@ -8366,311 +8913,329 @@ local nestedbrackets=P { lbracket*(nobracket+V(1))^0*rbracket } local spaces=space^0 local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/"")) local content=(1-endofstring)^0 -lpegpatterns.nestedbraces=nestedbraces +lpegpatterns.nestedbraces=nestedbraces lpegpatterns.nestedparents=nestedparents -lpegpatterns.nested=nestedbraces +lpegpatterns.nested=nestedbraces lpegpatterns.argument=argument lpegpatterns.content=content -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local key=C((1-equal-comma)^1) local pattern_a=(space+comma)^0*(key*equal*value+key*C("")) local pattern_c=(space+comma)^0*(key*equal*value) +local pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C("")) local key=C((1-space-equal-comma)^1) local pattern_b=spaces*comma^0*spaces*(key*((spaces*equal*spaces*value)+C(""))) local hash={} local function set(key,value) - hash[key]=value + hash[key]=value end local pattern_a_s=(pattern_a/set)^1 local pattern_b_s=(pattern_b/set)^1 local pattern_c_s=(pattern_c/set)^1 +local pattern_d_s=(pattern_d/set)^1 patterns.settings_to_hash_a=pattern_a_s patterns.settings_to_hash_b=pattern_b_s patterns.settings_to_hash_c=pattern_c_s +patterns.settings_to_hash_d=pattern_d_s function parsers.make_settings_to_hash_pattern(set,how) - if how=="strict" then - return (pattern_c/set)^1 - elseif how=="tolerant" then - return (pattern_b/set)^1 - else - return (pattern_a/set)^1 - end + if how=="strict" then + return (pattern_c/set)^1 + elseif how=="tolerant" then + return (pattern_b/set)^1 + else + return (pattern_a/set)^1 + end end function parsers.settings_to_hash(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_a_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_a_s,str) + return hash + end +end +function parsers.settings_to_hash_colon_too(str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + else + hash={} + lpegmatch(pattern_d_s,str) + return hash + end end function parsers.settings_to_hash_tolerant(str,existing) - if not str or str=="" then - return {} - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end + if not str or str=="" then + return {} + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting else - hash=existing or {} - lpegmatch(pattern_b_s,str) - return hash + return str end + else + hash=existing or {} + lpegmatch(pattern_b_s,str) + return hash + end end function parsers.settings_to_hash_strict(str,existing) - if not str or str=="" then - return nil - elseif type(str)=="table" then - if existing then - for k,v in next,str do - existing[k]=v - end - return exiting - else - return str - end - elseif str and str~="" then - hash=existing or {} - lpegmatch(pattern_c_s,str) - return next(hash) and hash + if not str or str=="" then + return nil + elseif type(str)=="table" then + if existing then + for k,v in next,str do + existing[k]=v + end + return exiting + else + return str end + elseif str and str~="" then + hash=existing or {} + lpegmatch(pattern_c_s,str) + return next(hash) and hash + end end local separator=comma*space^0 -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-comma))^0) +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) patterns.settings_to_array=pattern function parsers.settings_to_array(str,strict) - if not str or str=="" then - return {} - elseif type(str)=="table" then - return str - elseif strict then - if find(str,"{",1,true) then - return lpegmatch(pattern,str) - else - return { str } - end - elseif find(str,",",1,true) then - return lpegmatch(pattern,str) + if not str or str=="" then + return {} + elseif type(str)=="table" then + return str + elseif strict then + if find(str,"{",1,true) then + return lpegmatch(pattern,str) else - return { str } + return { str } end + elseif find(str,",",1,true) then + return lpegmatch(pattern,str) + else + return { str } + end end function parsers.settings_to_numbers(str) - if not str or str=="" then - return {} - end - if type(str)=="table" then - elseif find(str,",",1,true) then - str=lpegmatch(pattern,str) - else - return { tonumber(str) } - end - for i=1,#str do - str[i]=tonumber(str[i]) - end - return str -end -local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) + if not str or str=="" then + return {} + end + if type(str)=="table" then + elseif find(str,",",1,true) then + str=lpegmatch(pattern,str) + else + return { tonumber(str) } + end + for i=1,#str do + str[i]=tonumber(str[i]) + end + return str +end +local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+nestedbrackets+nestedparents+(1-comma))^0) local pattern=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_obey_fences(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache_a={} local cache_b={} function parsers.groupedsplitat(symbol,withaction) - if not symbol then - symbol="," - end - local pattern=(withaction and cache_b or cache_a)[symbol] - if not pattern then - local symbols=S(symbol) - local separator=space^0*symbols*space^0 - local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) - if withaction then - local withvalue=Carg(1)*value/function(f,s) return f(s) end - pattern=spaces*withvalue*(separator*withvalue)^0 - cache_b[symbol]=pattern - else - pattern=spaces*Ct(value*(separator*value)^0) - cache_a[symbol]=pattern - end - end - return pattern + if not symbol then + symbol="," + end + local pattern=(withaction and cache_b or cache_a)[symbol] + if not pattern then + local symbols=S(symbol) + local separator=space^0*symbols*space^0 + local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) + if withaction then + local withvalue=Carg(1)*value/function(f,s) return f(s) end + pattern=spaces*withvalue*(separator*withvalue)^0 + cache_b[symbol]=pattern + else + pattern=spaces*Ct(value*(separator*value)^0) + cache_a[symbol]=pattern + end + end + return pattern end local pattern_a=parsers.groupedsplitat(",",false) local pattern_b=parsers.groupedsplitat(",",true) function parsers.stripped_settings_to_array(str) - if not str or str=="" then - return {} - else - return lpegmatch(pattern_a,str) - end + 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 + if not str or str=="" then + return {} + else + return lpegmatch(pattern_b,str,1,action) + end end local function set(t,v) - t[#t+1]=v + t[#t+1]=v end local value=P(Carg(1)*value)/set local pattern=value*(separator*value)^0*Carg(1) function parsers.add_settings_to_array(t,str) - return lpegmatch(pattern,str,nil,t) + return lpegmatch(pattern,str,nil,t) end function parsers.hash_to_string(h,separator,yes,no,strict,omit) - if h then - local t,tn,s={},0,sortedkeys(h) - omit=omit and tohash(omit) - for i=1,#s do - local key=s[i] - if not omit or not omit[key] then - local value=h[key] - if type(value)=="boolean" then - if yes and no then - if value then - tn=tn+1 - t[tn]=key..'='..yes - elseif not strict then - tn=tn+1 - t[tn]=key..'='..no - end - elseif value or not strict then - tn=tn+1 - t[tn]=key..'='..tostring(value) - end - else - tn=tn+1 - t[tn]=key..'='..value - end - end + if h then + local t={} + local tn=0 + local s=sortedkeys(h) + omit=omit and tohash(omit) + for i=1,#s do + local key=s[i] + if not omit or not omit[key] then + local value=h[key] + if type(value)=="boolean" then + if yes and no then + if value then + tn=tn+1 + t[tn]=key..'='..yes + elseif not strict then + tn=tn+1 + t[tn]=key..'='..no + end + elseif value or not strict then + tn=tn+1 + t[tn]=key..'='..tostring(value) + end + else + tn=tn+1 + t[tn]=key..'='..value end - return concat(t,separator or ",") - else - return "" + end end + return concat(t,separator or ",") + else + return "" + end end function parsers.array_to_string(a,separator) - if a then - return concat(a,separator or ",") - else - return "" - end + if a then + return concat(a,separator or ",") + else + return "" + end end local pattern=Cf(Ct("")*Cg(C((1-S(", "))^1)*S(", ")^0*Cc(true))^1,rawset) function utilities.parsers.settings_to_set(str) - return str and lpegmatch(pattern,str) or {} + return str and lpegmatch(pattern,str) or {} end hashes.settings_to_set=table.setmetatableindex(function(t,k) - local v=k and lpegmatch(pattern,k) or {} - t[k]=v - return v + local v=k and lpegmatch(pattern,k) or {} + t[k]=v + return v end) getmetatable(hashes.settings_to_set).__mode="kv" function parsers.simple_hash_to_string(h,separator) - local t,tn={},0 - for k,v in sortedhash(h) do - if v then - tn=tn+1 - t[tn]=k - end + local t={} + local tn=0 + for k,v in sortedhash(h) do + if v then + tn=tn+1 + t[tn]=k end - return concat(t,separator or ",") + end + return concat(t,separator or ",") end local str=Cs(lpegpatterns.unquoted)+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 {} + return str and lpegmatch(splitter,str,1,target or {}) or {} end local splitter=lpeg.tsplitat(" ") function utilities.parsers.options_to_array(str) - return str and lpegmatch(splitter,str) or {} + return str and lpegmatch(splitter,str) 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) - if not n then - return str + if not n then + return str + else + local s=lpegmatch(pattern_a,str) + if n==1 then + return unpack(s) else - local s=lpegmatch(pattern_a,str) - if n==1 then - return unpack(s) - else - local t,tn={},0 - for i=1,n do - for j=1,#s do - tn=tn+1 - t[tn]=s[j] - end - end - return unpack(t) + local t={} + local tn=0 + for i=1,n do + for j=1,#s do + tn=tn+1 + t[tn]=s[j] end + end + return unpack(t) end + end end local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+(C(digit^1)/tonumber*lparent*Cs((noparent+nestedparents)^1)*rparent)/repeater+C((nestedbraces+(1-comma))^1) local pattern_b=spaces*Ct(value*(separator*value)^0) function parsers.settings_to_array_with_repeat(str,expand) - if expand then - return lpegmatch(pattern_b,str) or {} - else - return lpegmatch(pattern_a,str) or {} - end + if expand then + return lpegmatch(pattern_b,str) or {} + else + return lpegmatch(pattern_a,str) or {} + end end local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace local pattern=Ct((space+value)^0) function parsers.arguments_to_table(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end function parsers.getparameters(self,class,parentclass,settings) - local sc=self[class] - if not sc then - sc={} - self[class]=sc - if parentclass then - local sp=self[parentclass] - if not sp then - sp={} - self[parentclass]=sp - end - setmetatableindex(sc,sp) - end + local sc=self[class] + if not sc then + sc={} + self[class]=sc + if parentclass then + local sp=self[parentclass] + if not sp then + sp={} + self[parentclass]=sp + end + setmetatableindex(sc,sp) end - parsers.settings_to_hash(settings,sc) + end + parsers.settings_to_hash(settings,sc) end function parsers.listitem(str) - return gmatch(str,"[^, ]+") + return gmatch(str,"[^, ]+") end local pattern=Cs { "start", - start=V("one")+V("two")+V("three"), - rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, - thousand=digit*digit*digit, - one=digit*V("rest"), - two=digit*digit*V("rest"), - three=V("thousand")*V("rest"), + start=V("one")+V("two")+V("three"), + rest=(Cc(",")*V("thousand"))^0*(P(".")+endofstring)*anything^0, + thousand=digit*digit*digit, + one=digit*V("rest"), + two=digit*digit*V("rest"), + three=V("thousand")*V("rest"), } lpegpatterns.splitthousands=pattern function parsers.splitthousands(str) - return lpegmatch(pattern,str) or str + return lpegmatch(pattern,str) or str end local optionalwhitespace=whitespace^0 lpegpatterns.words=Ct((Cs((1-punctuation-whitespace)^1)+anything)^1) @@ -8684,75 +9249,75 @@ local key=C((1-equal)^1) local value=dquote*C((1-dquote-escape*dquote)^0)*dquote local pattern=Cf(Ct("")*(Cg(key*equal*value)*separator^0)^1,rawset)^0*P(-1) function parsers.keq_to_hash(str) - if str and str~="" then - return lpegmatch(pattern,str) - else - return {} - end + if str and str~="" then + return lpegmatch(pattern,str) + else + return {} + end end local defaultspecification={ separator=",",quote='"' } function parsers.csvsplitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=specification.quote - local separator=S(separator~="" and separator or ",") - local whatever=C((1-separator-newline)^0) - if quotechar and quotechar~="" then - local quotedata=nil - for chr in gmatch(quotechar,".") do - local quotechar=P(chr) - local quoteword=quotechar*C((1-quotechar)^0)*quotechar - if quotedata then - quotedata=quotedata+quoteword - else - quotedata=quoteword - end - end - whatever=quotedata+whatever - end - local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) - return function(data) - return lpegmatch(parser,data) + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=specification.quote + local separator=S(separator~="" and separator or ",") + local whatever=C((1-separator-newline)^0) + if quotechar and quotechar~="" then + local quotedata=nil + for chr in gmatch(quotechar,".") do + local quotechar=P(chr) + local quoteword=quotechar*C((1-quotechar)^0)*quotechar + if quotedata then + quotedata=quotedata+quoteword + else + quotedata=quoteword + end end + whatever=quotedata+whatever + end + local parser=Ct((Ct(whatever*(separator*whatever)^0)*S("\n\r")^1)^0 ) + return function(data) + return lpegmatch(parser,data) + end end function parsers.rfc4180splitter(specification) - specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification - local separator=specification.separator - local quotechar=P(specification.quote) - local dquotechar=quotechar*quotechar + specification=specification and setmetatableindex(specification,defaultspecification) or defaultspecification + local separator=specification.separator + local quotechar=P(specification.quote) + local dquotechar=quotechar*quotechar /specification.quote - 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+Cc("") - local record=Ct(field*(separator*field)^1) - local headerline=record*Cp() - local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 - local headeryes=Ct(morerecords) - local headernop=Ct(record*morerecords) - return function(data,getheader) - if getheader then - local header,position=lpegmatch(headerline,data) - local data=lpegmatch(headeryes,data,position) - return data,header - else - return lpegmatch(headernop,data) - end - end + 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+Cc("") + local record=Ct(field*(separator*field)^1) + local headerline=record*Cp() + local morerecords=(newline^(specification.strict and -1 or 1)*record)^0 + local headeryes=Ct(morerecords) + local headernop=Ct(record*morerecords) + return function(data,getheader) + if getheader then + local header,position=lpegmatch(headerline,data) + local data=lpegmatch(headeryes,data,position) + return data,header + else + return lpegmatch(headernop,data) + end + end end local function ranger(first,last,n,action) - if not first then - elseif last==true then - for i=first,n or first do - action(i) - end - elseif last then - for i=first,last do - action(i) - end - else - action(first) + if not first then + elseif last==true then + for i=first,n or first do + action(i) end + elseif last then + for i=first,last do + action(i) + end + else + action(first) + end end local cardinal=lpegpatterns.cardinal/tonumber local spacers=lpegpatterns.spacer^0 @@ -8760,89 +9325,89 @@ local endofstring=lpegpatterns.endofstring local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1 local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring function parsers.stepper(str,n,action) - if type(n)=="function" then - lpegmatch(stepper,str,1,false,n or print) - else - lpegmatch(stepper,str,1,n,action or print) - end + if type(n)=="function" then + lpegmatch(stepper,str,1,false,n or print) + else + lpegmatch(stepper,str,1,n,action or print) + end end local pattern_math=Cs((P("%")/"\\percent "+P("^")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) local pattern_text=Cs((P("%")/"\\percent "+(P("^")/"\\high")*Cc("{")*lpegpatterns.integer*Cc("}")+anything)^0) patterns.unittotex=pattern function parsers.unittotex(str,textmode) - return lpegmatch(textmode and pattern_text or pattern_math,str) + return lpegmatch(textmode and pattern_text or pattern_math,str) end local pattern=Cs((P("^")/"<sup>"*lpegpatterns.integer*Cc("</sup>")+anything)^0) function parsers.unittoxml(str) - return lpegmatch(pattern,str) + return lpegmatch(pattern,str) end local cache={} local spaces=lpegpatterns.space^0 local dummy=function() end setmetatableindex(cache,function(t,k) - local separator=P(k) - local value=(1-separator)^0 - local pattern=spaces*C(value)*separator^0*Cp() - t[k]=pattern - return pattern + local separator=P(k) + local value=(1-separator)^0 + local pattern=spaces*C(value)*separator^0*Cp() + t[k]=pattern + return pattern end) local commalistiterator=cache[","] function utilities.parsers.iterator(str,separator) - local n=#str - if n==0 then - return dummy - else - local pattern=separator and cache[separator] or commalistiterator - local p=1 - return function() - if p<=n then - local s,e=lpegmatch(pattern,str,p) - if e then - p=e - return s - end - end + local n=#str + if n==0 then + return dummy + else + local pattern=separator and cache[separator] or commalistiterator + local p=1 + return function() + if p<=n then + local s,e=lpegmatch(pattern,str,p) + if e then + p=e + return s end + end end + end end local function initialize(t,name) - local source=t[name] - if source then - local result={} - for k,v in next,t[name] do - result[k]=v - end - return result - else - return {} + local source=t[name] + if source then + local result={} + for k,v in next,t[name] do + result[k]=v end + return result + else + return {} + end end local function fetch(t,name) - return t[name] or {} + return t[name] or {} end local function process(result,more) - for k,v in next,more do - result[k]=v - end - return result + for k,v in next,more do + result[k]=v + end + return result end local name=C((1-S(", "))^1) local parser=(Carg(1)*name/initialize)*(S(", ")^1*(Carg(1)*name/fetch))^0 local merge=Cf(parser,process) function utilities.parsers.mergehashes(hash,list) - return lpegmatch(merge,list,1,hash) + 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 + 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 local spacing=whitespace^0 local apply=P("->") @@ -8850,11 +9415,11 @@ local method=C((1-apply)^1) local token=lbrace*C((1-rbrace)^1)*rbrace+C(anything^1) local pattern=spacing*(method*spacing*apply+Carg(1))*spacing*token function utilities.parsers.splitmethod(str,default) - if str then - return lpegmatch(pattern,str,1,default or false) - else - return default or false,"" - end + if str then + return lpegmatch(pattern,str,1,default or false) + else + return default or false,"" + end end @@ -8864,14 +9429,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-fmt"] = package.loaded["util-fmt"] or true --- original size: 2274, stripped down to: 1781 +-- original size: 2541, stripped down to: 1624 if not modules then modules={} end modules ['util-fmt']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities=utilities or {} utilities.formatters=utilities.formatters or {} @@ -8882,61 +9447,2887 @@ local strip=string.strip local lpegmatch=lpeg.match local stripper=lpeg.patterns.stripzeros function formatters.stripzeros(str) - return lpegmatch(stripper,str) + return lpegmatch(stripper,str) end function formatters.formatcolumns(result,between) - if result and #result>0 then - between=between or " " - local widths,numbers={},{} - local first=result[1] - local n=#first - for i=1,n do - widths[i]=0 + if result and #result>0 then + between=between or " " + local widths,numbers={},{} + local first=result[1] + local n=#first + for i=1,n do + widths[i]=0 + end + for i=1,#result do + local r=result[i] + for j=1,n do + local rj=r[j] + local tj=type(rj) + if tj=="number" then + numbers[j]=true + rj=tostring(rj) + elseif tj~="string" then + rj=tostring(rj) + r[j]=rj + end + local w=#rj + if w>widths[j] then + widths[j]=w end - for i=1,#result do - local r=result[i] - for j=1,n do - local rj=r[j] - local tj=type(rj) - if tj=="number" then - numbers[j]=true - end - if tj~="string" then - rj=tostring(rj) - r[j]=rj - end - local w=#rj - if w>widths[j] then - widths[j]=w - end + end + end + for i=1,n do + local w=widths[i] + if numbers[i] then + if w>80 then + widths[i]="%s"..between + else + widths[i]="%0"..w.."i"..between + end + else + if w>80 then + widths[i]="%s"..between + elseif w>0 then + widths[i]="%-"..w.."s"..between + else + widths[i]="%s" + end + end + end + local template=strip(concat(widths)) + for i=1,#result do + local str=format(template,unpack(result[i])) + result[i]=strip(str) + end + end + return result +end + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-reset"] = package.loaded["util-soc-imp-reset"] or true + +-- original size: 374, stripped down to: 282 + +local loaded=package.loaded +loaded["socket"]=nil +loaded["copas"]=nil +loaded["ltn12"]=nil +loaded["mbox"]=nil +loaded["mime"]=nil +loaded["socket.url"]=nil +loaded["socket.headers"]=nil +loaded["socket.tp"]=nil +loaded["socket.http"]=nil +loaded["socket.ftp"]=nil +loaded["socket.smtp"]=nil + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-socket"] = package.loaded["util-soc-imp-socket"] or true + +-- original size: 4870, stripped down to: 3527 + + +local type,tostring,setmetatable=type,tostring,setmetatable +local min=math.min +local format=string.format +local socket=require("socket.core") +local connect=socket.connect +local tcp4=socket.tcp4 +local tcp6=socket.tcp6 +local getaddrinfo=socket.dns.getaddrinfo +local defaulthost="0.0.0.0" +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("socket") + report(fmt,first,...) + elseif fmt then + fmt="socket: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +socket.report=report +function socket.connect4(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet") +end +function socket.connect6(address,port,laddress,lport) + return connect(address,port,laddress,lport,"inet6") +end +function socket.bind(host,port,backlog) + if host=="*" or host=="" then + host=defaulthost + end + local addrinfo,err=getaddrinfo(host) + if not addrinfo then + return nil,err + end + for i=1,#addrinfo do + local alt=addrinfo[i] + local sock,err=(alt.family=="inet" and tcp4 or tcp6)() + if not sock then + return nil,err or "unknown error" + end + sock:setoption("reuseaddr",true) + local res,err=sock:bind(alt.addr,port) + if res then + res,err=sock:listen(backlog) + if res then + return sock + else + sock:close() + end + else + sock:close() + end + end + return nil,"invalid address" +end +socket.try=socket.newtry() +function socket.choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local f=list[name or "nil"] + if f then + return f(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end +end +local sourcet={} +local sinkt={} +socket.sourcet=sourcet +socket.sinkt=sinkt +socket.BLOCKSIZE=2048 +sinkt["close-when-done"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + sock:close() + return 1 + end + end + } + ) +end +sinkt["keep-open"]=function(sock) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function(self,chunk,err) + if chunk then + return sock:send(chunk) + else + return 1 + end + end + } + ) +end +sinkt["default"]=sinkt["keep-open"] +socket.sink=socket.choose(sinkt) +sourcet["by-length"]=function(sock,length) + local blocksize=socket.BLOCKSIZE + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function() + if length<=0 then + return nil + end + local chunk,err=sock:receive(min(blocksize,length)) + if err then + return nil,err + end + length=length-#chunk + return chunk + end + } + ) +end +sourcet["until-closed"]=function(sock) + local blocksize=socket.BLOCKSIZE + local done=false + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + if done then + return nil + end + local chunk,status,partial=sock:receive(blocksize) + if not status then + return chunk + elseif status=="closed" then + sock:close() + done=true + return partial + else + return nil,status + end + end + } + ) +end +sourcet["default"]=sourcet["until-closed"] +socket.source=socket.choose(sourcet) +_G.socket=socket +package.loaded["socket"]=socket + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-copas"] = package.loaded["util-soc-imp-copas"] or true + +-- original size: 25844, stripped down to: 14821 + + +local socket=socket or require("socket") +local ssl=ssl or nil +local WATCH_DOG_TIMEOUT=120 +local UDP_DATAGRAM_MAX=8192 +local type,next,pcall,getmetatable,tostring=type,next,pcall,getmetatable,tostring +local min,max,random=math.min,math.max,math.random +local find=string.find +local insert,remove=table.insert,table.remove +local gettime=socket.gettime +local selectsocket=socket.select +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.yield +local runningcoroutine=coroutine.running +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("copas") + report(fmt,first,...) + elseif fmt then + fmt="copas: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local copas={ + _COPYRIGHT="Copyright (C) 2005-2016 Kepler Project", + _DESCRIPTION="Coroutine Oriented Portable Asynchronous Services", + _VERSION="Copas 2.0.1", + autoclose=true, + running=false, + report=report, +} +local function statushandler(status,...) + if status then + return... + end + local err=(...) + if type(err)=="table" then + err=err[1] + end + report("error: %s",tostring(err)) + return nil,err +end +function socket.protect(func) + return function(...) + return statushandler(pcall(func,...)) + end +end +function socket.newtry(finalizer) + return function (...) + local status=(...) + if not status then + local detail=select(2,...) + pcall(finalizer,detail) + report("error: %s",tostring(detail)) + return + end + return... + end +end +local function newset() + local reverse={} + local set={} + local queue={} + setmetatable(set,{ + __index={ + insert=function(set,value) + if not reverse[value] then + local n=#set+1 + set[n]=value + reverse[value]=n + end + end, + remove=function(set,value) + local index=reverse[value] + if index then + reverse[value]=nil + local n=#set + local top=set[n] + set[n]=nil + if top~=value then + reverse[top]=index + set[index]=top end + end + end, + push=function (set,key,itm) + local entry=queue[key] + if entry==nil then + queue[key]={ itm } + else + entry[#entry+1]=itm + end + end, + pop=function (set,key) + local top=queue[key] + if top~=nil then + local ret=remove(top,1) + if top[1]==nil then + queue[key]=nil + end + return ret + end end - for i=1,n do - local w=widths[i] - if numbers[i] then - if w>80 then - widths[i]="%s"..between - else - widths[i]="%0"..w.."i"..between - end - else - if w>80 then - widths[i]="%s"..between - elseif w>0 then - widths[i]="%-"..w.."s"..between - else - widths[i]="%s" - end + } + } ) + return set +end +local _sleeping={ + times={}, + cos={}, + lethargy={}, + insert=function() + end, + remove=function() + end, + push=function(self,sleeptime,co) + if not co then + return + end + if sleeptime<0 then + self.lethargy[co]=true + return + else + sleeptime=gettime()+sleeptime + end + local t=self.times + local c=self.cos + local i=1 + local n=#t + while i<=n and t[i]<=sleeptime do + i=i+1 + end + insert(t,i,sleeptime) + insert(c,i,co) + end, + getnext= + function(self) + local t=self.times + local delay=t[1] and t[1]-gettime() or nil + return delay and max(delay,0) or nil + end, + pop= + function(self,time) + local t=self.times + local c=self.cos + if #t==0 or time<t[1] then + return + end + local co=c[1] + remove(t,1) + remove(c,1) + return co + end, + wakeup=function(self,co) + local let=self.lethargy + if let[co] then + self:push(0,co) + let[co]=nil + else + local c=self.cos + local t=self.times + for i=1,#c do + if c[i]==co then + remove(c,i) + remove(t,i) + self:push(0,co) + return end + end end - local template=strip(concat(widths)) - for i=1,#result do - local str=format(template,unpack(result[i])) - result[i]=strip(str) + end +} +local _servers=newset() +local _reading=newset() +local _writing=newset() +local _reading_log={} +local _writing_log={} +local _is_timeout={ + timeout=true, + wantread=true, + wantwrite=true, +} +local function isTCP(socket) + return not find(tostring(socket),"^udp") +end +local function copasreceive(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local current_log=_reading_log + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (not _is_timeout[err]) then + current_log[client]=nil + return s,err,part + end + if err=="wantwrite" then + current_log=_writing_log + current_log[client]=gettime() + yieldcoroutine(client,_writing) + else + current_log=_reading_log + current_log[client]=gettime() + yieldcoroutine(client,_reading) + end + until false +end +local function copasreceivefrom(client,size) + local s,err,port + if not size or size==0 then + size=UDP_DATAGRAM_MAX + end + repeat + s,err,port=client:receivefrom(size) + if s or err~="timeout" then + _reading_log[client]=nil + return s,err,port + end + _reading_log[client]=gettime() + yieldcoroutine(client,_reading) + until false +end +local function copasreceivepartial(client,pattern,part) + if not pattern or pattern=="" then + pattern="*l" + end + local logger=_reading_log + local queue=_reading + local s,err + repeat + s,err,part=client:receive(pattern,part) + if s or (type(pattern)=="number" and part~="" and part) or not _is_timeout[err] then + logger[client]=nil + return s,err,part + end + if err=="wantwrite" then + logger=_writing_log + queue=_writing + else + logger=_reading_log + queue=_reading + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassend(client,data,from,to) + if not from then + from=1 + end + local lastIndex=from-1 + local logger=_writing_log + local queue=_writing + local s,err + repeat + s,err,lastIndex=client:send(data,lastIndex+1,to) + if random(100)>90 then + logger[client]=gettime() + yieldcoroutine(client,queue) + end + if s or not _is_timeout[err] then + logger[client]=nil + return s,err,lastIndex + end + if err=="wantread" then + logger=_reading_log + queue=_reading + else + logger=_writing_log + queue=_writing + end + logger[client]=gettime() + yieldcoroutine(client,queue) + until false +end +local function copassendto(client,data,ip,port) + repeat + local s,err=client:sendto(data,ip,port) + if random(100)>90 then + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + end + if s or err~="timeout" then + _writing_log[client]=nil + return s,err + end + _writing_log[client]=gettime() + yieldcoroutine(client,_writing) + until false +end +local function copasconnect(skt,host,port) + skt:settimeout(0) + local ret,err,tried_more_than_once + repeat + ret,err=skt:connect (host,port) + if ret or (err~="timeout" and err~="Operation already in progress") then + if not ret and err=="already connected" and tried_more_than_once then + ret=1 + err=nil + end + _writing_log[skt]=nil + return ret,err + end + tried_more_than_once=tried_more_than_once or true + _writing_log[skt]=gettime() + yieldcoroutine(skt,_writing) + until false +end +local function copasdohandshake(skt,sslt) + if not ssl then + ssl=require("ssl") + end + if not ssl then + report("error: no ssl library") + return + end + local nskt,err=ssl.wrap(skt,sslt) + if not nskt then + report("error: %s",tostring(err)) + return + end + nskt:settimeout(0) + local queue + repeat + local success,err=nskt:dohandshake() + if success then + return nskt + elseif err=="wantwrite" then + queue=_writing + elseif err=="wantread" then + queue=_reading + else + report("error: %s",tostring(err)) + return + end + yieldcoroutine(nskt,queue) + until false +end +local function copasflush(client) +end +copas.connect=copassconnect +copas.send=copassend +copas.sendto=copassendto +copas.receive=copasreceive +copas.receivefrom=copasreceivefrom +copas.copasreceivepartial=copasreceivepartial +copas.copasreceivePartial=copasreceivepartial +copas.dohandshake=copasdohandshake +copas.flush=copasflush +local function _skt_mt_tostring(self) + return tostring(self.socket).." (copas wrapped)" +end +local _skt_mt_tcp_index={ + send=function(self,data,from,to) + return copassend (self.socket,data,from,to) + end, + receive=function (self,pattern,prefix) + if self.timeout==0 then + return copasreceivePartial(self.socket,pattern,prefix) + else + return copasreceive(self.socket,pattern,prefix) + end + end, + flush=function (self) + return copasflush(self.socket) + end, + settimeout=function (self,time) + self.timeout=time + return true + end, + connect=function(self,...) + local res,err=copasconnect(self.socket,...) + if res and self.ssl_params then + res,err=self:dohandshake() + end + return res,err + end, + close=function(self,...) + return self.socket:close(...) + end, + bind=function(self,...) + return self.socket:bind(...) + end, + getsockname=function(self,...) + return self.socket:getsockname(...) + end, + getstats=function(self,...) + return self.socket:getstats(...) + end, + setstats=function(self,...) + return self.socket:setstats(...) + end, + listen=function(self,...) + return self.socket:listen(...) + end, + accept=function(self,...) + return self.socket:accept(...) + end, + setoption=function(self,...) + return self.socket:setoption(...) + end, + getpeername=function(self,...) + return self.socket:getpeername(...) + end, + shutdown=function(self,...) + return self.socket:shutdown(...) + end, + dohandshake=function(self,sslt) + self.ssl_params=sslt or self.ssl_params + local nskt,err=copasdohandshake(self.socket,self.ssl_params) + if not nskt then + return nskt,err + end + self.socket=nskt + return self + end, +} +local _skt_mt_tcp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_tcp_index, +} +local _skt_mt_udp_index={ + sendto=function (self,...) + return copassendto(self.socket,...) + end, + receive=function (self,size) + return copasreceive(self.socket,size or UDP_DATAGRAM_MAX) + end, + receivefrom=function (self,size) + return copasreceivefrom(self.socket,size or UDP_DATAGRAM_MAX) + end, + setpeername=function(self,...) + return self.socket:getpeername(...) + end, + setsockname=function(self,...) + return self.socket:setsockname(...) + end, + close=function(self,...) + return true + end +} +local _skt_mt_udp={ + __tostring=_skt_mt_tostring, + __index=_skt_mt_udp_index, +} +for k,v in next,_skt_mt_tcp_index do + if not _skt_mt_udp_index[k] then + _skt_mt_udp_index[k]=v + end +end +local function wrap(skt,sslt) + if getmetatable(skt)==_skt_mt_tcp or getmetatable(skt)==_skt_mt_udp then + return skt + end + skt:settimeout(0) + if isTCP(skt) then + return setmetatable ({ socket=skt,ssl_params=sslt },_skt_mt_tcp) + else + return setmetatable ({ socket=skt },_skt_mt_udp) + end +end +copas.wrap=wrap +function copas.handler(handler,sslparams) + return function (skt,...) + skt=wrap(skt) + if sslparams then + skt:dohandshake(sslparams) + end + return handler(skt,...) + end +end +local _errhandlers={} +function copas.setErrorHandler(err) + local co=runningcoroutine() + if co then + _errhandlers[co]=err + end +end +local function _deferror (msg,co,skt) + report("%s (%s) (%s)",msg,tostring(co),tostring(skt)) +end +local function _doTick (co,skt,...) + if not co then + return + end + local ok,res,new_q=resumecoroutine(co,skt,...) + if ok and res and new_q then + new_q:insert(res) + new_q:push(res,co) + else + if not ok then + pcall(_errhandlers[co] or _deferror,res,co,skt) + end + if skt and copas.autoclose and isTCP(skt) then + skt:close() + end + _errhandlers[co]=nil + end +end +local function _accept(input,handler) + local client=input:accept() + if client then + client:settimeout(0) + local co=createcoroutine(handler) + _doTick (co,client) + end + return client +end +local function _tickRead(skt) + _doTick(_reading:pop(skt),skt) +end +local function _tickWrite(skt) + _doTick(_writing:pop(skt),skt) +end +local function addTCPserver(server,handler,timeout) + server:settimeout(timeout or 0) + _servers[server]=handler + _reading:insert(server) +end +local function addUDPserver(server,handler,timeout) + server:settimeout(timeout or 0) + local co=createcoroutine(handler) + _reading:insert(server) + _doTick(co,server) +end +function copas.addserver(server,handler,timeout) + if isTCP(server) then + addTCPserver(server,handler,timeout) + else + addUDPserver(server,handler,timeout) + end +end +function copas.removeserver(server,keep_open) + local s=server + local mt=getmetatable(server) + if mt==_skt_mt_tcp or mt==_skt_mt_udp then + s=server.socket + end + _servers[s]=nil + _reading:remove(s) + if keep_open then + return true + end + return server:close() +end +function copas.addthread(handler,...) + local thread=createcoroutine(function(_,...) return handler(...) end) + _doTick(thread,nil,...) + return thread +end +local _tasks={} +local function addtaskRead(task) + task.def_tick=_tickRead + _tasks[task]=true +end +local function addtaskWrite(task) + task.def_tick=_tickWrite + _tasks[task]=true +end +local function tasks() + return next,_tasks +end +local _readable_t={ + events=function(self) + local i=0 + return function () + i=i+1 + return self._evs[i] + end + end, + tick=function(self,input) + local handler=_servers[input] + if handler then + input=_accept(input,handler) + else + _reading:remove(input) + self.def_tick(input) + end + end +} +addtaskRead(_readable_t) +local _writable_t={ + events=function(self) + local i=0 + return function() + i=i+1 + return self._evs[i] + end + end, + tick=function(self,output) + _writing:remove(output) + self.def_tick(output) + end +} +addtaskWrite(_writable_t) +local _sleeping_t={ + tick=function(self,time,...) + _doTick(_sleeping:pop(time),...) + end +} +function copas.sleep(sleeptime) + yieldcoroutine((sleeptime or 0),_sleeping) +end +function copas.wakeup(co) + _sleeping:wakeup(co) +end +local last_cleansing=0 +local function _select(timeout) + local now=gettime() + local r_evs,w_evs,err=selectsocket(_reading,_writing,timeout) + _readable_t._evs=r_evs + _writable_t._evs=w_evs + if (last_cleansing-now)>WATCH_DOG_TIMEOUT then + last_cleansing=now + for skt,time in next,_reading_log do + if not r_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#r_evs+1 + _reading_log[skt]=nil + r_evs[n]=skt + r_evs[skt]=n + end + end + for skt,time in next,_writing_log do + if not w_evs[skt] and (time-now)>WATCH_DOG_TIMEOUT then + local n=#w_evs+1 + _writing_log[skt]=nil + w_evs[n]=skt + w_evs[skt]=n + end + end + end + if err=="timeout" and #r_evs+#w_evs>0 then + return nil + else + return err + end +end +local function copasfinished() + return not (next(_reading) or next(_writing) or _sleeping:getnext()) +end +local function copasstep(timeout) + _sleeping_t:tick(gettime()) + local nextwait=_sleeping:getnext() + if nextwait then + timeout=timeout and min(nextwait,timeout) or nextwait + elseif copasfinished() then + return false + end + local err=_select(timeout) + if err then + if err=="timeout" then + return false + end + return nil,err + end + for task in tasks() do + for event in task:events() do + task:tick(event) + end + end + return true +end +copas.finished=copasfinished +copas.step=copasstep +function copas.loop(timeout) + copas.running=true + while not copasfinished() do + copasstep(timeout) + end + copas.running=false +end +package.loaded["copas"]=copas + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ltn12"] = package.loaded["util-soc-imp-ltn12"] or true + +-- original size: 8709, stripped down to: 5411 + + +local select,unpack=select,unpack +local insert,remove=table.insert,table.remove +local sub=string.sub +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("ltn12") + report(fmt,first,...) + elseif fmt then + fmt="ltn12: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +local filter={} +local source={} +local sink={} +local pump={} +local ltn12={ + _VERSION="LTN12 1.0.3", + BLOCKSIZE=2048, + filter=filter, + source=source, + sink=sink, + pump=pump, + report=report, +} +function filter.cycle(low,ctx,extra) + if low then + return function(chunk) + return (low(ctx,chunk,extra)) + end + end +end +function filter.chain(...) + local arg={... } + local n=select('#',...) + local top=1 + local index=1 + local retry="" + return function(chunk) + retry=chunk and retry + while true do + local action=arg[index] + if index==top then + chunk=action(chunk) + if chunk=="" or top==n then + return chunk + elseif chunk then + index=index+1 + else + top=top+1 + index=top + end + else + chunk=action(chunk or "") + if chunk=="" then + index=index-1 + chunk=retry + elseif chunk then + if index==n then + return chunk + else + index=index+1 + end + else + report("error: filter returned inappropriate 'nil'") + return end + end end - return result + end +end +local function empty() + return nil +end +function source.empty() + return empty +end +local function sourceerror(err) + return function() + return nil,err + end +end +source.error=sourceerror +function source.file(handle,io_err) + if handle then + local blocksize=ltn12.BLOCKSIZE + return function() + local chunk=handle:read(blocksize) + if not chunk then + handle:close() + end + return chunk + end + else + return sourceerror(io_err or "unable to open file") + end +end +function source.simplify(src) + return function() + local chunk,err_or_new=src() + if err_or_new then + src=err_or_new + end + if chunk then + return chunk + else + return nil,err_or_new + end + end +end +function source.string(s) + if s then + local blocksize=ltn12.BLOCKSIZE + local i=1 + return function() + local nexti=i+blocksize + local chunk=sub(s,i,nexti-1) + i=nexti + if chunk~="" then + return chunk + else + return nil + end + end + else return source.empty() end +end +function source.rewind(src) + local t={} + return function(chunk) + if chunk then + insert(t,chunk) + else + chunk=remove(t) + if chunk then + return chunk + else + return src() + end + end + end +end +function source.chain(src,f,...) + if... then + f=filter.chain(f,...) + end + local last_in="" + local last_out="" + local state="feeding" + local err + return function() + if not last_out then + report("error: source is empty") + return + end + while true do + if state=="feeding" then + last_in,err=src() + if err then + return nil,err + end + last_out=f(last_in) + if not last_out then + if last_in then + report("error: filter returned inappropriate 'nil'") + end + return nil + elseif last_out~="" then + state="eating" + if last_in then + last_in="" + end + return last_out + end + else + last_out=f(last_in) + if last_out=="" then + if last_in=="" then + state="feeding" + else + report("error: filter returned nothing") + return + end + elseif not last_out then + if last_in then + report("filter returned inappropriate 'nil'") + end + return nil + else + return last_out + end + end + end + end +end +function source.cat(...) + local arg={... } + local src=remove(arg,1) + return function() + while src do + local chunk,err=src() + if chunk then + return chunk + end + if err then + return nil,err + end + src=remove(arg,1) + end + end +end +function sink.table(t) + if not t then + t={} + end + local f=function(chunk,err) + if chunk then + insert(t,chunk) + end + return 1 + end + return f,t +end +function sink.simplify(snk) + return function(chunk,err) + local ret,err_or_new=snk(chunk,err) + if not ret then + return nil,err_or_new + end + if err_or_new then + snk=err_or_new + end + return 1 + end +end +local function null() + return 1 +end +function sink.null() + return null +end +local function sinkerror(err) + return function() + return nil,err + end +end +sink.error=sinkerror +function sink.file(handle,io_err) + if handle then + return function(chunk,err) + if not chunk then + handle:close() + return 1 + else + return handle:write(chunk) + end + end + else + return sinkerror(io_err or "unable to open file") + end +end +function sink.chain(f,snk,...) + if... then + local args={ f,snk,... } + snk=remove(args,#args) + f=filter.chain(unpack(args)) + end + return function(chunk,err) + if chunk~="" then + local filtered=f(chunk) + local done=chunk and "" + while true do + local ret,snkerr=snk(filtered,err) + if not ret then + return nil,snkerr + end + if filtered==done then + return 1 + end + filtered=f(done) + end + else + return 1 + end + end +end +function pump.step(src,snk) + local chunk,src_err=src() + local ret,snk_err=snk(chunk,src_err) + if chunk and ret then + return 1 + else + return nil,src_err or snk_err + end +end +function pump.all(src,snk,step) + if not step then + step=pump.step + end + while true do + local ret,err=step(src,snk) + if not ret then + if err then + return nil,err + else + return 1 + end + end + end +end +package.loaded["ltn12"]=ltn12 + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-mime"] = package.loaded["util-soc-imp-mime"] or true + +-- original size: 2328, stripped down to: 1874 + + +local type,tostring=type,tostring +local mime=require("mime.core") +local ltn12=ltn12 or require("ltn12") +local filtercycle=ltn12.filter.cycle +local function report(fmt,first,...) + if logs then + report=logs and logs.reporter("mime") + report(fmt,first,...) + elseif fmt then + fmt="mime: "..fmt + if first then + print(format(fmt,first,...)) + else + print(fmt) + end + end +end +mime.report=report +local encodet={} +local decodet={} +local wrapt={} +mime.encodet=encodet +mime.decodet=decodet +mime.wrapt=wrapt +local mime_b64=mime.b64 +local mime_qp=mime.qp +local mime_unb64=mime.unb64 +local mime_unqp=mime.unqp +local mime_wrp=mime.wrp +local mime_qpwrp=mime.qpwrp +local mime_eol=mime_eol +local mime_dot=mime_dot +encodet['base64']=function() + return filtercycle(mime_b64,"") +end +encodet['quoted-printable']=function(mode) + return filtercycle(mime_qp,"",mode=="binary" and "=0D=0A" or "\r\n") +end +decodet['base64']=function() + return filtercycle(mime_unb64,"") +end +decodet['quoted-printable']=function() + return filtercycle(mime_unqp,"") +end +local wraptext=function(length) + if not length then + length=76 + end + return filtercycle(mime_wrp,length,length) +end +local wrapquoted=function() + return filtercycle(mime_qpwrp,76,76) +end +wrapt['text']=wraptext +wrapt['base64']=wraptext +wrapt['default']=wraptext +wrapt['quoted-printable']=wrapquoted +function mime.normalize(marker) + return filtercycle(mime_eol,0,marker) +end +function mime.stuff() + return filtercycle(mime_dot,2) +end +local function choose(list) + return function(name,opt1,opt2) + if type(name)~="string" then + name,opt1,opt2="default",name,opt1 + end + local filter=list[name or "nil"] + if filter then + return filter(opt1,opt2) + else + report("error: unknown key '%s'",tostring(name)) + end + end end +mime.encode=choose(encodet) +mime.decode=choose(decodet) +mime.wrap=choose(wrapt) +package.loaded["mime"]=mime + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-url"] = package.loaded["util-soc-imp-url"] or true + +-- original size: 6863, stripped down to: 5269 + + +local tonumber,tostring,type=tonumber,tostring,type +local gsub,sub,match,find,format,byte,char=string.gsub,string.sub,string.match,string.find,string.format,string.byte,string.char +local insert=table.insert +local socket=socket or require("socket") +local url={ + _VERSION="URL 1.0.3", +} +socket.url=url +function url.escape(s) + return (gsub(s,"([^A-Za-z0-9_])",function(c) + return format("%%%02x",byte(c)) + end)) +end +local function make_set(t) + local s={} + for i=1,#t do + s[t[i]]=true + end + return s +end +local segment_set=make_set { + "-","_",".","!","~","*","'","(", + ")",":","@","&","=","+","$",",", +} +local function protect_segment(s) + return gsub(s,"([^A-Za-z0-9_])",function(c) + if segment_set[c] then + return c + else + return format("%%%02X",byte(c)) + end + end) +end +function url.unescape(s) + return (gsub(s,"%%(%x%x)",function(hex) + return char(tonumber(hex,16)) + end)) +end +local function absolute_path(base_path,relative_path) + if find(relative_path,"^/") then + return relative_path + end + local path=gsub(base_path,"[^/]*$","") + path=path..relative_path + path=gsub(path,"([^/]*%./)",function (s) + if s~="./" then + return s + else + return "" + end + end) + path=gsub(path,"/%.$","/") + local reduced + while reduced~=path do + reduced=path + path=gsub(reduced,"([^/]*/%.%./)",function (s) + if s~="../../" then + return "" + else + return s + end + end) + end + path=gsub(reduced,"([^/]*/%.%.)$",function (s) + if s~="../.." then + return "" + else + return s + end + end) + return path +end +function url.parse(url,default) + local parsed={} + for k,v in next,default or parsed do + parsed[k]=v + end + if not url or url=="" then + return nil,"invalid url" + end + url=gsub(url,"#(.*)$",function(f) + parsed.fragment=f + return "" + end) + url=gsub(url,"^([%w][%w%+%-%.]*)%:",function(s) + parsed.scheme=s + return "" + end) + url=gsub(url,"^//([^/]*)",function(n) + parsed.authority=n + return "" + end) + url=gsub(url,"%?(.*)",function(q) + parsed.query=q + return "" + end) + url=gsub(url,"%;(.*)",function(p) + parsed.params=p + return "" + end) + if url~="" then + parsed.path=url + end + local authority=parsed.authority + if not authority then + return parsed + end + authority=gsub(authority,"^([^@]*)@",function(u) + parsed.userinfo=u + return "" + end) + authority=gsub(authority,":([^:%]]*)$",function(p) + parsed.port=p + return "" + end) + if authority~="" then + parsed.host=match(authority,"^%[(.+)%]$") or authority + end + local userinfo=parsed.userinfo + if not userinfo then + return parsed + end + userinfo=gsub(userinfo,":([^:]*)$",function(p) + parsed.password=p + return "" + end) + parsed.user=userinfo + return parsed +end +function url.build(parsed) + local url=parsed.path or "" + if parsed.params then + url=url..";"..parsed.params + end + if parsed.query then + url=url.."?"..parsed.query + end + local authority=parsed.authority + if parsed.host then + authority=parsed.host + if find(authority,":") then + authority="["..authority.."]" + end + if parsed.port then + authority=authority..":"..tostring(parsed.port) + end + local userinfo=parsed.userinfo + if parsed.user then + userinfo=parsed.user + if parsed.password then + userinfo=userinfo..":"..parsed.password + end + end + if userinfo then authority=userinfo.."@"..authority end + end + if authority then + url="//"..authority..url + end + if parsed.scheme then + url=parsed.scheme..":"..url + end + if parsed.fragment then + url=url.."#"..parsed.fragment + end + return url +end +function url.absolute(base_url,relative_url) + local base_parsed + if type(base_url)=="table" then + base_parsed=base_url + base_url=url.build(base_parsed) + else + base_parsed=url.parse(base_url) + end + local relative_parsed=url.parse(relative_url) + if not base_parsed then + return relative_url + elseif not relative_parsed then + return base_url + elseif relative_parsed.scheme then + return relative_url + else + relative_parsed.scheme=base_parsed.scheme + if not relative_parsed.authority then + relative_parsed.authority=base_parsed.authority + if not relative_parsed.path then + relative_parsed.path=base_parsed.path + if not relative_parsed.params then + relative_parsed.params=base_parsed.params + if not relative_parsed.query then + relative_parsed.query=base_parsed.query + end + end + else + relative_parsed.path=absolute_path(base_parsed.path or "",relative_parsed.path) + end + end + return url.build(relative_parsed) + end +end +function url.parse_path(path) + local parsed={} + path=path or "" + gsub(path,"([^/]+)",function (s) + insert(parsed,s) + end) + for i=1,#parsed do + parsed[i]=url.unescape(parsed[i]) + end + if sub(path,1,1)=="/" then + parsed.is_absolute=1 + end + if sub(path,-1,-1)=="/" then + parsed.is_directory=1 + end + return parsed +end +function url.build_path(parsed,unsafe) + local path="" + local n=#parsed + if unsafe then + for i=1,n-1 do + path=path..parsed[i].."/" + end + if n>0 then + path=path..parsed[n] + if parsed.is_directory then + path=path.."/" + end + end + else + for i=1,n-1 do + path=path..protect_segment(parsed[i]).."/" + end + if n>0 then + path=path..protect_segment(parsed[n]) + if parsed.is_directory then + path=path.."/" + end + end + end + if parsed.is_absolute then + path="/"..path + end + return path +end +package.loaded["socket.url"]=url + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-headers"] = package.loaded["util-soc-imp-headers"] or true + +-- original size: 5721, stripped down to: 3754 + + +local next=next +local lower=string.lower +local concat=table.concat +local socket=socket or require("socket") +local headers={} +socket.headers=headers +local canonic={ + ["accept"]="Accept", + ["accept-charset"]="Accept-Charset", + ["accept-encoding"]="Accept-Encoding", + ["accept-language"]="Accept-Language", + ["accept-ranges"]="Accept-Ranges", + ["action"]="Action", + ["alternate-recipient"]="Alternate-Recipient", + ["age"]="Age", + ["allow"]="Allow", + ["arrival-date"]="Arrival-Date", + ["authorization"]="Authorization", + ["bcc"]="Bcc", + ["cache-control"]="Cache-Control", + ["cc"]="Cc", + ["comments"]="Comments", + ["connection"]="Connection", + ["content-description"]="Content-Description", + ["content-disposition"]="Content-Disposition", + ["content-encoding"]="Content-Encoding", + ["content-id"]="Content-ID", + ["content-language"]="Content-Language", + ["content-length"]="Content-Length", + ["content-location"]="Content-Location", + ["content-md5"]="Content-MD5", + ["content-range"]="Content-Range", + ["content-transfer-encoding"]="Content-Transfer-Encoding", + ["content-type"]="Content-Type", + ["cookie"]="Cookie", + ["date"]="Date", + ["diagnostic-code"]="Diagnostic-Code", + ["dsn-gateway"]="DSN-Gateway", + ["etag"]="ETag", + ["expect"]="Expect", + ["expires"]="Expires", + ["final-log-id"]="Final-Log-ID", + ["final-recipient"]="Final-Recipient", + ["from"]="From", + ["host"]="Host", + ["if-match"]="If-Match", + ["if-modified-since"]="If-Modified-Since", + ["if-none-match"]="If-None-Match", + ["if-range"]="If-Range", + ["if-unmodified-since"]="If-Unmodified-Since", + ["in-reply-to"]="In-Reply-To", + ["keywords"]="Keywords", + ["last-attempt-date"]="Last-Attempt-Date", + ["last-modified"]="Last-Modified", + ["location"]="Location", + ["max-forwards"]="Max-Forwards", + ["message-id"]="Message-ID", + ["mime-version"]="MIME-Version", + ["original-envelope-id"]="Original-Envelope-ID", + ["original-recipient"]="Original-Recipient", + ["pragma"]="Pragma", + ["proxy-authenticate"]="Proxy-Authenticate", + ["proxy-authorization"]="Proxy-Authorization", + ["range"]="Range", + ["received"]="Received", + ["received-from-mta"]="Received-From-MTA", + ["references"]="References", + ["referer"]="Referer", + ["remote-mta"]="Remote-MTA", + ["reply-to"]="Reply-To", + ["reporting-mta"]="Reporting-MTA", + ["resent-bcc"]="Resent-Bcc", + ["resent-cc"]="Resent-Cc", + ["resent-date"]="Resent-Date", + ["resent-from"]="Resent-From", + ["resent-message-id"]="Resent-Message-ID", + ["resent-reply-to"]="Resent-Reply-To", + ["resent-sender"]="Resent-Sender", + ["resent-to"]="Resent-To", + ["retry-after"]="Retry-After", + ["return-path"]="Return-Path", + ["sender"]="Sender", + ["server"]="Server", + ["smtp-remote-recipient"]="SMTP-Remote-Recipient", + ["status"]="Status", + ["subject"]="Subject", + ["te"]="TE", + ["to"]="To", + ["trailer"]="Trailer", + ["transfer-encoding"]="Transfer-Encoding", + ["upgrade"]="Upgrade", + ["user-agent"]="User-Agent", + ["vary"]="Vary", + ["via"]="Via", + ["warning"]="Warning", + ["will-retry-until"]="Will-Retry-Until", + ["www-authenticate"]="WWW-Authenticate", + ["x-mailer"]="X-Mailer", +} +headers.canonic=setmetatable(canonic,{ + __index=function(t,k) + socket.report("invalid header: %s",k) + t[k]=k + return k + end +}) +function headers.normalize(headers) + if not headers then + return {} + end + local normalized={} + for k,v in next,headers do + normalized[#normalized+1]=canonic[k]..": "..v + end + normalized[#normalized+1]="" + normalized[#normalized+1]="" + return concat(normalized,"\r\n") +end +function headers.lower(lowered,headers) + if not lowered then + return {} + end + if not headers then + lowered,headers={},lowered + end + for k,v in next,headers do + lowered[lower(k)]=v + end + return lowered +end +socket.headers=headers +package.loaded["socket.headers"]=headers + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-tp"] = package.loaded["util-soc-imp-tp"] or true + +-- original size: 3116, stripped down to: 2533 + + +local setmetatable,next,type,tonumber=setmetatable,next,type,tonumber +local find,upper=string.find,string.upper +local socket=socket or require("socket") +local ltn12=ltn12 or require("ltn12") +local skipsocket=socket.skip +local sinksocket=socket.sink +local tcpsocket=socket.tcp +local ltn12pump=ltn12.pump +local pumpall=ltn12pump.all +local pumpstep=ltn12pump.step +local tp={ + TIMEOUT=60, +} +socket.tp=tp +local function get_reply(c) + local line,err=c:receive() + local reply=line + if err then return + nil,err + end + local code,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + if not code then + return nil,"invalid server reply" + end + if sep=="-" then + local current + repeat + line,err=c:receive() + if err then + return nil,err + end + current,sep=skipsocket(2,find(line,"^(%d%d%d)(.?)")) + reply=reply.."\n"..line + until code==current and sep==" " + end + return code,reply +end +local methods={} +local mt={ __index=methods } +function methods.getpeername(self) + return self.c:getpeername() +end +function methods.getsockname(self) + return self.c:getpeername() +end +function methods.check(self,ok) + local code,reply=get_reply(self.c) + if not code then + return nil,reply + end + local c=tonumber(code) + local t=type(ok) + if t=="function" then + return ok(c,reply) + elseif t=="table" then + for i=1,#ok do + if find(code,ok[i]) then + return c,reply + end + end + return nil,reply + elseif find(code,ok) then + return c,reply + else + return nil,reply + end +end +function methods.command(self,cmd,arg) + cmd=upper(cmd) + if arg then + cmd=cmd.." "..arg.."\r\n" + else + cmd=cmd.."\r\n" + end + return self.c:send(cmd) +end +function methods.sink(self,snk,pat) + local chunk,err=self.c:receive(pat) + return snk(chunk,err) +end +function methods.send(self,data) + return self.c:send(data) +end +function methods.receive(self,pat) + return self.c:receive(pat) +end +function methods.getfd(self) + return self.c:getfd() +end +function methods.dirty(self) + return self.c:dirty() +end +function methods.getcontrol(self) + return self.c +end +function methods.source(self,source,step) + local sink=sinksocket("keep-open",self.c) + local ret,err=pumpall(source,sink,step or pumpstep) + return ret,err +end +function methods.close(self) + self.c:close() + return 1 +end +function tp.connect(host,port,timeout,create) + local c,e=(create or tcpsocket)() + if not c then + return nil,e + end + c:settimeout(timeout or tp.TIMEOUT) + local r,e=c:connect(host,port) + if not r then + c:close() + return nil,e + end + return setmetatable({ c=c },mt) +end +package.loaded["socket.tp"]=tp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-http"] = package.loaded["util-soc-imp-http"] or true + +-- original size: 12577, stripped down to: 9577 + + +local tostring,tonumber,setmetatable,next,type=tostring,tonumber,setmetatable,next,type +local find,lower,format,gsub,match=string.find,string.lower,string.format,string.gsub,string.match +local concat=table.concat +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local ltn12=ltn12 or require("ltn12") +local mime=mime or require("mime") +local headers=socket.headers or require("socket.headers") +local normalizeheaders=headers.normalize +local parseurl=url.parse +local buildurl=url.build +local absoluteurl=url.absolute +local unescapeurl=url.unescape +local skipsocket=socket.skip +local sinksocket=socket.sink +local sourcesocket=socket.source +local trysocket=socket.try +local tcpsocket=socket.tcp +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local emptysource=ltn12.source.empty +local stringsource=ltn12.source.string +local rewindsource=ltn12.source.rewind +local pumpstep=ltn12.pump.step +local pumpall=ltn12.pump.all +local sinknull=ltn12.sink.null +local sinktable=ltn12.sink.table +local lowerheaders=headers.lower +local mimeb64=mime.b64 +local http={ + TIMEOUT=60, + USERAGENT=socket._VERSION, +} +socket.http=http +local PORT=80 +local SCHEMES={ + http=true, +} +local function receiveheaders(sock,headers) + if not headers then + headers={} + end + local line,err=sock:receive() + if err then + return nil,err + end + while line~="" do + local name,value=skipsocket(2,find(line,"^(.-):%s*(.*)")) + if not (name and value) then + return nil,"malformed reponse headers" + end + name=lower(name) + line,err=sock:receive() + if err then + return nil,err + end + while find(line,"^%s") do + value=value..line + line=sock:receive() + if err then + return nil,err + end + end + local found=headers[name] + if found then + value=found..", "..value + end + headers[name]=value + end + return headers +end +socket.sourcet["http-chunked"]=function(sock,headers) + return setmetatable ( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + },{ + __call=function() + local line,err=sock:receive() + if err then + return nil,err + end + local size=tonumber(gsub(line,";.*",""),16) + if not size then + return nil,"invalid chunk size" + end + if size>0 then + local chunk,err,part=sock:receive(size) + if chunk then + sock:receive() + end + return chunk,err + else + headers,err=receiveheaders(sock,headers) + if not headers then + return nil,err + end + end + end + } + ) +end +socket.sinkt["http-chunked"]=function(sock) + return setmetatable( + { + getfd=function() return sock:getfd() end, + dirty=function() return sock:dirty() end, + }, + { + __call=function(self,chunk,err) + if not chunk then + chunk="" + end + return sock:send(format("%X\r\n%s\r\n",#chunk,chunk)) + end + }) +end +local methods={} +local mt={ __index=methods } +local function openhttp(host,port,create) + local c=trysocket((create or tcpsocket)()) + local h=setmetatable({ c=c },mt) + local try=newtrysocket(function() h:close() end) + h.try=try + try(c:settimeout(http.TIMEOUT)) + try(c:connect(host,port or PORT)) + return h +end +http.open=openhttp +function methods.sendrequestline(self,method,uri) + local requestline=format("%s %s HTTP/1.1\r\n",method or "GET",uri) + return self.try(self.c:send(requestline)) +end +function methods.sendheaders(self,headers) + self.try(self.c:send(normalizeheaders(headers))) + return 1 +end +function methods.sendbody(self,headers,source,step) + if not source then + source=emptysource() + end + if not step then + step=pumpstep + end + local mode="http-chunked" + if headers["content-length"] then + mode="keep-open" + end + return self.try(pumpall(source,sinksocket(mode,self.c),step)) +end +function methods.receivestatusline(self) + local try=self.try + local status=try(self.c:receive(5)) + if status~="HTTP/" then + return nil,status + end + status=try(self.c:receive("*l",status)) + local code=skipsocket(2,find(status,"HTTP/%d*%.%d* (%d%d%d)")) + return try(tonumber(code),status) +end +function methods.receiveheaders(self) + return self.try(receiveheaders(self.c)) +end +function methods.receivebody(self,headers,sink,step) + if not sink then + sink=sinknull() + end + if not step then + step=pumpstep + end + local length=tonumber(headers["content-length"]) + local encoding=headers["transfer-encoding"] + local mode="default" + if encoding and encoding~="identity" then + mode="http-chunked" + elseif length then + mode="by-length" + end + return self.try(pumpall(sourcesocket(mode,self.c,length),sink,step)) +end +function methods.receive09body(self,status,sink,step) + local source=rewindsource(sourcesocket("until-closed",self.c)) + source(status) + return self.try(pumpall(source,sink,step)) +end +function methods.close(self) + return self.c:close() +end +local function adjusturi(request) + if not request.proxy and not http.PROXY then + request={ + path=trysocket(request.path,"invalid path 'nil'"), + params=request.params, + query=request.query, + fragment=request.fragment, + } + end + return buildurl(request) +end +local function adjustheaders(request) + local headers={ + ["user-agent"]=http.USERAGENT, + ["host"]=gsub(request.authority,"^.-@",""), + ["connection"]="close, TE", + ["te"]="trailers" + } + local username=request.user + local password=request.password + if username and password then + headers["authorization"]="Basic "..(mimeb64(username..":"..unescapeurl(password))) + end + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + local username=proxy.user + local password=proxy.password + if username and password then + headers["proxy-authorization"]="Basic "..(mimeb64(username..":"..password)) + end + end + local requestheaders=request.headers + if requestheaders then + headers=lowerheaders(headers,requestheaders) + end + return headers +end +local default={ + host="", + port=PORT, + path="/", + scheme="http" +} +local function adjustrequest(originalrequest) + local url=originalrequest.url + local request=url and parseurl(url,default) or {} + for k,v in next,originalrequest do + request[k]=v + end + local host=request.host + local port=request.port + local uri=request.uri + if not host or host=="" then + trysocket(nil,"invalid host '"..tostring(host).."'") + end + if port=="" then + request.port=PORT + end + if not uri or uri=="" then + request.uri=adjusturi(request) + end + request.headers=adjustheaders(request) + local proxy=request.proxy or http.PROXY + if proxy then + proxy=parseurl(proxy) + request.host=proxy.host + request.port=proxy.port or 3128 + end + return request +end +local maxredericts=4 +local validredirects={ [301]=true,[302]=true,[303]=true,[307]=true } +local validmethods={ [false]=true,GET=true,HEAD=true } +local function shouldredirect(request,code,headers) + local location=headers.location + if not location then + return false + end + location=gsub(location,"%s","") + if location=="" then + return false + end + local scheme=match(location,"^([%w][%w%+%-%.]*)%:") + if scheme and not SCHEMES[scheme] then + return false + end + local method=request.method + local redirect=request.redirect + local redirects=request.nredirects or 0 + return redirect and validredirects[code] and validmethods[method] and redirects<=maxredericts +end +local function shouldreceivebody(request,code) + if request.method=="HEAD" then + return nil + end + if code==204 or code==304 then + return nil + end + if code>=100 and code<200 then + return nil + end + return 1 +end +local tredirect,trequest,srequest +tredirect=function(request,location) + local result,code,headers,status=trequest { + url=absoluteurl(request.url,location), + source=request.source, + sink=request.sink, + headers=request.headers, + proxy=request.proxy, + nredirects=(request.nredirects or 0)+1, + create=request.create, + } + if not headers then + headers={} + end + if not headers.location then + headers.location=location + end + return result,code,headers,status +end +trequest=function(originalrequest) + local request=adjustrequest(originalrequest) + local connection=openhttp(request.host,request.port,request.create) + local headers=request.headers + connection:sendrequestline(request.method,request.uri) + connection:sendheaders(headers) + if request.source then + connection:sendbody(headers,request.source,request.step) + end + local code,status=connection:receivestatusline() + if not code then + connection:receive09body(status,request.sink,request.step) + return 1,200 + end + while code==100 do + headers=connection:receiveheaders() + code,status=connection:receivestatusline() + end + headers=connection:receiveheaders() + if shouldredirect(request,code,headers) and not request.source then + connection:close() + return tredirect(originalrequest,headers.location) + end + if shouldreceivebody(request,code) then + connection:receivebody(headers,request.sink,request.step) + end + connection:close() + return 1,code,headers,status +end +local function genericform(url,body) + local buffer={} + local request={ + url=url, + sink=sinktable(buffer), + target=buffer, + } + if body then + request.source=stringsource(body) + request.method="POST" + request.headers={ + ["content-length"]=#body, + ["content-type"]="application/x-www-form-urlencoded" + } + end + return request +end +http.genericform=genericform +srequest=function(url,body) + local request=genericform(url,body) + local _,code,headers,status=trequest(request) + return concat(request.target),code,headers,status +end +http.request=protectsocket(function(request,body) + if type(request)=="string" then + return srequest(request,body) + else + return trequest(request) + end +end) +package.loaded["socket.http"]=http + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-ftp"] = package.loaded["util-soc-imp-ftp"] or true + +-- original size: 10357, stripped down to: 8548 + + +local setmetatable,type,next=setmetatable,type,next +local find,format,gsub,match=string.find,string.format,string.gsub,string.match +local concat=table.concat +local mod=math.mod +local socket=socket or require("socket") +local url=socket.url or require("socket.url") +local tp=socket.tp or require("socket.tp") +local ltn12=ltn12 or require("ltn12") +local tcpsocket=socket.tcp +local trysocket=socket.try +local skipsocket=socket.skip +local sinksocket=socket.sink +local selectsocket=socket.select +local bindsocket=socket.bind +local newtrysocket=socket.newtry +local sourcesocket=socket.source +local protectsocket=socket.protect +local parseurl=url.parse +local unescapeurl=url.unescape +local pumpall=ltn12.pump.all +local pumpstep=ltn12.pump.step +local sourcestring=ltn12.source.string +local sinktable=ltn12.sink.table +local ftp={ + TIMEOUT=60, + USER="ftp", + PASSWORD="anonymous@anonymous.org", +} +socket.ftp=ftp +local PORT=21 +local methods={} +local mt={ __index=methods } +function ftp.open(server,port,create) + local tp=trysocket(tp.connect(server,port or PORT,ftp.TIMEOUT,create)) + local f=setmetatable({ tp=tp },metat) + f.try=newtrysocket(function() f:close() end) + return f +end +function methods.portconnect(self) + local try=self.try + local server=self.server + try(server:settimeout(ftp.TIMEOUT)) + self.data=try(server:accept()) + try(self.data:settimeout(ftp.TIMEOUT)) +end +function methods.pasvconnect(self) + local try=self.try + self.data=try(tcpsocket()) + self(self.data:settimeout(ftp.TIMEOUT)) + self(self.data:connect(self.pasvt.address,self.pasvt.port)) +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("user",user or ftp.USER)) + local code,reply=try(tp:check{"2..",331}) + if code==331 then + try(tp:command("pass",password or ftp.PASSWORD)) + try(tp:check("2..")) + end + return 1 +end +function methods.pasv(self) + local try=self.try + local tp=self.tp + try(tp:command("pasv")) + local code,reply=try(self.tp:check("2..")) + local pattern="(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)%D(%d+)" + local a,b,c,d,p1,p2=skipsocket(2,find(reply,pattern)) + try(a and b and c and d and p1 and p2,reply) + local address=format("%d.%d.%d.%d",a,b,c,d) + local port=p1*256+p2 + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if server then + server:close() + self.server=nil + end + return address,port +end +function methods.epsv(self) + local try=self.try + local tp=self.tp + try(tp:command("epsv")) + local code,reply=try(tp:check("229")) + local pattern="%((.)(.-)%1(.-)%1(.-)%1%)" + local d,prt,address,port=match(reply,pattern) + try(port,"invalid epsv response") + local address=tp:getpeername() + local server=self.server + self.pasvt={ + address=address, + port=port, + } + if self.server then + server:close() + self.server=nil + end + return address,port +end +function methods.port(self,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local pl=mod(port,256) + local ph=(port-pl)/256 + local arg=gsub(format("%s,%d,%d",address,ph,pl),"%.",",") + try(tp:command("port",arg)) + try(tp:check("2..")) + return 1 +end +function methods.eprt(self,family,address,port) + local try=self.try + local tp=self.tp + self.pasvt=nil + if not address then + address,port=try(tp:getsockname()) + self.server=try(bindsocket(address,0)) + address,port=try(self.server:getsockname()) + try(self.server:settimeout(ftp.TIMEOUT)) + end + local arg=format("|%s|%s|%d|",family,address,port) + try(tp:command("eprt",arg)) + try(tp:check("2..")) + return 1 +end +function methods.send(self,sendt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then + self:pasvconnect() + end + local argument=sendt.argument or unescapeurl(gsub(sendt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=sendt.command or "stor" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"2..","1.."}) + if not self.pasvt then + self:portconnect() + end + local step=sendt.step or pumpstep + local readt={ tp } + local checkstep=function(src,snk) + local readyt=selectsocket(readt,nil,0) + if readyt[tp] then + code=try(tp:check("2..")) + end + return step(src,snk) + end + local sink=sinksocket("close-when-done",self.data) + try(pumpall(sendt.source,sink,checkstep)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + local sent=skipsocket(1,self.data:getstats()) + self.data=nil + return sent +end +function methods.receive(self,recvt) + local try=self.try + local tp=self.tp + try(self.pasvt or self.server,"need port or pasv first") + if self.pasvt then self:pasvconnect() end + local argument=recvt.argument or unescapeurl(gsub(recvt.path or "","^[/\\]","")) + if argument=="" then + argument=nil + end + local command=recvt.command or "retr" + try(tp:command(command,argument)) + local code,reply=try(tp:check{"1..","2.."}) + if code>=200 and code<=299 then + recvt.sink(reply) + return 1 + end + if not self.pasvt then + self:portconnect() + end + local source=sourcesocket("until-closed",self.data) + local step=recvt.step or pumpstep + try(pumpall(source,recvt.sink,step)) + if find(code,"1..") then + try(tp:check("2..")) + end + self.data:close() + self.data=nil + return 1 +end +function methods.cwd(self,dir) + local try=self.try + local tp=self.tp + try(tp:command("cwd",dir)) + try(tp:check(250)) + return 1 +end +function methods.type(self,typ) + local try=self.try + local tp=self.tp + try(tp:command("type",typ)) + try(tp:check(200)) + return 1 +end +function methods.greet(self) + local try=self.try + local tp=self.tp + local code=try(tp:check{"1..","2.."}) + if find(code,"1..") then + try(tp:check("2..")) + end + return 1 +end +function methods.quit(self) + local try=self.try + try(self.tp:command("quit")) + try(self.tp:check("2..")) + return 1 +end +function methods.close(self) + local data=self.data + if data then + data:close() + end + local server=self.server + if server then + server:close() + end + local tp=self.tp + if tp then + tp:close() + end +end +local function override(t) + if t.url then + local u=parseurl(t.url) + for k,v in next,t do + u[k]=v + end + return u + else + return t + end +end +local function tput(putt) + putt=override(putt) + local host=putt.host + trysocket(host,"missing hostname") + local f=ftp.open(host,putt.port,putt.create) + f:greet() + f:login(putt.user,putt.password) + local typ=putt.type + if typ then + f:type(typ) + end + f:epsv() + local sent=f:send(putt) + f:quit() + f:close() + return sent +end +local default={ + path="/", + scheme="ftp", +} +local function genericform(u) + local t=trysocket(parseurl(u,default)) + trysocket(t.scheme=="ftp","wrong scheme '"..t.scheme.."'") + trysocket(t.host,"missing hostname") + local pat="^type=(.)$" + if t.params then + local typ=skipsocket(2,find(t.params,pat)) + t.type=typ + trysocket(typ=="a" or typ=="i","invalid type '"..typ.."'") + end + return t +end +ftp.genericform=genericform +local function sput(u,body) + local putt=genericform(u) + putt.source=sourcestring(body) + return tput(putt) +end +ftp.put=protectsocket(function(putt,body) + if type(putt)=="string" then + return sput(putt,body) + else + return tput(putt) + end +end) +local function tget(gett) + gett=override(gett) + local host=gett.host + trysocket(host,"missing hostname") + local f=ftp.open(host,gett.port,gett.create) + f:greet() + f:login(gett.user,gett.password) + if gett.type then + f:type(gett.type) + end + f:epsv() + f:receive(gett) + f:quit() + return f:close() +end +local function sget(u) + local gett=genericform(u) + local t={} + gett.sink=sinktable(t) + tget(gett) + return concat(t) +end +ftp.command=protectsocket(function(cmdt) + cmdt=override(cmdt) + local command=cmdt.command + local argument=cmdt.argument + local check=cmdt.check + local host=cmdt.host + trysocket(host,"missing hostname") + trysocket(command,"missing command") + local f=ftp.open(host,cmdt.port,cmdt.create) + local try=f.try + local tp=f.tp + f:greet() + f:login(cmdt.user,cmdt.password) + if type(command)=="table" then + local argument=argument or {} + for i=1,#command do + local cmd=command[i] + try(tp:command(cmd,argument[i])) + if check and check[i] then + try(tp:check(check[i])) + end + end + else + try(tp:command(command,argument)) + if check then + try(tp:check(check)) + end + end + f:quit() + return f:close() +end) +ftp.get=protectsocket(function(gett) + if type(gett)=="string" then + return sget(gett) + else + return tget(gett) + end +end) +package.loaded["socket.ftp"]=ftp + + +end -- of closure + +do -- create closure to overcome 200 locals limit + +package.loaded["util-soc-imp-smtp"] = package.loaded["util-soc-imp-smtp"] or true + +-- original size: 7018, stripped down to: 5883 + + +local type,setmetatable,next=type,setmetatable,next +local find,lower,format=string.find,string.lower,string.format +local osdate,osgetenv=os.date,os.getenv +local random=math.random +local socket=socket or require("socket") +local headers=socket.headers or require("socket.headers") +local ltn12=ltn12 or require("ltn12") +local tp=socket.tp or require("socket.tp") +local mime=mime or require("mime") +local mimeb64=mime.b64 +local mimestuff=mime.stuff +local skipsocket=socket.skip +local trysocket=socket.try +local newtrysocket=socket.newtry +local protectsocket=socket.protect +local normalizeheaders=headers.normalize +local lowerheaders=headers.lower +local createcoroutine=coroutine.create +local resumecoroutine=coroutine.resume +local yieldcoroutine=coroutine.resume +local smtp={ + TIMEOUT=60, + SERVER="localhost", + PORT=25, + DOMAIN=osgetenv("SERVER_NAME") or "localhost", + ZONE="-0000", +} +socket.smtp=smtp +local methods={} +local mt={ __index=methods } +function methods.greet(self,domain) + local try=self.try + local tp=self.tp + try(tp:check("2..")) + try(tp:command("EHLO",domain or _M.DOMAIN)) + return skipsocket(1,try(tp:check("2.."))) +end +function methods.mail(self,from) + local try=self.try + local tp=self.tp + try(tp:command("MAIL","FROM:"..from)) + return try(tp:check("2..")) +end +function methods.rcpt(self,to) + local try=self.try + local tp=self.tp + try(tp:command("RCPT","TO:"..to)) + return try(tp:check("2..")) +end +function methods.data(self,src,step) + local try=self.try + local tp=self.tp + try(tp:command("DATA")) + try(tp:check("3..")) + try(tp:source(src,step)) + try(tp:send("\r\n.\r\n")) + return try(tp:check("2..")) +end +function methods.quit(self) + local try=self.try + local tp=self.tp + try(tp:command("QUIT")) + return try(tp:check("2..")) +end +function methods.close(self) + return self.tp:close() +end +function methods.login(self,user,password) + local try=self.try + local tp=self.tp + try(tp:command("AUTH","LOGIN")) + try(tp:check("3..")) + try(tp:send(mimeb64(user).."\r\n")) + try(tp:check("3..")) + try(tp:send(mimeb64(password).."\r\n")) + return try(tp:check("2..")) +end +function methods.plain(self,user,password) + local try=self.try + local tp=self.tp + local auth="PLAIN "..mimeb64("\0"..user.."\0"..password) + try(tp:command("AUTH",auth)) + return try(tp:check("2..")) +end +function methods.auth(self,user,password,ext) + if not user or not password then + return 1 + end + local try=self.try + if find(ext,"AUTH[^\n]+LOGIN") then + return self:login(user,password) + elseif find(ext,"AUTH[^\n]+PLAIN") then + return self:plain(user,password) + else + try(nil,"authentication not supported") + end +end +function methods.send(self,mail) + self:mail(mail.from) + local receipt=mail.rcpt + if type(receipt)=="table" then + for i=1,#receipt do + self:rcpt(receipt[i]) + end + elseif receipt then + self:rcpt(receipt) + end + self:data(ltn12.source.chain(mail.source,mimestuff()),mail.step) +end +local function opensmtp(self,server,port,create) + if not server or server=="" then + server=smtp.SERVER + end + if not port or port=="" then + port=smtp.PORT + end + local s={ + tp=trysocket(tp.connect(server,port,smtp.TIMEOUT,create)), + try=newtrysocket(function() + s:close() + end), + } + setmetatable(s,mt) + return s +end +smtp.open=opensmtp +local nofboundaries=0 +local function newboundary() + nofboundaries=nofboundaries+1 + return format('%s%05d==%05u',osdate('%d%m%Y%H%M%S'),random(0,99999),nofboundaries) +end +local send_message +local function send_headers(headers) + yieldcoroutine(normalizeheaders(headers)) +end +local function send_multipart(message) + local boundary=newboundary() + local headers=lowerheaders(message.headers) + local body=message.body + local preamble=body.preamble + local epilogue=body.epilogue + local content=headers['content-type'] or 'multipart/mixed' + headers['content-type']=content..'; boundary="'..boundary..'"' + send_headers(headers) + if preamble then + yieldcoroutine(preamble) + yieldcoroutine("\r\n") + end + for i=1,#body do + yieldcoroutine("\r\n--"..boundary.."\r\n") + send_message(body[i]) + end + yieldcoroutine("\r\n--"..boundary.."--\r\n\r\n") + if epilogue then + yieldcoroutine(epilogue) + yieldcoroutine("\r\n") + end +end +local default_content_type='text/plain; charset="UTF-8"' +local function send_source(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + local getchunk=message.body + while true do + local chunk,err=getchunk() + if err then + yieldcoroutine(nil,err) + elseif chunk then + yieldcoroutine(chunk) + else + break + end + end +end +local function send_string(message) + local headers=lowerheaders(message.headers) + if not headers['content-type'] then + headers['content-type']=default_content_type + end + send_headers(headers) + yieldcoroutine(message.body) +end +function send_message(message) + local body=message.body + if type(body)=="table" then + send_multipart(message) + elseif type(body)=="function" then + send_source(message) + else + send_string(message) + end +end +local function adjust_headers(message) + local headers=lowerheaders(message.headers) + if not headers["date"] then + headers["date"]=osdate("!%a, %d %b %Y %H:%M:%S ")..(message.zone or smtp.ZONE) + end + if not headers["x-mailer"] then + headers["x-mailer"]=socket._VERSION + end + headers["mime-version"]="1.0" + return headers +end +function smtp.message(message) + message.headers=adjust_headers(message) + local action=createcoroutine(function() + send_message(message) + end) + return function() + local ret,a,b=resumecoroutine(action) + if ret then + return a,b + else + return nil,a + end + end +end +smtp.send=protectsocket(function(mail) + local snd=opensmtp(smtp,mail.server,mail.port,mail.create) + local ext=snd:greet(mail.domain) + snd:auth(mail.user,mail.password,ext) + snd:send(mail) + snd:quit() + return snd:close() +end) +package.loaded["socket.smtp"]=smtp end -- of closure @@ -8945,14 +12336,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-set"] = package.loaded["trac-set"] or true --- original size: 13044, stripped down to: 9231 +-- original size: 13340, stripped down to: 8826 if not modules then modules={} end modules ['trac-set']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,next,tostring,tonumber=type,next,tostring,tonumber local concat,sortedhash=table.concat,table.sortedhash @@ -8967,305 +12358,318 @@ utilities.setters=setters local data={} local trace_initialize=false function setters.initialize(filename,name,values) - local setter=data[name] - if setter then - frozen=true - local data=setter.data - if data then - for key,newvalue in sortedhash(values) do - local newvalue=is_boolean(newvalue,newvalue,true) - local functions=data[key] - if functions then - local oldvalue=functions.value - if functions.frozen then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) - end - elseif #functions>0 and not oldvalue then - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) - end - for i=1,#functions do - functions[i](newvalue) - end - functions.value=newvalue - functions.frozen=functions.frozen or frozen - else - if trace_initialize then - setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) - end - end - else - functions={ default=newvalue,frozen=frozen } - data[key]=functions - if trace_initialize then - setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) - end - end + local setter=data[name] + if setter then + frozen=true + local data=setter.data + if data then + for key,newvalue in sortedhash(values) do + local newvalue=is_boolean(newvalue,newvalue,true) + local functions=data[key] + if functions then + local oldvalue=functions.value + if functions.frozen then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"frozen",oldvalue) + end + elseif #functions>0 and not oldvalue then + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"set",newvalue) + end + for i=1,#functions do + functions[i](newvalue) + end + functions.value=newvalue + functions.frozen=functions.frozen or frozen + else + if trace_initialize then + setter.report("%s: %a is %s as %a",filename,key,"kept",oldvalue) end - return true + end + else + functions={ default=newvalue,frozen=frozen } + data[key]=functions + if trace_initialize then + setter.report("%s: %a is %s to %a",filename,key,"defaulted",newvalue) + end end + end + return true end + end end local function set(t,what,newvalue) - local data=t.data - if not data.frozen then - local done=t.done - if type(what)=="string" then - what=settings_to_hash(what) - end - if type(what)~="table" then - return - end - if not done then - done={} - t.done=done - end - for w,value in sortedhash(what) do - if value=="" then - value=newvalue - elseif not value then - value=false - else - value=is_boolean(value,value,true) - end - w=topattern(w,true,true) - for name,functions in sortedhash(data) do - if done[name] then - elseif find(name,w) then - done[name]=true - for i=1,#functions do - functions[i](value) - end - functions.value=value - end - end + local data=t.data + if not data.frozen then + local done=t.done + if type(what)=="string" then + what=settings_to_hash(what) + end + if type(what)~="table" then + return + end + if not done then + done={} + t.done=done + end + for w,value in sortedhash(what) do + if value=="" then + value=newvalue + elseif not value then + value=false + else + value=is_boolean(value,value,true) + end + w=topattern(w,true,true) + for name,functions in sortedhash(data) do + if done[name] then + elseif find(name,w) then + done[name]=true + for i=1,#functions do + functions[i](value) + end + functions.value=value end + end end + end end local function reset(t) - local data=t.data - if not data.frozen then - for name,functions in sortedthash(data) do - for i=1,#functions do - functions[i](false) - end - functions.value=false - end + local data=t.data + if not data.frozen then + for name,functions in sortedthash(data) do + for i=1,#functions do + functions[i](false) + end + functions.value=false end + end end local function enable(t,what) - set(t,what,true) + set(t,what,true) end local function disable(t,what) - local data=t.data - if not what or what=="" then - t.done={} - reset(t) - else - set(t,what,false) - end + local data=t.data + if not what or what=="" then + t.done={} + reset(t) + else + set(t,what,false) + end end function setters.register(t,what,...) - local data=t.data - what=lower(what) - local functions=data[what] - if not functions then - functions={} - data[what]=functions - if trace_initialize then - t.report("defining %a",what) - end - end - local default=functions.default - for i=1,select("#",...) do - local fnc=select(i,...) - local typ=type(fnc) - if typ=="string" then - if trace_initialize then - t.report("coupling %a to %a",what,fnc) - end - local s=fnc - fnc=function(value) set(t,s,value) end - elseif typ~="function" then - fnc=nil - end - if fnc then - functions[#functions+1]=fnc - local value=functions.value or default - if value~=nil then - fnc(value) - functions.value=value - end - end + local data=t.data + what=lower(what) + local functions=data[what] + if not functions then + functions={} + data[what]=functions + if trace_initialize then + t.report("defining %a",what) + end + end + local default=functions.default + for i=1,select("#",...) do + local fnc=select(i,...) + local typ=type(fnc) + if typ=="string" then + if trace_initialize then + t.report("coupling %a to %a",what,fnc) + end + local s=fnc + fnc=function(value) set(t,s,value) end + elseif typ~="function" then + fnc=nil + end + if fnc then + functions[#functions+1]=fnc + local value=functions.value or default + if value~=nil then + fnc(value) + functions.value=value + end end - return false + end + return false end function setters.enable(t,what) - local e=t.enable - t.enable,t.done=enable,{} - enable(t,what) - t.enable,t.done=e,{} + local e=t.enable + t.enable,t.done=enable,{} + enable(t,what) + t.enable,t.done=e,{} end function setters.disable(t,what) - local e=t.disable - t.disable,t.done=disable,{} - disable(t,what) - t.disable,t.done=e,{} + local e=t.disable + t.disable,t.done=disable,{} + disable(t,what) + t.disable,t.done=e,{} end function setters.reset(t) - t.done={} - reset(t) + t.done={} + reset(t) end function setters.list(t) - local list=table.sortedkeys(t.data) - local user,system={},{} - for l=1,#list do - local what=list[l] - if find(what,"^%*") then - system[#system+1]=what - else - user[#user+1]=what - end + local list=table.sortedkeys(t.data) + local user,system={},{} + for l=1,#list do + local what=list[l] + if find(what,"^%*") then + system[#system+1]=what + else + user[#user+1]=what end - return user,system + end + return user,system end function setters.show(t) - local list=setters.list(t) - t.report() - for k=1,#list do - local name=list[k] - local functions=t.data[name] - if functions then - local value=functions.value - local default=functions.default - local modules=#functions - if default==nil then - default="unset" - elseif type(default)=="table" then - default=concat(default,"|") - else - default=tostring(default) - end - if value==nil then - value="unset" - elseif type(value)=="table" then - value=concat(value,"|") - else - value=tostring(value) - end - t.report(name) - t.report(" modules : %i",modules) - t.report(" default : %s",default) - t.report(" value : %s",value) - t.report() - end + local list=setters.list(t) + t.report() + for k=1,#list do + local name=list[k] + local functions=t.data[name] + if functions then + local value=functions.value + local default=functions.default + local modules=#functions + if default==nil then + default="unset" + elseif type(default)=="table" then + default=concat(default,"|") + else + default=tostring(default) + end + if value==nil then + value="unset" + elseif type(value)=="table" then + value=concat(value,"|") + else + value=tostring(value) + end + t.report(name) + t.report(" modules : %i",modules) + t.report(" default : %s",default) + t.report(" value : %s",value) + t.report() end + end end local enable,disable,register,list,show=setters.enable,setters.disable,setters.register,setters.list,setters.show function setters.report(setter,...) - print(format("%-15s : %s\n",setter.name,format(...))) + print(format("%-15s : %s\n",setter.name,format(...))) end local function default(setter,name) - local d=setter.data[name] - return d and d.default + local d=setter.data[name] + return d and d.default end local function value(setter,name) - local d=setter.data[name] - return d and (d.value or d.default) + local d=setter.data[name] + return d and (d.value or d.default) end function setters.new(name) - local setter - setter={ - data=allocate(), - name=name, - report=function(...) setters.report (setter,...) end, - enable=function(...) enable (setter,...) end, - disable=function(...) disable (setter,...) end, - reset=function(...) reset (setter,...) end, - register=function(...) register(setter,...) end, - list=function(...) list (setter,...) end, - show=function(...) show (setter,...) end, - default=function(...) return default (setter,...) end, - value=function(...) return value (setter,...) end, - } - data[name]=setter - return setter + local setter + setter={ + data=allocate(), + name=name, + report=function(...) setters.report (setter,...) end, + enable=function(...) enable (setter,...) end, + disable=function(...) disable (setter,...) end, + reset=function(...) reset (setter,...) end, + register=function(...) register(setter,...) end, + list=function(...) list (setter,...) end, + show=function(...) show (setter,...) end, + default=function(...) return default (setter,...) end, + value=function(...) return value (setter,...) end, + } + data[name]=setter + return setter end trackers=setters.new("trackers") directives=setters.new("directives") experiments=setters.new("experiments") -local t_enable,t_disable=trackers .enable,trackers .disable +local t_enable,t_disable=trackers .enable,trackers .disable local d_enable,d_disable=directives .enable,directives .disable local e_enable,e_disable=experiments.enable,experiments.disable -local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) -local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) +local trace_directives=false local trace_directives=false trackers.register("system.directives",function(v) trace_directives=v end) +local trace_experiments=false local trace_experiments=false trackers.register("system.experiments",function(v) trace_experiments=v end) function directives.enable(...) - if trace_directives then - directives.report("enabling: % t",{...}) - end - d_enable(...) + if trace_directives then + directives.report("enabling: % t",{...}) + end + d_enable(...) end function directives.disable(...) - if trace_directives then - directives.report("disabling: % t",{...}) - end - d_disable(...) + if trace_directives then + directives.report("disabling: % t",{...}) + end + d_disable(...) end function experiments.enable(...) - if trace_experiments then - experiments.report("enabling: % t",{...}) - end - e_enable(...) + if trace_experiments then + experiments.report("enabling: % t",{...}) + end + e_enable(...) end function experiments.disable(...) - if trace_experiments then - experiments.report("disabling: % t",{...}) - end - e_disable(...) + if trace_experiments then + experiments.report("disabling: % t",{...}) + end + e_disable(...) end directives.register("system.nostatistics",function(v) - if statistics then - statistics.enable=not v - else - end + if statistics then + statistics.enable=not v + else + end end) directives.register("system.nolibraries",function(v) - if libraries then - libraries=nil - else - end + if libraries then + libraries=nil + else + end end) if environment then - local engineflags=environment.engineflags - if engineflags then - local list=engineflags["c:trackers"] or engineflags["trackers"] - if type(list)=="string" then - setters.initialize("commandline flags","trackers",settings_to_hash(list)) - end - local list=engineflags["c:directives"] or engineflags["directives"] - if type(list)=="string" then - setters.initialize("commandline flags","directives",settings_to_hash(list)) - end + local engineflags=environment.engineflags + if engineflags then + local list=engineflags["c:trackers"] or engineflags["trackers"] + if type(list)=="string" then + setters.initialize("commandline flags","trackers",settings_to_hash(list)) end -end -if texconfig then - local function set(k,v) - v=tonumber(v) - if v then - texconfig[k]=v - end + local list=engineflags["c:directives"] or engineflags["directives"] + if type(list)=="string" then + setters.initialize("commandline flags","directives",settings_to_hash(list)) end - directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) - directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) - directives.register("luatex.nestsize",function(v) set("nest_size",v) end) - directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) - directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) - directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) - directives.register("luatex.paramsize",function(v) set("param_size",v) end) - directives.register("luatex.savesize",function(v) set("save_size",v) end) - directives.register("luatex.stacksize",function(v) set("stack_size",v) end) + end end +if texconfig then + local function set(k,v) + v=tonumber(v) + if v then + texconfig[k]=v + end + end + directives.register("luatex.expanddepth",function(v) set("expand_depth",v) end) + directives.register("luatex.hashextra",function(v) set("hash_extra",v) end) + directives.register("luatex.nestsize",function(v) set("nest_size",v) end) + directives.register("luatex.maxinopen",function(v) set("max_in_open",v) end) + directives.register("luatex.maxprintline",function(v) set("max_print_line",v) end) + directives.register("luatex.maxstrings",function(v) set("max_strings",v) end) + directives.register("luatex.paramsize",function(v) set("param_size",v) end) + directives.register("luatex.savesize",function(v) set("save_size",v) end) + directives.register("luatex.stacksize",function(v) set("stack_size",v) end) +end +local data=table.setmetatableindex("table") +updaters={ + register=function(what,f) + local d=data[what] + d[#d+1]=f + end, + apply=function(what,...) + local d=data[what] + for i=1,#d do + d[i](...) + end + end, +} end -- of closure @@ -9274,14 +12678,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-log"] = package.loaded["trac-log"] or true --- original size: 32922, stripped down to: 23011 +-- original size: 32608, stripped down to: 20925 if not modules then modules={} end modules ['trac-log']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local next,type,select,print=next,type,select,print local format,gmatch,find=string.format,string.gmatch,string.find @@ -9292,7 +12696,7 @@ local datetime=os.date local openfile=io.open local runningtex=tex and (tex.jobname or tex.formatname) local write_nl=runningtex and texio and texio.write_nl or print -local write=runningtex and texio and texio.write or io.write +local write=runningtex and texio and texio.write or io.write local setmetatableindex=table.setmetatableindex local formatters=string.formatters local settings_to_hash=utilities.parsers.settings_to_hash @@ -9308,404 +12712,404 @@ webpage : http://www.pragma-ade.nl / http://tex.aanhet.net wiki : http://contextgarden.net ]] formatters.add ( - formatters,"unichr", - [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] + formatters,"unichr", + [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] ) formatters.add ( - formatters,"chruni", - [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] + formatters,"chruni", + [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] ) 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,setlogfile,settimedlog,setprocessor,setformatters,newline if runningtex then - if texio.setescape then - texio.setescape(0) - end - if arg then - for k,v in next,arg do - if v=="--ansi" or v=="--c:ansi" then - variant="ansi" - break - end - end - end - local function useluawrites() - local texio_write_nl=texio.write_nl - local texio_write=texio.write - local io_write=io.write - write_nl=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write_nl("log",...) - texio_write_nl("term","") - io_write(...) - elseif target=="log" then - texio_write_nl("log",...) - elseif target=="term" then - texio_write_nl("term","") - io_write(...) - elseif type(target)=="number" then - texio_write_nl(target,...) - elseif target~="none" then - texio_write_nl("log",target,...) - texio_write_nl("term","") - io_write(target,...) - end - end - write=function(target,...) - if not io_write then - io_write=io.write - end - if target=="term and log" then - texio_write("log",...) - io_write(...) - elseif target=="log" then - texio_write("log",...) - elseif target=="term" then - io_write(...) - elseif type(target)=="number" then - texio_write(target,...) - elseif target~="none" then - texio_write("log",target,...) - io_write(target,...) - end - end - texio.write=write - texio.write_nl=write_nl - useluawrites=ignore - end - local whereto="both" - local target=nil - local targets=nil - local formats=table.setmetatableindex("self") - local translations=table.setmetatableindex("self") - local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes - local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s > %s\n"], - report_nop=formatters["%-15s >\n"], - direct_yes=formatters["%-15s > %s"], - direct_nop=formatters["%-15s >"], - subreport_yes=formatters["%-15s > %s > %s\n"], - subreport_nop=formatters["%-15s > %s >\n"], - subdirect_yes=formatters["%-15s > %s > %s"], - subdirect_nop=formatters["%-15s > %s >"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - targets={ - logfile="log", - log="log", - file="log", - console="term", - terminal="term", - both="term and log", - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], - report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], - direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], - direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], - subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], - subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], - subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], - subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], - status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], - }, - targets={ - logfile="none", - log="none", - file="none", - console="term", - terminal="term", - both="term", - }, - } - } - logs.flush=io.flush - writer=function(...) - write_nl(target,...) - end - newline=function() - write_nl(target,"\n") - end - report=function(a,b,c,...) - if c~=nil then - write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,report_yes(translations[a],formats[b])) - elseif a then - write_nl(target,report_nop(translations[a])) - else - write_nl(target,"\n") - end - end - direct=function(a,b,c,...) - if c~=nil then - return direct_yes(translations[a],formatters[formats[b]](c,...)) - elseif b then - return direct_yes(translations[a],formats[b]) - elseif a then - return direct_nop(translations[a]) - else - return "" - end - end - subreport=function(a,s,b,c,...) - if c~=nil then - write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) - elseif a then - write_nl(target,subreport_nop(translations[a],translations[s])) - else - write_nl(target,"\n") - end - end - subdirect=function(a,s,b,c,...) - if c~=nil then - return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) - elseif b then - return subdirect_yes(translations[a],translations[s],formats[b]) - elseif a then - return subdirect_nop(translations[a],translations[s]) - else - return "" - end + if texio.setescape then + texio.setescape(0) + end + if arg then + for k,v in next,arg do + if v=="--ansi" or v=="--c:ansi" then + variant="ansi" + break + end end - status=function(a,b,c,...) - if c~=nil then - write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,status_yes(translations[a],formats[b])) - elseif a then - write_nl(target,status_nop(translations[a])) - else - write_nl(target,"\n") - end + end + local function useluawrites() + local texio_write_nl=texio.write_nl + local texio_write=texio.write + local io_write=io.write + write_nl=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write_nl("log",...) + texio_write_nl("term","") + io_write(...) + elseif target=="log" then + texio_write_nl("log",...) + elseif target=="term" then + texio_write_nl("term","") + io_write(...) + elseif type(target)=="number" then + texio_write_nl(target,...) + elseif target~="none" then + texio_write_nl("log",target,...) + texio_write_nl("term","") + io_write(target,...) + end end - settarget=function(askedwhereto) - whereto=askedwhereto or whereto or "both" - target=targets[whereto] - if not target then - whereto="both" - target=targets[whereto] - end - if target=="term" or target=="term and log" then - logs.flush=io.flush - else - logs.flush=ignore - end + write=function(target,...) + if not io_write then + io_write=io.write + end + if target=="term and log" then + texio_write("log",...) + io_write(...) + elseif target=="log" then + texio_write("log",...) + elseif target=="term" then + io_write(...) + elseif type(target)=="number" then + texio_write(target,...) + elseif target~="none" then + texio_write("log",target,...) + io_write(target,...) + end end - local stack={} - pushtarget=function(newtarget) - insert(stack,target) - settarget(newtarget) + texio.write=write + texio.write_nl=write_nl + useluawrites=ignore + end + local whereto="both" + local target=nil + local targets=nil + local formats=table.setmetatableindex("self") + local translations=table.setmetatableindex("self") + local report_yes,subreport_yes,direct_yes,subdirect_yes,status_yes + local report_nop,subreport_nop,direct_nop,subdirect_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s > %s\n"], + report_nop=formatters["%-15s >\n"], + direct_yes=formatters["%-15s > %s"], + direct_nop=formatters["%-15s >"], + subreport_yes=formatters["%-15s > %s > %s\n"], + subreport_nop=formatters["%-15s > %s >\n"], + subdirect_yes=formatters["%-15s > %s > %s"], + subdirect_nop=formatters["%-15s > %s >"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + targets={ + logfile="log", + log="log", + file="log", + console="term", + terminal="term", + both="term and log", + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;33m%-15s [0;1m>[0m %s\n"], + report_nop=formatters["[0;33m%-15s [0;1m>[0m\n"], + direct_yes=formatters["[0;33m%-15s [0;1m>[0m %s"], + direct_nop=formatters["[0;33m%-15s [0;1m>[0m"], + subreport_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s\n"], + subreport_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m\n"], + subdirect_yes=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m %s"], + subdirect_nop=formatters["[0;33m%-15s [0;1m>[0;35m %s [0;1m>[0m"], + status_yes=formatters["[0;33m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;33m%-15s [0;1m:[0m\n"], + }, + targets={ + logfile="none", + log="none", + file="none", + console="term", + terminal="term", + both="term", + }, + } + } + logs.flush=io.flush + writer=function(...) + write_nl(target,...) + end + newline=function() + write_nl(target,"\n") + end + report=function(a,b,c,...) + if c~=nil then + write_nl(target,report_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,report_yes(translations[a],formats[b])) + elseif a then + write_nl(target,report_nop(translations[a])) + else + write_nl(target,"\n") end - poptarget=function() - if #stack>0 then - settarget(remove(stack)) - end + end + direct=function(a,b,c,...) + if c~=nil then + return direct_yes(translations[a],formatters[formats[b]](c,...)) + elseif b then + return direct_yes(translations[a],formats[b]) + elseif a then + return direct_nop(translations[a]) + else + return "" end - setformats=function(f) - formats=f + end + subreport=function(a,s,b,c,...) + if c~=nil then + write_nl(target,subreport_yes(translations[a],translations[s],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,subreport_yes(translations[a],translations[s],formats[b])) + elseif a then + write_nl(target,subreport_nop(translations[a],translations[s])) + else + write_nl(target,"\n") end - settranslations=function(t) - translations=t + end + subdirect=function(a,s,b,c,...) + if c~=nil then + return subdirect_yes(translations[a],translations[s],formatters[formats[b]](c,...)) + elseif b then + return subdirect_yes(translations[a],translations[s],formats[b]) + elseif a then + return subdirect_nop(translations[a],translations[s]) + else + return "" end - setprocessor=function(f) - local writeline=write_nl - write_nl=function(target,...) - writeline(target,f(...)) - end + end + status=function(a,b,c,...) + if c~=nil then + write_nl(target,status_yes(translations[a],formatters[formats[b]](c,...))) + elseif b then + write_nl(target,status_yes(translations[a],formats[b])) + elseif a then + write_nl(target,status_nop(translations[a])) + else + write_nl(target,"\n") + end + end + settarget=function(askedwhereto) + whereto=askedwhereto or whereto or "both" + target=targets[whereto] + if not target then + whereto="both" + target=targets[whereto] + end + if target=="term" or target=="term and log" then + logs.flush=io.flush + else + logs.flush=ignore + end + end + local stack={} + pushtarget=function(newtarget) + insert(stack,target) + settarget(newtarget) + end + poptarget=function() + if #stack>0 then + settarget(remove(stack)) + end + end + setformats=function(f) + formats=f + end + settranslations=function(t) + translations=t + end + setprocessor=function(f) + local writeline=write_nl + write_nl=function(target,...) + writeline(target,f(...)) + end + end + setformatters=function(specification) + local t=nil + local f=nil + local d=variants.default + if not specification then + elseif type(specification)=="table" then + t=specification.targets + f=specification.formats or specification + else + local v=variants[specification] + if v then + t=v.targets + f=v.formats + variant=specification + end end - setformatters=function(specification) - local t=nil - local f=nil - local d=variants.default - if not specification then - elseif type(specification)=="table" then - t=specification.targets - f=specification.formats or specification - else - local v=variants[specification] - if v then - t=v.targets - f=v.formats - variant=specification - end - end - targets=t or d.targets - target=targets[whereto] or target - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - direct_yes=f.direct_yes - direct_nop=f.direct_nop - subdirect_yes=f.subdirect_yes - subdirect_nop=f.subdirect_nop - status_yes=f.status_yes - status_nop=f.status_nop - if variant=="ansi" then - useluawrites() - end - settarget(whereto) - end - setformatters(variant) - setlogfile=ignore - settimedlog=ignore + targets=t or d.targets + target=targets[whereto] or target + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + direct_yes=f.direct_yes + direct_nop=f.direct_nop + subdirect_yes=f.subdirect_yes + subdirect_nop=f.subdirect_nop + status_yes=f.status_yes + status_nop=f.status_nop + if variant=="ansi" then + useluawrites() + end + settarget(whereto) + end + setformatters(variant) + setlogfile=ignore + settimedlog=ignore else - local report_yes,subreport_yes,status_yes - local report_nop,subreport_nop,status_nop - local variants={ - default={ - formats={ - report_yes=formatters["%-15s | %s"], - report_nop=formatters["%-15s |"], - subreport_yes=formatters["%-15s | %s | %s"], - subreport_nop=formatters["%-15s | %s |"], - status_yes=formatters["%-15s : %s\n"], - status_nop=formatters["%-15s :\n"], - }, - }, - ansi={ - formats={ - report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], - report_nop=formatters["[0;32m%-15s [0;1m|[0m"], - subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], - subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], - status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], - status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], - }, - }, - } - logs.flush=ignore - writer=function(s) - write_nl(s) - end - newline=function() - write_nl("\n") + local report_yes,subreport_yes,status_yes + local report_nop,subreport_nop,status_nop + local variants={ + default={ + formats={ + report_yes=formatters["%-15s | %s"], + report_nop=formatters["%-15s |"], + subreport_yes=formatters["%-15s | %s | %s"], + subreport_nop=formatters["%-15s | %s |"], + status_yes=formatters["%-15s : %s\n"], + status_nop=formatters["%-15s :\n"], + }, + }, + ansi={ + formats={ + report_yes=formatters["[0;32m%-15s [0;1m|[0m %s"], + report_nop=formatters["[0;32m%-15s [0;1m|[0m"], + subreport_yes=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m %s"], + subreport_nop=formatters["[0;32m%-15s [0;1m|[0;31m %s [0;1m|[0m"], + status_yes=formatters["[0;32m%-15s [0;1m:[0m %s\n"], + status_nop=formatters["[0;32m%-15s [0;1m:[0m\n"], + }, + }, + } + logs.flush=ignore + writer=function(s) + write_nl(s) + end + newline=function() + write_nl("\n") + end + report=function(a,b,c,...) + if c then + write_nl(report_yes(a,formatters[b](c,...))) + elseif b then + write_nl(report_yes(a,b)) + elseif a then + write_nl(report_nop(a)) + else + write_nl("") end - report=function(a,b,c,...) - if c then - write_nl(report_yes(a,formatters[b](c,...))) - elseif b then - write_nl(report_yes(a,b)) - elseif a then - write_nl(report_nop(a)) - else - write_nl("") - end + end + subreport=function(a,sub,b,c,...) + if c then + write_nl(subreport_yes(a,sub,formatters[b](c,...))) + elseif b then + write_nl(subreport_yes(a,sub,b)) + elseif a then + write_nl(subreport_nop(a,sub)) + else + write_nl("") end - subreport=function(a,sub,b,c,...) - if c then - write_nl(subreport_yes(a,sub,formatters[b](c,...))) - elseif b then - write_nl(subreport_yes(a,sub,b)) - elseif a then - write_nl(subreport_nop(a,sub)) - else - write_nl("") + end + status=function(a,b,c,...) + if c then + write_nl(status_yes(a,formatters[b](c,...))) + elseif b then + write_nl(status_yes(a,b)) + elseif a then + write_nl(status_nop(a)) + else + write_nl("\n") + end + end + direct=ignore + subdirect=ignore + settarget=ignore + pushtarget=ignore + poptarget=ignore + setformats=ignore + settranslations=ignore + setprocessor=function(f) + local writeline=write_nl + write_nl=function(s) + writeline(f(s)) + end + end + setformatters=function(specification) + local f=nil + local d=variants.default + if specification then + if type(specification)=="table" then + f=specification.formats or specification + else + local v=variants[specification] + if v then + f=v.formats end + end end - status=function(a,b,c,...) - if c then - write_nl(status_yes(a,formatters[b](c,...))) - elseif b then - write_nl(status_yes(a,b)) - elseif a then - write_nl(status_nop(a)) - else - write_nl("\n") - end - end - direct=ignore - subdirect=ignore - settarget=ignore - pushtarget=ignore - poptarget=ignore - setformats=ignore - settranslations=ignore - setprocessor=function(f) - local writeline=write_nl + if f then + d=d.formats + else + f=d.formats + d=f + end + setmetatableindex(f,d) + report_yes=f.report_yes + report_nop=f.report_nop + subreport_yes=f.subreport_yes + subreport_nop=f.subreport_nop + status_yes=f.status_yes + status_nop=f.status_nop + end + setformatters(variant) + 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(f(s)) - end - end - setformatters=function(specification) - local f=nil - local d=variants.default - if specification then - if type(specification)=="table" then - f=specification.formats or specification - else - local v=variants[specification] - if v then - f=v.formats - end - end - end - if f then - d=d.formats - else - f=d.formats - d=f - end - setmetatableindex(f,d) - report_yes=f.report_yes - report_nop=f.report_nop - subreport_yes=f.subreport_yes - subreport_nop=f.subreport_nop - status_yes=f.status_yes - status_nop=f.status_nop - end - setformatters(variant) - 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 + writeline(s) + f:write(localtime()," | ",s,"\n") end - setlogfile=ignore - end - settimedlog=function() - local localtime=os.localtime - local writeline=write_nl + else write_nl=function(s) - writeline(localtime().." | "..s) + writeline(s) + local f=io.open(name,"ab") + f:write(localtime()," | ",s,"\n") + f:close() end - settimedlog=ignore + 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 @@ -9727,198 +13131,186 @@ local data={} local states=nil local force=false function logs.reporter(category,subcategory) - local logger=data[category] - if not logger then - local state=states==true - if not state and type(states)=="table" then - for c,_ in next,states do - if find(category,c) then - state=true - break - end - end + local logger=data[category] + if not logger then + local state=states==true + if not state and type(states)=="table" then + for c,_ in next,states do + if find(category,c) then + state=true + break end - logger={ - reporters={}, - state=state, - } - data[category]=logger - end - local reporter=logger.reporters[subcategory or "default"] - if not reporter then - if subcategory then - reporter=function(...) - if force or not logger.state then - subreport(category,subcategory,...) - end - end - logger.reporters[subcategory]=reporter - else - local tag=category - reporter=function(...) - if force or not logger.state then - report(category,...) - end - end - logger.reporters.default=reporter + end + end + logger={ + reporters={}, + state=state, + } + data[category]=logger + end + local reporter=logger.reporters[subcategory or "default"] + if not reporter then + if subcategory then + reporter=function(...) + if force or not logger.state then + subreport(category,subcategory,...) end + end + logger.reporters[subcategory]=reporter + else + local tag=category + reporter=function(...) + if force or not logger.state then + report(category,...) + end + end + logger.reporters.default=reporter end - return reporter + end + return reporter end logs.new=logs.reporter local ctxreport=logs.writer function logs.setmessenger(m) - ctxreport=m + ctxreport=m end function logs.messenger(category,subcategory) - if subcategory then - return function(...) - ctxreport(subdirect(category,subcategory,...)) - end - else - return function(...) - ctxreport(direct(category,...)) - end + if subcategory then + return function(...) + ctxreport(subdirect(category,subcategory,...)) end + else + return function(...) + ctxreport(direct(category,...)) + end + end end local function setblocked(category,value) - if category==true or category=="all" then - category,value="*",true - elseif category==false then - category,value="*",false - elseif value==nil then - value=true - end - if category=="*" then - states=value + if category==true or category=="all" then + category,value="*",true + elseif category==false then + category,value="*",false + elseif value==nil then + value=true + end + if category=="*" then + states=value + for k,v in next,data do + v.state=value + end + else + alllocked=false + states=settings_to_hash(category,type(states)=="table" and states or nil) + for c in next,states do + local v=data[c] + if v then + v.state=value + else + c=topattern(c,true,true) for k,v in next,data do + if find(k,c) then v.state=value + end end - else - alllocked=false - states=settings_to_hash(category,type(states)=="table" and states or nil) - for c in next,states do - local v=data[c] - if v then - v.state=value - else - c=topattern(c,true,true) - for k,v in next,data do - if find(k,c) then - v.state=value - end - end - end - end + end end + end end function logs.disable(category,value) - setblocked(category,value==nil and true or value) + setblocked(category,value==nil and true or value) end function logs.enable(category) - setblocked(category,false) + setblocked(category,false) end function logs.categories() - return sortedkeys(data) + return sortedkeys(data) end function logs.show() - local n,c,s,max=0,0,0,0 - for category,v in table.sortedpairs(data) do - n=n+1 - local state=v.state - local reporters=v.reporters - local nc=#category - if nc>c then - c=nc - end - for subcategory,_ in next,reporters do - local ns=#subcategory - if ns>c then - s=ns - end - local m=nc+ns - if m>max then - max=m - end - end - local subcategories=concat(sortedkeys(reporters),", ") - if state==true then - state="disabled" - elseif state==false then - state="enabled" - else - state="unknown" - end - report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + local n,c,s,max=0,0,0,0 + for category,v in table.sortedpairs(data) do + n=n+1 + local state=v.state + local reporters=v.reporters + local nc=#category + if nc>c then + c=nc + end + for subcategory,_ in next,reporters do + local ns=#subcategory + if ns>c then + s=ns + end + local m=nc+ns + if m>max then + max=m + end + end + local subcategories=concat(sortedkeys(reporters),", ") + if state==true then + state="disabled" + elseif state==false then + state="enabled" + else + state="unknown" end - report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) + report("logging","category %a, subcategories %a, state %a",category,subcategories,state) + end + report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) end local delayed_reporters={} setmetatableindex(delayed_reporters,function(t,k) - local v=logs.reporter(k.name) - t[k]=v - return v + local v=logs.reporter(k.name) + t[k]=v + return v end) function utilities.setters.report(setter,...) - delayed_reporters[setter](...) + delayed_reporters[setter](...) end directives.register("logs.blocked",function(v) - setblocked(v,true) + setblocked(v,true) end) directives.register("logs.target",function(v) - settarget(v) + settarget(v) end) if tex then - local report=logs.reporter("pages") - local texgetcount=tex and tex.getcount - local real,user,sub - function logs.start_page_number() - real=texgetcount("realpageno") - user=texgetcount("userpageno") - sub=texgetcount("subpageno") - end - local timing=false - local starttime=nil - local lasttime=nil - trackers.register("pages.timing",function(v) - starttime=os.clock() - timing=true - end) - function logs.stop_page_number() - if timing then - local elapsed,average - local stoptime=os.clock() - if not lasttime or real<2 then - elapsed=stoptime - average=stoptime - starttime=stoptime - else - elapsed=stoptime-lasttime - average=(stoptime-starttime)/(real-1) - end - lasttime=stoptime - if real<=0 then - report("flushing page, time %0.04f / %0.04f",elapsed,average) - elseif user<=0 then - report("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average) - elseif sub<=0 then - report("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average) - else - report("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average) - end - else - if real<=0 then - report("flushing page") - elseif user<=0 then - report("flushing realpage %s",real) - elseif sub<=0 then - report("flushing realpage %s, userpage %s",real,user) - else - report("flushing realpage %s, userpage %s, subpage %s",real,user,sub) - end - end - logs.flush() + local report=logs.reporter("pages") + local texgetcount=tex and tex.getcount + local real,user,sub=0,0,0 + function logs.start_page_number() + real=texgetcount("realpageno") + user=texgetcount("userpageno") + sub=texgetcount("subpageno") + end + local timing=false + local lasttime=nil + trackers.register("pages.timing",function(v) + timing="" + end) + function logs.stop_page_number() + if timing then + local elapsed=statistics.currenttime(statistics) + local average,page + if not lasttime or real<2 then + average=elapsed + page=elapsed + else + average=elapsed/(real-1) + page=elapsed-lasttime + end + lasttime=elapsed + timing=formatters[", total %0.03f, page %0.03f, average %0.03f"](elapsed,page,average) end + if real<=0 then + report("flushing page%s",timing) + elseif user<=0 then + report("flushing realpage %s%s",real,timing) + elseif sub<=0 then + report("flushing realpage %s, userpage %s%s",real,user,timing) + else + report("flushing realpage %s, userpage %s, subpage %s%s",real,user,sub,timing) + end + logs.flush() + end end local nesting=0 local verbose=false @@ -9942,222 +13334,222 @@ logs.help=ignore local Carg,C,lpegmatch=lpeg.Carg,lpeg.C,lpeg.match local p_newline=lpeg.patterns.newline local linewise=( - Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline + Carg(1)*C((1-p_newline)^1)/function(t,s) t.report(s) end+Carg(1)*p_newline^2/function(t) t.report() end+p_newline )^1 local function reportlines(t,str) - if str then - lpegmatch(linewise,str,1,t) - end + if str then + lpegmatch(linewise,str,1,t) + end end local function reportbanner(t) - local banner=t.banner - if banner then - t.report(banner) - t.report() - end + local banner=t.banner + if banner then + t.report(banner) + t.report() + end end local function reportversion(t) - local banner=t.banner - if banner then - t.report(banner) - end + local banner=t.banner + if banner then + t.report(banner) + end end local function reporthelp(t,...) - local helpinfo=t.helpinfo - if type(helpinfo)=="string" then - reportlines(t,helpinfo) - elseif type(helpinfo)=="table" then - for i=1,select("#",...) do - reportlines(t,t.helpinfo[select(i,...)]) - if i<n then - t.report() - end - end + local helpinfo=t.helpinfo + if type(helpinfo)=="string" then + reportlines(t,helpinfo) + elseif type(helpinfo)=="table" then + for i=1,select("#",...) do + reportlines(t,t.helpinfo[select(i,...)]) + if i<n then + t.report() + end end + end end local function reportinfo(t) - t.report() - reportlines(t,t.moreinfo) + t.report() + reportlines(t,t.moreinfo) end local function reportexport(t,method) - report(t.helpinfo) + report(t.helpinfo) end local reporters={ - lines=reportlines, - banner=reportbanner, - version=reportversion, - help=reporthelp, - info=reportinfo, - export=reportexport, + lines=reportlines, + banner=reportbanner, + version=reportversion, + help=reporthelp, + info=reportinfo, + export=reportexport, } local exporters={ } logs.reporters=reporters logs.exporters=exporters function logs.application(t) - t.name=t.name or "unknown" - t.banner=t.banner - t.moreinfo=moreinfo - t.report=logs.reporter(t.name) - t.help=function(...) - reporters.banner(t) - reporters.help(t,...) - reporters.info(t) - end - t.export=function(...) - reporters.export(t,...) - end - t.identify=function() - reporters.banner(t) - end - t.version=function() - reporters.version(t) - end - return t + t.name=t.name or "unknown" + t.banner=t.banner + t.moreinfo=moreinfo + t.report=logs.reporter(t.name) + t.help=function(...) + reporters.banner(t) + reporters.help(t,...) + reporters.info(t) + end + t.export=function(...) + reporters.export(t,...) + end + t.identify=function() + reporters.banner(t) + end + t.version=function() + reporters.version(t) + end + return t end local f_syslog=formatters["%s %s => %s => %s => %s\r"] function logs.system(whereto,process,jobname,category,fmt,arg,...) - local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) - for i=1,10 do - local f=openfile(whereto,"a") - if f then - f:write(message) - f:close() - break - else - sleep(0.1) - end + local message=f_syslog(datetime("%d/%m/%y %H:%m:%S"),process,jobname,category,arg==nil and fmt or format(fmt,arg,...)) + for i=1,10 do + local f=openfile(whereto,"a") + if f then + f:write(message) + f:close() + break + else + sleep(0.1) end + end end local report_system=logs.reporter("system","logs") function logs.obsolete(old,new) - local o=loadstring("return "..new)() - if type(o)=="function" then - return function(...) - report_system("function %a is obsolete, use %a",old,new) - loadstring(old.."="..new.." return "..old)()(...) - end - elseif type(o)=="table" then - local t,m={},{} - m.__index=function(t,k) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - return o[k] - end - m.__newindex=function(t,k,v) - report_system("table %a is obsolete, use %a",old,new) - m.__index,m.__newindex=o,o - o[k]=v - end - if libraries then - libraries.obsolete[old]=t - end - setmetatable(t,m) - return t + local o=loadstring("return "..new)() + if type(o)=="function" then + return function(...) + report_system("function %a is obsolete, use %a",old,new) + loadstring(old.."="..new.." return "..old)()(...) + end + elseif type(o)=="table" then + local t,m={},{} + m.__index=function(t,k) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + return o[k] + end + m.__newindex=function(t,k,v) + report_system("table %a is obsolete, use %a",old,new) + m.__index,m.__newindex=o,o + o[k]=v + end + if libraries then + libraries.obsolete[old]=t end + setmetatable(t,m) + return t + end end if utilities then - utilities.report=report_system + utilities.report=report_system end if tex and tex.error then - function logs.texerrormessage(...) - tex.error(format(...),{}) - end + function logs.texerrormessage(...) + tex.error(format(...)) + end else - function logs.texerrormessage(...) - print(format(...)) - end + function logs.texerrormessage(...) + print(format(...)) + end end io.stdout:setvbuf('no') io.stderr:setvbuf('no') if package.helpers.report then - package.helpers.report=logs.reporter("package loader") + package.helpers.report=logs.reporter("package loader") end if tex then - local finalactions={} - local fatalerrors={} - local possiblefatal={} - local loggingerrors=false - function logs.loggingerrors() - return loggingerrors - end - directives.register("logs.errors",function(v) - loggingerrors=v - if type(v)=="string" then - fatalerrors=settings_to_hash(v) - else - fatalerrors={} - end - end) - function logs.registerfinalactions(...) - insert(finalactions,...) - end - local what=nil - local report=nil - local state=nil - local target=nil - local function startlogging(t,r,w,s) - target=t - state=force - force=true - report=type(r)=="function" and r or logs.reporter(r) - what=w - pushtarget(target) + local finalactions={} + local fatalerrors={} + local possiblefatal={} + local loggingerrors=false + function logs.loggingerrors() + return loggingerrors + end + directives.register("logs.errors",function(v) + loggingerrors=v + if type(v)=="string" then + fatalerrors=settings_to_hash(v) + else + fatalerrors={} + end + end) + function logs.registerfinalactions(...) + insert(finalactions,...) + end + local what=nil + local report=nil + local state=nil + local target=nil + local function startlogging(t,r,w,s) + target=t + state=force + force=true + report=type(r)=="function" and r or logs.reporter(r) + what=w + pushtarget(target) + newline() + if s then + report("start %s: %s",what,s) + else + report("start %s",what) + end + if target=="logfile" then + newline() + end + return report + end + local function stoplogging() + if target=="logfile" then + newline() + end + report("stop %s",what) + if target=="logfile" then + newline() + end + poptarget() + state=oldstate + end + function logs.startfilelogging(...) + return startlogging("logfile",...) + end + logs.stopfilelogging=stoplogging + local done=false + function logs.starterrorlogging(r,w,...) + if not done then + pushtarget("terminal") + newline() + logs.report("error logging","start possible issues") + poptarget() + done=true + end + if fatalerrors[w] then + possiblefatal[w]=true + end + return startlogging("terminal",r,w,...) + end + logs.stoperrorlogging=stoplogging + function logs.finalactions() + if #finalactions>0 then + for i=1,#finalactions do + finalactions[i]() + end + if done then + pushtarget("terminal") newline() - if s then - report("start %s: %s",what,s) - else - report("start %s",what) - end - if target=="logfile" then - newline() - end - return report - end - local function stoplogging() - if target=="logfile" then - newline() - end - report("stop %s",what) - if target=="logfile" then - newline() - end + logs.report("error logging","stop possible issues") poptarget() - state=oldstate - end - function logs.startfilelogging(...) - return startlogging("logfile",...) - end - logs.stopfilelogging=stoplogging - local done=false - function logs.starterrorlogging(r,w,...) - if not done then - pushtarget("terminal") - newline() - logs.report("error logging","start possible issues") - poptarget() - done=true - end - if fatalerrors[w] then - possiblefatal[w]=true - end - return startlogging("terminal",r,w,...) - end - logs.stoperrorlogging=stoplogging - function logs.finalactions() - if #finalactions>0 then - for i=1,#finalactions do - finalactions[i]() - end - if done then - pushtarget("terminal") - newline() - logs.report("error logging","stop possible issues") - poptarget() - end - return next(possiblefatal) and sortedkeys(possiblefatal) or false - end + end + return next(possiblefatal) and sortedkeys(possiblefatal) or false end + end end @@ -10167,14 +13559,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-inf"] = package.loaded["trac-inf"] or true --- original size: 8097, stripped down to: 5534 +-- original size: 9072, stripped down to: 6055 if not modules then modules={} end modules ['trac-inf']={ - version=1.001, - comment="companion to trac-inf.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-inf.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type,tonumber,select=type,tonumber,select local format,lower,find=string.format,string.lower,string.find @@ -10189,161 +13581,191 @@ statistics.enable=true statistics.threshold=0.01 local statusinfo,n,registered,timers={},0,{},{} setmetatableindex(timers,function(t,k) - local v={ timing=0,loadtime=0 } - t[k]=v - return v + local v={ timing=0,loadtime=0 } + t[k]=v + return v end) local function hastiming(instance) - return instance and timers[instance] + return instance and timers[instance] end local function resettiming(instance) - timers[instance or "notimer"]={ timing=0,loadtime=0 } + timers[instance or "notimer"]={ timing=0,loadtime=0 } end local ticks=clock local seconds=function(n) return n or 0 end -local function starttiming(instance) - local timer=timers[instance or "notimer"] - local it=timer.timing - if it==0 then - timer.starttime=ticks() - if not timer.loadtime then - timer.loadtime=0 - end - end - timer.timing=it+1 +local function starttiming(instance,reset) + local timer=timers[instance or "notimer"] + local it=timer.timing + if reset then + it=0 + timer.loadtime=0 + end + if it==0 then + timer.starttime=ticks() + if not timer.loadtime then + timer.loadtime=0 + end + end + timer.timing=it+1 end local function stoptiming(instance) + local timer=timers[instance or "notimer"] + local it=timer.timing + if it>1 then + timer.timing=it-1 + else + local starttime=timer.starttime + if starttime and starttime>0 then + local stoptime=ticks() + local loadtime=stoptime-starttime + timer.stoptime=stoptime + timer.loadtime=timer.loadtime+loadtime + timer.timing=0 + timer.starttime=0 + return loadtime + end + end + return 0 +end +local function elapsed(instance) + if type(instance)=="number" then + return instance + else + local timer=timers[instance or "notimer"] + return timer and seconds(timer.loadtime) or 0 + end +end +local function currenttime(instance) + if type(instance)=="number" then + return instance + else local timer=timers[instance or "notimer"] local it=timer.timing if it>1 then - timer.timing=it-1 else - local starttime=timer.starttime - if starttime and starttime>0 then - local stoptime=ticks() - local loadtime=stoptime-starttime - timer.stoptime=stoptime - timer.loadtime=timer.loadtime+loadtime - timer.timing=0 - timer.starttime=0 - return loadtime - end + local starttime=timer.starttime + if starttime and starttime>0 then + return seconds(timer.loadtime+ticks()-starttime) + end end return 0 -end -local function elapsed(instance) - if type(instance)=="number" then - return instance - else - local timer=timers[instance or "notimer"] - return timer and seconds(timer.loadtime) or 0 - end + end end local function elapsedtime(instance) - return format("%0.3f",elapsed(instance)) + return format("%0.3f",elapsed(instance)) end local function elapsedindeed(instance) - return elapsed(instance)>statistics.threshold + return elapsed(instance)>statistics.threshold end local function elapsedseconds(instance,rest) - if elapsedindeed(instance) then - return format("%0.3f seconds %s",elapsed(instance),rest or "") - end + if elapsedindeed(instance) then + return format("%0.3f seconds %s",elapsed(instance),rest or "") + end end statistics.hastiming=hastiming statistics.resettiming=resettiming statistics.starttiming=starttiming statistics.stoptiming=stoptiming +statistics.currenttime=currenttime statistics.elapsed=elapsed statistics.elapsedtime=elapsedtime statistics.elapsedindeed=elapsedindeed statistics.elapsedseconds=elapsedseconds function statistics.register(tag,fnc) - if statistics.enable and type(fnc)=="function" then - local rt=registered[tag] or (#statusinfo+1) - statusinfo[rt]={ tag,fnc } - registered[tag]=rt - if #tag>n then n=#tag end - end + if statistics.enable and type(fnc)=="function" then + local rt=registered[tag] or (#statusinfo+1) + statusinfo[rt]={ tag,fnc } + registered[tag]=rt + if #tag>n then n=#tag end + end end 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("used engine",function() - return format("%s version %s with functionality level %s, banner: %s", - LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) - end) - register("control sequences",function() - return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) - end) - register("callbacks",statistics.callbacks) - if TEXENGINE=="luajittex" and JITSUPPORTED then - local jitstatus=jit.status - if jitstatus then - local jitstatus={ jitstatus() } - if jitstatus[1] then - register("luajit options",concat(jitstatus," ",2)) - end - end - end - register("lua properties",function() - local hashchar=tonumber(status.luatex_hashchars) - local hashtype=status.luatex_hashtype - local mask=lua.mask or "ascii" - return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", - jit and "luajit" or "lua", - LUAVERSION, - statistics.memused(), - 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 - local s=statusinfo[i] - local r=s[2]() - if r then - report("%s: %s",s[1],r) - end + 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("used engine",function() + return format("%s version %s with functionality level %s, banner: %s", + LUATEXENGINE,LUATEXVERSION,LUATEXFUNCTIONALITY,lower(status.banner)) + end) + register("control sequences",function() + return format("%s of %s + %s",status.cs_count,status.hash_size,status.hash_extra) + end) + register("callbacks",statistics.callbacks) + if TEXENGINE=="luajittex" and JITSUPPORTED then + local jitstatus=jit.status + if jitstatus then + local jitstatus={ jitstatus() } + if jitstatus[1] then + register("luajit options",concat(jitstatus," ",2)) end - statistics.enable=false + end end + register("lua properties",function() + local hashchar=tonumber(status.luatex_hashchars) + local hashtype=status.luatex_hashtype + local mask=lua.mask or "ascii" + return format("engine: %s %s, used memory: %s, hash type: %s, hash chars: min(%i,40), symbol mask: %s (%s)", + jit and "luajit" or "lua", + LUAVERSION, + statistics.memused(), + 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 + local s=statusinfo[i] + local r=s[2]() + if r then + report("%s: %s",s[1],r) + end + end + statistics.enable=false + end end function statistics.memused() - local round=math.round or math.floor - return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) + local round=math.round or math.floor + return format("%s MB (ctx: %s MB)",round(collectgarbage("count")/1000),round(status.luastate_bytes/1000000)) end starttiming(statistics) function statistics.formatruntime(runtime) - return format("%s seconds",runtime) + return format("%s seconds",runtime) end function statistics.runtime() - stoptiming(statistics) - return statistics.formatruntime(elapsedtime(statistics)) + stoptiming(statistics) + local runtime=lua.getruntime and lua.getruntime() or elapsedtime(statistics) + return statistics.formatruntime(runtime) end local report=logs.reporter("system") -function statistics.timed(action) - starttiming("run") - action() - stoptiming("run") - report("total runtime: %s seconds",elapsedtime("run")) +function statistics.timed(action,all) + starttiming("run") + action() + stoptiming("run") + local runtime=tonumber(elapsedtime("run")) + if all then + local alltime=tonumber(lua.getruntime and lua.getruntime() or elapsedtime(statistics)) + if alltime and alltime>0 then + report("total runtime: %0.3f seconds of %0.3f seconds",runtime,alltime) + return + end + end + report("total runtime: %0.3f seconds",runtime) 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 + 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 @@ -10353,144 +13775,144 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-pro"] = package.loaded["trac-pro"] or true --- original size: 5841, stripped down to: 3511 +-- original size: 5841, stripped down to: 3352 if not modules then modules={} end modules ['trac-pro']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local getmetatable,setmetatable,rawset,type,next=getmetatable,setmetatable,rawset,type,next -local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) +local trace_namespaces=false trackers.register("system.namespaces",function(v) trace_namespaces=v end) local report_system=logs.reporter("system","protection") namespaces=namespaces or {} 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) - debugger.showtraceback(report_system) - else - report_system("reference to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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) - debugger.showtraceback(report_system) - else - report_system("assignment to %a in protected namespace %a",k,name) - end + if trace_namespaces then + 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 end local function register(name) - local data=name=="global" and _G or _G[name] - if not data then - return - end - registered[name]=data - local m=getmetatable(data) - if not m then - m={} - setmetatable(data,m) - end - local index,newindex={},{} - m.__saved__index=m.__index - m.__no__index=function(t,k) - if not index[k] then - index[k]=true - report_index(k,name) - end - return nil + local data=name=="global" and _G or _G[name] + if not data then + return + end + registered[name]=data + local m=getmetatable(data) + if not m then + m={} + setmetatable(data,m) + end + local index,newindex={},{} + m.__saved__index=m.__index + m.__no__index=function(t,k) + if not index[k] then + index[k]=true + report_index(k,name) end - m.__saved__newindex=m.__newindex - m.__no__newindex=function(t,k,v) - if not newindex[k] then - newindex[k]=true - report_newindex(k,name) - end - rawset(t,k,v) + return nil + end + m.__saved__newindex=m.__newindex + m.__no__newindex=function(t,k,v) + if not newindex[k] then + newindex[k]=true + report_newindex(k,name) end - m.__protection__depth=0 + rawset(t,k,v) + end + m.__protection__depth=0 end local function private(name) - local data=registered[name] + local data=registered[name] + if not data then + data=_G[name] if not data then - data=_G[name] - if not data then - data={} - _G[name]=data - end - register(name) + data={} + _G[name]=data end - return data + register(name) + end + return data end local function protect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>0 then - m.__protection__depth=pd+1 - else - m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex - m.__index,m.__newindex=m.__no__index,m.__no__newindex - m.__protection__depth=1 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>0 then + m.__protection__depth=pd+1 + else + m.__save_d_index,m.__saved__newindex=m.__index,m.__newindex + m.__index,m.__newindex=m.__no__index,m.__no__newindex + m.__protection__depth=1 + end end local function unprotect(name) - local data=registered[name] - if not data then - return - end - local m=getmetatable(data) - local pd=m.__protection__depth - if pd>1 then - m.__protection__depth=pd-1 - else - m.__index,m.__newindex=m.__saved__index,m.__saved__newindex - m.__protection__depth=0 - end + local data=registered[name] + if not data then + return + end + local m=getmetatable(data) + local pd=m.__protection__depth + if pd>1 then + m.__protection__depth=pd-1 + else + m.__index,m.__newindex=m.__saved__index,m.__saved__newindex + m.__protection__depth=0 + end end local function protectall() - for name,_ in next,registered do - if name~="global" then - protect(name) - end + for name,_ in next,registered do + if name~="global" then + protect(name) end + end end local function unprotectall() - for name,_ in next,registered do - if name~="global" then - unprotect(name) - end + for name,_ in next,registered do + if name~="global" then + unprotect(name) end + end end -namespaces.register=register -namespaces.private=private +namespaces.register=register +namespaces.private=private namespaces.protect=protect namespaces.unprotect=unprotect namespaces.protectall=protectall namespaces.unprotectall=unprotectall namespaces.private("namespaces") registered={} register("global") directives.register("system.protect",function(v) - if v then - protectall() - else - unprotectall() - end + if v then + protectall() + else + unprotectall() + end end) directives.register("system.checkglobals",function(v) - if v then - report_system("enabling global namespace guard") - protect("global") - else - report_system("disabling global namespace guard") - unprotect("global") - end + if v then + report_system("enabling global namespace guard") + protect("global") + else + report_system("disabling global namespace guard") + unprotect("global") + end end) @@ -10500,15 +13922,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lua"] = package.loaded["util-lua"] or true --- original size: 6621, stripped down to: 4764 +-- original size: 6664, stripped down to: 4589 if not modules then modules={} end modules ['util-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - comment="the strip code is written by Peter Cawley", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + comment="the strip code is written by Peter Cawley", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local rep,sub,byte,dump,format=string.rep,string.sub,string.byte,string.dump,string.format local load,loadfile,type,collectgarbage=load,loadfile,type,collectgarbage @@ -10519,150 +13941,151 @@ local report_lua=logs.reporter("system","lua") local report_mem=logs.reporter("system","lua memory") local tracestripping=false local tracememory=false -luautilities.stripcode=true +luautilities.stripcode=true luautilities.alwaysstripcode=false luautilities.nofstrippedchunks=0 luautilities.nofstrippedbytes=0 local strippedchunks={} luautilities.strippedchunks=strippedchunks luautilities.suffixes={ - tma="tma", - tmc=jit and "tmb" or "tmc", - lua="lua", - luc=jit and "lub" or "luc", - lui="lui", - luv="luv", - luj="luj", - tua="tua", - tuc="tuc", + tma="tma", + tmc=jit and "tmb" or "tmc", + lua="lua", + luc=jit and "lub" or "luc", + lui="lui", + luv="luv", + luj="luj", + tua="tua", + tuc="tuc", } 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 + 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 -end -function luautilities.loadedluacode(fullname,forcestrip,name,macros) - name=name or fullname - if macros then - macros=lua.macros - end - local code,message - if macros then - code,message=macros.loaded(fullname,true,false) - else - code,message=loadfile(fullname) - end + local code=io.loaddata(luafile) + if code and code~="" then + code=load(code) if code then - code() - else - report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") - end - if forcestrip and luautilities.stripcode then - if type(forcestrip)=="function" then - forcestrip=forcestrip(fullname) - end - if forcestrip or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end - elseif 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 + io.savedata(lucfile,code) + return true,0 + end else - return code,0 + 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 +end +function luautilities.loadedluacode(fullname,forcestrip,name,macros) + name=name or fullname + if macros then + macros=lua.macros + end + local code,message + if macros then + code,message=macros.loaded(fullname,true,false) + else + code,message=loadfile(fullname) + end + if code then + code() + else + report_lua("loading of file %a failed:\n\t%s",fullname,message or "no message") + code,message=loadfile(fullname) + end + if forcestrip and luautilities.stripcode then + if type(forcestrip)=="function" then + forcestrip=forcestrip(fullname) + end + 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 end function luautilities.strippedloadstring(code,name,forcestrip) - 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 - if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then - register(name) - return load(dump(code,true)),0 - else - return code,0 - end + 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 + if forcestrip and luautilities.stripcode or luautilities.alwaysstripcode then + register(name) + return load(dump(code,true)),0 + else + return code,0 + end end function luautilities.loadstring(code,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 - return code,0 + 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 + return 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 - end - return done + 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 + end + return done end function luautilities.loadstripped(...) - local l=load(...) - if l then - return load(dump(l,true)) - end + local l=load(...) + if l then + return load(dump(l,true)) + end end local finalizers={} setmetatable(finalizers,{ - __gc=function(t) - for i=1,#t do - pcall(t[i]) - end + __gc=function(t) + for i=1,#t do + pcall(t[i]) end + end } ) function luautilities.registerfinalizer(f) - finalizers[#finalizers+1]=f + finalizers[#finalizers+1]=f end function luautilities.checkmemory(previous,threshold,trace) - local current=collectgarbage("count") - if previous then - local checked=(threshold or 64)*1024 - local delta=current-previous - if current-previous>checked then - collectgarbage("collect") - local afterwards=collectgarbage("count") - if trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB, afterwards %i MB", - previous/1024,current/1024,delta/1024,threshold,afterwards) - end - return afterwards - elseif trace or tracememory then - report_mem("previous %i MB, current %i MB, delta %i MB, threshold %i MB", - previous/1024,current/1024,delta/1024,threshold) - end + local current=collectgarbage("count") + if previous then + local checked=(threshold or 64)*1024 + local delta=current-previous + if current-previous>checked then + collectgarbage("collect") + local afterwards=collectgarbage("count") + if trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB, afterwards %r MB", + previous/1024,current/1024,delta/1024,threshold,afterwards) + end + return afterwards + elseif trace or tracememory then + report_mem("previous %r MB, current %r MB, delta %r MB, threshold %r MB", + previous/1024,current/1024,delta/1024,threshold) end - return current + end + return current end @@ -10672,17 +14095,15 @@ do -- create closure to overcome 200 locals limit package.loaded["util-deb"] = package.loaded["util-deb"] or true --- original size: 8984, stripped down to: 6573 +-- original size: 9955, stripped down to: 6693 if not modules then modules={} end modules ['util-deb']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local debug=require "debug" -local getinfo,sethook=debug.getinfo,debug.sethook local type,next,tostring,tonumber=type,next,tostring,tonumber local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub local insert,remove,sort=table.insert,table.remove,table.sort @@ -10700,228 +14121,266 @@ local names={} local initialize=false if not (FFISUPPORTED and ffi) then elseif os.type=="windows" then - initialize=function() - local kernel=ffilib("kernel32","system") - if kernel then - local tonumber=ffi.number or tonumber - ffi.cdef[[ + initialize=function() + local kernel=ffilib("kernel32","system") + if kernel then + local tonumber=ffi.number or tonumber + ffi.cdef[[ int QueryPerformanceFrequency(int64_t *lpFrequency); int QueryPerformanceCounter(int64_t *lpPerformanceCount); ]] - local target=ffi.new("__int64[1]") - ticks=function() - if kernel.QueryPerformanceCounter(target)==1 then - return tonumber(target[0]) - else - return 0 - end - end - local target=ffi.new("__int64[1]") - seconds=function(ticks) - if kernel.QueryPerformanceFrequency(target)==1 then - return ticks/tonumber(target[0]) - else - return 0 - end - end + local target=ffi.new("__int64[1]") + ticks=function() + if kernel.QueryPerformanceCounter(target)==1 then + return tonumber(target[0]) + else + return 0 end - initialize=false + end + local target=ffi.new("__int64[1]") + seconds=function(ticks) + if kernel.QueryPerformanceFrequency(target)==1 then + return ticks/tonumber(target[0]) + else + return 0 + end + end end + initialize=false + end elseif os.type=="unix" then - initialize=function() - local C=ffi.C - local tonumber=ffi.number or tonumber - ffi.cdef [[ + initialize=function() + local C=ffi.C + local tonumber=ffi.number or tonumber + ffi.cdef [[ /* what a mess */ typedef int clk_id_t; typedef enum { CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID } clk_id; typedef struct timespec { long sec; long nsec; } ctx_timespec; int clock_gettime(clk_id_t timerid, struct timespec *t); ]] - local target=ffi.new("ctx_timespec[?]",1) - local clock=C.CLOCK_PROCESS_CPUTIME_ID - ticks=function () - C.clock_gettime(clock,target) - return tonumber(target[0].sec*1000000000+target[0].nsec) - end - seconds=function(ticks) - return ticks/1000000000 - end - initialize=false + local target=ffi.new("ctx_timespec[?]",1) + local clock=C.CLOCK_PROCESS_CPUTIME_ID + ticks=function () + C.clock_gettime(clock,target) + return tonumber(target[0].sec*1000000000+target[0].nsec) + end + seconds=function(ticks) + return ticks/1000000000 end + initialize=false + end end setmetatableindex(names,function(t,name) - local v=setmetatableindex(function(t,source) - local v=setmetatableindex(function(t,line) - local v={ total=0,count=0 } - t[line]=v - return v - end) - t[source]=v - return v + local v=setmetatableindex(function(t,source) + local v=setmetatableindex(function(t,line) + local v={ total=0,count=0,nesting=0 } + t[line]=v + return v end) - t[name]=v + t[source]=v return v + end) + t[name]=v + return v end) +local getinfo=nil +local sethook=nil local function hook(where) - local f=getinfo(2,"nSl") - if f then - local source=f.short_src - if not source then - return - end - local line=f.linedefined or 0 - local name=f.name - if not name then - local what=f.what - if what=="C" then - name="<anonymous>" - else - name=f.namewhat or what or "<unknown>" - end - end - local data=names[name][source][line] - if where=="call" then - data.count=data.count+1 - insert(data,ticks()) - elseif where=="return" then - local t=remove(data) - if t then - data.total=data.total+ticks()-t - end + local f=getinfo(2,"nSl") + if f then + local source=f.short_src + if not source then + return + end + local line=f.linedefined or 0 + local name=f.name + if not name then + local what=f.what + if what=="C" then + name="<anonymous>" + else + name=f.namewhat or what or "<unknown>" + end + end + local data=names[name][source][line] + if where=="call" then + local nesting=data.nesting + if nesting==0 then + data.count=data.count+1 + insert(data,ticks()) + data.nesting=1 + else + data.nesting=nesting+1 + end + elseif where=="return" then + local nesting=data.nesting + if nesting==1 then + local t=remove(data) + if t then + data.total=data.total+ticks()-t end + data.nesting=0 + else + data.nesting=nesting-1 + end end + end end function debugger.showstats(printer,threshold) - local printer=printer or report - local calls=0 - local functions=0 - local dataset={} - local length=0 - local realtime=0 - local totaltime=0 - local threshold=threshold or 0 - for name,sources in next,names do - for source,lines in next,sources do - for line,data in next,lines do - local count=data.count - if count>threshold then - if #name>length then - length=#name - end - local total=data.total - local real=total - if real>0 then - real=total-(count*overhead/dummycalls) - if real<0 then - real=0 - end - realtime=realtime+real - end - totaltime=totaltime+total - if line<0 then - line=0 - end - dataset[#dataset+1]={ real,total,count,name,source,line } - end - end + local printer=printer or report + local calls=0 + local functions=0 + local dataset={} + local length=0 + local realtime=0 + local totaltime=0 + local threshold=threshold or 0 + for name,sources in next,names do + for source,lines in next,sources do + for line,data in next,lines do + local count=data.count + if count>threshold then + if #name>length then + length=#name + end + local total=data.total + local real=total + if real>0 then + real=total-(count*overhead/dummycalls) + if real<0 then + real=0 + end + realtime=realtime+real + end + totaltime=totaltime+total + if line<0 then + line=0 + end + dataset[#dataset+1]={ real,total,count,name,source,line } end + end end - sort(dataset,function(a,b) - if a[1]==b[1] then - if a[2]==b[2] then - if a[3]==b[3] then - if a[4]==b[4] then - if a[5]==b[5] then - return a[6]<b[6] - else - return a[5]<b[5] - end - else - return a[4]<b[4] - end - else - return b[3]<a[3] - end + end + sort(dataset,function(a,b) + if a[1]==b[1] then + if a[2]==b[2] then + if a[3]==b[3] then + if a[4]==b[4] then + if a[5]==b[5] then + return a[6]<b[6] else - return b[2]<a[2] + return a[5]<b[5] end + else + return a[4]<b[4] + end else - return b[1]<a[1] + return b[3]<a[3] end - end) - if length>50 then - length=50 - end - local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] - for i=1,#dataset do - local data=dataset[i] - local real=data[1] - local total=data[2] - local count=data[3] - local name=data[4] - local source=data[5] - local line=data[6] - calls=calls+count - functions=functions+1 - name=gsub(name,"%s+"," ") - if #name>length then - name=sub(name,1,length) - end - printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) - end - printer("") - printer(format("functions : %i",functions)) - printer(format("calls : %i",calls)) - printer(format("overhead : %f",seconds(overhead/1000))) + else + return b[2]<a[2] + end + else + return b[1]<a[1] + end + end) + if length>50 then + length=50 + end + local fmt=string.formatters["%4.9k s %3.3k %% %4.9k s %3.3k %% %8i # %-"..length.."s %4i %s"] + for i=1,#dataset do + local data=dataset[i] + local real=data[1] + local total=data[2] + local count=data[3] + local name=data[4] + local source=data[5] + local line=data[6] + calls=calls+count + functions=functions+1 + name=gsub(name,"%s+"," ") + if #name>length then + name=sub(name,1,length) + end + printer(fmt(seconds(total),100*total/totaltime,seconds(real),100*real/realtime,count,name,line,source)) + end + printer("") + printer(format("functions : %i",functions)) + printer(format("calls : %i",calls)) + printer(format("overhead : %f",seconds(overhead/1000))) +end +local function getdebug() + if sethook and getinfo then + return + end + if not debug then + local okay + okay,debug=pcall(require,"debug") + end + if type(debug)~="table" then + return + end + getinfo=debug.getinfo + sethook=debug.sethook + if type(getinfo)~="function" then + getinfo=nil + end + if type(sethook)~="function" then + sethook=nil + end end function debugger.savestats(filename,threshold) - local f=io.open(filename,'w') - if f then - debugger.showstats(function(str) f:write(str,"\n") end,threshold) - f:close() - end + local f=io.open(filename,'w') + if f then + debugger.showstats(function(str) f:write(str,"\n") end,threshold) + f:close() + end end function debugger.enable() - if nesting==0 then - running=true - if initialize then - initialize() - end - sethook(hook,"cr") - local function dummy() end - local t=ticks() - for i=1,dummycalls do - dummy() - end - overhead=ticks()-t - end - if nesting>0 then - nesting=nesting+1 - end + getdebug() + if sethook and getinfo and nesting==0 then + running=true + if initialize then + initialize() + end + sethook(hook,"cr") + local function dummy() end + local t=ticks() + for i=1,dummycalls do + dummy() + end + overhead=ticks()-t + end + if nesting>0 then + nesting=nesting+1 + end end function debugger.disable() - if nesting>0 then - nesting=nesting-1 - end - if nesting==0 then - sethook() - end + if nesting>0 then + nesting=nesting-1 + end + if sethook and getinfo and nesting==0 then + sethook() + end end local function showtraceback(rep) + getdebug() + if getinfo then local level=2 local reporter=rep or report while true do - local info=getinfo(level,"Sl") - if not info then - break - elseif info.what=="C" then - reporter("%2i : %s",level-1,"C function") - else - reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) - end - level=level+1 + local info=getinfo(level,"Sl") + if not info then + break + elseif info.what=="C" then + reporter("%2i : %s",level-1,"C function") + else + reporter("%2i : %s : %s",level-1,info.short_src,info.currentline) + end + level=level+1 end + end end debugger.showtraceback=showtraceback @@ -10932,91 +14391,91 @@ do -- create closure to overcome 200 locals limit package.loaded["util-tpl"] = package.loaded["util-tpl"] or true --- original size: 7112, stripped down to: 3988 +-- original size: 7112, stripped down to: 3887 if not modules then modules={} end modules ['util-tpl']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } utilities.templates=utilities.templates or {} local templates=utilities.templates -local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) +local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end) local report_template=logs.reporter("template") local tostring,next=tostring,next 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] - if not v then - if trace_template then - report_template("unknown key %a",k) - end - return "" + local v=t[k] + if not v then + if trace_template then + report_template("unknown key %a",k) + end + return "" + else + v=tostring(v) + if trace_template then + report_template("setting key %a to value %a",k,v) + end + if recursive then + return lpegmatch(replacer,v,1,t,how,recursive) else - v=tostring(v) - if trace_template then - report_template("setting key %a to value %a",k,v) - end - if recursive then - return lpegmatch(replacer,v,1,t,how,recursive) - else - return v - end + return v end + end end local sqlescape=lpeg.replacer { - { "'","''" }, - { "\\","\\\\" }, - { "\r\n","\\n" }, - { "\r","\\n" }, + { "'","''" }, + { "\\","\\\\" }, + { "\r\n","\\n" }, + { "\r","\\n" }, } local sqlquoted=Cs(Cc("'")*sqlescape*Cc("'")) lpegpatterns.sqlescape=sqlescape lpegpatterns.sqlquoted=sqlquoted local luaescape=lpegpatterns.luaescape local escapers={ - lua=function(s) - return lpegmatch(luaescape,s) - end, - sql=function(s) - return lpegmatch(sqlescape,s) - end, + lua=function(s) + return lpegmatch(luaescape,s) + end, + sql=function(s) + return lpegmatch(sqlescape,s) + end, } local quotedescapers={ - lua=function(s) - return format("%q",s) - end, - sql=function(s) - return lpegmatch(sqlquoted,s) - end, + lua=function(s) + return format("%q",s) + end, + sql=function(s) + return lpegmatch(sqlquoted,s) + end, } local luaescaper=escapers.lua local quotedluaescaper=quotedescapers.lua local function replacekeyunquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and escapers[how] or luaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and escapers[how] or luaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replacekeyquoted(s,t,how,recurse) - if how==false then - return replacekey(s,t,how,recurse) - else - local escaper=how and quotedescapers[how] or quotedluaescaper - return escaper(replacekey(s,t,how,recurse)) - end + if how==false then + return replacekey(s,t,how,recurse) + else + local escaper=how and quotedescapers[how] or quotedluaescaper + return escaper(replacekey(s,t,how,recurse)) + end end local function replaceoptional(l,m,r,t,how,recurse) - local v=t[l] - return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" + local v=t[l] + return v and v~="" and lpegmatch(replacer,r,1,t,how or "lua",recurse or false) or "" end -local single=P("%") +local single=P("%") local double=P("%%") local lquoted=P("%[") local rquoted=P("]%") @@ -11033,41 +14492,41 @@ local noloptional=P("%?")/'' local noroptional=P("?%")/'' local nomoptional=P(":")/'' local args=Carg(1)*Carg(2)*Carg(3) -local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle -local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq -local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted +local key=nosingle*((C((1-nosingle )^1)*args)/replacekey )*nosingle +local quoted=nolquotedq*((C((1-norquotedq )^1)*args)/replacekeyquoted )*norquotedq +local unquoted=nolquoted*((C((1-norquoted )^1)*args)/replacekeyunquoted)*norquoted local optional=noloptional*((C((1-nomoptional)^1)*nomoptional*C((1-noroptional)^1)*args)/replaceoptional)*noroptional local any=P(1) replacer=Cs((unquoted+quoted+escape+optional+key+any)^0) local function replace(str,mapping,how,recurse) - if mapping and str then - return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str - else - return str - end + if mapping and str then + return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str + else + return str + 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 + 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 - return replace(data,mapping,how,recurse) - else - return data - end + local data=io.loaddata(filename) or "" + if mapping and next(mapping) then + return replace(data,mapping,how,recurse) + else + return data + end end function templates.resolve(t,mapping,how,recurse) - if not mapping then - mapping=t - end - for k,v in next,t do - t[k]=replace(v,mapping,how,recurse) - end - return t + if not mapping then + mapping=t + end + for k,v in next,t do + t[k]=replace(v,mapping,how,recurse) + end + return t end @@ -11077,14 +14536,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-sbx"] = package.loaded["util-sbx"] or true --- original size: 20393, stripped down to: 13924 +-- original size: 20393, stripped down to: 13121 if not modules then modules={} end modules ['util-sbx']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } if not sandbox then require("l-sandbox") end local next,type=next,type @@ -11117,144 +14576,144 @@ local report=logs.reporter("sandbox") trackers.register("sandbox",function(v) trace=v end) sandbox.setreporter(report) sandbox.finalizer { - category="files", - action=function() - finalized=true - end + category="files", + action=function() + finalized=true + end } local function registerroot(root,what) - if finalized then - report("roots are already finalized") - else - if type(root)=="table" then - root,what=root[1],root[2] - end - if type(root)=="string" and root~="" then - root=collapsepath(expandname(root)) - if what=="r" or what=="ro" or what=="readable" then - what="read" - elseif what=="w" or what=="wo" or what=="writable" then - what="write" - end - validroots[root]=what=="write" or false - end + if finalized then + report("roots are already finalized") + else + if type(root)=="table" then + root,what=root[1],root[2] + end + if type(root)=="string" and root~="" then + root=collapsepath(expandname(root)) + if what=="r" or what=="ro" or what=="readable" then + what="read" + elseif what=="w" or what=="wo" or what=="writable" then + what="write" + end + validroots[root]=what=="write" or false end + end end sandbox.finalizer { - category="files", - action=function() + category="files", + action=function() + if p_validroot then + report("roots are already initialized") + else + sandbox.registerroot(".","write") + for name in sortedhash(validroots) do if p_validroot then - report("roots are already initialized") + p_validroot=P(name)+p_validroot else - sandbox.registerroot(".","write") - for name in sortedhash(validroots) do - if p_validroot then - p_validroot=P(name)+p_validroot - else - p_validroot=P(name) - end - end - p_validroot=p_validroot/validroots + p_validroot=P(name) end + end + p_validroot=p_validroot/validroots end + end } local function registerbinary(name) - if finalized then - report("binaries are already finalized") - elseif type(name)=="string" and name~="" then - if not validbinaries then - return - end - if validbinaries==true then - validbinaries={ [name]=true } - else - validbinaries[name]=true - end - elseif name==true then - validbinaries={} + if finalized then + report("binaries are already finalized") + elseif type(name)=="string" and name~="" then + if not validbinaries then + return + end + if validbinaries==true then + validbinaries={ [name]=true } + else + validbinaries[name]=true end + elseif name==true then + validbinaries={} + end end local function registerlibrary(name) - if finalized then - report("libraries are already finalized") - elseif type(name)=="string" and name~="" then - if not validlibraries then - return - end - if validlibraries==true then - validlibraries={ [nameonly(name)]=true } - else - validlibraries[nameonly(name)]=true - end - elseif name==true then - validlibraries={} + if finalized then + report("libraries are already finalized") + elseif type(name)=="string" and name~="" then + if not validlibraries then + return + end + if validlibraries==true then + validlibraries={ [nameonly(name)]=true } + else + validlibraries[nameonly(name)]=true end + elseif name==true then + validlibraries={} + end end local p_write=S("wa") p_write=(1-p_write)^0*p_write -local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path +local p_path=S("\\/~$%:") p_path=(1-p_path )^0*p_path local function normalized(name) - if platform=="windows" then - name=gsub(name,"/","\\") - end - return name + if platform=="windows" then + name=gsub(name,"/","\\") + end + return name end function sandbox.possiblepath(name) - return lpegmatch(p_path,name) and true or false + return lpegmatch(p_path,name) and true or false end local filenamelogger=false function sandbox.setfilenamelogger(l) - filenamelogger=type(l)=="function" and l or false + filenamelogger=type(l)=="function" and l or false end local function validfilename(name,what) - if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then - local asked=collapsepath(expandname(name)) - local okay=lpegmatch(p_validroot,asked) - if okay==true then - if filenamelogger then - filenamelogger(name,"w",asked,true) - end - return name - elseif okay==false then - if not what then - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - elseif lpegmatch(p_write,what) then - if filenamelogger then - filenamelogger(name,"w",asked,false) - end - return - else - if filenamelogger then - filenamelogger(name,"r",asked,true) - end - return name - end - elseif filenamelogger then - filenamelogger(name,"*",name,false) + if p_validroot and type(name)=="string" and lpegmatch(p_path,name) then + local asked=collapsepath(expandname(name)) + local okay=lpegmatch(p_validroot,asked) + if okay==true then + if filenamelogger then + filenamelogger(name,"w",asked,true) + end + return name + elseif okay==false then + if not what then + if filenamelogger then + filenamelogger(name,"r",asked,true) end - else return name + elseif lpegmatch(p_write,what) then + if filenamelogger then + filenamelogger(name,"w",asked,false) + end + return + else + if filenamelogger then + filenamelogger(name,"r",asked,true) + end + return name + end + elseif filenamelogger then + filenamelogger(name,"*",name,false) end + else + return name + end end local function readable(name,finalized) - return validfilename(name,"r") + return validfilename(name,"r") end local function normalizedreadable(name,finalized) - local valid=validfilename(name,"r") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"r") + if valid then + return normalized(valid) + end end local function writeable(name,finalized) - return validfilename(name,"w") + return validfilename(name,"w") end local function normalizedwriteable(name,finalized) - local valid=validfilename(name,"w") - if valid then - return normalized(valid) - end + local valid=validfilename(name,"w") + if valid then + return normalized(valid) + end end validators.readable=readable validators.writeable=normalizedwriteable @@ -11262,316 +14721,316 @@ validators.normalizedreadable=normalizedreadable validators.normalizedwriteable=writeable validators.filename=readable table.setmetatableindex(validators,function(t,k) - if k then - t[k]=readable - end - return readable + if k then + t[k]=readable + end + return readable end) function validators.string(s,finalized) - if finalized and suspicious(s) then - return "" - else - return s - end + if finalized and suspicious(s) then + return "" + else + return s + end end function validators.cache(s) - if finalized then - return basename(s) - else - return s - end + if finalized then + return basename(s) + else + return s + end end function validators.url(s) - if finalized and find("^file:") then - return "" - else - return s - end + if finalized and find("^file:") then + return "" + else + return s + end end local function filehandlerone(action,one,...) - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - else - end + local checkedone=validfilename(one) + if checkedone then + return action(one,...) + else + end end local function filehandlertwo(action,one,two,...) - local checkedone=validfilename(one) - if checkedone then - local checkedtwo=validfilename(two) - if checkedtwo then - return action(one,two,...) - else - end + local checkedone=validfilename(one) + if checkedone then + local checkedtwo=validfilename(two) + if checkedtwo then + return action(one,two,...) else end + else + end end local function iohandler(action,one,...) - if type(one)=="string" then - local checkedone=validfilename(one) - if checkedone then - return action(one,...) - end - elseif one then - return action(one,...) - else - return action() + if type(one)=="string" then + local checkedone=validfilename(one) + if checkedone then + return action(one,...) end + elseif one then + return action(one,...) + else + return action() + end end local osexecute=sandbox.original(os.execute) local iopopen=sandbox.original(io.popen) local reported={} local function validcommand(name,program,template,checkers,defaults,variables,reporter,strict) - if validbinaries~=false and (validbinaries==true or validbinaries[program]) then - if variables then - for variable,value in next,variables do - local checker=validators[checkers[variable]] - if checker then - value=checker(unquoted(value),strict) - if value then - variables[variable]=optionalquoted(value) - else - report("variable %a with value %a fails the check",variable,value) - return - end - else - report("variable %a has no checker",variable) - return - end - end - for variable,default in next,defaults do - local value=variables[variable] - if not value or value=="" then - local checker=validators[checkers[variable]] - if checker then - default=checker(unquoted(default),strict) - if default then - variables[variable]=optionalquoted(default) - else - report("variable %a with default %a fails the check",variable,default) - return - end - end - end - end - end - local command=program.." "..replace(template,variables) - if reporter then - reporter("executing runner %a: %s",name,command) - elseif trace then - report("executing runner %a: %s",name,command) - end - return command - elseif not reported[name] then - report("executing program %a of runner %a is not permitted",program,name) - reported[name]=true - end -end -local runners={ - resultof=function(...) - local command=validcommand(...) - if command then - if trace then - report("resultof: %s",command) - end - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - end - end - end, - execute=function(...) - local command=validcommand(...) - if command then - if trace then - report("execute: %s",command) - end - return osexecute(command) + if validbinaries~=false and (validbinaries==true or validbinaries[program]) then + if variables then + for variable,value in next,variables do + local checker=validators[checkers[variable]] + if checker then + value=checker(unquoted(value),strict) + if value then + variables[variable]=optionalquoted(value) + else + report("variable %a with value %a fails the check",variable,value) + return + end + else + report("variable %a has no checker",variable) + return end - end, - pipeto=function(...) - local command=validcommand(...) - if command then - if trace then - report("pipeto: %s",command) + end + for variable,default in next,defaults do + local value=variables[variable] + if not value or value=="" then + local checker=validators[checkers[variable]] + if checker then + default=checker(unquoted(default),strict) + if default then + variables[variable]=optionalquoted(default) + else + report("variable %a with default %a fails the check",variable,default) + return end - return iopopen(command,"w") - end - end, -} -function sandbox.registerrunner(specification) - if type(specification)=="string" then - local wrapped=validrunners[specification] - inspect(table.sortedkeys(validrunners)) - if wrapped then - return wrapped - else - report("unknown predefined runner %a",specification) - return + end end + end end - if type(specification)~="table" then - report("specification should be a table (or string)") - return - end - local name=specification.name - if type(name)~="string" then - report("invalid name, string expected",name) - return - end - if validrunners[name] then - report("invalid name, runner %a already defined") - return - end - local program=specification.program - if type(program)=="string" then - elseif type(program)=="table" then - program=program[platform] or program.default or program.unix - end - if type(program)~="string" or program=="" then - report("invalid runner %a specified for platform %a",name,platform) - return + local command=program.." "..replace(template,variables) + if reporter then + reporter("executing runner %a: %s",name,command) + elseif trace then + report("executing runner %a: %s",name,command) end - local template=specification.template - if not template then - report("missing template for runner %a",name) - return + return command + elseif not reported[name] then + report("executing program %a of runner %a is not permitted",program,name) + reported[name]=true + end +end +local runners={ + resultof=function(...) + local command=validcommand(...) + if command then + if trace then + report("resultof: %s",command) + end + local handle=iopopen(command,"r") + if handle then + local result=handle:read("*all") or "" + handle:close() + return result + end end - local method=specification.method or "execute" - local checkers=specification.checkers or {} - local defaults=specification.defaults or {} - local runner=runners[method] - if runner then - local finalized=finalized - local wrapped=function(variables) - return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) - end - validrunners[name]=wrapped - return wrapped - else - validrunners[name]=nil - report("invalid method for runner %a",name) + end, + execute=function(...) + local command=validcommand(...) + if command then + if trace then + report("execute: %s",command) + end + return osexecute(command) + end + end, + pipeto=function(...) + local command=validcommand(...) + if command then + if trace then + report("pipeto: %s",command) + end + return iopopen(command,"w") end + end, +} +function sandbox.registerrunner(specification) + if type(specification)=="string" then + local wrapped=validrunners[specification] + inspect(table.sortedkeys(validrunners)) + if wrapped then + return wrapped + else + report("unknown predefined runner %a",specification) + return + end + end + if type(specification)~="table" then + report("specification should be a table (or string)") + return + end + local name=specification.name + if type(name)~="string" then + report("invalid name, string expected",name) + return + end + if validrunners[name] then + report("invalid name, runner %a already defined") + return + end + local program=specification.program + if type(program)=="string" then + elseif type(program)=="table" then + program=program[platform] or program.default or program.unix + end + if type(program)~="string" or program=="" then + report("invalid runner %a specified for platform %a",name,platform) + return + end + local template=specification.template + if not template then + report("missing template for runner %a",name) + return + end + local method=specification.method or "execute" + local checkers=specification.checkers or {} + local defaults=specification.defaults or {} + local runner=runners[method] + if runner then + local finalized=finalized + local wrapped=function(variables) + return runner(name,program,template,checkers,defaults,variables,specification.reporter,finalized) + end + validrunners[name]=wrapped + return wrapped + else + validrunners[name]=nil + report("invalid method for runner %a",name) + end end function sandbox.getrunner(name) - return name and validrunners[name] + return name and validrunners[name] end local function suspicious(str) - return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false + return (find(str,"[/\\]") or find(command,"..",1,true)) and true or false end local function binaryrunner(action,command,...) - if validbinaries==false then - report("no binaries permitted, ignoring command: %s",command) - return - end - if type(command)~="string" then - report("command should be a string") - return - end - local program=lpegmatch(p_split,command) - if not program or program=="" then - report("unable to filter binary from command: %s",command) - return - end - if validbinaries==true then - elseif not validbinaries[program] then - report("binary not permitted, ignoring command: %s",command) - return - elseif suspicious(command) then - report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) - return - end - return action(command,...) + if validbinaries==false then + report("no binaries permitted, ignoring command: %s",command) + return + end + if type(command)~="string" then + report("command should be a string") + return + end + local program=lpegmatch(p_split,command) + if not program or program=="" then + report("unable to filter binary from command: %s",command) + return + end + if validbinaries==true then + elseif not validbinaries[program] then + report("binary not permitted, ignoring command: %s",command) + return + elseif suspicious(command) then + report("/ \\ or .. found, ignoring command (use sandbox.registerrunner): %s",command) + return + end + return action(command,...) end local function dummyrunner(action,command,...) - if type(command)=="table" then - command=concat(command," ",command[0] and 0 or 1) - end - report("ignoring command: %s",command) + if type(command)=="table" then + command=concat(command," ",command[0] and 0 or 1) + end + report("ignoring command: %s",command) end sandbox.filehandlerone=filehandlerone sandbox.filehandlertwo=filehandlertwo sandbox.iohandler=iohandler function sandbox.disablerunners() - validbinaries=false + validbinaries=false end function sandbox.disablelibraries() - validlibraries=false + validlibraries=false end if FFISUPPORTED and ffi then - function sandbox.disablelibraries() - validlibraries=false - for k,v in next,ffi do - if k~="gc" then - ffi[k]=nil - end - end + function sandbox.disablelibraries() + validlibraries=false + for k,v in next,ffi do + if k~="gc" then + ffi[k]=nil + end end - local fiiload=ffi.load - if fiiload then - local reported={} - function ffi.load(name,...) - if validlibraries==false then - elseif validlibraries==true then - return fiiload(name,...) - elseif validlibraries[nameonly(name)] then - return fiiload(name,...) - else - end - if not reported[name] then - report("using library %a is not permitted",name) - reported[name]=true - end - return nil - end + end + local fiiload=ffi.load + if fiiload then + local reported={} + function ffi.load(name,...) + if validlibraries==false then + elseif validlibraries==true then + return fiiload(name,...) + elseif validlibraries[nameonly(name)] then + return fiiload(name,...) + else + end + if not reported[name] then + report("using library %a is not permitted",name) + reported[name]=true + end + return nil end + end end local overload=sandbox.overload local register=sandbox.register - overload(loadfile,filehandlerone,"loadfile") + overload(loadfile,filehandlerone,"loadfile") if io then - overload(io.open,filehandlerone,"io.open") - overload(io.popen,binaryrunner,"io.popen") - overload(io.input,iohandler,"io.input") - overload(io.output,iohandler,"io.output") - overload(io.lines,filehandlerone,"io.lines") + overload(io.open,filehandlerone,"io.open") + overload(io.popen,binaryrunner,"io.popen") + overload(io.input,iohandler,"io.input") + overload(io.output,iohandler,"io.output") + overload(io.lines,filehandlerone,"io.lines") end if os then - overload(os.execute,binaryrunner,"os.execute") - overload(os.spawn,dummyrunner,"os.spawn") - overload(os.exec,dummyrunner,"os.exec") - overload(os.resultof,binaryrunner,"os.resultof") - overload(os.pipeto,binaryrunner,"os.pipeto") - overload(os.rename,filehandlertwo,"os.rename") - overload(os.remove,filehandlerone,"os.remove") + overload(os.execute,binaryrunner,"os.execute") + overload(os.spawn,dummyrunner,"os.spawn") + overload(os.exec,dummyrunner,"os.exec") + overload(os.resultof,binaryrunner,"os.resultof") + overload(os.pipeto,binaryrunner,"os.pipeto") + overload(os.rename,filehandlertwo,"os.rename") + overload(os.remove,filehandlerone,"os.remove") end if lfs then - overload(lfs.chdir,filehandlerone,"lfs.chdir") - overload(lfs.mkdir,filehandlerone,"lfs.mkdir") - overload(lfs.rmdir,filehandlerone,"lfs.rmdir") - overload(lfs.isfile,filehandlerone,"lfs.isfile") - overload(lfs.isdir,filehandlerone,"lfs.isdir") - overload(lfs.attributes,filehandlerone,"lfs.attributes") - overload(lfs.dir,filehandlerone,"lfs.dir") - overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") - overload(lfs.touch,filehandlerone,"lfs.touch") - overload(lfs.link,filehandlertwo,"lfs.link") - overload(lfs.setmode,filehandlerone,"lfs.setmode") - overload(lfs.readlink,filehandlerone,"lfs.readlink") - overload(lfs.shortname,filehandlerone,"lfs.shortname") - overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") + overload(lfs.chdir,filehandlerone,"lfs.chdir") + overload(lfs.mkdir,filehandlerone,"lfs.mkdir") + overload(lfs.rmdir,filehandlerone,"lfs.rmdir") + overload(lfs.isfile,filehandlerone,"lfs.isfile") + overload(lfs.isdir,filehandlerone,"lfs.isdir") + overload(lfs.attributes,filehandlerone,"lfs.attributes") + overload(lfs.dir,filehandlerone,"lfs.dir") + overload(lfs.lock_dir,filehandlerone,"lfs.lock_dir") + overload(lfs.touch,filehandlerone,"lfs.touch") + overload(lfs.link,filehandlertwo,"lfs.link") + overload(lfs.setmode,filehandlerone,"lfs.setmode") + overload(lfs.readlink,filehandlerone,"lfs.readlink") + overload(lfs.shortname,filehandlerone,"lfs.shortname") + overload(lfs.symlinkattributes,filehandlerone,"lfs.symlinkattributes") end if zip then - zip.open=register(zip.open,filehandlerone,"zip.open") + zip.open=register(zip.open,filehandlerone,"zip.open") end if fontloader then - fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") - fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") + fontloader.open=register(fontloader.open,filehandlerone,"fontloader.open") + fontloader.info=register(fontloader.info,filehandlerone,"fontloader.info") end if epdf then - epdf.open=register(epdf.open,filehandlerone,"epdf.open") + epdf.open=register(epdf.open,filehandlerone,"epdf.open") end sandbox.registerroot=registerroot sandbox.registerbinary=registerbinary @@ -11585,14 +15044,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-mrg"] = package.loaded["util-mrg"] or true --- original size: 7757, stripped down to: 6015 +-- original size: 7819, stripped down to: 5881 if not modules then modules={} end modules ['util-mrg']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gsub,format=string.gsub,string.format local concat=table.concat @@ -11620,19 +15079,19 @@ local m_report=[[ ]] local m_preloaded=[[package.loaded[%q] = package.loaded[%q] or true]] local function self_fake() - return m_faked + return m_faked end local function self_nothing() - return "" + return "" end local function self_load(name) - local data=io.loaddata(name) or "" - if data=="" then - report("unknown file %a",name) - else - report("inserting file %a",name) - end - return data or "" + local data=io.loaddata(name) or "" + if data=="" then + report("unknown file %a",name) + else + report("inserting file %a",name) + end + return data or "" end local space=patterns.space local eol=patterns.newline @@ -11661,98 +15120,99 @@ local mandatespacing=(eol+space)^1/"" local pack=digit*space^1*operator4*optionalspacing+optionalspacing*operator1*optionalspacing+optionalspacing*operator2*optionalspaces+mandatespacing*operator3*mandatespaces+optionalspaces*separator*optionalspaces local lines=emptyline^2/"\n" local spaces=(space*space)/" " +local spaces=(space*space*space*space)/" " local compact=Cs (( - ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 + ignore+strings+longcmt+longstr+comment+pack+lines+spaces+1 )^1 ) local strip=Cs((emptyline^2/"\n"+1)^0) local stripreturn=Cs((1-P("return")*space^1*P(1-space-eol)^1*(space+eol)^0*P(-1))^1) function merger.compact(data) - return lpegmatch(strip,lpegmatch(compact,data)) + return lpegmatch(strip,lpegmatch(compact,data)) end local function self_compact(data) - local delta=0 - if merger.strip_comment then - local before=#data - data=lpegmatch(compact,data) - data=lpegmatch(strip,data) - local after=#data - delta=before-after - report("original size %s, compacted to %s, stripped %s",before,after,delta) - data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) - end - return lpegmatch(stripreturn,data) or data,delta + local delta=0 + if merger.strip_comment then + local before=#data + data=lpegmatch(compact,data) + data=lpegmatch(strip,data) + local after=#data + delta=before-after + report("original size %s, compacted to %s, stripped %s",before,after,delta) + data=format("-- original size: %s, stripped down to: %s\n\n%s",before,after,data) + end + return lpegmatch(stripreturn,data) or data,delta end local function self_save(name,data) - if data~="" then - io.savedata(name,data) - report("saving %s with size %s",name,#data) - end + if data~="" then + io.savedata(name,data) + report("saving %s with size %s",name,#data) + end end local function self_swap(data,code) - return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" + return data~="" and (gsub(data,m_pattern,function() return format(m_format,code) end,1)) or "" end local function self_libs(libs,list) - local result,f,frozen,foundpath={},nil,false,nil - result[#result+1]="\n" - if type(libs)=='string' then libs={ libs } end - if type(list)=='string' then list={ list } end + local result,f,frozen,foundpath={},nil,false,nil + result[#result+1]="\n" + if type(libs)=='string' then libs={ libs } end + if type(list)=='string' then list={ list } end + for i=1,#libs do + local lib=libs[i] + for j=1,#list do + local pth=gsub(list[j],"\\","/") + report("checking library path %a",pth) + local name=pth.."/"..lib + if lfs.isfile(name) then + foundpath=pth + end + end + if foundpath then break end + end + if foundpath then + report("using library path %a",foundpath) + local right,wrong,original,stripped={},{},0,0 for i=1,#libs do - local lib=libs[i] - for j=1,#list do - local pth=gsub(list[j],"\\","/") - report("checking library path %a",pth) - local name=pth.."/"..lib - if lfs.isfile(name) then - foundpath=pth - end - end - if foundpath then break end - end - if foundpath then - report("using library path %a",foundpath) - local right,wrong,original,stripped={},{},0,0 - for i=1,#libs do - local lib=libs[i] - local fullname=foundpath.."/"..lib - if lfs.isfile(fullname) then - report("using library %a",fullname) - local preloaded=file.nameonly(lib) - local data=io.loaddata(fullname,true) - original=original+#data - local data,delta=self_compact(data) - right[#right+1]=lib - result[#result+1]=m_begin_closure - result[#result+1]=format(m_preloaded,preloaded,preloaded) - result[#result+1]=data - result[#result+1]=m_end_closure - stripped=stripped+delta - else - report("skipping library %a",fullname) - wrong[#wrong+1]=lib - end - end - right=#right>0 and concat(right," ") or "-" - wrong=#wrong>0 and concat(wrong," ") or "-" - report("used libraries: %a",right) - report("skipped libraries: %a",wrong) - report("original bytes: %a",original) - report("stripped bytes: %a",stripped) - result[#result+1]=format(m_report,right,wrong,original,stripped) - else - report("no valid library path found") + local lib=libs[i] + local fullname=foundpath.."/"..lib + if lfs.isfile(fullname) then + report("using library %a",fullname) + local preloaded=file.nameonly(lib) + local data=io.loaddata(fullname,true) + original=original+#data + local data,delta=self_compact(data) + right[#right+1]=lib + result[#result+1]=m_begin_closure + result[#result+1]=format(m_preloaded,preloaded,preloaded) + result[#result+1]=data + result[#result+1]=m_end_closure + stripped=stripped+delta + else + report("skipping library %a",fullname) + wrong[#wrong+1]=lib + end end - return concat(result,"\n\n") + right=#right>0 and concat(right," ") or "-" + wrong=#wrong>0 and concat(wrong," ") or "-" + report("used libraries: %a",right) + report("skipped libraries: %a",wrong) + report("original bytes: %a",original) + report("stripped bytes: %a",stripped) + result[#result+1]=format(m_report,right,wrong,original,stripped) + else + report("no valid library path found") + end + return concat(result,"\n\n") end function merger.selfcreate(libs,list,target) - if target then - self_save(target,self_swap(self_fake(),self_libs(libs,list))) - end + if target then + self_save(target,self_swap(self_fake(),self_libs(libs,list))) + end end function merger.selfmerge(name,libs,list,target) - self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) + self_save(target or name,self_swap(self_load(name),self_libs(libs,list))) end function merger.selfclean(name) - self_save(name,self_swap(self_load(name),self_nothing())) + self_save(name,self_swap(self_load(name),self_nothing())) end @@ -11762,14 +15222,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-env"] = package.loaded["util-env"] or true --- original size: 9400, stripped down to: 5499 +-- original size: 9738, stripped down to: 5531 if not modules then modules={} end modules ['util-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate,mark=utilities.storage.allocate,utilities.storage.mark local format,sub,match,gsub,find=string.format,string.sub,string.match,string.gsub,string.find @@ -11781,178 +15241,193 @@ local setlocale=os.setlocale setlocale(nil,nil) local report=logs.reporter("system") function os.setlocale(a,b) - if a or b then - if report then - report() - report("You're messing with os.locale in a supposedly locale neutral enviroment. From") - report("now on are on your own and without support. Crashes or unexpected side effects") - report("can happen but don't bother the luatex and context developer team with it.") - report() - report=nil - end - setlocale(a,b) - end + if a or b then + if report then + report() + report("You're messing with os.locale in a supposedly locale neutral enviroment. From") + report("now on are on your own and without support. Crashes or unexpected side effects") + report("can happen but don't bother the luatex and context developer team with it.") + report() + report=nil + end + setlocale(a,b) + end end local validengines=allocate { - ["luatex"]=true, - ["luajittex"]=true, + ["luatex"]=true, + ["luajittex"]=true, } local basicengines=allocate { - ["luatex"]="luatex", - ["texlua"]="luatex", - ["texluac"]="luatex", - ["luajittex"]="luajittex", - ["texluajit"]="luajittex", + ["luatex"]="luatex", + ["texlua"]="luatex", + ["texluac"]="luatex", + ["luajittex"]="luajittex", + ["texluajit"]="luajittex", } local luaengines=allocate { - ["lua"]=true, - ["luajit"]=true, + ["lua"]=true, + ["luajit"]=true, } environment.validengines=validengines environment.basicengines=basicengines if not arg then - environment.used_as_library=true + environment.used_as_library=true elseif luaengines[file.removesuffix(arg[-1])] then elseif validengines[file.removesuffix(arg[0])] then - if arg[1]=="--luaonly" then - arg[-1]=arg[0] - arg[ 0]=arg[2] - for k=3,#arg do - arg[k-2]=arg[k] - end - remove(arg) - remove(arg) - else - end - local originalzero=file.basename(arg[0]) - local specialmapping={ luatools=="base" } - if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then + if arg[1]=="--luaonly" then + arg[-1]=arg[0] + arg[ 0]=arg[2] + for k=3,#arg do + arg[k-2]=arg[k] + end + remove(arg) + remove(arg) + else + end + local originalzero=file.basename(arg[0]) + local specialmapping={ luatools=="base" } + if originalzero~="mtxrun" and originalzero~="mtxrun.lua" then arg[0]=specialmapping[originalzero] or originalzero insert(arg,0,"--script") insert(arg,0,"mtxrun") - end + end end environment.arguments=allocate() environment.files=allocate() environment.sortedflags=nil function environment.initializearguments(arg) - local arguments,files={},{} - environment.arguments,environment.files,environment.sortedflags=arguments,files,nil - for index=1,#arg do - local argument=arg[index] - if index>0 then - local flag,value=match(argument,"^%-+(.-)=(.-)$") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=unquoted(value or "") - else - flag=match(argument,"^%-+(.+)") - if flag then - flag=gsub(flag,"^c:","") - arguments[flag]=true - else - files[#files+1]=argument - end - end + local arguments={} + local files={} + environment.arguments=arguments + environment.files=files + environment.sortedflags=nil + for index=1,#arg do + local argument=arg[index] + if index>0 then + local flag,value=match(argument,"^%-+(.-)=(.-)$") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=unquoted(value or "") + else + flag=match(argument,"^%-+(.+)") + if flag then + flag=gsub(flag,"^c:","") + arguments[flag]=true + else + files[#files+1]=argument end + end + end + end + if not environment.ownname then + if os.selfpath and os.selfname then + environment.ownname=file.addsuffix(file.join(os.selfpath,os.selfname),"lua") end - environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') + end + environment.ownname=file.reslash(environment.ownname or arg[0] or 'unknown.lua') end function environment.setargument(name,value) - environment.arguments[name]=value + environment.arguments[name]=value end function environment.getargument(name,partial) - local arguments,sortedflags=environment.arguments,environment.sortedflags - if arguments[name] then - return arguments[name] - elseif partial then - if not sortedflags then - sortedflags=allocate(table.sortedkeys(arguments)) - for k=1,#sortedflags do - sortedflags[k]="^"..sortedflags[k] - end - environment.sortedflags=sortedflags - end - for k=1,#sortedflags do - local v=sortedflags[k] - if find(name,v) then - return arguments[sub(v,2,#v)] - end - end + local arguments,sortedflags=environment.arguments,environment.sortedflags + if arguments[name] then + return arguments[name] + elseif partial then + if not sortedflags then + sortedflags=allocate(table.sortedkeys(arguments)) + for k=1,#sortedflags do + sortedflags[k]="^"..sortedflags[k] + end + environment.sortedflags=sortedflags end - return nil + for k=1,#sortedflags do + local v=sortedflags[k] + if find(name,v) then + return arguments[sub(v,2,#v)] + end + end + end + return nil end environment.argument=environment.getargument function environment.splitarguments(separator) - local done,before,after=false,{},{} - local originalarguments=environment.originalarguments - for k=1,#originalarguments do - local v=originalarguments[k] - if not done and v==separator then - done=true - elseif done then - after[#after+1]=v - else - before[#before+1]=v - end + local done,before,after=false,{},{} + local originalarguments=environment.originalarguments + for k=1,#originalarguments do + local v=originalarguments[k] + if not done and v==separator then + done=true + elseif done then + after[#after+1]=v + else + before[#before+1]=v end - return before,after + end + return before,after end function environment.reconstructcommandline(arg,noquote) - local resolveprefix=resolvers.resolve - arg=arg or environment.originalarguments - if noquote and #arg==1 then - return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) - elseif #arg>0 then - local result={} - for i=1,#arg do - result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) - end - return concat(result," ") - else - return "" + local resolveprefix=resolvers.resolve + arg=arg or environment.originalarguments + if noquote and #arg==1 then + return unquoted(resolveprefix and resolveprefix(arg[1]) or arg[1]) + elseif #arg>0 then + local result={} + for i=1,#arg do + result[i]=optionalquoted(resolveprefix and resolveprefix(arg[i]) or resolveprefix) end + return concat(result," ") + else + return "" + end end function environment.relativepath(path,root) - if not path then - path="" + if not path then + path="" + end + if not file.is_rootbased_path(path) then + if not root then + root=file.pathpart(environment.ownscript or environment.ownname or ".") end - if not file.is_rootbased_path(path) then - if not root then - root=file.pathpart(environment.ownscript or environment.ownname or ".") - end - if root=="" then - root="." - end - path=root.."/"..path + if root=="" then + root="." end - return file.collapsepath(path,true) + path=root.."/"..path + end + return file.collapsepath(path,true) end if arg then - local newarg,instring={},false - for index=1,#arg do - local argument=arg[index] - if find(argument,"^\"") then - newarg[#newarg+1]=gsub(argument,"^\"","") - if not find(argument,"\"$") then - instring=true - end - elseif find(argument,"\"$") then - newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") - instring=false - elseif instring then - newarg[#newarg]=newarg[#newarg].." "..argument - else - newarg[#newarg+1]=argument - end - end - for i=1,-5,-1 do - newarg[i]=arg[i] + local newarg,instring={},false + for index=1,#arg do + local argument=arg[index] + if find(argument,"^\"") then + if find(argument,"\"$") then + newarg[#newarg+1]=gsub(argument,"^\"(.-)\"$","%1") + instring=false + else + newarg[#newarg+1]=gsub(argument,"^\"","") + instring=true + end + elseif find(argument,"\"$") then + if instring then + newarg[#newarg]=newarg[#newarg].." "..gsub(argument,"\"$","") + instring=false + else + newarg[#newarg+1]=argument + end + elseif instring then + newarg[#newarg]=newarg[#newarg].." "..argument + else + newarg[#newarg+1]=argument end - environment.initializearguments(newarg) - environment.originalarguments=mark(newarg) - environment.rawarguments=mark(arg) - arg={} + end + for i=1,-5,-1 do + newarg[i]=arg[i] + end + environment.initializearguments(newarg) + environment.originalarguments=mark(newarg) + environment.rawarguments=mark(arg) + arg={} end @@ -11962,17 +15437,18 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-env"] = package.loaded["luat-env"] or true --- original size: 5820, stripped down to: 4155 +-- original size: 6134, stripped down to: 4118 if not modules then modules={} end modules ['luat-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local rawset,rawget,loadfile,assert=rawset,rawget,loadfile,assert -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local rawset,rawget,loadfile=rawset,rawget,loadfile +local gsub=string.gsub +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_lua=logs.reporter("resolvers","lua") local luautilities=utilities.lua local luasuffixes=luautilities.suffixes @@ -11980,133 +15456,146 @@ local texgettoks=tex and tex.gettoks environment=environment or {} local environment=environment local mt={ - __index=function(_,k) - if k=="version" then - local version=texgettoks and texgettoks("contextversiontoks") - if version and version~="" then - rawset(environment,"version",version) - return version - else - return "unknown" - end - elseif k=="kind" then - local kind=texgettoks and texgettoks("contextkindtoks") - if kind and kind~="" then - rawset(environment,"kind",kind) - return kind - else - return "unknown" - end - elseif k=="jobname" or k=="formatname" then - local name=tex and tex[k] - if name or name=="" then - rawset(environment,k,name) - return name - else - return "unknown" - end - elseif k=="outputfilename" then - local name=environment.jobname - rawset(environment,k,name) - return name - end + __index=function(_,k) + if k=="version" then + local version=texgettoks and texgettoks("contextversiontoks") + if version and version~="" then + rawset(environment,"version",version) + return version + else + return "unknown" + end + elseif k=="kind" then + local kind=texgettoks and texgettoks("contextkindtoks") + if kind and kind~="" then + rawset(environment,"kind",kind) + return kind + else + return "unknown" + end + elseif k=="jobname" or k=="formatname" then + local name=tex and tex[k] + if name or name=="" then + rawset(environment,k,name) + return name + else + return "unknown" + end + elseif k=="outputfilename" then + local name=environment.jobname + rawset(environment,k,name) + return name end + end } setmetatable(environment,mt) function environment.texfile(filename) - return resolvers.findfile(filename,'tex') + return resolvers.findfile(filename,'tex') end function environment.luafile(filename) - local resolved=resolvers.findfile(filename,'tex') or "" - if resolved~="" then - return resolved - end - resolved=resolvers.findfile(filename,'texmfscripts') or "" - if resolved~="" then - return resolved - end - return resolvers.findfile(filename,'luatexlibs') or "" -end -local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) + local resolved=resolvers.findfile(filename,'tex') or "" + if resolved~="" then + return resolved + end + resolved=resolvers.findfile(filename,'texmfscripts') or "" + if resolved~="" then + return resolved + end + return resolvers.findfile(filename,'luatexlibs') or "" +end +local stripindeed=false directives.register("system.compile.strip",function(v) stripindeed=v end) local function strippable(filename) - if stripindeed then - local modu=modules[file.nameonly(filename)] - return modu and modu.dataonly - else - return false - end + if stripindeed then + local modu=modules[file.nameonly(filename)] + return modu and modu.dataonly + else + return false + end end function environment.luafilechunk(filename,silent,macros) - filename=file.replacesuffix(filename,"lua") - local fullname=environment.luafile(filename) - if fullname and fullname~="" then - local data=luautilities.loadedluacode(fullname,strippable,filename,macros) - if not silent then - report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") - end - return data - else - if not silent then - report_lua("unknown file %a",filename) - end - return nil + filename=file.replacesuffix(filename,"lua") + local fullname=environment.luafile(filename) + if fullname and fullname~="" then + local data=luautilities.loadedluacode(fullname,strippable,filename,macros) + if not silent then + report_lua("loading file %a %s",fullname,not data and "failed" or "succeeded") + end + return data + else + if not silent then + report_lua("unknown file %a",filename) end + return nil + end end function environment.loadluafile(filename,version) - local lucname,luaname,chunk - local basename=file.removesuffix(filename) - if basename==filename then - luaname=file.addsuffix(basename,luasuffixes.lua) - lucname=file.addsuffix(basename,luasuffixes.luc) - else - luaname=basename - lucname=nil - end - local fullname=(lucname and environment.luafile(lucname)) or "" - if fullname~="" then + local lucname,luaname,chunk + local basename=file.removesuffix(filename) + if basename==filename then + luaname=file.addsuffix(basename,luasuffixes.lua) + lucname=file.addsuffix(basename,luasuffixes.luc) + else + luaname=filename + lucname=nil + end + local fullname=(lucname and environment.luafile(lucname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) + end + chunk=loadfile(fullname) + end + if chunk then + chunk() + if version then + local v=version + if modules and modules[filename] then + v=modules[filename].version + elseif versions and versions[filename] then + v=versions[filename] + end + if v==version then + return true + else if trace_locating then - report_lua("loading %a",fullname) + report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) end - chunk=loadfile(fullname) + environment.loadluafile(filename) + end + else + return true end - if chunk then - assert(chunk)() - if version then - local v=version - if modules and modules[filename] then - v=modules[filename].version - elseif versions and versions[filename] then - v=versions[filename] - end - if v==version then - return true - else - if trace_locating then - report_lua("version mismatch for %a, lua version %a, luc version %a",filename,v,version) - end - environment.loadluafile(filename) - end - else - return true - end + end + fullname=(luaname and environment.luafile(luaname)) or "" + if fullname~="" then + if trace_locating then + report_lua("loading %a",fullname) end - fullname=(luaname and environment.luafile(luaname)) or "" - if fullname~="" then - if trace_locating then - report_lua("loading %a",fullname) - end - chunk=loadfile(fullname) - if not chunk then - if trace_locating then - report_lua("unknown file %a",filename) - end - else - assert(chunk)() - return true - end + chunk=loadfile(fullname) + if not chunk then + if trace_locating then + report_lua("unknown file %a",filename) + end + else + chunk() + return true end - return false + end + return false end +environment.filenames=setmetatable({},{ + __index=function(t,k) + local v=environment.files[k] + if v then + return (gsub(v,"%.+$","")) + end + end, + __newindex=function(t,k) + end, + __len=function(t) + return #environment.files + end, +} ) end -- of closure @@ -12115,16 +15604,16 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-tab"] = package.loaded["lxml-tab"] or true --- original size: 60383, stripped down to: 38562 +-- original size: 60383, stripped down to: 35698 if not modules then modules={} end modules ['lxml-tab']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_entities=false trackers.register("xml.entities",function(v) trace_entities=v end) +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 {} @@ -12142,17 +15631,17 @@ xml.xmlns=xml.xmlns or {} local check=P(false) local parse=check function xml.registerns(namespace,pattern) - check=check+C(P(lower(pattern)))/namespace - parse=P { P(check)+1*V(1) } + check=check+C(P(lower(pattern)))/namespace + parse=P { P(check)+1*V(1) } end function xml.checkns(namespace,url) - local ns=lpegmatch(parse,lower(url)) - if ns and namespace~=ns then - xml.xmlns[namespace]=ns - end + local ns=lpegmatch(parse,lower(url)) + if ns and namespace~=ns then + xml.xmlns[namespace]=ns + end end function xml.resolvens(url) - return lpegmatch(parse,lower(url)) or "" + return lpegmatch(parse,lower(url)) or "" end end local nsremap,resolvens=xml.xmlns,xml.resolvens @@ -12170,661 +15659,661 @@ local handle_dec_entity local handle_any_entity_dtd local handle_any_entity_text local function preparexmlstate(settings) - if settings then - linenumbers=settings.linenumbers - stack={} - level=0 - top={} - at={} - mt={} - dt={} - nt=0 - xmlns={} - errorstr=nil - strip=settings.strip_cm_and_dt - utfize=settings.utfize_entities - resolve=settings.resolve_entities - resolve_predefined=settings.resolve_predefined_entities - unify_predefined=settings.unify_predefined_entities - cleanup=settings.text_cleanup - entities=settings.entities or {} - currentfilename=settings.currentresource - currentline=1 - parameters={} - reported_at_errors={} - dcache={} - hcache={} - acache={} - if utfize==nil then - settings.utfize_entities=true - utfize=true - end - if resolve_predefined==nil then - settings.resolve_predefined_entities=true - resolve_predefined=true - end - else - linenumbers=false - stack=nil - level=nil - top=nil - at=nil - mt=nil - dt=nil - nt=nil - xmlns=nil - errorstr=nil - strip=nil - utfize=nil - resolve=nil - resolve_predefined=nil - unify_predefined=nil - cleanup=nil - entities=nil - parameters=nil - reported_at_errors=nil - dcache=nil - hcache=nil - acache=nil - currentfilename=nil - currentline=1 - end + if settings then + linenumbers=settings.linenumbers + stack={} + level=0 + top={} + at={} + mt={} + dt={} + nt=0 + xmlns={} + errorstr=nil + strip=settings.strip_cm_and_dt + utfize=settings.utfize_entities + resolve=settings.resolve_entities + resolve_predefined=settings.resolve_predefined_entities + unify_predefined=settings.unify_predefined_entities + cleanup=settings.text_cleanup + entities=settings.entities or {} + currentfilename=settings.currentresource + currentline=1 + parameters={} + reported_at_errors={} + dcache={} + hcache={} + acache={} + if utfize==nil then + settings.utfize_entities=true + utfize=true + end + if resolve_predefined==nil then + settings.resolve_predefined_entities=true + resolve_predefined=true + end + else + linenumbers=false + stack=nil + level=nil + top=nil + at=nil + mt=nil + dt=nil + nt=nil + xmlns=nil + errorstr=nil + strip=nil + utfize=nil + resolve=nil + resolve_predefined=nil + unify_predefined=nil + cleanup=nil + entities=nil + parameters=nil + reported_at_errors=nil + dcache=nil + hcache=nil + acache=nil + currentfilename=nil + currentline=1 + end end local function initialize_mt(root) - mt={ __index=root } + mt={ __index=root } end function xml.setproperty(root,k,v) - getmetatable(root).__index[k]=v + getmetatable(root).__index[k]=v end function xml.checkerror(top,toclose) - return "" + return "" end local checkns=xml.checkns local function add_attribute(namespace,tag,value) - if cleanup and value~="" then - value=cleanup(value) - end - if tag=="xmlns" then - xmlns[#xmlns+1]=resolvens(value) - at[tag]=value - elseif namespace=="" then - at[tag]=value - elseif namespace=="xmlns" then - checkns(tag,value) - at["xmlns:"..tag]=value - else - at[namespace..":"..tag]=value - end + if cleanup and value~="" then + value=cleanup(value) + end + if tag=="xmlns" then + xmlns[#xmlns+1]=resolvens(value) + at[tag]=value + elseif namespace=="" then + at[tag]=value + elseif namespace=="xmlns" then + checkns(tag,value) + at["xmlns:"..tag]=value + else + at[namespace..":"..tag]=value + end end local function add_empty(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - top=stack[level] - dt=top.dt - nt=#dt+1 - local t=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - cf=currentfilename, - cl=currentline, - __p__=top, - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt={}, - ni=nt, - __p__=top, - } - dt[nt]=t - setmetatable(t,mt) - if at.xmlns then - remove(xmlns) - end - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + top=stack[level] + dt=top.dt + nt=#dt+1 + local t=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + cf=currentfilename, + cl=currentline, + __p__=top, + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt={}, + ni=nt, + __p__=top, + } + dt[nt]=t + setmetatable(t,mt) + if at.xmlns then + remove(xmlns) + end + at={} end local function add_begin(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace - dt={} - top=linenumbers and { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - cf=currentfilename, - cl=currentline, - __p__=stack[level], - } or { - ns=namespace or "", - rn=resolved, - tg=tag, - at=at, - dt=dt, - ni=nil, - __p__=stack[level], - } - setmetatable(top,mt) - nt=0 - level=level+1 - stack[level]=top - at={} + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local resolved=namespace=="" and xmlns[#xmlns] or nsremap[namespace] or namespace + dt={} + top=linenumbers and { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + cf=currentfilename, + cl=currentline, + __p__=stack[level], + } or { + ns=namespace or "", + rn=resolved, + tg=tag, + at=at, + dt=dt, + ni=nil, + __p__=stack[level], + } + setmetatable(top,mt) + nt=0 + level=level+1 + stack[level]=top + at={} end local function add_end(spacing,namespace,tag) - if spacing~="" then - nt=nt+1 - dt[nt]=spacing - end - local toclose=stack[level] - level=level-1 - top=stack[level] - if level<1 then - errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - elseif toclose.tg~=tag then - errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") - report_xml(errorstr) - end - dt=top.dt - nt=#dt+1 - dt[nt]=toclose - toclose.ni=nt - if toclose.at.xmlns then - remove(xmlns) - end + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + local toclose=stack[level] + level=level-1 + top=stack[level] + if level<1 then + errorstr=formatters["unable to close %s %s"](tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + elseif toclose.tg~=tag then + errorstr=formatters["unable to close %s with %s %s"](toclose.tg,tag,xml.checkerror(top,toclose) or "") + report_xml(errorstr) + end + dt=top.dt + nt=#dt+1 + dt[nt]=toclose + toclose.ni=nt + if toclose.at.xmlns then + remove(xmlns) + end end local function add_text(text) - if text=="" then - return - end - if cleanup then - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..cleanup(text) - else - nt=nt+1 - dt[nt]=cleanup(text) - end - else - nt=1 - dt[1]=cleanup(text) - end + if text=="" then + return + end + if cleanup then + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..cleanup(text) + else + nt=nt+1 + dt[nt]=cleanup(text) + end else - if nt>0 then - local s=dt[nt] - if type(s)=="string" then - dt[nt]=s..text - else - nt=nt+1 - dt[nt]=text - end - else - nt=1 - dt[1]=text - end + nt=1 + dt[1]=cleanup(text) end -end -local function add_special(what,spacing,text) - if spacing~="" then + else + if nt>0 then + local s=dt[nt] + if type(s)=="string" then + dt[nt]=s..text + else nt=nt+1 - dt[nt]=spacing - end - if strip and (what=="@cm@" or what=="@dt@") then + dt[nt]=text + end else - nt=nt+1 - dt[nt]=linenumbers and { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - cf=currentfilename, - cl=currentline, - } or { - special=true, - ns="", - tg=what, - ni=nil, - dt={ text }, - } + nt=1 + dt[1]=text end + end +end +local function add_special(what,spacing,text) + if spacing~="" then + nt=nt+1 + dt[nt]=spacing + end + if strip and (what=="@cm@" or what=="@dt@") then + else + nt=nt+1 + dt[nt]=linenumbers and { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + cf=currentfilename, + cl=currentline, + } or { + special=true, + ns="", + tg=what, + ni=nil, + dt={ text }, + } + end end local function set_message(txt) - errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") + errorstr="garbage at the end of the file: "..gsub(txt,"([ \n\r\t]*)","") end local function attribute_value_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute value %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute value %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end local function attribute_specification_error(str) - if not reported_at_errors[str] then - report_xml("invalid attribute specification %a",str) - reported_at_errors[str]=true - at._error_=str - end - return str + if not reported_at_errors[str] then + report_xml("invalid attribute specification %a",str) + reported_at_errors[str]=true + at._error_=str + end + return str end do - local badentity="&" - xml.placeholders={ - unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, - unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, - unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, - } - local function fromhex(s) - local n=tonumber(s,16) - if n then - return utfchar(n) - else - return formatters["h:%s"](s),true + local badentity="&" + xml.placeholders={ + unknown_dec_entity=function(str) return str=="" and badentity or formatters["&%s;"](str) end, + unknown_hex_entity=function(str) return formatters["&#x%s;"](str) end, + unknown_any_entity=function(str) return formatters["&#x%s;"](str) end, + } + local function fromhex(s) + local n=tonumber(s,16) + if n then + return utfchar(n) + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return utfchar(n) + else + return formatters["d:%s"](s),true + end + end + local p_rest=(1-P(";"))^0 + local p_many=P(1)^0 + local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) + xml.parsedentitylpeg=parsedentity + local predefined_unified={ + [38]="&", + [42]=""", + [47]="'", + [74]="<", + [76]=">", + } + local predefined_simplified={ + [38]="&",amp="&", + [42]='"',quot='"', + [47]="'",apos="'", + [74]="<",lt="<", + [76]=">",gt=">", + } + local nofprivates=0xF0000 + local privates_u={ + [ [[&]] ]="&", + [ [["]] ]=""", + [ [[']] ]="'", + [ [[<]] ]="<", + [ [[>]] ]=">", + } + local privates_p={ + } + local privates_s={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[&]] ]="&U+26;", + [ [[']] ]="&U+27;", + [ [[<]] ]="&U+3C;", + [ [[>]] ]="&U+3E;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_x={ + [ [["]] ]="&U+22;", + [ [[#]] ]="&U+23;", + [ [[$]] ]="&U+24;", + [ [[%]] ]="&U+25;", + [ [[']] ]="&U+27;", + [ [[\]] ]="&U+5C;", + [ [[{]] ]="&U+7B;", + [ [[|]] ]="&U+7C;", + [ [[}]] ]="&U+7D;", + [ [[~]] ]="&U+7E;", + } + local privates_n={ + } + local escaped=utf.remapper(privates_u,"dynamic") + local unprivatized=utf.remapper(privates_p,"dynamic") + local unspecialized=utf.remapper(privates_s,"dynamic") + local despecialized=utf.remapper(privates_x,"dynamic") + xml.unprivatized=unprivatized + xml.unspecialized=unspecialized + xml.despecialized=despecialized + xml.escaped=escaped + local function unescaped(s) + local p=privates_n[s] + if not p then + nofprivates=nofprivates+1 + p=utfchar(nofprivates) + privates_n[s]=p + s="&"..s..";" + privates_u[p]=s + privates_p[p]=s + privates_s[p]=s + end + return p + end + xml.privatetoken=unescaped + xml.privatecodes=privates_n + xml.specialcodes=privates_s + function xml.addspecialcode(key,value) + privates_s[key]=value or "&"..s..";" + end + handle_hex_entity=function(str) + local h=hcache[str] + if not h then + local n=tonumber(str,16) + h=unify_predefined and predefined_unified[n] + if h then + if trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + elseif utfize then + h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" + if not n then + report_xml("utfize, ignoring hex entity &#x%s;",str) + elseif trace_entities then + report_xml("utfize, converting hex entity &#x%s; into %a",str,h) + end + else + if trace_entities then + report_xml("found entity &#x%s;",str) end + h="&#x"..str..";" + end + hcache[str]=h end - local function fromdec(s) - local n=tonumber(s) - if n then - return utfchar(n) - else - return formatters["d:%s"](s),true - end - end - local p_rest=(1-P(";"))^0 - local p_many=P(1)^0 - local parsedentity=P("&#")*(P("x")*(p_rest/fromhex)+(p_rest/fromdec))*P(";")*P(-1)+P ("#")*(P("x")*(p_many/fromhex)+(p_many/fromdec)) - xml.parsedentitylpeg=parsedentity - local predefined_unified={ - [38]="&", - [42]=""", - [47]="'", - [74]="<", - [76]=">", - } - local predefined_simplified={ - [38]="&",amp="&", - [42]='"',quot='"', - [47]="'",apos="'", - [74]="<",lt="<", - [76]=">",gt=">", - } - local nofprivates=0xF0000 - local privates_u={ - [ [[&]] ]="&", - [ [["]] ]=""", - [ [[']] ]="'", - [ [[<]] ]="<", - [ [[>]] ]=">", - } - local privates_p={ - } - local privates_s={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[&]] ]="&U+26;", - [ [[']] ]="&U+27;", - [ [[<]] ]="&U+3C;", - [ [[>]] ]="&U+3E;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_x={ - [ [["]] ]="&U+22;", - [ [[#]] ]="&U+23;", - [ [[$]] ]="&U+24;", - [ [[%]] ]="&U+25;", - [ [[']] ]="&U+27;", - [ [[\]] ]="&U+5C;", - [ [[{]] ]="&U+7B;", - [ [[|]] ]="&U+7C;", - [ [[}]] ]="&U+7D;", - [ [[~]] ]="&U+7E;", - } - local privates_n={ - } - local escaped=utf.remapper(privates_u,"dynamic") - local unprivatized=utf.remapper(privates_p,"dynamic") - local unspecialized=utf.remapper(privates_s,"dynamic") - local despecialized=utf.remapper(privates_x,"dynamic") - xml.unprivatized=unprivatized - xml.unspecialized=unspecialized - xml.despecialized=despecialized - xml.escaped=escaped - local function unescaped(s) - local p=privates_n[s] - if not p then - nofprivates=nofprivates+1 - p=utfchar(nofprivates) - privates_n[s]=p - s="&"..s..";" - privates_u[p]=s - privates_p[p]=s - privates_s[p]=s - end - return p - end - xml.privatetoken=unescaped - xml.privatecodes=privates_n - xml.specialcodes=privates_s - function xml.addspecialcode(key,value) - privates_s[key]=value or "&"..s..";" - end - handle_hex_entity=function(str) - local h=hcache[str] - if not h then - local n=tonumber(str,16) - h=unify_predefined and predefined_unified[n] - if h then - if trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - elseif utfize then - h=(n and utfchar(n)) or xml.unknown_hex_entity(str) or "" - if not n then - report_xml("utfize, ignoring hex entity &#x%s;",str) - elseif trace_entities then - report_xml("utfize, converting hex entity &#x%s; into %a",str,h) - end - else - if trace_entities then - report_xml("found entity &#x%s;",str) - end - h="&#x"..str..";" - end - hcache[str]=h - end - return h - end - handle_dec_entity=function(str) - local d=dcache[str] - if not d then - local n=tonumber(str) - d=unify_predefined and predefined_unified[n] - if d then - if trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - elseif utfize then - d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" - if not n then - report_xml("utfize, ignoring dec entity &#%s;",str) - elseif trace_entities then - report_xml("utfize, converting dec entity &#%s; into %a",str,d) - end - else - if trace_entities then - report_xml("found entity &#%s;",str) - end - d="&#"..str..";" - end - dcache[str]=d + return h + end + handle_dec_entity=function(str) + local d=dcache[str] + if not d then + local n=tonumber(str) + d=unify_predefined and predefined_unified[n] + if d then + if trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + elseif utfize then + d=(n and utfchar(n)) or placeholders.unknown_dec_entity(str) or "" + if not n then + report_xml("utfize, ignoring dec entity &#%s;",str) + elseif trace_entities then + report_xml("utfize, converting dec entity &#%s; into %a",str,d) + end + else + if trace_entities then + report_xml("found entity &#%s;",str) end - return d + d="&#"..str..";" + end + dcache[str]=d end - handle_any_entity_dtd=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end - end - return a + return d + end + handle_any_entity_dtd=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end - end - return a + a=entities[str] end - end - handle_any_entity_text=function(str) - if resolve then - local a=resolve_predefined and predefined_simplified[str] - if a then - if trace_entities then - report_xml("resolving entity &%s; to predefined %a",str,a) - end - else - if type(resolve)=="function" then - a=resolve(str,entities) or entities[str] - else - a=entities[str] - end - if a then - if type(a)=="function" then - if trace_entities then - report_xml("expanding entity &%s; to function call",str) - end - a=a(str) or "" - end - a=lpegmatch(grammar_parsed_text_two,a) or a - if type(a)=="number" then - return "" - else - a=lpegmatch(parsedentity,a) or a - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - end - if trace_entities then - report_xml("resolving entity &%s; to internal %a",str,a) - end - else - local unknown_any_entity=placeholders.unknown_any_entity - if unknown_any_entity then - a=unknown_any_entity(str) or "" - end - if a then - if trace_entities then - report_xml("resolving entity &%s; to external %s",str,a) - end - else - if trace_entities then - report_xml("keeping entity &%s;",str) - end - if str=="" then - a=badentity - else - a="&"..str..";" - end - end - end + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) end - return a + a=a(str) or "" + end + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - local a=acache[str] - if not a then - a=resolve_predefined and predefined_simplified[str] - if a then - acache[str]=a - if trace_entities then - report_xml("entity &%s; becomes %a",str,a) - end - elseif str=="" then - if trace_entities then - report_xml("invalid entity &%s;",str) - end - a=badentity - acache[str]=a - else - if trace_entities then - report_xml("entity &%s; is made private",str) - end - a=unescaped(str) - acache[str]=a - end + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) end - return a - end - end - local p_rest=(1-P(";"))^1 - local spec={ - [0x23]="\\Ux{23}", - [0x24]="\\Ux{24}", - [0x25]="\\Ux{25}", - [0x5C]="\\Ux{5C}", - [0x7B]="\\Ux{7B}", - [0x7C]="\\Ux{7C}", - [0x7D]="\\Ux{7D}", - [0x7E]="\\Ux{7E}", - } - local hash=table.setmetatableindex(spec,function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] - else - return formatters["u:%s"](s),true + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end - end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] + end + return a + end + end + handle_any_entity_text=function(str) + if resolve then + local a=resolve_predefined and predefined_simplified[str] + if a then + if trace_entities then + report_xml("resolving entity &%s; to predefined %a",str,a) + end + else + if type(resolve)=="function" then + a=resolve(str,entities) or entities[str] else - return formatters["d:%s"](s),true + a=entities[str] end - end - local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - local hash=table.setmetatableindex(function(t,k) - local v=utfchar(k) - t[k]=v - return v - end) - local function fromuni(s) - local n=tonumber(s,16) - if n then - return hash[n] + if a then + if type(a)=="function" then + if trace_entities then + report_xml("expanding entity &%s; to function call",str) + end + a=a(str) or "" + end + a=lpegmatch(grammar_parsed_text_two,a) or a + if type(a)=="number" then + return "" + else + a=lpegmatch(parsedentity,a) or a + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end + end + if trace_entities then + report_xml("resolving entity &%s; to internal %a",str,a) + end else - return formatters["u:%s"](s),true + local unknown_any_entity=placeholders.unknown_any_entity + if unknown_any_entity then + a=unknown_any_entity(str) or "" + end + if a then + if trace_entities then + report_xml("resolving entity &%s; to external %s",str,a) + end + else + if trace_entities then + report_xml("keeping entity &%s;",str) + end + if str=="" then + a=badentity + else + a="&"..str..";" + end + end end - end - local function fromhex(s) - local n=tonumber(s,16) - if n then - return hash[n] + end + return a + else + local a=acache[str] + if not a then + a=resolve_predefined and predefined_simplified[str] + if a then + acache[str]=a + if trace_entities then + report_xml("entity &%s; becomes %a",str,a) + end + elseif str=="" then + if trace_entities then + report_xml("invalid entity &%s;",str) + end + a=badentity + acache[str]=a else - return formatters["h:%s"](s),true + if trace_entities then + report_xml("entity &%s; is made private",str) + end + a=unescaped(str) + acache[str]=a end + end + return a + end + end + local p_rest=(1-P(";"))^1 + local spec={ + [0x23]="\\Ux{23}", + [0x24]="\\Ux{24}", + [0x25]="\\Ux{25}", + [0x5C]="\\Ux{5C}", + [0x7B]="\\Ux{7B}", + [0x7C]="\\Ux{7C}", + [0x7D]="\\Ux{7D}", + [0x7E]="\\Ux{7E}", + } + local hash=table.setmetatableindex(spec,function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true end - local function fromdec(s) - local n=tonumber(s) - if n then - return hash[n] - else - return formatters["d:%s"](s),true - end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true end - local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( - P("x")*(p_rest/fromhex)+p_rest/fromdec - ) - xml.reparsedentitylpeg=reparsedentity - xml.unescapedentitylpeg=unescapedentity + end + local reparsedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + local hash=table.setmetatableindex(function(t,k) + local v=utfchar(k) + t[k]=v + return v + end) + local function fromuni(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["u:%s"](s),true + end + end + local function fromhex(s) + local n=tonumber(s,16) + if n then + return hash[n] + else + return formatters["h:%s"](s),true + end + end + local function fromdec(s) + local n=tonumber(s) + if n then + return hash[n] + else + return formatters["d:%s"](s),true + end + end + local unescapedentity=P("U+")*(p_rest/fromuni)+P("#")*( + P("x")*(p_rest/fromhex)+p_rest/fromdec + ) + xml.reparsedentitylpeg=reparsedentity + xml.unescapedentitylpeg=unescapedentity end local escaped=xml.escaped local unescaped=xml.unescaped local placeholders=xml.placeholders local function handle_end_entity(str) - report_xml("error in entity, %a found without ending %a",str,";") - return str + report_xml("error in entity, %a found without ending %a",str,";") + return str end local function handle_crap_error(chr) - report_xml("error in parsing, unexpected %a found ",chr) - add_text(chr) - return chr + report_xml("error in parsing, unexpected %a found ",chr) + add_text(chr) + return chr end local function handlenewline() - currentline=currentline+1 + currentline=currentline+1 end local spacetab=S(' \t') local space=S(' \r\n\t') @@ -12849,141 +16338,141 @@ local space_nl=spacetab+newline local spacing_nl=Cs((space_nl)^0) local anything_nl=newline+P(1) local function weirdentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","weird",k,v) - end - parameters[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","weird",k,v) + end + parameters[k]=v end local function normalentity(k,v) - if trace_entities then - report_xml("registering %s entity %a as %a","normal",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","normal",k,v) + end + entities[k]=v end local function systementity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","system",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","system",k,v) + end + entities[k]=v end local function publicentity(k,v,n) - if trace_entities then - report_xml("registering %s entity %a as %a","public",k,v) - end - entities[k]=v + if trace_entities then + report_xml("registering %s entity %a as %a","public",k,v) + end + entities[k]=v end local function entityfile(pattern,k,v,n) - if n then - local okay,data - if resolvers then - okay,data=resolvers.loadbinfile(n) - else - data=io.loaddata(n) - okay=data and data~="" - end - if okay then - if trace_entities then - report_xml("loading public entities %a as %a from %a",k,v,n) - end - lpegmatch(pattern,data) - return - end + if n then + local okay,data + if resolvers then + okay,data=resolvers.loadbinfile(n) + else + data=io.loaddata(n) + okay=data and data~="" end - report_xml("ignoring public entities %a as %a from %a",k,v,n) + if okay then + if trace_entities then + report_xml("loading public entities %a as %a from %a",k,v,n) + end + lpegmatch(pattern,data) + return + end + end + report_xml("ignoring public entities %a as %a from %a",k,v,n) end local function install(spacenewline,spacing,anything) - local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 - local hexentitycontent=R("AF","af","09")^1 - local decentitycontent=R("09")^1 - local parsedentity=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_dtd) - local parsedentity_text=P("#")/""*( - P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) - )+(anyentitycontent/handle_any_entity_text) - local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) - local text_unparsed=Cs((anything-open)^1) - local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 - local somespace=(spacenewline)^1 - local optionalspace=(spacenewline)^0 - local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) - local endofattributes=slash*close+close - local whatever=space*name*optionalspace*equal - local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error - local attributevalue=value+wrongvalue - local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute - local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 - local parsedtext=text_parsed - local unparsedtext=text_unparsed/add_text - local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } - local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty - local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin - local endelement=(spacing*open*slash*name*optionalspace*close)/add_end - local begincomment=open*P("!--") - local endcomment=P("--")*close - local begininstruction=open*P("?") - local endinstruction=P("?")*close - local begincdata=open*P("![CDATA[") - local endcdata=P("]]")*close - local someinstruction=C((anything-endinstruction)^0) - local somecomment=C((anything-endcomment )^0) - local somecdata=C((anything-endcdata )^0) - local begindoctype=open*P("!DOCTYPE") - local enddoctype=close - local beginset=P("[") - local endset=P("]") - local wrdtypename=C((anything-somespace-P(";"))^1) - local doctypename=C((anything-somespace-close)^0) - local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close - local basiccomment=begincomment*((anything-endcomment)^0)*endcomment - local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity - local normalentitytype=(doctypename*somespace*value)/normalentity - local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity - local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity - local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close - local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) - entityfile(entitydoctype,...) - end - local function weirdresolve(s) - lpegmatch(entitydoctype,parameters[s]) - end - local function normalresolve(s) - lpegmatch(entitydoctype,entities[s]) - end - local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") - entitydoctype=entitydoctype+entityresolve - local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset - local definitiondoctype=doctypename*somespace*doctypeset - local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset - local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset - local simpledoctype=(anything-close)^1 - local somedoctype=C((somespace*( + local anyentitycontent=(1-open-semicolon-space-close-ampersand)^0 + local hexentitycontent=R("AF","af","09")^1 + local decentitycontent=R("09")^1 + local parsedentity=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_dtd) + local parsedentity_text=P("#")/""*( + P("x")/""*(hexentitycontent/handle_hex_entity)+(decentitycontent/handle_dec_entity) + )+(anyentitycontent/handle_any_entity_text) + local entity=(ampersand/"")*parsedentity*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local entity_text=(ampersand/"")*parsedentity_text*(semicolon/"")+ampersand*(anyentitycontent/handle_end_entity) + local text_unparsed=Cs((anything-open)^1) + local text_parsed=(Cs((anything-open-ampersand)^1)/add_text+Cs(entity_text)/add_text)^1 + local somespace=(spacenewline)^1 + local optionalspace=(spacenewline)^0 + local value=(squote*Cs((entity+(anything-squote))^0)*squote)+(dquote*Cs((entity+(anything-dquote))^0)*dquote) + local endofattributes=slash*close+close + local whatever=space*name*optionalspace*equal + local wrongvalue=Cs(P(entity+(1-space-endofattributes))^1)/attribute_value_error + local attributevalue=value+wrongvalue + local attribute=(somespace*name*optionalspace*equal*optionalspace*attributevalue)/add_attribute + local attributes=(attribute+somespace^-1*(((anything-endofattributes)^1)/attribute_specification_error))^0 + local parsedtext=text_parsed + local unparsedtext=text_unparsed/add_text + local balanced=P { "["*((anything-S"[]")+V(1))^0*"]" } + local emptyelement=(spacing*open*name*attributes*optionalspace*slash*close)/add_empty + local beginelement=(spacing*open*name*attributes*optionalspace*close)/add_begin + local endelement=(spacing*open*slash*name*optionalspace*close)/add_end + local begincomment=open*P("!--") + local endcomment=P("--")*close + local begininstruction=open*P("?") + local endinstruction=P("?")*close + local begincdata=open*P("![CDATA[") + local endcdata=P("]]")*close + local someinstruction=C((anything-endinstruction)^0) + local somecomment=C((anything-endcomment )^0) + local somecdata=C((anything-endcdata )^0) + local begindoctype=open*P("!DOCTYPE") + local enddoctype=close + local beginset=P("[") + local endset=P("]") + local wrdtypename=C((anything-somespace-P(";"))^1) + local doctypename=C((anything-somespace-close)^0) + local elementdoctype=optionalspace*P("<!ELEMENT")*(anything-close)^0*close + local basiccomment=begincomment*((anything-endcomment)^0)*endcomment + local weirdentitytype=P("%")*(somespace*doctypename*somespace*value)/weirdentity + local normalentitytype=(doctypename*somespace*value)/normalentity + local publicentitytype=(doctypename*somespace*P("PUBLIC")*somespace*value)/publicentity + local systementitytype=(doctypename*somespace*P("SYSTEM")*somespace*value*somespace*P("NDATA")*somespace*doctypename)/systementity + local entitydoctype=optionalspace*P("<!ENTITY")*somespace*(systementitytype+publicentitytype+normalentitytype+weirdentitytype)*optionalspace*close + local publicentityfile=(doctypename*somespace*P("PUBLIC")*somespace*value*(somespace*value)^0)/function(...) + entityfile(entitydoctype,...) + end + local function weirdresolve(s) + lpegmatch(entitydoctype,parameters[s]) + end + local function normalresolve(s) + lpegmatch(entitydoctype,entities[s]) + end + local entityresolve=P("%")*(wrdtypename/weirdresolve )*P(";")+P("&")*(wrdtypename/normalresolve)*P(";") + entitydoctype=entitydoctype+entityresolve + local doctypeset=beginset*optionalspace*P(elementdoctype+entitydoctype+entityresolve+basiccomment+space)^0*optionalspace*endset + local definitiondoctype=doctypename*somespace*doctypeset + local publicdoctype=doctypename*somespace*P("PUBLIC")*somespace*value*somespace*value*somespace*doctypeset + local systemdoctype=doctypename*somespace*P("SYSTEM")*somespace*value*somespace*doctypeset + local simpledoctype=(anything-close)^1 + local somedoctype=C((somespace*( publicentityfile+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 - local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end - local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand - local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error - local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error - local trailer=space^0*(text_unparsed/set_message)^0 - local grammar_parsed_text_one=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, - } - local grammar_parsed_text_two=P { "followup", - followup=V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, - } - local grammar_unparsed_text=P { "preamble", - preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, - parent=beginelement*V("children")^0*endelement, - children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, - } - return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text + 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 + local doctype=(spacing*begindoctype*somedoctype*enddoctype )/function(...) add_special("@dt@",...) end + local crap_parsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata-ampersand + local crap_unparsed=anything-beginelement-endelement-emptyelement-begininstruction-begincomment-begincdata + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local parsedcrap=Cs((crap_parsed^1+entity_text)^1)/handle_crap_error + local unparsedcrap=Cs((crap_unparsed )^1)/handle_crap_error + local trailer=space^0*(text_unparsed/set_message)^0 + local grammar_parsed_text_one=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0, + } + local grammar_parsed_text_two=P { "followup", + followup=V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=parsedtext+V("parent")+emptyelement+comment+cdata+instruction+parsedcrap, + } + local grammar_unparsed_text=P { "preamble", + preamble=utfbom^0*instruction^0*(doctype+comment+instruction)^0*V("parent")*trailer, + parent=beginelement*V("children")^0*endelement, + children=unparsedtext+V("parent")+emptyelement+comment+cdata+instruction+unparsedcrap, + } + return grammar_parsed_text_one,grammar_parsed_text_two,grammar_unparsed_text end grammar_parsed_text_one_nop, grammar_parsed_text_two_nop, @@ -12992,576 +16481,576 @@ grammar_parsed_text_one_yes, grammar_parsed_text_two_yes, grammar_unparsed_text_yes=install(space_nl,spacing_nl,anything_nl) local function _xmlconvert_(data,settings,detail) - settings=settings or {} - preparexmlstate(settings) - if settings.linenumbers then - grammar_parsed_text_one=grammar_parsed_text_one_yes - grammar_parsed_text_two=grammar_parsed_text_two_yes - grammar_unparsed_text=grammar_unparsed_text_yes - else - grammar_parsed_text_one=grammar_parsed_text_one_nop - grammar_parsed_text_two=grammar_parsed_text_two_nop - grammar_unparsed_text=grammar_unparsed_text_nop - end - local preprocessor=settings.preprocessor - if data and data~="" and type(preprocessor)=="function" then - data=preprocessor(data,settings) or data + settings=settings or {} + preparexmlstate(settings) + if settings.linenumbers then + grammar_parsed_text_one=grammar_parsed_text_one_yes + grammar_parsed_text_two=grammar_parsed_text_two_yes + grammar_unparsed_text=grammar_unparsed_text_yes + else + grammar_parsed_text_one=grammar_parsed_text_one_nop + grammar_parsed_text_two=grammar_parsed_text_two_nop + grammar_unparsed_text=grammar_unparsed_text_nop + end + local preprocessor=settings.preprocessor + if data and data~="" and type(preprocessor)=="function" then + data=preprocessor(data,settings) or data + end + if settings.parent_root then + mt=getmetatable(settings.parent_root) + else + initialize_mt(top) + end + level=level+1 + stack[level]=top + top.dt={} + dt=top.dt + nt=0 + if not data or data=="" then + errorstr="empty xml file" + elseif data==true then + errorstr=detail or "problematic xml file" + elseif utfize or resolve then + local m=lpegmatch(grammar_parsed_text_one,data) + if m then + m=lpegmatch(grammar_parsed_text_two,data,m) end - if settings.parent_root then - mt=getmetatable(settings.parent_root) - else - initialize_mt(top) - end - level=level+1 - stack[level]=top - top.dt={} - dt=top.dt - nt=0 - if not data or data=="" then - errorstr="empty xml file" - elseif data==true then - errorstr=detail or "problematic xml file" - elseif utfize or resolve then - local m=lpegmatch(grammar_parsed_text_one,data) - if m then - m=lpegmatch(grammar_parsed_text_two,data,m) - end - if m then - else - errorstr="invalid xml file - parsed text" - end - elseif type(data)=="string" then - if lpegmatch(grammar_unparsed_text,data) then - errorstr="" - else - errorstr="invalid xml file - unparsed text" - end + if m then else - errorstr="invalid xml file - no text at all" - end - local result - if errorstr and errorstr~="" then - result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } - setmetatable(result,mt) - setmetatable(result.dt[1],mt) - setmetatable(stack,mt) - local errorhandler=settings.error_handler - if errorhandler==false then + errorstr="invalid xml file - parsed text" + end + elseif type(data)=="string" then + if lpegmatch(grammar_unparsed_text,data) then + errorstr="" + else + errorstr="invalid xml file - unparsed text" + end + else + errorstr="invalid xml file - no text at all" + end + local result + if errorstr and errorstr~="" then + result={ dt={ { ns="",tg="error",dt={ errorstr },at={},er=true } } } + setmetatable(result,mt) + setmetatable(result.dt[1],mt) + setmetatable(stack,mt) + local errorhandler=settings.error_handler + if errorhandler==false then + else + errorhandler=errorhandler or xml.errorhandler + if errorhandler then + local currentresource=settings.currentresource + if currentresource and currentresource~="" then + xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) else - errorhandler=errorhandler or xml.errorhandler - if errorhandler then - local currentresource=settings.currentresource - if currentresource and currentresource~="" then - xml.errorhandler(formatters["load error in [%s]: %s"](currentresource,errorstr),currentresource) - else - xml.errorhandler(formatters["load error: %s"](errorstr)) - end - end - end - else - result=stack[1] - end - if not settings.no_root then - result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } - setmetatable(result,mt) - local rdt=result.dt - for k=1,#rdt do - local v=rdt[k] - if type(v)=="table" and not v.special then - result.ri=k - v.__p__=result - break - end + xml.errorhandler(formatters["load error: %s"](errorstr)) end + end end - if errorstr and errorstr~="" then - result.error=true - else - errorstr=nil - end - result.statistics={ - errormessage=errorstr, - entities={ - decimals=dcache, - hexadecimals=hcache, - names=acache, - intermediates=parameters, - } + else + result=stack[1] + end + if not settings.no_root then + result={ special=true,ns="",tg='@rt@',dt=result.dt,at={},entities=entities,settings=settings } + setmetatable(result,mt) + local rdt=result.dt + for k=1,#rdt do + local v=rdt[k] + if type(v)=="table" and not v.special then + result.ri=k + v.__p__=result + break + end + end + end + if errorstr and errorstr~="" then + result.error=true + else + errorstr=nil + end + result.statistics={ + errormessage=errorstr, + entities={ + decimals=dcache, + hexadecimals=hcache, + names=acache, + intermediates=parameters, } - preparexmlstate() - return result + } + preparexmlstate() + return result end local function xmlconvert(data,settings) - local ok,result=pcall(function() return _xmlconvert_(data,settings) end) - if ok then - return result - elseif type(result)=="string" then - return _xmlconvert_(true,settings,result) - else - return _xmlconvert_(true,settings) - end + local ok,result=pcall(function() return _xmlconvert_(data,settings) end) + if ok then + return result + elseif type(result)=="string" then + return _xmlconvert_(true,settings,result) + else + return _xmlconvert_(true,settings) + end end xml.convert=xmlconvert function xml.inheritedconvert(data,xmldata) - local settings=xmldata.settings - if settings then - settings.parent_root=xmldata - end - local xc=xmlconvert(data,settings) - return xc + local settings=xmldata.settings + if settings then + settings.parent_root=xmldata + end + local xc=xmlconvert(data,settings) + return xc end function xml.is_valid(root) - return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er + return root and root.dt and root.dt[1] and type(root.dt[1])=="table" and not root.dt[1].er end function xml.package(tag,attributes,data) - local ns,tg=match(tag,"^(.-):?([^:]+)$") - local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } - setmetatable(t,mt) - return t + local ns,tg=match(tag,"^(.-):?([^:]+)$") + local t={ ns=ns,tg=tg,dt=data or "",at=attributes or {} } + setmetatable(t,mt) + return t end function xml.is_valid(root) - return root and not root.error + return root and not root.error end xml.errorhandler=report_xml function xml.load(filename,settings) - local data="" - if type(filename)=="string" then - local f=io.open(filename,'r') - if f then - data=f:read("*all") - f:close() - end - elseif filename then - data=filename:read("*all") - end - if settings then - settings.currentresource=filename - local result=xmlconvert(data,settings) - settings.currentresource=nil - return result - else - return xmlconvert(data,{ currentresource=filename }) - end + local data="" + if type(filename)=="string" then + local f=io.open(filename,'r') + if f then + data=f:read("*all") + f:close() + end + elseif filename then + data=filename:read("*all") + end + if settings then + settings.currentresource=filename + local result=xmlconvert(data,settings) + settings.currentresource=nil + return result + else + return xmlconvert(data,{ currentresource=filename }) + end end local no_root={ no_root=true } function xml.toxml(data) - if type(data)=="string" then - local root={ xmlconvert(data,no_root) } - return (#root>1 and root) or root[1] - else - return data - end + if type(data)=="string" then + local root={ xmlconvert(data,no_root) } + return (#root>1 and root) or root[1] + else + return data + end end local function copy(old,p) - if old then - local new={} - for k,v in next,old do - local t=type(v)=="table" - if k=="at" then - local t={} - for k,v in next,v do - t[k]=v - end - new[k]=t - elseif k=="dt" then - v.__p__=nil - v=copy(v,new) - new[k]=v - v.__p__=p - else - new[k]=v - end - end - local mt=getmetatable(old) - if mt then - setmetatable(new,mt) - end - return new - else - return {} + if old then + local new={} + for k,v in next,old do + local t=type(v)=="table" + if k=="at" then + local t={} + for k,v in next,v do + t[k]=v + end + new[k]=t + elseif k=="dt" then + v.__p__=nil + v=copy(v,new) + new[k]=v + v.__p__=p + else + new[k]=v + end end + local mt=getmetatable(old) + if mt then + setmetatable(new,mt) + end + return new + else + return {} + end end xml.copy=copy function xml.checkbom(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then - return - end - end - insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) - insert(dt,2,"\n" ) + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" and find(v.dt[1],"xml.*version=") then + return + end end + insert(dt,1,{ special=true,ns="",tg="@pi@",dt={ "xml version='1.0' standalone='yes'" } } ) + insert(dt,2,"\n" ) + end end local f_attribute=formatters['%s=%q'] local function verbose_element(e,handlers,escape) - local handle=handlers.handle - local serialize=handlers.serialize - local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn - local ats=eat and next(eat) and {} - if ats then - local n=0 - for k in next,eat do - n=n+1 - ats[n]=k - end - if n==1 then - local k=ats[1] - ats=f_attribute(k,escaped(eat[k])) - else - sort(ats) - for i=1,n do - local k=ats[i] - ats[i]=f_attribute(k,escaped(eat[k])) - end - ats=concat(ats," ") - end - end - if ern and trace_entities and ern~=ens then - ens=ern + local handle=handlers.handle + local serialize=handlers.serialize + local ens,etg,eat,edt,ern=e.ns,e.tg,e.at,e.dt,e.rn + local ats=eat and next(eat) and {} + if ats then + local n=0 + for k in next,eat do + n=n+1 + ats[n]=k end - local n=edt and #edt - if ens~="" then - if n and n>0 then - if ats then - handle("<",ens,":",etg," ",ats,">") - else - handle("<",ens,":",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",ens,":",etg,">") + if n==1 then + local k=ats[1] + ats=f_attribute(k,escaped(eat[k])) + else + sort(ats) + for i=1,n do + local k=ats[i] + ats[i]=f_attribute(k,escaped(eat[k])) + end + ats=concat(ats," ") + end + end + if ern and trace_entities and ern~=ens then + ens=ern + end + local n=edt and #edt + if ens~="" then + if n and n>0 then + if ats then + handle("<",ens,":",etg," ",ats,">") + else + handle("<",ens,":",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",ens,":",etg," ",ats,"/>") - else - handle("<",ens,":",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",ens,":",etg,">") else - if n and n>0 then - if ats then - handle("<",etg," ",ats,">") - else - handle("<",etg,">") - end - for i=1,n do - local e=edt[i] - if type(e)=="string" then - handle(escaped(e)) - else - serialize(e,handlers) - end - end - handle("</",etg,">") + if ats then + handle("<",ens,":",etg," ",ats,"/>") + else + handle("<",ens,":",etg,"/>") + end + end + else + if n and n>0 then + if ats then + handle("<",etg," ",ats,">") + else + handle("<",etg,">") + end + for i=1,n do + local e=edt[i] + if type(e)=="string" then + handle(escaped(e)) else - if ats then - handle("<",etg," ",ats,"/>") - else - handle("<",etg,"/>") - end + serialize(e,handlers) end + end + handle("</",etg,">") + else + if ats then + handle("<",etg," ",ats,"/>") + else + handle("<",etg,"/>") + end end + end end local function verbose_pi(e,handlers) - handlers.handle("<?",e.dt[1],"?>") + handlers.handle("<?",e.dt[1],"?>") end local function verbose_comment(e,handlers) - handlers.handle("<!--",e.dt[1],"-->") + handlers.handle("<!--",e.dt[1],"-->") end local function verbose_cdata(e,handlers) - handlers.handle("<![CDATA[",e.dt[1],"]]>") + handlers.handle("<![CDATA[",e.dt[1],"]]>") end local function verbose_doctype(e,handlers) - handlers.handle("<!DOCTYPE",e.dt[1],">") + handlers.handle("<!DOCTYPE",e.dt[1],">") end local function verbose_root(e,handlers) - handlers.serialize(e.dt,handlers) + handlers.serialize(e.dt,handlers) end local function verbose_text(e,handlers) - handlers.handle(escaped(e)) + handlers.handle(escaped(e)) end local function verbose_document(e,handlers) - local serialize=handlers.serialize - local functions=handlers.functions - for i=1,#e do - local ei=e[i] - if type(ei)=="string" then - functions["@tx@"](ei,handlers) - else - serialize(ei,handlers) - end + local serialize=handlers.serialize + local functions=handlers.functions + for i=1,#e do + local ei=e[i] + if type(ei)=="string" then + functions["@tx@"](ei,handlers) + else + serialize(ei,handlers) end + end end local function serialize(e,handlers,...) - 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 + 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 end local function xserialize(e,handlers) - if e then - local functions=handlers.functions - local etg=e.tg - if etg then - (functions[etg] or functions["@el@"])(e,handlers) - else - functions["@dc@"](e,handlers) - end + if e then + local functions=handlers.functions + local etg=e.tg + if etg then + (functions[etg] or functions["@el@"])(e,handlers) + else + functions["@dc@"](e,handlers) end + end end local handlers={} local function newhandlers(settings) - local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) - if settings then - for k,v in next,settings do - if type(v)=="table" then - local tk=t[k] if not tk then tk={} t[k]=tk end - for kk,vv in next,v do - tk[kk]=vv - end - else - t[k]=v - end - end - if settings.name then - handlers[settings.name]=t - end + local t=table.copy(handlers[settings and settings.parent or "verbose"] or {}) + if settings then + for k,v in next,settings do + if type(v)=="table" then + local tk=t[k] if not tk then tk={} t[k]=tk end + for kk,vv in next,v do + tk[kk]=vv + end + else + t[k]=v + end end - utilities.storage.mark(t) - return t + if settings.name then + handlers[settings.name]=t + end + end + utilities.storage.mark(t) + return t end local nofunction=function() end function xml.sethandlersfunction(handler,name,fnc) - handler.functions[name]=fnc or nofunction + handler.functions[name]=fnc or nofunction end function xml.gethandlersfunction(handler,name) - return handler.functions[name] + return handler.functions[name] end function xml.gethandlers(name) - return handlers[name] + return handlers[name] end newhandlers { - name="verbose", - initialize=false, - finalize=false, - serialize=xserialize, - handle=print, - functions={ - ["@dc@"]=verbose_document, - ["@dt@"]=verbose_doctype, - ["@rt@"]=verbose_root, - ["@el@"]=verbose_element, - ["@pi@"]=verbose_pi, - ["@cm@"]=verbose_comment, - ["@cd@"]=verbose_cdata, - ["@tx@"]=verbose_text, - } + name="verbose", + initialize=false, + finalize=false, + serialize=xserialize, + handle=print, + functions={ + ["@dc@"]=verbose_document, + ["@dt@"]=verbose_doctype, + ["@rt@"]=verbose_root, + ["@el@"]=verbose_element, + ["@pi@"]=verbose_pi, + ["@cm@"]=verbose_comment, + ["@cd@"]=verbose_cdata, + ["@tx@"]=verbose_text, + } } local result local xmlfilehandler=newhandlers { - name="file", - initialize=function(name) - result=io.open(name,"wb") - return result - end, - finalize=function() - result:close() - return true - end, - handle=function(...) - result:write(...) - end, + name="file", + initialize=function(name) + result=io.open(name,"wb") + return result + end, + finalize=function() + result:close() + return true + end, + handle=function(...) + result:write(...) + end, } function xml.save(root,name) - serialize(root,xmlfilehandler,name) + serialize(root,xmlfilehandler,name) end local result,r,threshold={},0,512 local xmlstringhandler=newhandlers { - name="string", - initialize=function() - r=0 - return result - end, - finalize=function() - local done=concat(result,"",1,r) - r=0 - if r>threshold then - result={} - end - return done - end, - handle=function(...) - for i=1,select("#",...) do - r=r+1 - result[r]=select(i,...) - end - end, + name="string", + initialize=function() + r=0 + return result + end, + finalize=function() + local done=concat(result,"",1,r) + r=0 + if r>threshold then + result={} + end + return done + end, + handle=function(...) + for i=1,select("#",...) do + r=r+1 + result[r]=select(i,...) + end + end, } local function xmltostring(root) - if not root then - return "" - elseif type(root)=="string" then - return root - else - return serialize(root,xmlstringhandler) or "" - end + if not root then + return "" + elseif type(root)=="string" then + return root + else + return serialize(root,xmlstringhandler) or "" + end end local function __tostring(root) - return (root and xmltostring(root)) or "" + return (root and xmltostring(root)) or "" end initialize_mt=function(root) - mt={ __tostring=__tostring,__index=root } + mt={ __tostring=__tostring,__index=root } end xml.defaulthandlers=handlers xml.newhandlers=newhandlers xml.serialize=serialize xml.tostring=xmltostring local function xmlstring(e,handle) - if not handle or (e.special and e.tg~="@rt@") then - elseif e.tg then - local edt=e.dt - if edt then - for i=1,#edt do - xmlstring(edt[i],handle) - end - end - else - handle(e) + if not handle or (e.special and e.tg~="@rt@") then + elseif e.tg then + local edt=e.dt + if edt then + for i=1,#edt do + xmlstring(edt[i],handle) + end end + else + handle(e) + end end xml.string=xmlstring function xml.settings(e) - while e do - local s=e.settings - if s then - return s - else - e=e.__p__ - end + while e do + local s=e.settings + if s then + return s + else + e=e.__p__ end - return nil + end + return nil end function xml.root(e) - local r=e - while e do - e=e.__p__ - if e then - r=e - end + local r=e + while e do + e=e.__p__ + if e then + r=e end - return r + end + return r end function xml.parent(root) - return root.__p__ + return root.__p__ end function xml.body(root) - return root.ri and root.dt[root.ri] or root + return root.ri and root.dt[root.ri] or root end function xml.name(root) - if not root then - return "" - end - local ns=root.ns - local tg=root.tg - if ns=="" then - return tg - else - return ns..":"..tg - end + if not root then + return "" + end + local ns=root.ns + local tg=root.tg + if ns=="" then + return tg + else + return ns..":"..tg + end end function xml.erase(dt,k) - if dt then - if k then - dt[k]="" - else for k=1,#dt do - dt[1]={ "" } - end end - end + if dt then + if k then + dt[k]="" + else for k=1,#dt do + dt[1]={ "" } + end end + end end function xml.assign(dt,k,root) - if dt and k then - dt[k]=type(root)=="table" and xml.body(root) or root - return dt[k] - else - return xml.body(root) - end + if dt and k then + dt[k]=type(root)=="table" and xml.body(root) or root + return dt[k] + else + return xml.body(root) + end end function xml.tocdata(e,wrapper) - local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" - if wrapper then - whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) - end - local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } - setmetatable(t,getmetatable(e)) - e.dt={ t } + local whatever=type(e)=="table" and xmltostring(e.dt) or e or "" + if wrapper then + whatever=formatters["<%s>%s</%s>"](wrapper,whatever,wrapper) + end + local t={ special=true,ns="",tg="@cd@",at={},rn="",dt={ whatever },__p__=e } + setmetatable(t,getmetatable(e)) + e.dt={ t } end function xml.makestandalone(root) - if root.ri then - local dt=root.dt - for k=1,#dt do - local v=dt[k] - if type(v)=="table" and v.special and v.tg=="@pi@" then - local txt=v.dt[1] - if find(txt,"xml.*version=") then - v.dt[1]=txt.." standalone='yes'" - break - end - end + if root.ri then + local dt=root.dt + for k=1,#dt do + local v=dt[k] + if type(v)=="table" and v.special and v.tg=="@pi@" then + local txt=v.dt[1] + if find(txt,"xml.*version=") then + v.dt[1]=txt.." standalone='yes'" + break end + end end - return root + end + return root end function xml.kind(e) - local dt=e and e.dt - if dt then - local n=#dt - if n==1 then - local d=dt[1] - if d.special then - local tg=d.tg - if tg=="@cd@" then - return "cdata" - elseif tg=="@cm" then - return "comment" - elseif tg=="@pi@" then - return "instruction" - elseif tg=="@dt@" then - return "declaration" - end - elseif type(d)=="string" then - return "text" - end - return "element" - elseif n>0 then - return "mixed" - end + local dt=e and e.dt + if dt then + local n=#dt + if n==1 then + local d=dt[1] + if d.special then + local tg=d.tg + if tg=="@cd@" then + return "cdata" + elseif tg=="@cm" then + return "comment" + elseif tg=="@pi@" then + return "instruction" + elseif tg=="@dt@" then + return "declaration" + end + elseif type(d)=="string" then + return "text" + end + return "element" + elseif n>0 then + return "mixed" end - return "empty" + end + return "empty" end @@ -13571,14 +17060,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-lpt"] = package.loaded["lxml-lpt"] or true --- original size: 53301, stripped down to: 32477 +-- original size: 55145, stripped down to: 30992 if not modules then modules={} end modules ['lxml-lpt']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local concat,remove,insert=table.concat,table.remove,table.insert local type,next,tonumber,tostring,setmetatable,load,select=type,next,tonumber,tostring,setmetatable,load,select @@ -13591,21 +17080,21 @@ local trace_lparse=false local trace_lprofile=false local report_lpath=logs.reporter("xml","lpath") if trackers then - trackers.register("xml.path",function(v) - trace_lpath=v - end) - trackers.register("xml.parse",function(v) - trace_lparse=v - end) - trackers.register("xml.profile",function(v) - trace_lpath=v - trace_lparse=v - trace_lprofile=v - end) + trackers.register("xml.path",function(v) + trace_lpath=v + end) + trackers.register("xml.parse",function(v) + trace_lparse=v + end) + trackers.register("xml.profile",function(v) + trace_lpath=v + trace_lparse=v + trace_lprofile=v + end) end local xml=xml -local lpathcalls=0 function xml.lpathcalls () return lpathcalls end -local lpathcached=0 function xml.lpathcached() return lpathcached end +local lpathcalls=0 function xml.lpathcalls () return lpathcalls end +local lpathcached=0 function xml.lpathcached() return lpathcached end xml.functions=xml.functions or {} local functions=xml.functions xml.expressions=xml.expressions or {} @@ -13619,216 +17108,271 @@ local xmlpatterns=lpegpatterns.xml finalizers.xml=finalizers.xml or {} finalizers.tex=finalizers.tex or {} local function fallback (t,name) - local fn=finalizers[name] - if fn then - t[name]=fn - else - report_lpath("unknown sub finalizer %a",name) - fn=function() end - end - return fn + local fn=finalizers[name] + if fn then + t[name]=fn + else + report_lpath("unknown sub finalizer %a",name) + fn=function() end + end + return fn end setmetatableindex(finalizers.xml,fallback) setmetatableindex(finalizers.tex,fallback) xml.defaultprotocol="xml" local apply_axis={} apply_axis['root']=function(list) - local collected={} - for l=1,#list do - local ll=list[l] - local rt=ll - while ll do - ll=ll.__p__ - if ll then - rt=ll - end - end - collected[l]=rt + local collected={} + for l=1,#list do + local ll=list[l] + local rt=ll + while ll do + ll=ll.__p__ + if ll then + rt=ll + end end - return collected + collected[l]=rt + end + return collected end apply_axis['self']=function(list) - return list + return list end apply_axis['child']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local dt=ll.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - end - end - ll.en=en + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local dt=ll.dt + if dt then + local n=#dt + if n==0 then + ll.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + ll.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + end end + ll.en=en + end end - return collected + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + else + list.en=0 + end + else + local en=0 + for k=1,n do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant']=function(list) - local collected,c={},0 - for l=1,#list do - c=collect(list[l],collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + c=collect(list[l],collected,c) + end + return collected end local function collect(list,collected,c) - local dt=list.dt - if dt then - local en=0 - for k=1,#dt do - local dk=dt[k] - if dk.tg then - c=c+1 - collected[c]=dk - dk.ni=k - en=en+1 - dk.ei=en - c=collect(dk,collected,c) - end + local dt=list.dt + if dt then + local n=#dt + if n==0 then + list.en=0 + elseif n==1 then + local dk=dt[1] + if dk.tg then + c=c+1 + collected[c]=dk + dk.ni=1 + dk.ei=1 + c=collect(dk,collected,c) + list.en=1 + end + else + local en=0 + for k=1,#dt do + local dk=dt[k] + if dk.tg then + c=c+1 + en=en+1 + collected[c]=dk + dk.ni=k + dk.ei=en + c=collect(dk,collected,c) end - list.en=en + end + list.en=en end - return c + end + return c end apply_axis['descendant-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - if ll.special~=true then - c=c+1 - collected[c]=ll - end - c=collect(ll,collected,c) - end - return collected + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + if ll.special~=true then + c=c+1 + collected[c]=ll + end + c=collect(ll,collected,c) + end + return collected end apply_axis['ancestor']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + while ll do + ll=ll.__p__ + if ll then + c=c+1 + collected[c]=ll + end end - return collected + end + return collected end apply_axis['ancestor-or-self']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + c=c+1 + collected[c]=ll + while ll do + ll=ll.__p__ + if ll then c=c+1 collected[c]=ll - while ll do - ll=ll.__p__ - if ll then - c=c+1 - collected[c]=ll - end - end + end end - return collected + end + return collected end apply_axis['parent']=function(list) - local collected,c={},0 - for l=1,#list do - local pl=list[l].__p__ - if pl then - c=c+1 - collected[c]=pl - end + local collected={} + local c=0 + for l=1,#list do + local pl=list[l].__p__ + if pl then + c=c+1 + collected[c]=pl end - return collected + end + return collected end apply_axis['attribute']=function(list) - return {} + return {} end apply_axis['namespace']=function(list) - return {} + return {} end apply_axis['following']=function(list) - return {} + return {} end apply_axis['preceding']=function(list) - return {} + return {} end apply_axis['following-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni+1,#d do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni+1,#d do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['preceding-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=1,ll.ni-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=1,ll.ni-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['reverse-sibling']=function(list) - local collected,c={},0 - for l=1,#list do - local ll=list[l] - local p=ll.__p__ - local d=p.dt - for i=ll.ni-1,1,-1 do - local di=d[i] - if type(di)=="table" then - c=c+1 - collected[c]=di - end - end + local collected={} + local c=0 + for l=1,#list do + local ll=list[l] + local p=ll.__p__ + local d=p.dt + for i=ll.ni-1,1,-1 do + local di=d[i] + if type(di)=="table" then + c=c+1 + collected[c]=di + end end - return collected + end + return collected end apply_axis['auto-descendant-or-self']=apply_axis['descendant-or-self'] apply_axis['auto-descendant']=apply_axis['descendant'] @@ -13836,130 +17380,147 @@ apply_axis['auto-child']=apply_axis['child'] apply_axis['auto-self']=apply_axis['self'] apply_axis['initial-child']=apply_axis['child'] local function apply_nodes(list,directive,nodes) - local maxn=#nodes - if maxn==3 then - local nns,ntg=nodes[2],nodes[3] - if not nns and not ntg then + local maxn=#nodes + if maxn==3 then + local nns=nodes[2] + local ntg=nodes[3] + if not nns and not ntg then + if directive then + return list + else + return {} + end + else + local collected={} + local c=0 + local m=0 + local p=nil + if not nns then + for l=1,#list do + local ll=list[l] + local ltg=ll.tg + if ltg then if directive then - return list - else - return {} + if ntg==ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif ntg~=ltg then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - else - local collected,c,m,p={},0,0,nil - if not nns then - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - if directive then - if ntg==ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif ntg~=ltg then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - elseif not ntg then - for l=1,#list do - local ll=list[l] - local lns=ll.rn or ll.ns - if lns then - if directive then - if lns==nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif lns~=nns then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end - else - for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=ltg==ntg and lns==nns - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - end - end + end + end + elseif not ntg then + for l=1,#list do + local ll=list[l] + local lns=ll.rn or ll.ns + if lns then + if directive then + if lns==nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif lns~=nns then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - return collected + end end - else - local collected,c,m,p={},0,0,nil + else for l=1,#list do - local ll=list[l] - local ltg=ll.tg - if ltg then - local lns=ll.rn or ll.ns - local ok=false - for n=1,maxn,3 do - local nns,ntg=nodes[n+1],nodes[n+2] - ok=(not ntg or ltg==ntg) and (not nns or lns==nns) - if ok then - break - end - end - if directive then - if ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end - elseif not ok then - local llp=ll.__p__;if llp~=p then p,m=llp,1 else m=m+1 end - c=c+1 - collected[c],ll.mi=ll,m - end + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=ltg==ntg and lns==nns + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end + end end - return collected + end + return collected end -end -local quit_expression=false -local function apply_expression(list,expression,order) - local collected,c={},0 - quit_expression=false + else + local collected={} + local c=0 + local m=0 + local p=nil for l=1,#list do - local ll=list[l] - if expression(list,ll,l,order) then + local ll=list[l] + local ltg=ll.tg + if ltg then + local lns=ll.rn or ll.ns + local ok=false + for n=1,maxn,3 do + local nns=nodes[n+1] + local ntg=nodes[n+2] + ok=(not ntg or ltg==ntg) and (not nns or lns==nns) + if ok then + break + end + end + if directive then + if ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end c=c+1 collected[c]=ll + ll.mi=m + end + elseif not ok then + local llp=ll.__p__;if llp~=p then p=llp;m=1 else m=m+1 end + c=c+1 + collected[c]=ll + ll.mi=m end - if quit_expression then - break - end + end end return collected + end end -local function apply_selector(list,specification) - if xml.applyselector then - apply_selector=xml.applyselector - return apply_selector(list,specification) - else - return list +local quit_expression=false +local function apply_expression(list,expression,order) + local collected={} + local c=0 + quit_expression=false + for l=1,#list do + local ll=list[l] + if expression(list,ll,l,order) then + c=c+1 + collected[c]=ll + end + if quit_expression then + break end + end + return collected +end +local function apply_selector(list,specification) + if xml.applyselector then + apply_selector=xml.applyselector + return apply_selector(list,specification) + else + return list + end end local P,V,C,Cs,Cc,Ct,R,S,Cg,Cb=lpeg.P,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.R,lpeg.S,lpeg.Cg,lpeg.Cb local spaces=S(" \n\r\t\f")^0 @@ -13970,24 +17531,24 @@ local lp_doequal=P("=")/"==" local lp_or=P("|")/" or " local lp_and=P("&")/" and " local builtin={ - text="(ll.dt[1] or '')", - content="ll.dt", - name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", - tag="ll.tg", - position="l", - firstindex="1", - firstelement="1", - first="1", - lastindex="(#ll.__p__.dt or 1)", - lastelement="(ll.__p__.en or 1)", - last="#list", - rootposition="order", - order="order", - element="(ll.ei or 1)", - index="(ll.ni or 1)", - match="(ll.mi or 1)", - namespace="ll.ns", - ns="ll.ns", + text="(ll.dt[1] or '')", + content="ll.dt", + name="((ll.ns~='' and ll.ns..':'..ll.tg) or ll.tg)", + tag="ll.tg", + position="l", + firstindex="1", + firstelement="1", + first="1", + lastindex="(#ll.__p__.dt or 1)", + lastelement="(ll.__p__.en or 1)", + last="#list", + rootposition="order", + order="order", + element="(ll.ei or 1)", + index="(ll.ni or 1)", + match="(ll.mi or 1)", + namespace="ll.ns", + ns="ll.ns", } local lp_builtin=lpeg.utfchartabletopattern(builtin)/builtin*((spaces*P("(")*spaces*P(")"))/"") local lp_attribute=(P("@")+P("attribute::"))/""*Cc("(ll.at and ll.at['")*((R("az","AZ")+S("-_:"))^1)*Cc("'])") @@ -13997,11 +17558,11 @@ local lp_fastpos=lp_fastpos_n+lp_fastpos_p local lp_reserved=C("and")+C("or")+C("not")+C("div")+C("mod")+C("true")+C("false") local lp_lua_function=Cs((R("az","AZ","__")^1*(P(".")*R("az","AZ","__")^1)^1)*("("))/"%0" local lp_function=C(R("az","AZ","__")^1)*P("(")/function(t) - if expressions[t] then - return "expr."..t.."(" - else - return "expr.error(" - end + if expressions[t] then + return "expr."..t.."(" + else + return "expr.error(" + end end local lparent=P("(") local rparent=P(")") @@ -14014,24 +17575,24 @@ local lp_string=Cc("'")*R("az","AZ","--","__")^1*Cc("'") local lp_content=(P("'")*(1-P("'"))^0*P("'")+P('"')*(1-P('"'))^0*P('"')) local cleaner local lp_special=(C(P("name")+P("text")+P("tag")+P("count")+P("child")))*value/function(t,s) - if expressions[t] then - s=s and s~="" and lpegmatch(cleaner,s) - if s and s~="" then - return "expr."..t.."(ll,"..s..")" - else - return "expr."..t.."(ll)" - end + if expressions[t] then + s=s and s~="" and lpegmatch(cleaner,s) + if s and s~="" then + return "expr."..t.."(ll,"..s..")" else - return "expr.error("..t..")" + return "expr."..t.."(ll)" end + else + return "expr.error("..t..")" + end end local content=lp_builtin+lp_attribute+lp_special+lp_noequal+lp_doequal+lp_or+lp_and+lp_reserved+lp_lua_function+lp_function+lp_content+ - lp_child+lp_any + lp_child+lp_any local converter=Cs ( - lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 + lp_fastpos+(P { lparent*(V(1))^0*rparent+content } )^0 ) cleaner=Cs (( - lp_reserved+lp_number+lp_string+1 )^1 ) + lp_reserved+lp_number+lp_string+1 )^1 ) local template_e=[[ local expr = xml.expressions return function(list,ll,l,order) @@ -14047,75 +17608,75 @@ local template_f_y=[[ local template_f_n=[[ return xml.finalizers['%s']['%s'] ]] -local register_last_match={ kind="axis",axis="last-match" } -local register_self={ kind="axis",axis="self" } -local register_parent={ kind="axis",axis="parent" } -local register_descendant={ kind="axis",axis="descendant" } -local register_child={ kind="axis",axis="child" } +local register_last_match={ kind="axis",axis="last-match" } +local register_self={ kind="axis",axis="self" } +local register_parent={ kind="axis",axis="parent" } +local register_descendant={ kind="axis",axis="descendant" } +local register_child={ kind="axis",axis="child" } local register_descendant_or_self={ kind="axis",axis="descendant-or-self" } -local register_root={ kind="axis",axis="root" } -local register_ancestor={ kind="axis",axis="ancestor" } -local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } -local register_attribute={ kind="axis",axis="attribute" } -local register_namespace={ kind="axis",axis="namespace" } -local register_following={ kind="axis",axis="following" } +local register_root={ kind="axis",axis="root" } +local register_ancestor={ kind="axis",axis="ancestor" } +local register_ancestor_or_self={ kind="axis",axis="ancestor-or-self" } +local register_attribute={ kind="axis",axis="attribute" } +local register_namespace={ kind="axis",axis="namespace" } +local register_following={ kind="axis",axis="following" } local register_following_sibling={ kind="axis",axis="following-sibling" } -local register_preceding={ kind="axis",axis="preceding" } +local register_preceding={ kind="axis",axis="preceding" } local register_preceding_sibling={ kind="axis",axis="preceding-sibling" } -local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } +local register_reverse_sibling={ kind="axis",axis="reverse-sibling" } local register_auto_descendant_or_self={ kind="axis",axis="auto-descendant-or-self" } -local register_auto_descendant={ kind="axis",axis="auto-descendant" } -local register_auto_self={ kind="axis",axis="auto-self" } -local register_auto_child={ kind="axis",axis="auto-child" } -local register_initial_child={ kind="axis",axis="initial-child" } +local register_auto_descendant={ kind="axis",axis="auto-descendant" } +local register_auto_self={ kind="axis",axis="auto-self" } +local register_auto_child={ kind="axis",axis="auto-child" } +local register_initial_child={ kind="axis",axis="initial-child" } local register_all_nodes={ kind="nodes",nodetest=true,nodes={ true,false,false } } local skip={} local function errorrunner_e(str,cnv) - if not skip[str] then - report_lpath("error in expression: %s => %s",str,cnv) - skip[str]=cnv or str - end - return false + if not skip[str] then + report_lpath("error in expression: %s => %s",str,cnv) + skip[str]=cnv or str + end + return false end local function errorrunner_f(str,arg) - report_lpath("error in finalizer: %s(%s)",str,arg or "") - return false + report_lpath("error in finalizer: %s(%s)",str,arg or "") + return false end local function register_nodes(nodetest,nodes) - return { kind="nodes",nodetest=nodetest,nodes=nodes } + return { kind="nodes",nodetest=nodetest,nodes=nodes } end local function register_selector(specification) - return { kind="selector",specification=specification } + return { kind="selector",specification=specification } end local function register_expression(expression) - local converted=lpegmatch(converter,expression) - local runner=load(format(template_e,converted)) - runner=(runner and runner()) or function() errorrunner_e(expression,converted) end - return { kind="expression",expression=expression,converted=converted,evaluator=runner } + local converted=lpegmatch(converter,expression) + local runner=load(format(template_e,converted)) + runner=(runner and runner()) or function() errorrunner_e(expression,converted) end + return { kind="expression",expression=expression,converted=converted,evaluator=runner } end local function register_finalizer(protocol,name,arguments) - local runner - if arguments and arguments~="" then - runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) - else - runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) - end - runner=(runner and runner()) or function() errorrunner_f(name,arguments) end - return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } + local runner + if arguments and arguments~="" then + runner=load(format(template_f_y,protocol or xml.defaultprotocol,name,arguments)) + else + runner=load(format(template_f_n,protocol or xml.defaultprotocol,name)) + end + runner=(runner and runner()) or function() errorrunner_f(name,arguments) end + return { kind="finalizer",name=name,arguments=arguments,finalizer=runner } end local expression=P { "ex", - ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", - sq="'"*(1-S("'"))^0*"'", - dq='"'*(1-S('"'))^0*'"', + ex="["*C((V("sq")+V("dq")+(1-S("[]"))+V("ex"))^0)*"]", + sq="'"*(1-S("'"))^0*"'", + dq='"'*(1-S('"'))^0*'"', } local arguments=P { "ar", - ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", - nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, - sq=P("'")*(1-P("'"))^0*P("'"), - dq=P('"')*(1-P('"'))^0*P('"'), + ar="("*Cs((V("sq")+V("dq")+V("nq")+P(1-P(")")))^0)*")", + nq=((1-S("),'\""))^1)/function(s) return format("%q",s) end, + sq=P("'")*(1-P("'"))^0*P("'"), + dq=P('"')*(1-P('"'))^0*P('"'), } local function register_error(str) - return { kind="error",error=format("unparsed: %s",str) } + return { kind="error",error=format("unparsed: %s",str) } end local special_1=P("*")*Cc(register_auto_descendant)*Cc(register_all_nodes) local special_2=P("/")*Cc(register_auto_self) @@ -14123,367 +17684,368 @@ local special_3=P("")*Cc(register_auto_self) local no_nextcolon=P(-1)+#(1-P(":")) local no_nextlparent=P(-1)+#(1-P("(")) local pathparser=Ct { "patterns", - patterns=spaces*V("protocol")*spaces*( - (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) - ), - protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), - step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, - axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), - special=special_1+special_2+special_3, - initial=(P("/")*spaces*Cc(register_initial_child))^-1, - error=(P(1)^1)/register_error, - shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), - shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, - s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), - s_descendant=P("**")*Cc(register_descendant), - s_child=P("*")*no_nextcolon*Cc(register_child), - s_parent=P("..")*Cc(register_parent), - s_self=P("." )*Cc(register_self), - s_root=P("^^")*Cc(register_root), - s_ancestor=P("^")*Cc(register_ancestor), - s_lastmatch=P("=")*Cc(register_last_match), - descendant=P("descendant::")*Cc(register_descendant), - child=P("child::")*Cc(register_child), - parent=P("parent::")*Cc(register_parent), - self=P("self::")*Cc(register_self), - root=P('root::')*Cc(register_root), - ancestor=P('ancestor::')*Cc(register_ancestor), - descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), - ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), - following=P('following::')*Cc(register_following), - following_sibling=P('following-sibling::')*Cc(register_following_sibling), - preceding=P('preceding::')*Cc(register_preceding), - preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), - reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), - last_match=P('last-match::')*Cc(register_last_match), - selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, - nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, - expressions=expression/register_expression, - letters=R("az")^1, - name=(1-S("/[]()|:*!"))^1, - negate=P("!")*Cc(false), - nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), - nodetest=V("negate")+Cc(true), - nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), - wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, - nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, - finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, + patterns=spaces*V("protocol")*spaces*( + (V("special")*spaces*P(-1) )+(V("initial")*spaces*V("step")*spaces*(P("/")*spaces*V("step")*spaces)^0 ) + ), + protocol=Cg(V("letters"),"protocol")*P("://")+Cg(Cc(nil),"protocol"), + step=((V("shortcuts")+V("selector")+P("/")+V("axis"))*spaces*V("nodes")^0+V("error"))*spaces*V("expressions")^0*spaces*V("finalizer")^0, + axis=V("last_match")+V("descendant")+V("child")+V("parent")+V("self")+V("root")+V("ancestor")+V("descendant_or_self")+V("following_sibling")+V("following")+V("reverse_sibling")+V("preceding_sibling")+V("preceding")+V("ancestor_or_self")+#(1-P(-1))*Cc(register_auto_child), + special=special_1+special_2+special_3, + initial=(P("/")*spaces*Cc(register_initial_child))^-1, + error=(P(1)^1)/register_error, + shortcuts_a=V("s_descendant_or_self")+V("s_descendant")+V("s_child")+V("s_parent")+V("s_self")+V("s_root")+V("s_ancestor")+V("s_lastmatch"), + shortcuts=V("shortcuts_a")*(spaces*"/"*spaces*V("shortcuts_a"))^0, + s_descendant_or_self=(P("***/")+P("/"))*Cc(register_descendant_or_self), + s_descendant=P("**")*Cc(register_descendant), + s_child=P("*")*no_nextcolon*Cc(register_child), + s_parent=P("..")*Cc(register_parent), + s_self=P("." )*Cc(register_self), + s_root=P("^^")*Cc(register_root), + s_ancestor=P("^")*Cc(register_ancestor), + s_lastmatch=P("=")*Cc(register_last_match), + descendant=P("descendant::")*Cc(register_descendant), + child=P("child::")*Cc(register_child), + parent=P("parent::")*Cc(register_parent), + self=P("self::")*Cc(register_self), + root=P('root::')*Cc(register_root), + ancestor=P('ancestor::')*Cc(register_ancestor), + descendant_or_self=P('descendant-or-self::')*Cc(register_descendant_or_self), + ancestor_or_self=P('ancestor-or-self::')*Cc(register_ancestor_or_self), + following=P('following::')*Cc(register_following), + following_sibling=P('following-sibling::')*Cc(register_following_sibling), + preceding=P('preceding::')*Cc(register_preceding), + preceding_sibling=P('preceding-sibling::')*Cc(register_preceding_sibling), + reverse_sibling=P('reverse-sibling::')*Cc(register_reverse_sibling), + last_match=P('last-match::')*Cc(register_last_match), + selector=P("{")*C((1-P("}"))^1)*P("}")/register_selector, + nodes=(V("nodefunction")*spaces*P("(")*V("nodeset")*P(")")+V("nodetest")*V("nodeset"))/register_nodes, + expressions=expression/register_expression, + letters=R("az")^1, + name=(1-S("/[]()|:*!"))^1, + negate=P("!")*Cc(false), + nodefunction=V("negate")+P("not")*Cc(false)+Cc(true), + nodetest=V("negate")+Cc(true), + nodename=(V("negate")+Cc(true))*spaces*((V("wildnodename")*P(":")*V("wildnodename"))+(Cc(false)*V("wildnodename"))), + wildnodename=(C(V("name"))+P("*")*Cc(false))*no_nextlparent, + nodeset=spaces*Ct(V("nodename")*(spaces*P("|")*spaces*V("nodename"))^0)*spaces, + finalizer=(Cb("protocol")*P("/")^-1*C(V("name"))*arguments*P(-1))/register_finalizer, } xmlpatterns.pathparser=pathparser local cache={} local function nodesettostring(set,nodetest) - local t={} - for i=1,#set,3 do - local directive,ns,tg=set[i],set[i+1],set[i+2] - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - t[#t+1]=(directive and tg) or format("not(%s)",tg) - end - if nodetest==false then - return format("not(%s)",concat(t,"|")) - else - return concat(t,"|") - end + local t={} + for i=1,#set,3 do + local directive,ns,tg=set[i],set[i+1],set[i+2] + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + tg=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) + t[#t+1]=(directive and tg) or format("not(%s)",tg) + end + if nodetest==false then + return format("not(%s)",concat(t,"|")) + else + return concat(t,"|") + end end local function tagstostring(list) - if #list==0 then - return "no elements" - else - local t={} - for i=1,#list do - local li=list[i] - local ns,tg=li.ns,li.tg - if not ns or ns=="" then ns="*" end - if not tg or tg=="" then tg="*" end - t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) - end - return concat(t," ") + if #list==0 then + return "no elements" + else + local t={} + for i=1,#list do + local li=list[i] + local ns=li.ns + local tg=li.tg + if not ns or ns=="" then ns="*" end + if not tg or tg=="" then tg="*" end + t[i]=(tg=="@rt@" and "[root]") or format("%s:%s",ns,tg) end + return concat(t," ") + end end xml.nodesettostring=nodesettostring local lpath local function lshow(parsed) - if type(parsed)=="string" then - parsed=lpath(parsed) - end - report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, - table.serialize(parsed,false)) + if type(parsed)=="string" then + parsed=lpath(parsed) + end + report_lpath("%s://%s => %s",parsed.protocol or xml.defaultprotocol,parsed.pattern, + table.serialize(parsed,false)) end xml.lshow=lshow local function add_comment(p,str) - local pc=p.comment - if not pc then - p.comment={ str } - else - pc[#pc+1]=str - end + local pc=p.comment + if not pc then + p.comment={ str } + else + pc[#pc+1]=str + end end lpath=function (pattern) - lpathcalls=lpathcalls+1 - if type(pattern)=="table" then - return pattern - else - local parsed=cache[pattern] - if parsed then - lpathcached=lpathcached+1 + lpathcalls=lpathcalls+1 + if type(pattern)=="table" then + return pattern + else + local parsed=cache[pattern] + if parsed then + lpathcached=lpathcached+1 + else + parsed=lpegmatch(pathparser,pattern) + if parsed then + parsed.pattern=pattern + local np=#parsed + if np==0 then + parsed={ pattern=pattern,register_self,state="parsing error" } + report_lpath("parsing error in pattern: %s",pattern) + lshow(parsed) else - parsed=lpegmatch(pathparser,pattern) - if parsed then - parsed.pattern=pattern - local np=#parsed - if np==0 then - parsed={ pattern=pattern,register_self,state="parsing error" } - report_lpath("parsing error in pattern: %s",pattern) - lshow(parsed) - else - local pi=parsed[1] - if pi.axis=="auto-child" then - if false then - add_comment(parsed,"auto-child replaced by auto-descendant-or-self") - parsed[1]=register_auto_descendant_or_self - else - add_comment(parsed,"auto-child replaced by auto-descendant") - parsed[1]=register_auto_descendant - end - elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then - add_comment(parsed,"initial-child removed") - remove(parsed,1) - end - local np=#parsed - if np>1 then - local pnp=parsed[np] - if pnp.kind=="nodes" and pnp.nodetest==true then - local nodes=pnp.nodes - if nodes[1]==true and nodes[2]==false and nodes[3]==false then - add_comment(parsed,"redundant final wildcard filter removed") - remove(parsed,np) - end - end - end - end + local pi=parsed[1] + if pi.axis=="auto-child" then + if false then + add_comment(parsed,"auto-child replaced by auto-descendant-or-self") + parsed[1]=register_auto_descendant_or_self else - parsed={ pattern=pattern } + add_comment(parsed,"auto-child replaced by auto-descendant") + parsed[1]=register_auto_descendant end - cache[pattern]=parsed - if trace_lparse and not trace_lprofile then - lshow(parsed) + elseif pi.axis=="initial-child" and np>1 and parsed[2].axis then + add_comment(parsed,"initial-child removed") + remove(parsed,1) + end + local np=#parsed + if np>1 then + local pnp=parsed[np] + if pnp.kind=="nodes" and pnp.nodetest==true then + local nodes=pnp.nodes + if nodes[1]==true and nodes[2]==false and nodes[3]==false then + add_comment(parsed,"redundant final wildcard filter removed") + remove(parsed,np) + end end + end end - return parsed + else + parsed={ pattern=pattern } + end + cache[pattern]=parsed + if trace_lparse and not trace_lprofile then + lshow(parsed) + end end + return parsed + end end xml.lpath=lpath do - local profiled={} - xml.profiled=profiled - local lastmatch=nil - local keepmatch=nil - if directives then - directives.register("xml.path.keeplastmatch",function(v) - keepmatch=v - lastmatch=nil - end) - end - apply_axis["last-match"]=function() - return lastmatch or {} - end - local function profiled_apply(list,parsed,nofparsed,order) - local p=profiled[parsed.pattern] - if p then - p.tested=p.tested+1 - else - p={ tested=1,matched=0,finalized=0 } - profiled[parsed.pattern]=p - end - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - p.matched=p.matched+1 - p.finalized=p.finalized+1 - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - p.finalized=p.finalized+1 - return collected - end - return nil - end - end - if collected then - p.matched=p.matched+1 - end - return collected - end - local function traced_apply(list,parsed,nofparsed,order) - if trace_lparse then - lshow(parsed) - end - report_lpath("collecting: %s",parsed.pattern) - report_lpath("root tags : %s",tagstostring(list)) - report_lpath("order : %s",order or "unset") - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - collected=apply_axis[pi.axis](collected) - report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) - elseif kind=="finalizer" then - collected=pi.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") - return collected - end - if not collected or #collected==0 then - local pn=i<nofparsed and parsed[nofparsed] - if pn and pn.kind=="finalizer" then - collected=pn.finalizer(collected) - report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") - return collected - end - return nil - end - end + local profiled={} + xml.profiled=profiled + local lastmatch=nil + local keepmatch=nil + if directives then + directives.register("xml.path.keeplastmatch",function(v) + keepmatch=v + lastmatch=nil + end) + end + apply_axis["last-match"]=function() + return lastmatch or {} + end + local function profiled_apply(list,parsed,nofparsed,order) + local p=profiled[parsed.pattern] + if p then + p.tested=p.tested+1 + else + p={ tested=1,matched=0,finalized=0 } + profiled[parsed.pattern]=p + end + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + p.matched=p.matched+1 + p.finalized=p.finalized+1 return collected - end - local function normal_apply(list,parsed,nofparsed,order) - local collected=list - for i=1,nofparsed do - local pi=parsed[i] - local kind=pi.kind - if kind=="axis" then - local axis=pi.axis - if axis~="self" then - collected=apply_axis[axis](collected) - end - elseif kind=="nodes" then - collected=apply_nodes(collected,pi.nodetest,pi.nodes) - elseif kind=="expression" then - collected=apply_expression(collected,pi.evaluator,order) - elseif kind=="selector" then - collected=apply_selector(collected,pi.specification) - elseif kind=="finalizer" then - return pi.finalizer(collected) - end - if not collected or #collected==0 then - local pf=i<nofparsed and parsed[nofparsed].finalizer - if pf then - return pf(collected) - end - return nil - end + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + p.finalized=p.finalized+1 + return collected end - return collected + return nil + end end - local apply=normal_apply - if trackers then - trackers.register("xml.path,xml.parse,xml.profile",function() - if trace_lprofile then - apply=profiled_apply - elseif trace_lpath then - apply=traced_apply - else - apply=normal_apply - end - end) + if collected then + p.matched=p.matched+1 end - function xml.applylpath(list,pattern) - if not list then - lastmatch=nil - return - end - local parsed=cache[pattern] - if parsed then - lpathcalls=lpathcalls+1 - lpathcached=lpathcached+1 - elseif type(pattern)=="table" then - lpathcalls=lpathcalls+1 - parsed=pattern - else - parsed=lpath(pattern) or pattern - end - if not parsed then - lastmatch=nil - return - end - local nofparsed=#parsed - if nofparsed==0 then - lastmatch=nil - return - end - local collected=apply({ list },parsed,nofparsed,list.mi) - lastmatch=keepmatch and collected or nil + return collected + end + local function traced_apply(list,parsed,nofparsed,order) + if trace_lparse then + lshow(parsed) + end + report_lpath("collecting: %s",parsed.pattern) + report_lpath("root tags : %s",tagstostring(list)) + report_lpath("order : %s",order or "unset") + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + collected=apply_axis[pi.axis](collected) + report_lpath("% 10i : ax : %s",(collected and #collected) or 0,pi.axis) + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + report_lpath("% 10i : ns : %s",(collected and #collected) or 0,nodesettostring(pi.nodes,pi.nodetest)) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + report_lpath("% 10i : ex : %s -> %s",(collected and #collected) or 0,pi.expression,pi.converted) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + report_lpath("% 10i : se : %s ",(collected and #collected) or 0,pi.specification) + elseif kind=="finalizer" then + collected=pi.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pi.name,pi.arguments or "") return collected + end + if not collected or #collected==0 then + local pn=i<nofparsed and parsed[nofparsed] + if pn and pn.kind=="finalizer" then + collected=pn.finalizer(collected) + report_lpath("% 10i : fi : %s : %s(%s)",(type(collected)=="table" and #collected) or 0,parsed.protocol or xml.defaultprotocol,pn.name,pn.arguments or "") + return collected + end + return nil + end end - function xml.lastmatch() - return lastmatch - end - local stack={} - function xml.pushmatch() - insert(stack,lastmatch) - end - function xml.popmatch() - lastmatch=remove(stack) + return collected + end + local function normal_apply(list,parsed,nofparsed,order) + local collected=list + for i=1,nofparsed do + local pi=parsed[i] + local kind=pi.kind + if kind=="axis" then + local axis=pi.axis + if axis~="self" then + collected=apply_axis[axis](collected) + end + elseif kind=="nodes" then + collected=apply_nodes(collected,pi.nodetest,pi.nodes) + elseif kind=="expression" then + collected=apply_expression(collected,pi.evaluator,order) + elseif kind=="selector" then + collected=apply_selector(collected,pi.specification) + elseif kind=="finalizer" then + return pi.finalizer(collected) + end + if not collected or #collected==0 then + local pf=i<nofparsed and parsed[nofparsed].finalizer + if pf then + return pf(collected) + end + return nil + end end + return collected + end + local apply=normal_apply + if trackers then + trackers.register("xml.path,xml.parse,xml.profile",function() + if trace_lprofile then + apply=profiled_apply + elseif trace_lpath then + apply=traced_apply + else + apply=normal_apply + end + end) + end + function xml.applylpath(list,pattern) + if not list then + lastmatch=nil + return + end + local parsed=cache[pattern] + if parsed then + lpathcalls=lpathcalls+1 + lpathcached=lpathcached+1 + elseif type(pattern)=="table" then + lpathcalls=lpathcalls+1 + parsed=pattern + else + parsed=lpath(pattern) or pattern + end + if not parsed then + lastmatch=nil + return + end + local nofparsed=#parsed + if nofparsed==0 then + lastmatch=nil + return + end + local collected=apply({ list },parsed,nofparsed,list.mi) + lastmatch=keepmatch and collected or nil + return collected + end + function xml.lastmatch() + return lastmatch + end + local stack={} + function xml.pushmatch() + insert(stack,lastmatch) + end + function xml.popmatch() + lastmatch=remove(stack) + end end local applylpath=xml.applylpath function xml.filter(root,pattern) - return applylpath(root,pattern) + return applylpath(root,pattern) end expressions.child=function(e,pattern) - return applylpath(e,pattern) + return applylpath(e,pattern) end expressions.count=function(e,pattern) - local collected=applylpath(e,pattern) - return pattern and (collected and #collected) or 0 + local collected=applylpath(e,pattern) + return pattern and (collected and #collected) or 0 end expressions.oneof=function(s,...) - for i=1,select("#",...) do - if s==select(i,...) then - return true - end + for i=1,select("#",...) do + if s==select(i,...) then + return true end - return false + end + return false end expressions.error=function(str) - xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) - return false + xml.errorhandler(format("unknown function in lpath expression: %s",tostring(str or "?"))) + return false end expressions.undefined=function(s) - return s==nil + return s==nil end expressions.quit=function(s) - if s or s==nil then - quit_expression=true - end - return true + if s or s==nil then + quit_expression=true + end + return true end expressions.print=function(...) - print(...) - return true + print(...) + return true end expressions.find=find expressions.upper=upper @@ -14491,233 +18053,238 @@ expressions.lower=lower expressions.number=tonumber expressions.boolean=toboolean function expressions.contains(str,pattern) - local t=type(str) - if t=="string" then - if find(str,pattern) then - return true - end - elseif t=="table" then - for i=1,#str do - local d=str[i] - if type(d)=="string" and find(d,pattern) then - return true - end - end + local t=type(str) + if t=="string" then + if find(str,pattern) then + return true end - return false + elseif t=="table" then + for i=1,#str do + local d=str[i] + if type(d)=="string" and find(d,pattern) then + return true + end + end + end + return false end function xml.expressions.idstring(str) - return type(str)=="string" and gsub(str,"^#","") or "" + return type(str)=="string" and gsub(str,"^#","") or "" end local function traverse(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local r=e.__p__ - handle(r,r.dt,e.ni) - end + local collected=applylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local r=e.__p__ + handle(r,r.dt,e.ni) end + end end local function selection(root,pattern,handle) - local collected=applylpath(root,pattern) - if collected then - if handle then - for c=1,#collected do - handle(collected[c]) - end - else - return collected - end + local collected=applylpath(root,pattern) + if collected then + if handle then + for c=1,#collected do + handle(collected[c]) + end + else + return collected end + end end -xml.traverse=traverse +xml.traverse=traverse xml.selection=selection local function dofunction(collected,fnc,...) - if collected then - local f=functions[fnc] - if f then - for c=1,#collected do - f(collected[c],...) - end - else - report_lpath("unknown function %a",fnc) - end + if collected then + local f=functions[fnc] + if f then + for c=1,#collected do + f(collected[c],...) + end + else + report_lpath("unknown function %a",fnc) end + end end finalizers.xml["function"]=dofunction finalizers.tex["function"]=dofunction expressions.text=function(e,n) - local rdt=e.__p__.dt - return rdt and rdt[n] or "" + local rdt=e.__p__.dt + return rdt and rdt[n] or "" end expressions.name=function(e,n) - local found=false - n=tonumber(n) or 0 - if n==0 then - found=type(e)=="table" and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end + local found=false + n=tonumber(n) or 0 + if n==0 then + found=type(e)=="table" and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 end + end end - if found then - local ns,tg=found.rn or found.ns or "",found.tg - if ns~="" then - return ns..":"..tg + else + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break else - return tg + n=n-1 end + end + end + end + if found then + local ns=found.rn or found.ns or "" + local tg=found.tg + if ns~="" then + return ns..":"..tg else - return "" + return tg end + else + return "" + end end expressions.tag=function(e,n) - if not e then - return "" + if not e then + return "" + else + local found=false + n=tonumber(n) or 0 + if n==0 then + found=(type(e)=="table") and e + elseif n<0 then + local d=e.__p__.dt + local k=e.ni + for i=k-1,1,-1 do + local di=d[i] + if type(di)=="table" then + if n==-1 then + found=di + break + else + n=n+1 + end + end + end else - local found=false - n=tonumber(n) or 0 - if n==0 then - found=(type(e)=="table") and e - elseif n<0 then - local d,k=e.__p__.dt,e.ni - for i=k-1,1,-1 do - local di=d[i] - if type(di)=="table" then - if n==-1 then - found=di - break - else - n=n+1 - end - end - end - else - local d,k=e.__p__.dt,e.ni - for i=k+1,#d,1 do - local di=d[i] - if type(di)=="table" then - if n==1 then - found=di - break - else - n=n-1 - end - end - end + local d=e.__p__.dt + local k=e.ni + for i=k+1,#d,1 do + local di=d[i] + if type(di)=="table" then + if n==1 then + found=di + break + else + n=n-1 + end end - return (found and found.tg) or "" + end end + return (found and found.tg) or "" + end end local dummy=function() end function xml.elements(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end 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 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - local e=collected[c] - local r=e.__p__ - return r,r.dt,e.ni - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + local e=collected[c] + local r=e.__p__ + return r,r.dt,e.ni + end end + end end function xml.collected(root,pattern,reverse) - local collected=applylpath(root,pattern) - if not collected then - return dummy + local collected=applylpath(root,pattern) + if not collected then + return dummy + 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 + return collected[c] + end 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 - return collected[c] - end - end - else - local c=0 - return function() - if c<n then - c=c+1 - return collected[c] - end - end + else + local c=0 + return function() + if c<n then + c=c+1 + return collected[c] + end end + end end function xml.inspect(collection,pattern) - pattern=pattern or "." - for e in xml.collected(collection,pattern or ".") do - report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) - end + pattern=pattern or "." + for e in xml.collected(collection,pattern or ".") do + report_lpath("pattern: %s\n\n%s\n",pattern,xml.tostring(e)) + end end local function split(e) - local dt=e.dt - if dt then - for i=1,#dt do - local dti=dt[i] - if type(dti)=="string" then - dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") - dti=gsub(dti,"[\n\r]+","\n\n") - dt[i]=dti - else - split(dti) - end - end + local dt=e.dt + if dt then + for i=1,#dt do + local dti=dt[i] + if type(dti)=="string" then + dti=gsub(dti,"^[\n\r]*(.-)[\n\r]*","%1") + dti=gsub(dti,"[\n\r]+","\n\n") + dt[i]=dti + else + split(dti) + end end - return e + end + return e end function xml.finalizers.paragraphs(c) - for i=1,#c do - split(c[i]) - end - return c + for i=1,#c do + split(c[i]) + end + return c end @@ -14727,14 +18294,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-mis"] = package.loaded["lxml-mis"] or true --- original size: 3574, stripped down to: 1863 +-- original size: 3574, stripped down to: 1808 if not modules then modules={} end modules ['lxml-mis']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local xml,lpeg,string=xml,lpeg,string local type=type @@ -14745,26 +18312,26 @@ local P,S,R,C,V,Cc,Cs=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.V,lpeg.Cc,lpeg.Cs lpegpatterns.xml=lpegpatterns.xml or {} local xmlpatterns=lpegpatterns.xml local function xmlgsub(t,old,new) - local dt=t.dt - if dt then - for k=1,#dt do - local v=dt[k] - if type(v)=="string" then - dt[k]=gsub(v,old,new) - else - xmlgsub(v,old,new) - end - end + local dt=t.dt + if dt then + for k=1,#dt do + local v=dt[k] + if type(v)=="string" then + dt[k]=gsub(v,old,new) + else + xmlgsub(v,old,new) + end end + end end function xml.stripleadingspaces(dk,d,k) - if d and k then - local dkm=d[k-1] - if dkm and type(dkm)=="string" then - local s=match(dkm,"\n(%s+)") - xmlgsub(dk,"\n"..rep(" ",#s),"\n") - end + if d and k then + local dkm=d[k-1] + if dkm and type(dkm)=="string" then + local s=match(dkm,"\n(%s+)") + xmlgsub(dk,"\n"..rep(" ",#s),"\n") end + end end local normal=(1-S("<&>"))^0 local special=P("<")/"<"+P(">")/">"+P("&")/"&" @@ -14776,17 +18343,17 @@ local cleansed=Cs(((P("<")*(1-P(">"))^0*P(">"))/""+1)^0) xmlpatterns.escaped=escaped xmlpatterns.unescaped=unescaped xmlpatterns.cleansed=cleansed -function xml.escaped (str) return lpegmatch(escaped,str) end +function xml.escaped (str) return lpegmatch(escaped,str) end function xml.unescaped(str) return lpegmatch(unescaped,str) end -function xml.cleansed (str) return lpegmatch(cleansed,str) end +function xml.cleansed (str) return lpegmatch(cleansed,str) end function xml.fillin(root,pattern,str,check) - local e=xml.first(root,pattern) - if e then - local n=#e.dt - if not check or n==0 or (n==1 and e.dt[1]=="") then - e.dt={ str } - end + local e=xml.first(root,pattern) + if e then + local n=#e.dt + if not check or n==0 or (n==1 and e.dt[1]=="") then + e.dt={ str } end + end end @@ -14796,17 +18363,17 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-aux"] = package.loaded["lxml-aux"] or true --- original size: 30650, stripped down to: 21793 +-- original size: 30771, stripped down to: 19680 if not modules then modules={} end modules ['lxml-aux']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) -local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) +local trace_manipulations=false trackers.register("lxml.manipulations",function(v) trace_manipulations=v end) +local trace_inclusions=false trackers.register("lxml.inclusions",function(v) trace_inclusions=v end) local report_xml=logs.reporter("xml") local xml=xml local xmlcopy,xmlname=xml.copy,xml.name @@ -14819,308 +18386,313 @@ local utfbyte=utf.byte local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns local striplinepatterns=utilities.strings.striplinepatterns local function report(what,pattern,c,e) - report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) + report_xml("%s element %a, root %a, position %a, index %a, pattern %a",what,xmlname(e),xmlname(e.__p__),c,e.ni,pattern) end local function withelements(e,handle,depth) - if e and handle then - local edt=e.dt - if edt then - depth=depth or 0 - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - handle(e,depth) - withelements(e,handle,depth+1) - end - end + if e and handle then + local edt=e.dt + if edt then + depth=depth or 0 + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + handle(e,depth) + withelements(e,handle,depth+1) end + end end + end end xml.withelements=withelements function xml.withelement(e,n,handle) - if e and n~=0 and handle then - local edt=e.dt - if edt then - if n>0 then - for i=1,#edt do - local ei=edt[i] - if type(ei)=="table" then - if n==1 then - handle(ei) - return - else - n=n-1 - end - end - end - elseif n<0 then - for i=#edt,1,-1 do - local ei=edt[i] - if type(ei)=="table" then - if n==-1 then - handle(ei) - return - else - n=n+1 - end - end - end + if e and n~=0 and handle then + local edt=e.dt + if edt then + if n>0 then + for i=1,#edt do + local ei=edt[i] + if type(ei)=="table" then + if n==1 then + handle(ei) + return + else + n=n-1 end + end end - end -end -function xml.each(root,pattern,handle,reverse) - local collected=xmlapplylpath(root,pattern) - if collected then - if handle then - if reverse then - for c=#collected,1,-1 do - handle(collected[c]) - end + elseif n<0 then + for i=#edt,1,-1 do + local ei=edt[i] + if type(ei)=="table" then + if n==-1 then + handle(ei) + return else - for c=1,#collected do - handle(collected[c]) - end + n=n+1 end + end end - return collected + end end + end end -function xml.processattributes(root,pattern,handle) - local collected=xmlapplylpath(root,pattern) - if collected and handle then +function xml.each(root,pattern,handle,reverse) + local collected=xmlapplylpath(root,pattern) + if collected then + if handle then + if reverse then + for c=#collected,1,-1 do + handle(collected[c]) + end + else for c=1,#collected do - handle(collected[c].at) + handle(collected[c]) end + end end return collected + end +end +function xml.processattributes(root,pattern,handle) + local collected=xmlapplylpath(root,pattern) + if collected and handle then + for c=1,#collected do + handle(collected[c].at) + end + end + return collected end function xml.collect(root,pattern) - return xmlapplylpath(root,pattern) + return xmlapplylpath(root,pattern) end function xml.collecttexts(root,pattern,flatten) - local collected=xmlapplylpath(root,pattern) - if collected and flatten then - local xmltostring=xml.tostring - for c=1,#collected do - collected[c]=xmltostring(collected[c].dt) - end + local collected=xmlapplylpath(root,pattern) + if collected and flatten then + local xmltostring=xml.tostring + for c=1,#collected do + collected[c]=xmltostring(collected[c].dt) end - return collected or {} + end + return collected or {} end function xml.collect_tags(root,pattern,nonamespace) - local collected=xmlapplylpath(root,pattern) - if collected then - local t,n={},0 - for c=1,#collected do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace then - t[n]=tg - elseif ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end - end - return t + local collected=xmlapplylpath(root,pattern) + if collected then + local t={} + local n=0 + for c=1,#collected do + local e=collected[c] + local ns=e.ns + local tg=e.tg + n=n+1 + if nonamespace then + t[n]=tg + elseif ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg + end end + return t + end end local no_root={ no_root=true } local function redo_ni(d) - for k=1,#d do - local dk=d[k] - if type(dk)=="table" then - dk.ni=k - end + for k=1,#d do + local dk=d[k] + if type(dk)=="table" then + dk.ni=k end + end end xml.reindex=redo_ni local function xmltoelement(whatever,root) - if not whatever then - return nil - end - local element - if type(whatever)=="string" then - element=xmlinheritedconvert(whatever,root) - else - element=whatever - end - if element.error then - return whatever - end - if element then - end - return element + if not whatever then + return nil + end + local element + if type(whatever)=="string" then + element=xmlinheritedconvert(whatever,root) + else + element=whatever + end + if element.error then + return whatever + end + if element then + end + return element end xml.toelement=xmltoelement local function copiedelement(element,newparent) - if type(element)=="string" then - return element - else - element=xmlcopy(element).dt - if newparent and type(element)=="table" then - element.__p__=newparent - end - return element + if type(element)=="string" then + return element + else + element=xmlcopy(element).dt + if newparent and type(element)=="table" then + element.__p__=newparent end + return element + end end function xml.delete(root,pattern) - if not pattern or pattern=="" then - local p=root.__p__ + if not pattern or pattern=="" then + local p=root.__p__ + if p then + if trace_manipulations then + report('deleting',"--",c,root) + end + local d=p.dt + remove(d,root.ni) + redo_ni(d) + end + else + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ if p then - if trace_manipulations then - report('deleting',"--",c,root) - end - local d=p.dt - remove(d,root.ni) - redo_ni(d) - end - else - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('deleting',pattern,c,e) - end - local d=p.dt - local ni=e.ni - if ni<=#d then - if false then - p.dt[ni]="" - else - remove(d,ni) - redo_ni(d) - end - else - end - end + if trace_manipulations then + report('deleting',pattern,c,e) + end + local d=p.dt + local ni=e.ni + if ni<=#d then + if false then + p.dt[ni]="" + else + remove(d,ni) + redo_ni(d) end + else + end end + end end + end end function xml.replace(root,pattern,whatever) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local p=e.__p__ - if p then - if trace_manipulations then - report('replacing',pattern,c,e) - end - local d=p.dt - local n=e.ni - local t=copiedelement(element,p) - if type(t)=="table" then - d[n]=t[1] - for i=2,#t do - n=n+1 - insert(d,n,t[i]) - end - else - d[n]=t - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local p=e.__p__ + if p then + if trace_manipulations then + report('replacing',pattern,c,e) + end + local d=p.dt + local n=e.ni + local t=copiedelement(element,p) + if type(t)=="table" then + d[n]=t[1] + for i=2,#t do + n=n+1 + insert(d,n,t[i]) + end + else + d[n]=t end + redo_ni(d) + end end + end end local function wrap(e,wrapper) - local t={ - rn=e.rn, - tg=e.tg, - ns=e.ns, - at=e.at, - dt=e.dt, - __p__=e, - } - setmetatable(t,getmetatable(e)) - e.rn=wrapper.rn or e.rn or "" - e.tg=wrapper.tg or e.tg or "" - e.ns=wrapper.ns or e.ns or "" - e.at=fastcopy(wrapper.at) - e.dt={ t } + local t={ + rn=e.rn, + tg=e.tg, + ns=e.ns, + at=e.at, + dt=e.dt, + __p__=e, + } + setmetatable(t,getmetatable(e)) + e.rn=wrapper.rn or e.rn or "" + e.tg=wrapper.tg or e.tg or "" + e.ns=wrapper.ns or e.ns or "" + e.at=fastcopy(wrapper.at) + e.dt={ t } end function xml.wrap(root,pattern,whatever) - if whatever then - local wrapper=xmltoelement(whatever,root) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if trace_manipulations then - report('wrapping',pattern,c,e) - end - wrap(e,wrapper) - end + if whatever then + local wrapper=xmltoelement(whatever,root) + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if trace_manipulations then + report('wrapping',pattern,c,e) end - else - wrap(root,xmltoelement(pattern)) + wrap(e,wrapper) + end end + else + wrap(root,xmltoelement(pattern)) + end end local function inject_element(root,pattern,whatever,prepend) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function inject_e(e) - local r=e.__p__ - local d,k,rri=r.dt,e.ni,r.ri - local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) - if edt then - local be,af - local cp=copiedelement(element,e) - if prepend then - be,af=cp,edt - else - be,af=edt,cp - end - local bn=#be - for i=1,#af do - bn=bn+1 - be[bn]=af[i] - end - if rri then - r.dt[rri].dt=be - else - d[k].dt=be - end - redo_ni(d) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function inject_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + local rri=r.ri + local edt=(rri and d[rri].dt) or (d and d[k] and d[k].dt) + if edt then + local be,af + local cp=copiedelement(element,e) + if prepend then + be,af=cp,edt + else + be,af=edt,cp + end + local bn=#be + for i=1,#af do + bn=bn+1 + be[bn]=af[i] + end + if rri then + r.dt[rri].dt=be + else + d[k].dt=be + end + redo_ni(d) end - if not collected then - elseif collected.tg then - inject_e(collected) - else - for c=1,#collected do - inject_e(collected[c]) - end + end + if not collected then + elseif collected.tg then + inject_e(collected) + else + for c=1,#collected do + inject_e(collected[c]) end + end end local function insert_element(root,pattern,whatever,before) - local element=root and xmltoelement(whatever,root) - local collected=element and xmlapplylpath(root,pattern) - local function insert_e(e) - local r=e.__p__ - local d,k=r.dt,e.ni - if not before then - k=k+1 - end - insert(d,k,copiedelement(element,r)) - redo_ni(d) - end - if not collected then - elseif collected.tg then - insert_e(collected) - else - for c=1,#collected do - insert_e(collected[c]) - end + local element=root and xmltoelement(whatever,root) + local collected=element and xmlapplylpath(root,pattern) + local function insert_e(e) + local r=e.__p__ + local d=r.dt + local k=e.ni + if not before then + k=k+1 + end + insert(d,k,copiedelement(element,r)) + redo_ni(d) + end + if not collected then + elseif collected.tg then + insert_e(collected) + else + for c=1,#collected do + insert_e(collected[c]) end + end end xml.insert_element=insert_element xml.insertafter=insert_element @@ -15128,124 +18700,124 @@ xml.insertbefore=function(r,p,e) insert_element(r,p,e,true) end xml.injectafter=inject_element xml.injectbefore=function(r,p,e) inject_element(r,p,e,true) end local function include(xmldata,pattern,attribute,recursive,loaddata,level) - pattern=pattern or 'include' - loaddata=loaddata or io.loaddata - local collected=xmlapplylpath(xmldata,pattern) - if collected then - if not level then - level=1 - end - for c=1,#collected do - local ek=collected[c] - local name=nil - local ekdt=ek.dt - if ekdt then - local ekat=ek.at - local ekrt=ek.__p__ - if ekrt then - local epdt=ekrt.dt - if not attribute or attribute=="" then - name=(type(ekdt)=="table" and ekdt[1]) or ekdt - end - if not name then - for a in gmatch(attribute or "href","([^|]+)") do - name=ekat[a] - if name then - break - end - end - end - local data=nil - if name and name~="" then - local d,n=loaddata(name) - data=d or "" - name=n or name - if trace_inclusions then - report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") - end - end - if not data or data=="" then - epdt[ek.ni]="" - elseif ekat["parse"]=="text" then - epdt[ek.ni]=xml.escaped(data) - else + pattern=pattern or 'include' + loaddata=loaddata or io.loaddata + local collected=xmlapplylpath(xmldata,pattern) + if collected then + if not level then + level=1 + end + for c=1,#collected do + local ek=collected[c] + local name=nil + local ekdt=ek.dt + if ekdt then + local ekat=ek.at + local ekrt=ek.__p__ + if ekrt then + local epdt=ekrt.dt + if not attribute or attribute=="" then + name=(type(ekdt)=="table" and ekdt[1]) or ekdt + end + if not name then + for a in gmatch(attribute or "href","([^|]+)") do + name=ekat[a] + if name then + break + end + end + end + local data=nil + if name and name~="" then + local d,n=loaddata(name) + data=d or "" + name=n or name + if trace_inclusions then + report_xml("including %s bytes from %a at level %s by pattern %a and attribute %a (%srecursing)",#data,name,level,pattern,attribute or "",recursive and "" or "not ") + end + end + if not data or data=="" then + epdt[ek.ni]="" + elseif ekat["parse"]=="text" then + epdt[ek.ni]=xml.escaped(data) + else local settings=xmldata.settings local savedresource=settings.currentresource settings.currentresource=name - local xi=xmlinheritedconvert(data,xmldata) - if not xi then - epdt[ek.ni]="" - else - if recursive then - include(xi,pattern,attribute,recursive,loaddata,level+1) - end - local child=xml.body(xi) - child.__p__=ekrt - child.__f__=name + local xi=xmlinheritedconvert(data,xmldata) + if not xi then + epdt[ek.ni]="" + else + if recursive then + include(xi,pattern,attribute,recursive,loaddata,level+1) + end + local child=xml.body(xi) + child.__p__=ekrt + child.__f__=name child.cf=name - epdt[ek.ni]=child - local settings=xmldata.settings - local inclusions=settings and settings.inclusions - if inclusions then - inclusions[#inclusions+1]=name - elseif settings then - settings.inclusions={ name } - else - settings={ inclusions={ name } } - xmldata.settings=settings - end - if child.er then - local badinclusions=settings.badinclusions - if badinclusions then - badinclusions[#badinclusions+1]=name - else - settings.badinclusions={ name } - end - end - end -settings.currentresource=savedresource - end + epdt[ek.ni]=child + local settings=xmldata.settings + local inclusions=settings and settings.inclusions + if inclusions then + inclusions[#inclusions+1]=name + elseif settings then + settings.inclusions={ name } + else + settings={ inclusions={ name } } + xmldata.settings=settings + end + if child.er then + local badinclusions=settings.badinclusions + if badinclusions then + badinclusions[#badinclusions+1]=name + else + settings.badinclusions={ name } end + end end +settings.currentresource=savedresource + end end + end end + end end xml.include=include function xml.inclusion(e,default) - while e do - local f=e.__f__ - if f then - return f - else - e=e.__p__ - end + while e do + local f=e.__f__ + if f then + return f + else + e=e.__p__ end - return default + end + return default end local function getinclusions(key,e,sorted) - while e do - local settings=e.settings - if settings then - local inclusions=settings[key] - if inclusions then - inclusions=table.unique(inclusions) - if sorted then - table.sort(inclusions) - end - return inclusions - else - e=e.__p__ - end - else - e=e.__p__ - end + while e do + local settings=e.settings + if settings then + local inclusions=settings[key] + if inclusions then + inclusions=table.unique(inclusions) + if sorted then + table.sort(inclusions) + end + return inclusions + else + e=e.__p__ + end + else + e=e.__p__ end + end end function xml.inclusions(e,sorted) - return getinclusions("inclusions",e,sorted) + return getinclusions("inclusions",e,sorted) end function xml.badinclusions(e,sorted) - return getinclusions("badinclusions",e,sorted) + return getinclusions("badinclusions",e,sorted) end local b_collapser=lpegpatterns.b_collapser local m_collapser=lpegpatterns.m_collapser @@ -15254,194 +18826,194 @@ local b_stripper=lpegpatterns.b_stripper local m_stripper=lpegpatterns.m_stripper local e_stripper=lpegpatterns.e_stripper local function stripelement(e,nolines,anywhere) - local edt=e.dt - if edt then - local n=#edt - if n==0 then - return e - elseif anywhere then - local t={} - local m=0 - for e=1,n do - local str=edt[e] - if type(str)~="string" then - m=m+1 - t[m]=str - elseif str~="" then - if nolines then - str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) - else - str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) - end - if str~="" then - m=m+1 - t[m]=str - end - end - end - e.dt=t + local edt=e.dt + if edt then + local n=#edt + if n==0 then + return e + elseif anywhere then + local t={} + local m=0 + for e=1,n do + local str=edt[e] + if type(str)~="string" then + m=m+1 + t[m]=str + elseif str~="" then + if nolines then + str=lpegmatch((n==1 and b_collapser) or (n==m and e_collapser) or m_collapser,str) + else + str=lpegmatch((n==1 and b_stripper) or (n==m and e_stripper) or m_stripper,str) + end + if str~="" then + m=m+1 + t[m]=str + end + end + end + e.dt=t + else + local str=edt[1] + if type(str)=="string" then + if str~="" then + str=lpegmatch(nolines and b_collapser or b_stripper,str) + end + if str=="" then + remove(edt,1) + n=n-1 else - local str=edt[1] - if type(str)=="string" then - if str~="" then - str=lpegmatch(nolines and b_collapser or b_stripper,str) - end - if str=="" then - remove(edt,1) - n=n-1 - else - edt[1]=str - end - end - if n>0 then - str=edt[n] - if type(str)=="string" then - if str=="" then - remove(edt) - else - str=lpegmatch(nolines and e_collapser or e_stripper,str) - if str=="" then - remove(edt) - else - edt[n]=str - end - end - end + edt[1]=str + end + end + if n>0 then + str=edt[n] + if type(str)=="string" then + if str=="" then + remove(edt) + else + str=lpegmatch(nolines and e_collapser or e_stripper,str) + if str=="" then + remove(edt) + else + edt[n]=str end + end end + end end - return e + end + return e end xml.stripelement=stripelement function xml.strip(root,pattern,nolines,anywhere) - local collected=xmlapplylpath(root,pattern) - if collected then - for i=1,#collected do - stripelement(collected[i],nolines,anywhere) - end + local collected=xmlapplylpath(root,pattern) + if collected then + for i=1,#collected do + stripelement(collected[i],nolines,anywhere) end + end end local function renamespace(root,oldspace,newspace) - local ndt=#root.dt - for i=1,ndt or 0 do - local e=root[i] - if type(e)=="table" then - if e.ns==oldspace then - e.ns=newspace - if e.rn then - e.rn=newspace - end - end - local edt=e.dt - if edt then - renamespace(edt,oldspace,newspace) - end + local ndt=#root.dt + for i=1,ndt or 0 do + local e=root[i] + if type(e)=="table" then + if e.ns==oldspace then + e.ns=newspace + if e.rn then + e.rn=newspace end + end + local edt=e.dt + if edt then + renamespace(edt,oldspace,newspace) + end end + end end xml.renamespace=renamespace function xml.remaptag(root,pattern,newtg) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].tg=newtg - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].tg=newtg end + end end function xml.remapnamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - collected[c].ns=newns - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + collected[c].ns=newns end + end end function xml.checknamespace(root,pattern,newns) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - if (not e.rn or e.rn=="") and e.ns=="" then - e.rn=newns - end - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + if (not e.rn or e.rn=="") and e.ns=="" then + e.rn=newns + end end + end end function xml.remapname(root,pattern,newtg,newns,newrn) - local collected=xmlapplylpath(root,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - e.tg,e.ns,e.rn=newtg,newns,newrn - end + local collected=xmlapplylpath(root,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + e.tg,e.ns,e.rn=newtg,newns,newrn end + end end function xml.cdatatotext(e) - local dt=e.dt - if #dt==1 then - local first=dt[1] - if first.tg=="@cd@" then - e.dt=first.dt - end - else + local dt=e.dt + if #dt==1 then + local first=dt[1] + if first.tg=="@cd@" then + e.dt=first.dt end + else + end end function xml.texttocdata(e) - local dt=e.dt - local s=xml.tostring(dt) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(dt) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end function xml.elementtocdata(e) - local dt=e.dt - local s=xml.tostring(e) - e.tg="@cd@" - e.special=true - e.ns="" - e.rn="" - e.dt={ s } - e.at=nil + local dt=e.dt + local s=xml.tostring(e) + e.tg="@cd@" + e.special=true + e.ns="" + e.rn="" + e.dt={ s } + e.at=nil end xml.builtinentities=table.tohash { "amp","quot","apos","lt","gt" } local entities=characters and characters.entities or nil local builtinentities=xml.builtinentities function xml.addentitiesdoctype(root,option) - if not entities then - require("char-ent") - entities=characters.entities - end - if entities and root and root.tg=="@rt@" and root.statistics then - local list={} - local hexify=option=="hexadecimal" - for k,v in table.sortedhash(root.statistics.entities.names) do - if not builtinentities[k] then - local e=entities[k] - if not e then - e=format("[%s]",k) - elseif hexify then - e=format("&#%05X;",utfbyte(k)) - end - list[#list+1]=format(" <!ENTITY %s %q >",k,e) - end - end - local dt=root.dt - local n=dt[1].tg=="@pi@" and 2 or 1 - if #list>0 then - insert(dt,n,{ "\n" }) - insert(dt,n,{ - tg="@dt@", - dt={ format("Something [\n%s\n] ",concat(list)) }, - ns="", - special=true, - }) - insert(dt,n,{ "\n\n" }) - else - end + if not entities then + require("char-ent") + entities=characters.entities + end + if entities and root and root.tg=="@rt@" and root.statistics then + local list={} + local hexify=option=="hexadecimal" + for k,v in table.sortedhash(root.statistics.entities.names) do + if not builtinentities[k] then + local e=entities[k] + if not e then + e=format("[%s]",k) + elseif hexify then + e=format("&#%05X;",utfbyte(k)) + end + list[#list+1]=format(" <!ENTITY %s %q >",k,e) + end end + local dt=root.dt + local n=dt[1].tg=="@pi@" and 2 or 1 + if #list>0 then + insert(dt,n,{ "\n" }) + insert(dt,n,{ + tg="@dt@", + dt={ format("Something [\n%s\n] ",concat(list)) }, + ns="", + special=true, + }) + insert(dt,n,{ "\n\n" }) + else + end + end end xml.all=xml.each xml.insert=xml.insertafter @@ -15451,239 +19023,241 @@ xml.before=xml.insertbefore xml.process=xml.each xml.obsolete=xml.obsolete or {} local obsolete=xml.obsolete -xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip -xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect -xml.delete_element=xml.delete obsolete.delete_element=xml.delete -xml.replace_element=xml.replace obsolete.replace_element=xml.replace -xml.each_element=xml.each obsolete.each_element=xml.each -xml.process_elements=xml.process obsolete.process_elements=xml.process -xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter -xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore -xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter -xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore -xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes -xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts -xml.inject_element=xml.inject obsolete.inject_element=xml.inject -xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag -xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname -xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace +xml.strip_whitespace=xml.strip obsolete.strip_whitespace=xml.strip +xml.collect_elements=xml.collect obsolete.collect_elements=xml.collect +xml.delete_element=xml.delete obsolete.delete_element=xml.delete +xml.replace_element=xml.replace obsolete.replace_element=xml.replace +xml.each_element=xml.each obsolete.each_element=xml.each +xml.process_elements=xml.process obsolete.process_elements=xml.process +xml.insert_element_after=xml.insertafter obsolete.insert_element_after=xml.insertafter +xml.insert_element_before=xml.insertbefore obsolete.insert_element_before=xml.insertbefore +xml.inject_element_after=xml.injectafter obsolete.inject_element_after=xml.injectafter +xml.inject_element_before=xml.injectbefore obsolete.inject_element_before=xml.injectbefore +xml.process_attributes=xml.processattributes obsolete.process_attributes=xml.processattributes +xml.collect_texts=xml.collecttexts obsolete.collect_texts=xml.collecttexts +xml.inject_element=xml.inject obsolete.inject_element=xml.inject +xml.remap_tag=xml.remaptag obsolete.remap_tag=xml.remaptag +xml.remap_name=xml.remapname obsolete.remap_name=xml.remapname +xml.remap_namespace=xml.remapnamespace obsolete.remap_namespace=xml.remapnamespace function xml.cdata(e) - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" end - return "" + end + return "" end function xml.finalizers.xml.cdata(collected) - if collected then - local e=collected[1] - if e then - local dt=e.dt - if dt and #dt==1 then - local first=dt[1] - return first.tg=="@cd@" and first.dt[1] or "" - end - end + if collected then + local e=collected[1] + if e then + local dt=e.dt + if dt and #dt==1 then + local first=dt[1] + return first.tg=="@cd@" and first.dt[1] or "" + end end - return "" + end + return "" end function xml.insertcomment(e,str,n) - insert(e.dt,n or 1,{ - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.insertcdata(e,str,n) - insert(e.dt,n or 1,{ - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - }) + insert(e.dt,n or 1,{ + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + }) end function xml.setcomment(e,str,n) - e.dt={ { - tg="@cm@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cm@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.setcdata(e,str) - e.dt={ { - tg="@cd@", - ns="", - special=true, - at={}, - dt={ str }, - } } + e.dt={ { + tg="@cd@", + ns="", + special=true, + at={}, + dt={ str }, + } } end function xml.separate(x,pattern) - local collected=xmlapplylpath(x,pattern) - if collected then - for c=1,#collected do - local e=collected[c] - local d=e.dt - if d==x then - report_xml("warning: xml.separate changes root") - x=d - end - local t,n={ "\n" },1 - local i,nd=1,#d - while i<=nd do - while i<=nd do - local di=d[i] - if type(di)=="string" then - if di=="\n" or find(di,"^%s+$") then - i=i+1 - else - d[i]=strip(di) - break - end - else - break - end - end - if i>nd then - break - end - t[n+1]="\n" - t[n+2]=d[i] - t[n+3]="\n" - n=n+3 - i=i+1 + local collected=xmlapplylpath(x,pattern) + if collected then + for c=1,#collected do + local e=collected[c] + local d=e.dt + if d==x then + report_xml("warning: xml.separate changes root") + x=d + end + local t={ "\n" } + local n=1 + local i=1 + local nd=#d + while i<=nd do + while i<=nd do + local di=d[i] + if type(di)=="string" then + if di=="\n" or find(di,"^%s+$") then + i=i+1 + else + d[i]=strip(di) + break end - t[n+1]="\n" - setmetatable(t,getmetatable(d)) - e.dt=t + else + break + end + end + if i>nd then + break end + t[n+1]="\n" + t[n+2]=d[i] + t[n+3]="\n" + n=n+3 + i=i+1 + end + t[n+1]="\n" + setmetatable(t,getmetatable(d)) + e.dt=t end - return x + end + return x end local helpers=xml.helpers or {} xml.helpers=helpers local function normal(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)=="string" and str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)=="string" and str~="" then + edt[i]=action(str) + end end + end end local function recurse(e,action) - local edt=e.dt - if edt then - for i=1,#edt do - local str=edt[i] - if type(str)~="string" then - recurse(str,action) - elseif str~="" then - edt[i]=action(str) - end - end + local edt=e.dt + if edt then + for i=1,#edt do + local str=edt[i] + if type(str)~="string" then + recurse(str,action) + elseif str~="" then + edt[i]=action(str) + end end + end end function helpers.recursetext(collected,action,recursive) - if recursive then - for i=1,#collected do - recurse(collected[i],action) - end - else - for i=1,#collected do - normal(collected[i],action) - end + if recursive then + for i=1,#collected do + recurse(collected[i],action) end + else + for i=1,#collected do + normal(collected[i],action) + end + end end local specials={ - ["@rt@"]="root", - ["@pi@"]="instruction", - ["@cm@"]="comment", - ["@dt@"]="declaration", - ["@cd@"]="cdata", + ["@rt@"]="root", + ["@pi@"]="instruction", + ["@cm@"]="comment", + ["@dt@"]="declaration", + ["@cd@"]="cdata", } local function convert(x,strip,flat) - local ns=x.ns - local tg=x.tg - local at=x.at - local dt=x.dt - local node=flat and { - [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, - } or { - _namespace=ns~="" and ns or nil, - _tag=not x.special and tg or nil, - _type=specials[tg] or "_element", - } - if at then - for k,v in next,at do - node[k]=v - end - end - local n=0 - for i=1,#dt do - local di=dt[i] - if type(di)=="table" then - if flat and di.special then - else - di=convert(di,strip,flat) - if di then - n=n+1 - node[n]=di - end - end - elseif strip then - di=lpegmatch(strip,di) - if di~="" then - n=n+1 - node[n]=di - end - else - n=n+1 - node[n]=di + local ns=x.ns + local tg=x.tg + local at=x.at + local dt=x.dt + local node=flat and { + [0]=(not x.special and (ns~="" and ns..":"..tg or tg)) or nil, + } or { + _namespace=ns~="" and ns or nil, + _tag=not x.special and tg or nil, + _type=specials[tg] or "_element", + } + if at then + for k,v in next,at do + node[k]=v + end + end + local n=0 + for i=1,#dt do + local di=dt[i] + if type(di)=="table" then + if flat and di.special then + else + di=convert(di,strip,flat) + if di then + n=n+1 + node[n]=di end + end + elseif strip then + di=lpegmatch(strip,di) + if di~="" then + n=n+1 + node[n]=di + end + else + n=n+1 + node[n]=di end - if next(node) then - return node - end + end + if next(node) then + return node + end end function xml.totable(x,strip,flat) - if type(x)=="table" then - if strip then - strip=striplinepatterns[strip] - end - return convert(x,strip,flat) + if type(x)=="table" then + if strip then + strip=striplinepatterns[strip] end + return convert(x,strip,flat) + end end function xml.rename(e,namespace,name,attributes) - if type(e)~="table" or not e.tg then - return - end - if type(name)=="table" then - attributes=name - name=namespace - namespace="" - elseif type(name)~="string" then - attributes={} - name=namespace - namespace="" - end - if type(attributes)~="table" then - attributes={} - end - e.ns=namespace - e.rn=namespace - e.tg=name - e.at=attributes + if type(e)~="table" or not e.tg then + return + end + if type(name)=="table" then + attributes=name + name=namespace + namespace="" + elseif type(name)~="string" then + attributes={} + name=namespace + namespace="" + end + if type(attributes)~="table" then + attributes={} + end + e.ns=namespace + e.rn=namespace + e.tg=name + e.at=attributes end @@ -15693,14 +19267,14 @@ do -- create closure to overcome 200 locals limit package.loaded["lxml-xml"] = package.loaded["lxml-xml"] or true --- original size: 11096, stripped down to: 8243 +-- original size: 11096, stripped down to: 7702 if not modules then modules={} end modules ['lxml-xml']={ - version=1.001, - comment="this module is the basis for the lxml-* ones", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="this module is the basis for the lxml-* ones", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local tonumber,next=tonumber,next local concat=table.concat @@ -15712,241 +19286,241 @@ local xmltostring=xml.tostring local xmlserialize=xml.serialize local xmlcollected=xml.collected local xmlnewhandlers=xml.newhandlers -local reparsedentity=xml.reparsedentitylpeg +local reparsedentity=xml.reparsedentitylpeg local unescapedentity=xml.unescapedentitylpeg local parsedentity=reparsedentity local function first(collected) - return collected and collected[1] + return collected and collected[1] end local function last(collected) - return collected and collected[#collected] + return collected and collected[#collected] end local function all(collected) - return collected + return collected end local reverse=table.reversed local function attribute(collected,name) - if collected and #collected>0 then - local at=collected[1].at - return at and at[name] - end + if collected and #collected>0 then + local at=collected[1].at + return at and at[name] + end end local function att(id,name) - local at=id.at - return at and at[name] + local at=id.at + return at and at[name] end local function count(collected) - return collected and #collected or 0 + return collected and #collected or 0 end local function position(collected,n) - if not collected then - return 0 - end - local nc=#collected - if nc==0 then - return 0 - end - n=tonumber(n) or 0 - if n<0 then - return collected[nc+n+1] - elseif n>0 then - return collected[n] - else - return collected[1].mi or 0 - end + if not collected then + return 0 + end + local nc=#collected + if nc==0 then + return 0 + end + n=tonumber(n) or 0 + if n<0 then + return collected[nc+n+1] + elseif n>0 then + return collected[n] + else + return collected[1].mi or 0 + end end local function match(collected) - return collected and #collected>0 and collected[1].mi or 0 + return collected and #collected>0 and collected[1].mi or 0 end local function index(collected) - return collected and #collected>0 and collected[1].ni or 0 + return collected and #collected>0 and collected[1].ni or 0 end local function attributes(collected,arguments) - if collected and #collected>0 then - local at=collected[1].at - if arguments then - return at[arguments] - elseif next(at) then - return at - end + if collected and #collected>0 then + local at=collected[1].at + if arguments then + return at[arguments] + elseif next(at) then + return at end + end end local function chainattribute(collected,arguments) - if collected and #collected>0 then - local e=collected[1] - while e do - local at=e.at - if at then - local a=at[arguments] - if a then - return a - end - else - break - end - e=e.__p__ + if collected and #collected>0 then + local e=collected[1] + while e do + local at=e.at + if at then + local a=at[arguments] + if a then + return a end + else + break + end + e=e.__p__ end - return "" + end + return "" end local function raw(collected) - if collected and #collected>0 then - local e=collected[1] or collected - return e and xmltostring(e) or "" - else - return "" - end + if collected and #collected>0 then + local e=collected[1] or collected + return e and xmltostring(e) or "" + else + return "" + end end local xmltexthandler=xmlnewhandlers { - name="string", - initialize=function() - result={} - return result - end, - finalize=function() - return concat(result) - end, - handle=function(...) - result[#result+1]=concat {... } - end, - escape=false, + name="string", + initialize=function() + result={} + return result + end, + finalize=function() + return concat(result) + end, + handle=function(...) + result[#result+1]=concat {... } + end, + escape=false, } local function xmltotext(root) - local dt=root.dt - if not dt then - return "" - end - local nt=#dt - if nt==0 then - return "" - elseif nt==1 and type(dt[1])=="string" then - return dt[1] - else - return xmlserialize(root,xmltexthandler) or "" - end + local dt=root.dt + if not dt then + return "" + end + local nt=#dt + if nt==0 then + return "" + elseif nt==1 and type(dt[1])=="string" then + return dt[1] + else + return xmlserialize(root,xmltexthandler) or "" + end end function xml.serializetotext(root) - return root and xmlserialize(root,xmltexthandler) or "" + return root and xmlserialize(root,xmltexthandler) or "" end local function text(collected) - if collected then - local e=collected[1] or collected - return e and xmltotext(e) or "" - else - return "" - end + if collected then + local e=collected[1] or collected + return e and xmltotext(e) or "" + else + return "" + end end local function texts(collected) - if not collected then - return {} - end - local nc=#collected - if nc==0 then - return {} - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - if e and e.dt then - n=n+1 - t[n]=e.dt - end - end - return t + if not collected then + return {} + end + local nc=#collected + if nc==0 then + return {} + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + if e and e.dt then + n=n+1 + t[n]=e.dt + end + end + return t end local function tag(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - return c and c.tg + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + return c and c.tg end local function name(collected,n) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local c - if n==0 or not n then - c=collected[1] - elseif n>1 then - c=collected[n] - else - c=collected[nc-n+1] - end - if not c then - elseif c.ns=="" then - return c.tg - else - return c.ns..":"..c.tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local c + if n==0 or not n then + c=collected[1] + elseif n>1 then + c=collected[n] + else + c=collected[nc-n+1] + end + if not c then + elseif c.ns=="" then + return c.tg + else + return c.ns..":"..c.tg + end end local function tags(collected,nonamespace) - if not collected then - return - end - local nc=#collected - if nc==0 then - return - end - local t,n={},0 - for c=1,nc do - local e=collected[c] - local ns,tg=e.ns,e.tg - n=n+1 - if nonamespace or ns=="" then - t[n]=tg - else - t[n]=ns..":"..tg - end + if not collected then + return + end + local nc=#collected + if nc==0 then + return + end + local t,n={},0 + for c=1,nc do + local e=collected[c] + local ns,tg=e.ns,e.tg + n=n+1 + if nonamespace or ns=="" then + t[n]=tg + else + t[n]=ns..":"..tg end - return t + end + return t end local function empty(collected,spacesonly) - if not collected then - return true - end - local nc=#collected - if nc==0 then - return true - end - for c=1,nc do - local e=collected[c] - if e then - local edt=e.dt - if edt then - local n=#edt - if n==1 then - local edk=edt[1] - local typ=type(edk) - if typ=="table" then - return false - elseif edk~="" then - return false - elseif spacesonly and not find(edk,"%S") then - return false - end - elseif n>1 then - return false - end - end + if not collected then + return true + end + local nc=#collected + if nc==0 then + return true + end + for c=1,nc do + local e=collected[c] + if e then + local edt=e.dt + if edt then + local n=#edt + if n==1 then + local edk=edt[1] + local typ=type(edk) + if typ=="table" then + return false + elseif edk~="" then + return false + elseif spacesonly and not find(edk,"%S") then + return false + end + elseif n>1 then + return false end + end end - return true + end + return true end finalizers.first=first finalizers.last=last @@ -15969,124 +19543,124 @@ finalizers.name=name finalizers.tags=tags finalizers.empty=empty function xml.first(id,pattern) - return first(xmlfilter(id,pattern)) + return first(xmlfilter(id,pattern)) end function xml.last(id,pattern) - return last(xmlfilter(id,pattern)) + return last(xmlfilter(id,pattern)) end function xml.count(id,pattern) - return count(xmlfilter(id,pattern)) + return count(xmlfilter(id,pattern)) end function xml.attribute(id,pattern,a,default) - return attribute(xmlfilter(id,pattern),a,default) + return attribute(xmlfilter(id,pattern),a,default) end function xml.raw(id,pattern) - if pattern then - return raw(xmlfilter(id,pattern)) - else - return raw(id) - end + if pattern then + return raw(xmlfilter(id,pattern)) + else + return raw(id) + end end function xml.text(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - return collected and #collected>0 and xmltotext(collected[1]) or "" - elseif id then - return xmltotext(id) or "" - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + return collected and #collected>0 and xmltotext(collected[1]) or "" + elseif id then + return xmltotext(id) or "" + else + return "" + end end function xml.pure(id,pattern) - if pattern then - local collected=xmlfilter(id,pattern) - if collected and #collected>0 then - parsedentity=unescapedentity - local s=collected and #collected>0 and xmltotext(collected[1]) or "" - parsedentity=reparsedentity - return s - else - return "" - end + if pattern then + local collected=xmlfilter(id,pattern) + if collected and #collected>0 then + parsedentity=unescapedentity + local s=collected and #collected>0 and xmltotext(collected[1]) or "" + parsedentity=reparsedentity + return s else - parsedentity=unescapedentity - local s=xmltotext(id) or "" - parsedentity=reparsedentity - return s + return "" end + else + parsedentity=unescapedentity + local s=xmltotext(id) or "" + parsedentity=reparsedentity + return s + end end xml.content=text function xml.position(id,pattern,n) - return position(xmlfilter(id,pattern),n) + return position(xmlfilter(id,pattern),n) end function xml.match(id,pattern) - return match(xmlfilter(id,pattern)) + return match(xmlfilter(id,pattern)) end function xml.empty(id,pattern,spacesonly) - return empty(xmlfilter(id,pattern),spacesonly) + return empty(xmlfilter(id,pattern),spacesonly) end xml.all=xml.filter xml.index=xml.position xml.found=xml.filter local function totable(x) - local t={} - for e in xmlcollected(x[1] or x,"/*") do - t[e.tg]=xmltostring(e.dt) or "" - end - return next(t) and t or nil + local t={} + for e in xmlcollected(x[1] or x,"/*") do + t[e.tg]=xmltostring(e.dt) or "" + end + return next(t) and t or nil end xml.table=totable finalizers.table=totable local function textonly(e,t) - if e then - local edt=e.dt - if edt then - for i=1,#edt do - local e=edt[i] - if type(e)=="table" then - textonly(e,t) - else - t[#t+1]=e - end - end + if e then + local edt=e.dt + if edt then + for i=1,#edt do + local e=edt[i] + if type(e)=="table" then + textonly(e,t) + else + t[#t+1]=e end + end end - return t + end + return t end function xml.textonly(e) - return concat(textonly(e,{})) + return concat(textonly(e,{})) end function finalizers.lowerall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=lower(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[lower(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=lower(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[lower(k)]=v end + e.at=t + end end + end end function finalizers.upperall(collected) - for c=1,#collected do - local e=collected[c] - if not e.special then - e.tg=upper(e.tg) - local eat=e.at - if eat then - local t={} - for k,v in next,eat do - t[upper(k)]=v - end - e.at=t - end + for c=1,#collected do + local e=collected[c] + if not e.special then + e.tg=upper(e.tg) + local eat=e.at + if eat then + local t={} + for k,v in next,eat do + t[upper(k)]=v end + e.at=t + end end + end end @@ -16096,14 +19670,14 @@ do -- create closure to overcome 200 locals limit package.loaded["trac-xml"] = package.loaded["trac-xml"] or true --- original size: 6407, stripped down to: 4965 +-- original size: 6407, stripped down to: 4640 if not modules then modules={} end modules ['trac-xml']={ - version=1.001, - comment="companion to trac-log.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to trac-log.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local formatters=string.formatters local reporters=logs.reporters @@ -16112,152 +19686,152 @@ local xmlcollected=xml.collected local xmltext=xml.text local xmlfirst=xml.first local function showhelp(specification,...) - local root=xml.convert(specification.helpinfo or "") - if not root then - return - end - local xs=xml.gethandlers("string") - xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) - xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) - local wantedcategories=select("#",...)==0 and true or table.tohash {... } - local nofcategories=xml.count(root,"/application/flags/category") - local report=specification.report - for category in xmlcollected(root,"/application/flags/category") do - local categoryname=category.at.name or "" - if wantedcategories==true or wantedcategories[categoryname] then - if nofcategories>1 then - report("%s options:",categoryname) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for flag in xmlcollected(subcategory,"/flag") do - local name=flag.at.name - local value=flag.at.value - local short=xmltext(xmlfirst(flag,"/short")) - if value then - report("--%-20s %s",formatters["%s=%s"](name,value),short) - else - report("--%-20s %s",name,short) - end - end - report() - end - end - end - for category in xmlcollected(root,"/application/examples/category") do - local title=xmltext(xmlfirst(category,"/title")) - if title and title~="" then - report() - report(title) - report() - end - for subcategory in xmlcollected(category,"/subcategory") do - for example in xmlcollected(subcategory,"/example") do - local command=xmltext(xmlfirst(example,"/command")) - local comment=xmltext(xmlfirst(example,"/comment")) - report(command) - end - report() - end - end - for comment in xmlcollected(root,"/application/comments/comment") do - local comment=xmltext(comment) + local root=xml.convert(specification.helpinfo or "") + if not root then + return + end + local xs=xml.gethandlers("string") + xml.sethandlersfunction(xs,"short",function(e,handler) xmlserialize(e.dt,handler) end) + xml.sethandlersfunction(xs,"ref",function(e,handler) handler.handle("--"..e.at.name) end) + local wantedcategories=select("#",...)==0 and true or table.tohash {... } + local nofcategories=xml.count(root,"/application/flags/category") + local report=specification.report + for category in xmlcollected(root,"/application/flags/category") do + local categoryname=category.at.name or "" + if wantedcategories==true or wantedcategories[categoryname] then + if nofcategories>1 then + report("%s options:",categoryname) report() - report(comment) + end + for subcategory in xmlcollected(category,"/subcategory") do + for flag in xmlcollected(subcategory,"/flag") do + local name=flag.at.name + local value=flag.at.value + local short=xmltext(xmlfirst(flag,"/short")) + if value then + report("--%-20s %s",formatters["%s=%s"](name,value),short) + else + report("--%-20s %s",name,short) + end + end report() + end + end + end + for category in xmlcollected(root,"/application/examples/category") do + local title=xmltext(xmlfirst(category,"/title")) + if title and title~="" then + report() + report(title) + report() + end + for subcategory in xmlcollected(category,"/subcategory") do + for example in xmlcollected(subcategory,"/example") do + local command=xmltext(xmlfirst(example,"/command")) + local comment=xmltext(xmlfirst(example,"/comment")) + report(command) + end + report() end + end + for comment in xmlcollected(root,"/application/comments/comment") do + local comment=xmltext(comment) + report() + report(comment) + report() + end end local reporthelp=reporters.help local exporthelp=reporters.export local function xmlfound(t) - local helpinfo=t.helpinfo - if type(helpinfo)=="table" then - return false + local helpinfo=t.helpinfo + if type(helpinfo)=="table" then + return false + end + if type(helpinfo)~="string" then + helpinfo="Warning: no helpinfo found." + t.helpinfo=helpinfo + return false + end + if string.find(helpinfo,".xml$") then + local ownscript=environment.ownscript + local helpdata=false + if ownscript then + local helpfile=file.join(file.pathpart(ownscript),helpinfo) + helpdata=io.loaddata(helpfile) + if helpdata=="" then + helpdata=false + end end - if type(helpinfo)~="string" then - helpinfo="Warning: no helpinfo found." - t.helpinfo=helpinfo - return false + if not helpdata then + local helpfile=resolvers.findfile(helpinfo,"tex") + helpdata=helpfile and io.loaddata(helpfile) end - if string.find(helpinfo,".xml$") then - local ownscript=environment.ownscript - local helpdata=false - if ownscript then - local helpfile=file.join(file.pathpart(ownscript),helpinfo) - helpdata=io.loaddata(helpfile) - if helpdata=="" then - helpdata=false - end - end - if not helpdata then - local helpfile=resolvers.findfile(helpinfo,"tex") - helpdata=helpfile and io.loaddata(helpfile) - end - if helpdata and helpdata~="" then - helpinfo=helpdata - else - helpinfo=formatters["Warning: help file %a is not found."](helpinfo) - end + if helpdata and helpdata~="" then + helpinfo=helpdata + else + helpinfo=formatters["Warning: help file %a is not found."](helpinfo) end - t.helpinfo=helpinfo - return string.find(t.helpinfo,"^<%?xml") and true or false + end + t.helpinfo=helpinfo + return string.find(t.helpinfo,"^<%?xml") and true or false end function reporters.help(t,...) - if xmlfound(t) then - showhelp(t,...) - else - reporthelp(t,...) - end + if xmlfound(t) then + showhelp(t,...) + else + reporthelp(t,...) + end end function reporters.export(t,methods,filename) - if not xmlfound(t) then - return exporthelp(t) - end - if not methods or methods=="" then - methods=environment.arguments["exporthelp"] - end - if not filename or filename=="" then - filename=environment.files[1] - end - dofile(resolvers.findfile("trac-exp.lua","tex")) - local exporters=logs.exporters - if not exporters or not methods then - return exporthelp(t) - end - if methods=="all" then - methods=table.keys(exporters) - elseif type(methods)=="string" then - methods=utilities.parsers.settings_to_array(methods) - else - return exporthelp(t) - end - if type(filename)~="string" or filename=="" then - filename=false - elseif file.pathpart(filename)=="" then - t.report("export file %a will not be saved on the current path (safeguard)",filename) - return - end - for i=1,#methods do - local method=methods[i] - local exporter=exporters[method] - if exporter then - local result=exporter(t,method) - if result and result~="" then - if filename then - local fullname=file.replacesuffix(filename,method) - t.report("saving export in %a",fullname) - dir.mkdirs(file.pathpart(fullname)) - io.savedata(fullname,result) - else - reporters.lines(t,result) - end - else - t.report("no output from exporter %a",method) - end + if not xmlfound(t) then + return exporthelp(t) + end + if not methods or methods=="" then + methods=environment.arguments["exporthelp"] + end + if not filename or filename=="" then + filename=environment.files[1] + end + dofile(resolvers.findfile("trac-exp.lua","tex")) + local exporters=logs.exporters + if not exporters or not methods then + return exporthelp(t) + end + if methods=="all" then + methods=table.keys(exporters) + elseif type(methods)=="string" then + methods=utilities.parsers.settings_to_array(methods) + else + return exporthelp(t) + end + if type(filename)~="string" or filename=="" then + filename=false + elseif file.pathpart(filename)=="" then + t.report("export file %a will not be saved on the current path (safeguard)",filename) + return + end + for i=1,#methods do + local method=methods[i] + local exporter=exporters[method] + if exporter then + local result=exporter(t,method) + if result and result~="" then + if filename then + local fullname=file.replacesuffix(filename,method) + t.report("saving export in %a",fullname) + dir.mkdirs(file.pathpart(fullname)) + io.savedata(fullname,result) else - t.report("unknown exporter %a",method) + reporters.lines(t,result) end + else + t.report("no output from exporter %a",method) + end + else + t.report("unknown exporter %a",method) end + end end @@ -16267,149 +19841,149 @@ do -- create closure to overcome 200 locals limit package.loaded["data-ini"] = package.loaded["data-ini"] or true --- original size: 11099, stripped down to: 7516 +-- original size: 11099, stripped down to: 7152 if not modules then modules={} end modules ['data-ini']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local next,type,getmetatable,rawset=next,type,getmetatable,rawset local gsub,find,gmatch,char=string.gsub,string.find,string.gmatch,string.char local filedirname,filebasename,filejoin=file.dirname,file.basename,file.join local ostype,osname,osuname,ossetenv,osgetenv=os.type,os.name,os.uname,os.setenv,os.getenv local P,S,R,C,Cs,Cc,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers.register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) local report_initialization=logs.reporter("resolvers","initialization") resolvers=resolvers or {} local resolvers=resolvers texconfig.kpse_init=false texconfig.shell_escape='t' if not (environment and environment.default_texmfcnf) and kpse and kpse.default_texmfcnf then - local default_texmfcnf=kpse.default_texmfcnf() - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") - default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") - default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") - environment.default_texmfcnf=default_texmfcnf + local default_texmfcnf=kpse.default_texmfcnf() + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOLOC","selfautoloc:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTODIR","selfautodir:") + default_texmfcnf=gsub(default_texmfcnf,"$SELFAUTOPARENT","selfautoparent:") + default_texmfcnf=gsub(default_texmfcnf,"$HOME","home:") + environment.default_texmfcnf=default_texmfcnf end kpse={ original=kpse } setmetatable(kpse,{ - __index=function(kp,name) - report_initialization("fatal error: kpse library is accessed (key: %s)",name) - os.exit() - end + __index=function(kp,name) + report_initialization("fatal error: kpse library is accessed (key: %s)",name) + os.exit() + end } ) do - local osfontdir=osgetenv("OSFONTDIR") - if osfontdir and osfontdir~="" then - elseif osname=="windows" then - ossetenv("OSFONTDIR","c:/windows/fonts//") - elseif osname=="macosx" then - ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") - end + local osfontdir=osgetenv("OSFONTDIR") + if osfontdir and osfontdir~="" then + elseif osname=="windows" then + ossetenv("OSFONTDIR","c:/windows/fonts//") + elseif osname=="macosx" then + ossetenv("OSFONTDIR","$HOME/Library/Fonts//;/Library/Fonts//;/System/Library/Fonts//") + end end do - local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' - if not homedir or homedir=="" then - homedir=char(127) - end - homedir=file.collapsepath(homedir) - ossetenv("HOME",homedir) - ossetenv("USERPROFILE",homedir) - environment.homedir=homedir + local homedir=osgetenv(ostype=="windows" and 'USERPROFILE' or 'HOME') or '' + if not homedir or homedir=="" then + homedir=char(127) + end + homedir=file.collapsepath(homedir) + ossetenv("HOME",homedir) + ossetenv("USERPROFILE",homedir) + environment.homedir=homedir end do - local args=environment.originalarguments or arg - if not environment.ownmain then - environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" - end - local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" - local ownpath=environment.ownpath or os.selfdir - ownbin=file.collapsepath(ownbin) - ownpath=file.collapsepath(ownpath) - if not ownpath or ownpath=="" or ownpath=="unset" then - ownpath=args[-1] or arg[-1] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - if not ownpath or ownpath=="" then - ownpath=args[-0] or arg[-0] - ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) - end - local binary=ownbin - if not ownpath or ownpath=="" then - ownpath=ownpath and filedirname(binary) - end - if not ownpath or ownpath=="" then - if os.binsuffix~="" then - binary=file.replacesuffix(binary,os.binsuffix) - end - local path=osgetenv("PATH") - if path then - for p in gmatch(path,"[^"..io.pathseparator.."]+") do - local b=filejoin(p,binary) - if lfs.isfile(b) then - local olddir=lfs.currentdir() - if lfs.chdir(p) then - local pp=lfs.currentdir() - if trace_locating and p~=pp then - report_initialization("following symlink %a to %a",p,pp) - end - ownpath=pp - lfs.chdir(olddir) - else - if trace_locating then - report_initialization("unable to check path %a",p) - end - ownpath=p - end - break - end - end + local args=environment.originalarguments or arg + if not environment.ownmain then + environment.ownmain=status and string.match(string.lower(status.banner),"this is ([%a]+)") or "luatex" + end + local ownbin=environment.ownbin or args[-2] or arg[-2] or args[-1] or arg[-1] or arg[0] or "luatex" + local ownpath=environment.ownpath or os.selfdir + ownbin=file.collapsepath(ownbin) + ownpath=file.collapsepath(ownpath) + if not ownpath or ownpath=="" or ownpath=="unset" then + ownpath=args[-1] or arg[-1] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + if not ownpath or ownpath=="" then + ownpath=args[-0] or arg[-0] + ownpath=ownpath and filedirname(gsub(ownpath,"\\","/")) + end + local binary=ownbin + if not ownpath or ownpath=="" then + ownpath=ownpath and filedirname(binary) + end + if not ownpath or ownpath=="" then + if os.binsuffix~="" then + binary=file.replacesuffix(binary,os.binsuffix) + end + local path=osgetenv("PATH") + if path then + for p in gmatch(path,"[^"..io.pathseparator.."]+") do + local b=filejoin(p,binary) + if lfs.isfile(b) then + local olddir=lfs.currentdir() + if lfs.chdir(p) then + local pp=lfs.currentdir() + if trace_locating and p~=pp then + report_initialization("following symlink %a to %a",p,pp) + end + ownpath=pp + lfs.chdir(olddir) + else + if trace_locating then + report_initialization("unable to check path %a",p) + end + ownpath=p end + break + end end - if not ownpath or ownpath=="" then - ownpath="." - report_initialization("forcing fallback to ownpath %a",ownpath) - elseif trace_locating then - report_initialization("using ownpath %a",ownpath) - end + end end - environment.ownbin=ownbin - environment.ownpath=ownpath + if not ownpath or ownpath=="" then + ownpath="." + report_initialization("forcing fallback to ownpath %a",ownpath) + elseif trace_locating then + report_initialization("using ownpath %a",ownpath) + end + end + environment.ownbin=ownbin + environment.ownpath=ownpath end resolvers.ownpath=environment.ownpath function resolvers.getownpath() - return environment.ownpath + return environment.ownpath end do - local ownpath=environment.ownpath or dir.current() - if ownpath then - ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) - ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) - ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) - else - report_initialization("error: unable to locate ownpath") - os.exit() - end -end -local texos=environment.texos or osgetenv("TEXOS") + local ownpath=environment.ownpath or dir.current() + if ownpath then + ossetenv('SELFAUTOLOC',file.collapsepath(ownpath)) + ossetenv('SELFAUTODIR',file.collapsepath(ownpath.."/..")) + ossetenv('SELFAUTOPARENT',file.collapsepath(ownpath.."/../..")) + else + report_initialization("error: unable to locate ownpath") + os.exit() + end +end +local texos=environment.texos or osgetenv("TEXOS") local texmfos=environment.texmfos or osgetenv('SELFAUTODIR') if not texos or texos=="" then - texos=file.basename(texmfos) + texos=file.basename(texmfos) end ossetenv('TEXMFOS',texmfos) -ossetenv('TEXOS',texos) -ossetenv('SELFAUTOSYSTEM',os.platform) +ossetenv('TEXOS',texos) +ossetenv('SELFAUTOSYSTEM',os.platform) environment.texos=texos environment.texmfos=texmfos local texroot=environment.texroot or osgetenv("TEXROOT") if not texroot or texroot=="" then - texroot=osgetenv('SELFAUTOPARENT') - ossetenv('TEXROOT',texroot) + texroot=osgetenv('SELFAUTOPARENT') + ossetenv('TEXROOT',texroot) end environment.texroot=file.collapsepath(texroot) local prefixes=utilities.storage.allocate() @@ -16418,30 +19992,30 @@ local resolved={} local abstract={} local dynamic={} function resolvers.resetresolve(str) - resolved,abstract={},{} + resolved,abstract={},{} end function resolvers.allprefixes(separator) - local all=table.sortedkeys(prefixes) - if separator then - for i=1,#all do - all[i]=all[i]..":" - end + local all=table.sortedkeys(prefixes) + if separator then + for i=1,#all do + all[i]=all[i]..":" end - return all + end + return all end local function _resolve_(method,target) - local action=prefixes[method] - if action then - return action(target) - else - return method..":"..target - end + local action=prefixes[method] + if action then + return action(target) + else + return method..":"..target + end end function resolvers.unresolve(str) - return abstract[str] or str + return abstract[str] or str end function resolvers.setdynamic(str) - dynamic[str]=true + dynamic[str]=true end local pattern=Cs((C(R("az")^2)*P(":")*C((1-S(" \"\';,"))^1)/_resolve_+P(1))^0) local prefix=C(R("az")^2)*P(":") @@ -16450,65 +20024,65 @@ local notarget=(#S(";,")+P(-1))*Cc("") local p_resolve=Cs(((prefix*(target+notarget))/_resolve_+P(1))^0) local p_simple=prefix*P(-1) local function resolve(str) - if type(str)=="table" then - local res={} - for i=1,#str do - res[i]=resolve(str[i]) - end - return res - end - local res=resolved[str] - if res then - return res + if type(str)=="table" then + local res={} + for i=1,#str do + res[i]=resolve(str[i]) end - local simple=lpegmatch(p_simple,str) - local action=prefixes[simple] - if action then - local res=action(res) - if not dynamic[simple] then - resolved[simple]=res - abstract[res]=simple - end - return res + return res + end + local res=resolved[str] + if res then + return res + end + local simple=lpegmatch(p_simple,str) + local action=prefixes[simple] + if action then + local res=action(res) + if not dynamic[simple] then + resolved[simple]=res + abstract[res]=simple end - res=lpegmatch(p_resolve,str) - resolved[str]=res - abstract[res]=str return res + end + res=lpegmatch(p_resolve,str) + resolved[str]=res + abstract[res]=str + return res end resolvers.resolve=resolve if type(osuname)=="function" then - for k,v in next,osuname() do - if not prefixes[k] then - prefixes[k]=function() return v end - end + for k,v in next,osuname() do + if not prefixes[k] then + prefixes[k]=function() return v end end + end end if ostype=="unix" then - local pattern - local function makepattern(t,k,v) - if t then - rawset(t,k,v) - end - local colon=P(":") - for k,v in table.sortedpairs(prefixes) do - if p then - p=P(k)+p - else - p=P(k) - end - end - pattern=Cs((p*colon+colon/";"+P(1))^0) - end - makepattern() - table.setmetatablenewindex(prefixes,makepattern) - function resolvers.repath(str) - return lpegmatch(pattern,str) + local pattern + local function makepattern(t,k,v) + if t then + rawset(t,k,v) + end + local colon=P(":") + for k,v in table.sortedpairs(prefixes) do + if p then + p=P(k)+p + else + p=P(k) + end end + pattern=Cs((p*colon+colon/";"+P(1))^0) + end + makepattern() + table.setmetatablenewindex(prefixes,makepattern) + function resolvers.repath(str) + return lpegmatch(pattern,str) + end else - function resolvers.repath(str) - return str - end + function resolvers.repath(str) + return str + end end @@ -16518,14 +20092,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-exp"] = package.loaded["data-exp"] or true --- original size: 18105, stripped down to: 11207 +-- original size: 18105, stripped down to: 10389 if not modules then modules={} end modules ['data-exp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } 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 @@ -16535,21 +20109,21 @@ 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 isdir=lfs.isdir local collapsepath,joinpath,basename=file.collapsepath,file.join,file.basename -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_expansions=false trackers.register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_globbing=true trackers.register("resolvers.globbing",function(v) trace_globbing=v end) local report_expansions=logs.reporter("resolvers","expansions") local report_globbing=logs.reporter("resolvers","globbing") local resolvers=resolvers local resolveprefix=resolvers.resolve local function f_both(a,b) - local t,n={},0 - for sb in gmatch(b,"[^,]+") do - for sa in gmatch(a,"[^,]+") do - n=n+1;t[n]=sa..sb - end + local t,n={},0 + for sb in gmatch(b,"[^,]+") do + for sa in gmatch(a,"[^,]+") do + n=n+1;t[n]=sa..sb end - return concat(t,",") + end + return concat(t,",") end local comma=P(",") local nocomma=(1-comma)^1 @@ -16559,7 +20133,7 @@ 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 function f_both (a,b) return lpegmatch(both,b,1,a) end local left=P("{") local right=P("}") local var=P((1-S("{}" ))^0) @@ -16572,141 +20146,141 @@ local l_rest=Cs((left*var*(left/"")*var*(right/"")*var*right+other )^0 ) local stripper_1=lpeg.stripper ("{}@") local replacer_1=lpeg.replacer { { ",}",",@}" },{ "{,","{@," },} local function splitpathexpr(str,newlist,validate) - if trace_expansions then - report_expansions("expanding variable %a",str) - end - local t,ok,done=newlist or {},false,false - local n=#t - str=lpegmatch(replacer_1,str) + if trace_expansions then + report_expansions("expanding variable %a",str) + end + local t,ok,done=newlist or {},false,false + local n=#t + str=lpegmatch(replacer_1,str) + repeat + local old=str repeat - local old=str - repeat - local old=str - str=lpegmatch(l_first,str) - until old==str - repeat - local old=str - str=lpegmatch(l_second,str) - until old==str - repeat - local old=str - str=lpegmatch(l_both,str) - until old==str - repeat - local old=str - str=lpegmatch(l_rest,str) - until old==str - until old==str - str=lpegmatch(stripper_1,str) - if validate then - for s in gmatch(str,"[^,]+") do - s=validate(s) - if s then - n=n+1 - t[n]=s - end - end - else - for s in gmatch(str,"[^,]+") do - n=n+1 - t[n]=s - end + local old=str + str=lpegmatch(l_first,str) + until old==str + repeat + local old=str + str=lpegmatch(l_second,str) + until old==str + repeat + local old=str + str=lpegmatch(l_both,str) + until old==str + repeat + local old=str + str=lpegmatch(l_rest,str) + until old==str + until old==str + str=lpegmatch(stripper_1,str) + if validate then + for s in gmatch(str,"[^,]+") do + s=validate(s) + if s then + n=n+1 + t[n]=s + end end - if trace_expansions then - for k=1,#t do - report_expansions("% 4i: %s",k,t[k]) - end + else + for s in gmatch(str,"[^,]+") do + n=n+1 + t[n]=s end - return t + end + if trace_expansions then + for k=1,#t do + report_expansions("% 4i: %s",k,t[k]) + end + end + return t end local function validate(s) - s=collapsepath(s) - return s~="" and not find(s,"^!*unset/*$") and s + s=collapsepath(s) + return s~="" and not find(s,"^!*unset/*$") and s end resolvers.validatedpath=validate function resolvers.expandedpathfromlist(pathlist) - local newlist={} - for k=1,#pathlist do - splitpathexpr(pathlist[k],newlist,validate) - end - return newlist + local newlist={} + for k=1,#pathlist do + splitpathexpr(pathlist[k],newlist,validate) + end + return newlist end local usedhomedir=nil -local donegation=(P("!")/"" )^0 +local donegation=(P("!")/"" )^0 local doslashes=(P("\\")/"/"+1)^0 local function expandedhome() - if not usedhomedir then - usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") - if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then - if trace_expansions then - report_expansions("no home dir set, ignoring dependent path using current path") - end - usedhomedir="." - end + if not usedhomedir then + usedhomedir=lpegmatch(Cs(donegation*doslashes),environment.homedir or "") + if usedhomedir=="~" or usedhomedir=="" or not isdir(usedhomedir) then + if trace_expansions then + report_expansions("no home dir set, ignoring dependent path using current path") + end + usedhomedir="." end - return usedhomedir + end + return usedhomedir end local dohome=((P("~")+P("$HOME")+P("%HOME%"))/expandedhome)^0 local cleanup=Cs(donegation*dohome*doslashes) resolvers.cleanpath=function(str) - return str and lpegmatch(cleanup,str) or "" + return str and lpegmatch(cleanup,str) or "" end local expandhome=P("~")/"$HOME" local dodouble=P('"')/""*(expandhome+(1-P('"')))^0*P('"')/"" local dosingle=P("'")/""*(expandhome+(1-P("'")))^0*P("'")/"" -local dostring=(expandhome+1 )^0 +local dostring=(expandhome+1 )^0 local stripper=Cs( - lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer + lpegpatterns.unspacer*(dosingle+dodouble+dostring)*lpegpatterns.unspacer ) function resolvers.checkedvariable(str) - return type(str)=="string" and lpegmatch(stripper,str) or str + return type(str)=="string" and lpegmatch(stripper,str) or str end local cache={} local splitter=lpeg.tsplitat(";") local backslashswapper=lpeg.replacer("\\","/") local function splitconfigurationpath(str) - if str then - local found=cache[str] - if not found then - if str=="" then - found={} - else - local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) - found={} - local noffound=0 - for i=1,#split do - local s=split[i] - if not find(s,"^{*unset}*") then - noffound=noffound+1 - found[noffound]=s - end - end - if trace_expansions then - report_expansions("splitting path specification %a",str) - for k=1,noffound do - report_expansions("% 4i: %s",k,found[k]) - end - end - cache[str]=found - end + if str then + local found=cache[str] + if not found then + if str=="" then + found={} + else + local split=lpegmatch(splitter,lpegmatch(backslashswapper,str)) + found={} + local noffound=0 + for i=1,#split do + local s=split[i] + if not find(s,"^{*unset}*") then + noffound=noffound+1 + found[noffound]=s + end end - return found + if trace_expansions then + report_expansions("splitting path specification %a",str) + for k=1,noffound do + report_expansions("% 4i: %s",k,found[k]) + end + end + cache[str]=found + end end + return found + end end resolvers.splitconfigurationpath=splitconfigurationpath function resolvers.splitpath(str) - if type(str)=='table' then - return str - else - return splitconfigurationpath(str) - end + if type(str)=='table' then + return str + else + return splitconfigurationpath(str) + end end function resolvers.joinpath(str) - if type(str)=='table' then - return joinpath(str) - else - return str - end + if type(str)=='table' then + return joinpath(str) + else + return str + end end local attributes,directory=lfs.attributes,lfs.dir local weird=P(".")^1+lpeg.anywhere(S("~`!#$%^&*()={}[]:;\"\'||<>,?\n\r\t")) @@ -16719,201 +20293,201 @@ local fullcache={} local nofsharedscans=0 local addcasecraptoo=true local function scan(files,remap,spec,path,n,m,r,onlyone,tolerant) - local full=path=="" and spec or (spec..path..'/') - local dirlist={} - local nofdirs=0 - local pattern=tolerant and lessweird or weird - local filelist={} - local noffiles=0 - for name in directory(full) do - if not lpegmatch(pattern,name) then - local mode=attributes(full..name,"mode") - if mode=="file" then - n=n+1 - noffiles=noffiles+1 - filelist[noffiles]=name - elseif mode=="directory" then - m=m+1 - nofdirs=nofdirs+1 - if path~="" then - dirlist[nofdirs]=path.."/"..name - else - dirlist[nofdirs]=name - end - end + local full=path=="" and spec or (spec..path..'/') + local dirlist={} + local nofdirs=0 + local pattern=tolerant and lessweird or weird + local filelist={} + local noffiles=0 + for name in directory(full) do + if not lpegmatch(pattern,name) then + local mode=attributes(full..name,"mode") + if mode=="file" then + n=n+1 + noffiles=noffiles+1 + filelist[noffiles]=name + elseif mode=="directory" then + m=m+1 + nofdirs=nofdirs+1 + if path~="" then + dirlist[nofdirs]=path.."/"..name + else + dirlist[nofdirs]=name end + end end - if noffiles>0 then - sort(filelist) - for i=1,noffiles do - local name=filelist[i] - local lower=lower(name) - local paths=files[lower] - if paths then - if onlyone then - else - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - if addcasecraptoo then - local paths=files[name] - if not paths then - files[name]=path - elseif type(paths)=="string" then - files[name]={ paths,path } - else - paths[#paths+1]=path - end - end - end - if type(paths)=="string" then - files[lower]={ paths,path } - else - paths[#paths+1]=path - end - end - else - files[lower]=path - if name~=lower then - local rl=remap[lower] - if not rl then - remap[lower]=name - r=r+1 - elseif trace_globbing and rl~=name then - report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) - end - end + end + if noffiles>0 then + sort(filelist) + for i=1,noffiles do + local name=filelist[i] + local lower=lower(name) + local paths=files[lower] + if paths then + if onlyone then + else + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end + if addcasecraptoo then + local paths=files[name] + if not paths then + files[name]=path + elseif type(paths)=="string" then + files[name]={ paths,path } + else + paths[#paths+1]=path + end end + end + if type(paths)=="string" then + files[lower]={ paths,path } + else + paths[#paths+1]=path + end end - end - if nofdirs>0 then - sort(dirlist) - for i=1,nofdirs do - files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) + else + files[lower]=path + if name~=lower then + local rl=remap[lower] + if not rl then + remap[lower]=name + r=r+1 + elseif trace_globbing and rl~=name then + report_globbing("confusing filename, name: %a, lower: %a, already: %a",name,lower,rl) + end end + end + end + end + if nofdirs>0 then + sort(dirlist) + for i=1,nofdirs do + files,remap,n,m,r=scan(files,remap,spec,dirlist[i],n,m,r,onlyonce,tolerant) end - scancache[sub(full,1,-2)]=files - return files,remap,n,m,r + end + scancache[sub(full,1,-2)]=files + return files,remap,n,m,r end function resolvers.scanfiles(path,branch,usecache,onlyonce,tolerant) - local realpath=resolveprefix(path) - if usecache then - local content=fullcache[realpath] - if content then - if trace_locating then - report_expansions("using cached scan of path %a, branch %a",path,branch or path) - end - nofsharedscans=nofsharedscans+1 - return content - end - end - statistics.starttiming(timer) + local realpath=resolveprefix(path) + if usecache then + local content=fullcache[realpath] + if content then + if trace_locating then + report_expansions("using cached scan of path %a, branch %a",path,branch or path) + end + nofsharedscans=nofsharedscans+1 + return content + end + end + statistics.starttiming(timer) + if trace_locating then + report_expansions("scanning path %a, branch %a",path,branch or path) + end + local content + if isdir(realpath) then + local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) + content={ + metadata={ + path=path, + files=n, + directories=m, + remappings=r, + }, + files=files, + remap=remap, + } if trace_locating then - report_expansions("scanning path %a, branch %a",path,branch or path) + report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) end - local content - if isdir(realpath) then - local files,remap,n,m,r=scan({},{},realpath..'/',"",0,0,0,onlyonce,tolerant) - content={ - metadata={ - path=path, - files=n, - directories=m, - remappings=r, - }, - files=files, - remap=remap, - } - if trace_locating then - report_expansions("%s files found on %s directories with %s uppercase remappings",n,m,r) - end - else - content={ - metadata={ - path=path, - files=0, - directories=0, - remappings=0, - }, - files={}, - remap={}, - } - if trace_locating then - report_expansions("invalid path %a",realpath) - end - end - if usecache then - scanned[#scanned+1]=realpath - fullcache[realpath]=content + else + content={ + metadata={ + path=path, + files=0, + directories=0, + remappings=0, + }, + files={}, + remap={}, + } + if trace_locating then + report_expansions("invalid path %a",realpath) end - nofscans=nofscans+1 - statistics.stoptiming(timer) - return content + end + if usecache then + scanned[#scanned+1]=realpath + fullcache[realpath]=content + end + nofscans=nofscans+1 + statistics.stoptiming(timer) + return content end function resolvers.simplescanfiles(path,branch,usecache) - return resolvers.scanfiles(path,branch,usecache,true,true) + return resolvers.scanfiles(path,branch,usecache,true,true) end function resolvers.scandata() - table.sort(scanned) - return { - n=nofscans, - shared=nofsharedscans, - time=statistics.elapsedtime(timer), - paths=scanned, - } + table.sort(scanned) + return { + n=nofscans, + shared=nofsharedscans, + time=statistics.elapsedtime(timer), + paths=scanned, + } end function resolvers.get_from_content(content,path,name) - if not content then - return - end - local files=content.files - if not files then - return - end - local remap=content.remap - if not remap then - return - end - if name then - local used=lower(name) - return path,remap[used] or used - else - local name=path - local used=lower(name) - local path=files[used] - if path then - return path,remap[used] or used - end - end + if not content then + return + end + local files=content.files + if not files then + return + end + local remap=content.remap + if not remap then + return + end + if name then + local used=lower(name) + return path,remap[used] or used + else + local name=path + local used=lower(name) + local path=files[used] + if path then + return path,remap[used] or used + end + end end local nothing=function() end function resolvers.filtered_from_content(content,pattern) - if content and type(pattern)=="string" then - local pattern=lower(pattern) - local files=content.files - local remap=content.remap - if files and remap then - local f=sortedkeys(files) - local n=#f - local i=0 - local function iterator() - while i<n do - i=i+1 - local k=f[i] - if find(k,pattern) then - return files[k],remap and remap[k] or k - end - end - end - return iterator + if content and type(pattern)=="string" then + local pattern=lower(pattern) + local files=content.files + local remap=content.remap + if files and remap then + local f=sortedkeys(files) + local n=#f + local i=0 + local function iterator() + while i<n do + i=i+1 + local k=f[i] + if find(k,pattern) then + return files[k],remap and remap[k] or k + end end + end + return iterator end - return nothing + end + return nothing end @@ -16923,14 +20497,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-env"] = package.loaded["data-env"] or true --- original size: 9360, stripped down to: 6903 +-- original size: 9360, stripped down to: 6312 if not modules then modules={} end modules ['data-env']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local lower,gsub=string.lower,string.gsub local next=next @@ -16950,255 +20524,255 @@ resolvers.suffixmap=suffixmap resolvers.usertypes=usertypes local luasuffixes=utilities.lua.suffixes local relations=allocate { - core={ - ofm={ - names={ "ofm","omega font metric","omega font metrics" }, - variable='OFMFONTS', - suffixes={ 'ofm','tfm' }, - }, - ovf={ - names={ "ovf","omega virtual font","omega virtual fonts" }, - variable='OVFFONTS', - suffixes={ 'ovf','vf' }, - }, - tfm={ - names={ "tfm","tex font metric","tex font metrics" }, - variable='TFMFONTS', - suffixes={ 'tfm' }, - }, - vf={ - names={ "vf","virtual font","virtual fonts" }, - variable='VFFONTS', - suffixes={ 'vf' }, - }, - otf={ - names={ "otf","opentype","opentype font","opentype fonts"}, - variable='OPENTYPEFONTS', - suffixes={ 'otf' }, - }, - ttf={ - names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, - variable='TTFONTS', - suffixes={ 'ttf','ttc','dfont' }, - }, - afm={ - names={ "afm","adobe font metric","adobe font metrics" }, - variable="AFMFONTS", - suffixes={ "afm" }, - }, - pfb={ - names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, - variable='T1FONTS', - suffixes={ 'pfb','pfa' }, - }, - fea={ - names={ "fea","font feature","font features","font feature file","font feature files" }, - variable='FONTFEATURES', - suffixes={ 'fea' }, - }, - cid={ - names={ "cid","cid map","cid maps","cid file","cid files" }, - variable='FONTCIDMAPS', - suffixes={ 'cid','cidmap' }, - }, - fmt={ - names={ "fmt","format","tex format" }, - variable='TEXFORMATS', - suffixes={ 'fmt' }, - }, - mem={ - names={ 'mem',"metapost format" }, - variable='MPMEMS', - suffixes={ 'mem' }, - }, - mp={ - names={ "mp" }, - variable='MPINPUTS', - suffixes={ 'mp','mpvi','mpiv','mpii' }, - usertype=true, - }, - tex={ - names={ "tex" }, - variable='TEXINPUTS', - suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, - usertype=true, - }, - icc={ - names={ "icc","icc profile","icc profiles" }, - variable='ICCPROFILES', - suffixes={ 'icc' }, - }, - texmfscripts={ - names={ "texmfscript","texmfscripts","script","scripts" }, - variable='TEXMFSCRIPTS', - suffixes={ 'lua','rb','pl','py' }, - }, - lua={ - names={ "lua" }, - variable='LUAINPUTS', - suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, - usertype=true, - }, - lib={ - names={ "lib" }, - variable='CLUAINPUTS', - suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, - }, - bib={ - names={ 'bib' }, - variable='BIBINPUTS', - suffixes={ 'bib' }, - usertype=true, - }, - bst={ - names={ 'bst' }, - variable='BSTINPUTS', - suffixes={ 'bst' }, - usertype=true, - }, - fontconfig={ - names={ 'fontconfig','fontconfig file','fontconfig files' }, - variable='FONTCONFIG_PATH', - }, - pk={ - names={ "pk" }, - variable='PKFONTS', - suffixes={ 'pk' }, - }, + core={ + ofm={ + names={ "ofm","omega font metric","omega font metrics" }, + variable='OFMFONTS', + suffixes={ 'ofm','tfm' }, + }, + ovf={ + names={ "ovf","omega virtual font","omega virtual fonts" }, + variable='OVFFONTS', + suffixes={ 'ovf','vf' }, + }, + tfm={ + names={ "tfm","tex font metric","tex font metrics" }, + variable='TFMFONTS', + suffixes={ 'tfm' }, + }, + vf={ + names={ "vf","virtual font","virtual fonts" }, + variable='VFFONTS', + suffixes={ 'vf' }, + }, + otf={ + names={ "otf","opentype","opentype font","opentype fonts"}, + variable='OPENTYPEFONTS', + suffixes={ 'otf' }, + }, + ttf={ + names={ "ttf","truetype","truetype font","truetype fonts","truetype collection","truetype collections","truetype dictionary","truetype dictionaries" }, + variable='TTFONTS', + suffixes={ 'ttf','ttc','dfont' }, + }, + afm={ + names={ "afm","adobe font metric","adobe font metrics" }, + variable="AFMFONTS", + suffixes={ "afm" }, + }, + pfb={ + names={ "pfb","type1","type 1","type1 font","type 1 font","type1 fonts","type 1 fonts" }, + variable='T1FONTS', + suffixes={ 'pfb','pfa' }, + }, + fea={ + names={ "fea","font feature","font features","font feature file","font feature files" }, + variable='FONTFEATURES', + suffixes={ 'fea' }, + }, + cid={ + names={ "cid","cid map","cid maps","cid file","cid files" }, + variable='FONTCIDMAPS', + suffixes={ 'cid','cidmap' }, + }, + fmt={ + names={ "fmt","format","tex format" }, + variable='TEXFORMATS', + suffixes={ 'fmt' }, + }, + mem={ + names={ 'mem',"metapost format" }, + variable='MPMEMS', + suffixes={ 'mem' }, + }, + mp={ + names={ "mp" }, + variable='MPINPUTS', + suffixes={ 'mp','mpvi','mpiv','mpii' }, + usertype=true, + }, + tex={ + names={ "tex" }, + variable='TEXINPUTS', + suffixes={ "tex","mkvi","mkiv","mkii","cld","lfg","xml" }, + usertype=true, + }, + icc={ + names={ "icc","icc profile","icc profiles" }, + variable='ICCPROFILES', + suffixes={ 'icc' }, + }, + texmfscripts={ + names={ "texmfscript","texmfscripts","script","scripts" }, + variable='TEXMFSCRIPTS', + suffixes={ 'lua','rb','pl','py' }, + }, + lua={ + names={ "lua" }, + variable='LUAINPUTS', + suffixes={ luasuffixes.lua,luasuffixes.luc,luasuffixes.tma,luasuffixes.tmc }, + usertype=true, }, - obsolete={ - enc={ - names={ "enc","enc files","enc file","encoding files","encoding file" }, - variable='ENCFONTS', - suffixes={ 'enc' }, - }, - map={ - names={ "map","map files","map file" }, - variable='TEXFONTMAPS', - suffixes={ 'map' }, - }, - lig={ - names={ "lig files","lig file","ligature file","ligature files" }, - variable='LIGFONTS', - suffixes={ 'lig' }, - }, - opl={ - names={ "opl" }, - variable='OPLFONTS', - suffixes={ 'opl' }, - }, - ovp={ - names={ "ovp" }, - variable='OVPFONTS', - suffixes={ 'ovp' }, - }, + lib={ + names={ "lib" }, + variable='CLUAINPUTS', + suffixes=os.libsuffix and { os.libsuffix } or { 'dll','so' }, }, - kpse={ - base={ - names={ 'base',"metafont format" }, - variable='MFBASES', - suffixes={ 'base','bas' }, - }, - cmap={ - names={ 'cmap','cmap files','cmap file' }, - variable='CMAPFONTS', - suffixes={ 'cmap' }, - }, - cnf={ - names={ 'cnf' }, - suffixes={ 'cnf' }, - }, - web={ - names={ 'web' }, - suffixes={ 'web','ch' } - }, - cweb={ - names={ 'cweb' }, - suffixes={ 'w','web','ch' }, - }, - gf={ - names={ 'gf' }, - suffixes={ '<resolution>gf' }, - }, - mf={ - names={ 'mf' }, - variable='MFINPUTS', - suffixes={ 'mf' }, - }, - mft={ - names={ 'mft' }, - suffixes={ 'mft' }, - }, - pk={ - names={ 'pk' }, - suffixes={ '<resolution>pk' }, - }, + bib={ + names={ 'bib' }, + variable='BIBINPUTS', + suffixes={ 'bib' }, + usertype=true, }, + bst={ + names={ 'bst' }, + variable='BSTINPUTS', + suffixes={ 'bst' }, + usertype=true, + }, + fontconfig={ + names={ 'fontconfig','fontconfig file','fontconfig files' }, + variable='FONTCONFIG_PATH', + }, + pk={ + names={ "pk" }, + variable='PKFONTS', + suffixes={ 'pk' }, + }, + }, + obsolete={ + enc={ + names={ "enc","enc files","enc file","encoding files","encoding file" }, + variable='ENCFONTS', + suffixes={ 'enc' }, + }, + map={ + names={ "map","map files","map file" }, + variable='TEXFONTMAPS', + suffixes={ 'map' }, + }, + lig={ + names={ "lig files","lig file","ligature file","ligature files" }, + variable='LIGFONTS', + suffixes={ 'lig' }, + }, + opl={ + names={ "opl" }, + variable='OPLFONTS', + suffixes={ 'opl' }, + }, + ovp={ + names={ "ovp" }, + variable='OVPFONTS', + suffixes={ 'ovp' }, + }, + }, + kpse={ + base={ + names={ 'base',"metafont format" }, + variable='MFBASES', + suffixes={ 'base','bas' }, + }, + cmap={ + names={ 'cmap','cmap files','cmap file' }, + variable='CMAPFONTS', + suffixes={ 'cmap' }, + }, + cnf={ + names={ 'cnf' }, + suffixes={ 'cnf' }, + }, + web={ + names={ 'web' }, + suffixes={ 'web','ch' } + }, + cweb={ + names={ 'cweb' }, + suffixes={ 'w','web','ch' }, + }, + gf={ + names={ 'gf' }, + suffixes={ '<resolution>gf' }, + }, + mf={ + names={ 'mf' }, + variable='MFINPUTS', + suffixes={ 'mf' }, + }, + mft={ + names={ 'mft' }, + suffixes={ 'mft' }, + }, + pk={ + names={ 'pk' }, + suffixes={ '<resolution>pk' }, + }, + }, } resolvers.relations=relations function resolvers.updaterelations() - for category,categories in next,relations do - for name,relation in next,categories do - local rn=relation.names - local rv=relation.variable - if rn and rv then - local rs=relation.suffixes - local ru=relation.usertype - for i=1,#rn do - local rni=lower(gsub(rn[i]," ","")) - formats[rni]=rv - if rs then - suffixes[rni]=rs - for i=1,#rs do - local rsi=rs[i] - suffixmap[rsi]=rni - end - end - end - if ru then - usertypes[name]=true - end + for category,categories in next,relations do + for name,relation in next,categories do + local rn=relation.names + local rv=relation.variable + if rn and rv then + local rs=relation.suffixes + local ru=relation.usertype + for i=1,#rn do + local rni=lower(gsub(rn[i]," ","")) + formats[rni]=rv + if rs then + suffixes[rni]=rs + for i=1,#rs do + local rsi=rs[i] + suffixmap[rsi]=rni end + end + end + if ru then + usertypes[name]=true end + end end + end end resolvers.updaterelations() local function simplified(t,k) - return k and rawget(t,lower(gsub(k," ",""))) or nil + return k and rawget(t,lower(gsub(k," ",""))) or nil end setmetatableindex(formats,simplified) setmetatableindex(suffixes,simplified) setmetatableindex(suffixmap,simplified) function resolvers.suffixofformat(str) - local s=suffixes[str] - return s and s[1] or "" + local s=suffixes[str] + return s and s[1] or "" end function resolvers.suffixofformat(str) - return suffixes[str] or {} + return suffixes[str] or {} end for name,format in next,formats do - dangerous[name]=true + dangerous[name]=true end dangerous.tex=nil function resolvers.formatofvariable(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.formatofsuffix(str) - return suffixmap[suffixonly(str)] or 'tex' + return suffixmap[suffixonly(str)] or 'tex' end function resolvers.variableofformat(str) - return formats[str] or '' + return formats[str] or '' end function resolvers.variableofformatorsuffix(str) - local v=formats[str] - if v then - return v - end - v=suffixmap[suffixonly(str)] - if v then - return formats[v] - end - return '' + local v=formats[str] + if v then + return v + end + v=suffixmap[suffixonly(str)] + if v then + return formats[v] + end + return '' end @@ -17208,14 +20782,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmp"] = package.loaded["data-tmp"] or true --- original size: 16116, stripped down to: 11459 +-- original size: 16116, stripped down to: 10782 if not modules then modules={} end modules ['data-tmp']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,concat=string.format,string.lower,string.gsub,table.concat local concat=table.concat @@ -17223,19 +20797,19 @@ local mkdirs,isdir,isfile=dir.mkdirs,lfs.isdir,lfs.isfile local addsuffix,is_writable,is_readable=file.addsuffix,file.is_writable,file.is_readable local formatters=string.formatters local next,type=next,type -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) local report_caches=logs.reporter("resolvers","caches") local report_resolvers=logs.reporter("resolvers","caching") local resolvers=resolvers local cleanpath=resolvers.cleanpath -local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) -local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) +local directive_cleanup=false directives.register("system.compile.cleanup",function(v) directive_cleanup=v end) +local directive_strip=false directives.register("system.compile.strip",function(v) directive_strip=v end) local compile=utilities.lua.compile function utilities.lua.compile(luafile,lucfile,cleanup,strip) - if cleanup==nil then cleanup=directive_cleanup end - if strip==nil then strip=directive_strip end - return compile(luafile,lucfile,cleanup,strip) + if cleanup==nil then cleanup=directive_cleanup end + if strip==nil then strip=directive_strip end + return compile(luafile,lucfile,cleanup,strip) end caches=caches or {} local caches=caches @@ -17250,324 +20824,324 @@ caches.relocate=false caches.defaults={ "TMPDIR","TEMPDIR","TMP","TEMP","HOME","HOMEPATH" } local writable,readables,usedreadables=nil,{},{} local function identify() - local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - cachepath=file.collapsepath(cachepath) - local valid=isdir(cachepath) - if valid then - if is_readable(cachepath) then - readables[#readables+1]=cachepath - if not writable and is_writable(cachepath) then - writable=cachepath - end - end - elseif not writable and caches.force then - local cacheparent=file.dirname(cachepath) - if is_writable(cacheparent) and true then - if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then - mkdirs(cachepath) - if isdir(cachepath) and is_writable(cachepath) then - report_caches("path %a created",cachepath) - writable=cachepath - readables[#readables+1]=cachepath - end - end - end - end + local texmfcaches=resolvers.cleanpathlist("TEXMFCACHE") + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + cachepath=file.collapsepath(cachepath) + local valid=isdir(cachepath) + if valid then + if is_readable(cachepath) then + readables[#readables+1]=cachepath + if not writable and is_writable(cachepath) then + writable=cachepath end - end - end - local texmfcaches=caches.defaults - if texmfcaches then - for k=1,#texmfcaches do - local cachepath=texmfcaches[k] - cachepath=resolvers.expansion(cachepath) - if cachepath~="" then - cachepath=resolvers.resolve(cachepath) - cachepath=resolvers.cleanpath(cachepath) - local valid=isdir(cachepath) - if valid and is_readable(cachepath) then - if not writable and is_writable(cachepath) then - readables[#readables+1]=cachepath - writable=cachepath - break - end - end + end + elseif not writable and caches.force then + local cacheparent=file.dirname(cachepath) + if is_writable(cacheparent) and true then + if not caches.ask or io.ask(format("\nShould I create the cache path %s?",cachepath),"no",{ "yes","no" })=="yes" then + mkdirs(cachepath) + if isdir(cachepath) and is_writable(cachepath) then + report_caches("path %a created",cachepath) + writable=cachepath + readables[#readables+1]=cachepath + end end + end end + end end - if not writable then - report_caches("fatal error: there is no valid writable cache path defined") - os.exit() - elseif #readables==0 then - report_caches("fatal error: there is no valid readable cache path defined") - os.exit() - end - writable=dir.expandname(resolvers.cleanpath(writable)) - local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() - if tree then - caches.tree=tree - writable=mkdirs(writable,base,more,tree) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more,tree) - end - else - writable=mkdirs(writable,base,more) - for i=1,#readables do - readables[i]=file.join(readables[i],base,more) + end + local texmfcaches=caches.defaults + if texmfcaches then + for k=1,#texmfcaches do + local cachepath=texmfcaches[k] + cachepath=resolvers.expansion(cachepath) + if cachepath~="" then + cachepath=resolvers.resolve(cachepath) + cachepath=resolvers.cleanpath(cachepath) + local valid=isdir(cachepath) + if valid and is_readable(cachepath) then + if not writable and is_writable(cachepath) then + readables[#readables+1]=cachepath + writable=cachepath + break + end end + end end - if trace_cache then - for i=1,#readables do - report_caches("using readable path %a (order %s)",readables[i],i) - end - report_caches("using writable path %a",writable) + end + if not writable then + report_caches("fatal error: there is no valid writable cache path defined") + os.exit() + elseif #readables==0 then + report_caches("fatal error: there is no valid readable cache path defined") + os.exit() + end + writable=dir.expandname(resolvers.cleanpath(writable)) + local base,more,tree=caches.base,caches.more,caches.tree or caches.treehash() + if tree then + caches.tree=tree + writable=mkdirs(writable,base,more,tree) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more,tree) end - identify=function() - return writable,readables + else + writable=mkdirs(writable,base,more) + for i=1,#readables do + readables[i]=file.join(readables[i],base,more) end + end + if trace_cache then + for i=1,#readables do + report_caches("using readable path %a (order %s)",readables[i],i) + end + report_caches("using writable path %a",writable) + end + identify=function() return writable,readables + end + return writable,readables end function caches.usedpaths(separator) - local writable,readables=identify() - if #readables>1 then - local result={} - local done={} - for i=1,#readables do - local readable=readables[i] - if readable==writable then - done[readable]=true - result[#result+1]=formatters["readable+writable: %a"](readable) - elseif usedreadables[i] then - done[readable]=true - result[#result+1]=formatters["readable: %a"](readable) - end - end - if not done[writable] then - result[#result+1]=formatters["writable: %a"](writable) - end - return concat(result,separator or " | ") - else - return writable or "?" + local writable,readables=identify() + if #readables>1 then + local result={} + local done={} + for i=1,#readables do + local readable=readables[i] + if readable==writable then + done[readable]=true + result[#result+1]=formatters["readable+writable: %a"](readable) + elseif usedreadables[i] then + done[readable]=true + result[#result+1]=formatters["readable: %a"](readable) + end end + if not done[writable] then + result[#result+1]=formatters["writable: %a"](writable) + end + return concat(result,separator or " | ") + else + return writable or "?" + end end function caches.configfiles() - return concat(resolvers.configurationfiles(),";") + return concat(resolvers.configurationfiles(),";") end function caches.hashed(tree) - tree=gsub(tree,"[\\/]+$","") - tree=lower(tree) - local hash=md5.hex(tree) - if trace_cache or trace_locating then - report_caches("hashing tree %a, hash %a",tree,hash) - end - return hash + tree=gsub(tree,"[\\/]+$","") + tree=lower(tree) + local hash=md5.hex(tree) + if trace_cache or trace_locating then + report_caches("hashing tree %a, hash %a",tree,hash) + end + return hash end function caches.treehash() - local tree=caches.configfiles() - if not tree or tree=="" then - return false - else - return caches.hashed(tree) - end + local tree=caches.configfiles() + if not tree or tree=="" then + return false + else + return caches.hashed(tree) + end end local r_cache,w_cache={},{} local function getreadablepaths(...) - local tags={... } - local hash=concat(tags,"/") - local done=r_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done={} - for i=1,#readables do - done[i]=file.join(readables[i],...) - end - else - done=readables - end - r_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=r_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done={} + for i=1,#readables do + done[i]=file.join(readables[i],...) + end + else + done=readables end - return done + r_cache[hash]=done + end + return done end local function getwritablepath(...) - local tags={... } - local hash=concat(tags,"/") - local done=w_cache[hash] - if not done then - local writable,readables=identify() - if #tags>0 then - done=mkdirs(writable,...) - else - done=writable - end - w_cache[hash]=done + local tags={... } + local hash=concat(tags,"/") + local done=w_cache[hash] + if not done then + local writable,readables=identify() + if #tags>0 then + done=mkdirs(writable,...) + else + done=writable end - return done + w_cache[hash]=done + end + return done end caches.getreadablepaths=getreadablepaths caches.getwritablepath=getwritablepath function caches.getfirstreadablefile(filename,...) - local fullname,path=caches.setfirstwritablefile(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 - 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 + usedreadables[i]=true + return fullname,path end - return fullname,path + end + return fullname,path end function caches.setfirstwritablefile(filename,...) - local wr=getwritablepath(...) - local fullname=file.join(wr,filename) - return fullname,wr + local wr=getwritablepath(...) + local fullname=file.join(wr,filename) + return fullname,wr end function caches.define(category,subcategory) - return function() - return getwritablepath(category,subcategory) - end + return function() + return getwritablepath(category,subcategory) + end end function caches.setluanames(path,name) - return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) + return format("%s/%s.%s",path,name,luasuffixes.tma),format("%s/%s.%s",path,name,luasuffixes.tmc) end function caches.loaddata(readables,name,writable) - if type(readables)=="string" then - readables={ readables } + if type(readables)=="string" then + readables={ readables } + end + for i=1,#readables do + local path=readables[i] + local loader=false + local tmaname,tmcname=caches.setluanames(path,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader and isfile(tmaname) then + local tmacrap,tmcname=caches.setluanames(writable,name) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + utilities.lua.compile(tmaname,tmcname) + if isfile(tmcname) then + loader=loadfile(tmcname) + end + if not loader then + loader=loadfile(tmaname) + end end - for i=1,#readables do - local path=readables[i] - local loader=false - local tmaname,tmcname=caches.setluanames(path,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader and isfile(tmaname) then - local tmacrap,tmcname=caches.setluanames(writable,name) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - utilities.lua.compile(tmaname,tmcname) - if isfile(tmcname) then - loader=loadfile(tmcname) - end - if not loader then - loader=loadfile(tmaname) - end - end - if loader then - loader=loader() - collectgarbage("step") - return loader - end + if loader then + loader=loader() + collectgarbage("step") + return loader end - return false + end + return false end function caches.is_writable(filepath,filename) - local tmaname,tmcname=caches.setluanames(filepath,filename) - return is_writable(tmaname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + return is_writable(tmaname) end local saveoptions={ compact=true } function caches.savedata(filepath,filename,data,raw) - local tmaname,tmcname=caches.setluanames(filepath,filename) - data.cache_uuid=os.uuid() - if caches.direct then - file.savedata(tmaname,table.serialize(data,true,saveoptions)) - else - table.tofile(tmaname,data,true,saveoptions) - end - utilities.lua.compile(tmaname,tmcname) + local tmaname,tmcname=caches.setluanames(filepath,filename) + data.cache_uuid=os.uuid() + if caches.direct then + file.savedata(tmaname,table.serialize(data,true,saveoptions)) + else + table.tofile(tmaname,data,true,saveoptions) + end + utilities.lua.compile(tmaname,tmcname) end local content_state={} function caches.contentstate() - return content_state or {} + return content_state or {} end function caches.loadcontent(cachename,dataname,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) - if blob then - local data=blob() - if data and data.content then - if data.type==dataname then - if data.version==resolvers.cacheversion then - content_state[#content_state+1]=data.uuid - if trace_locating then - report_resolvers("loading %a for %a from %a",dataname,cachename,filename) - end - return data.content - else - report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) - end - else - report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) - end - elseif trace_locating then - report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.getfirstreadablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local blob=loadfile(addsuffix(filename,luasuffixes.luc)) or loadfile(addsuffix(filename,luasuffixes.lua)) + if blob then + local data=blob() + if data and data.content then + if data.type==dataname then + if data.version==resolvers.cacheversion then + content_state[#content_state+1]=data.uuid + if trace_locating then + report_resolvers("loading %a for %a from %a",dataname,cachename,filename) + end + return data.content + else + report_resolvers("skipping %a for %a from %a (version mismatch)",dataname,cachename,filename) end + else + report_resolvers("skipping %a for %a from %a (datatype mismatch)",dataname,cachename,filename) + end elseif trace_locating then - report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + report_resolvers("skipping %a for %a from %a (no content)",dataname,cachename,filename) end + elseif trace_locating then + report_resolvers("skipping %a for %a from %a (invalid file)",dataname,cachename,filename) + end end function caches.collapsecontent(content) - for k,v in next,content do - if type(v)=="table" and #v==1 then - content[k]=v[1] - end + for k,v in next,content do + if type(v)=="table" and #v==1 then + content[k]=v[1] end + end end function caches.savecontent(cachename,dataname,content,filename) - if not filename then - local name=caches.hashed(cachename) - local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") - filename=file.join(path,name) - end - local luaname=addsuffix(filename,luasuffixes.lua) - local lucname=addsuffix(filename,luasuffixes.luc) + if not filename then + local name=caches.hashed(cachename) + local full,path=caches.setfirstwritablefile(addsuffix(name,luasuffixes.lua),"trees") + filename=file.join(path,name) + end + local luaname=addsuffix(filename,luasuffixes.lua) + local lucname=addsuffix(filename,luasuffixes.luc) + if trace_locating then + report_resolvers("preparing %a for %a",dataname,cachename) + end + local data={ + type=dataname, + root=cachename, + version=resolvers.cacheversion, + date=os.date("%Y-%m-%d"), + time=os.date("%H:%M:%S"), + content=content, + uuid=os.uuid(), + } + local ok=io.savedata(luaname,table.serialize(data,true)) + if ok then if trace_locating then - report_resolvers("preparing %a for %a",dataname,cachename) - end - local data={ - type=dataname, - root=cachename, - version=resolvers.cacheversion, - date=os.date("%Y-%m-%d"), - time=os.date("%H:%M:%S"), - content=content, - uuid=os.uuid(), - } - local ok=io.savedata(luaname,table.serialize(data,true)) - if ok then - if trace_locating then - report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) - end - if utilities.lua.compile(luaname,lucname) then - if trace_locating then - report_resolvers("%a compiled to %a",dataname,lucname) - end - return true - else - if trace_locating then - report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) - end - os.remove(lucname) - end - elseif trace_locating then - report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + report_resolvers("category %a, cachename %a saved in %a",dataname,cachename,luaname) + end + if utilities.lua.compile(luaname,lucname) then + if trace_locating then + report_resolvers("%a compiled to %a",dataname,lucname) + end + return true + else + if trace_locating then + report_resolvers("compiling failed for %a, deleting file %a",dataname,lucname) + end + os.remove(lucname) end + elseif trace_locating then + report_resolvers("unable to save %a in %a (access error)",dataname,luaname) + end end @@ -17577,14 +21151,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-met"] = package.loaded["data-met"] or true --- original size: 5310, stripped down to: 3980 +-- original size: 5310, stripped down to: 3784 if not modules then modules={} end modules ['data-met']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,format=string.find,string.format local sequenced=table.sequenced @@ -17598,86 +21172,86 @@ local allocate=utilities.storage.allocate local resolvers=resolvers local registered={} local function splitmethod(filename) - if not filename then - return { scheme="unknown",original=filename } - end - if type(filename)=="table" then - return filename - end - filename=file.collapsepath(filename,".") - if not find(filename,"://",1,true) then - return { scheme="file",path=filename,original=filename,filename=filename } - end - local specification=url.hashed(filename) - if not specification.scheme or specification.scheme=="" then - return { scheme="file",path=filename,original=filename,filename=filename } - else - return specification - end + if not filename then + return { scheme="unknown",original=filename } + end + if type(filename)=="table" then + return filename + end + filename=file.collapsepath(filename,".") + if not find(filename,"://",1,true) then + return { scheme="file",path=filename,original=filename,filename=filename } + end + local specification=url.hashed(filename) + if not specification.scheme or specification.scheme=="" then + return { scheme="file",path=filename,original=filename,filename=filename } + else + return specification + end end resolvers.splitmethod=splitmethod local function methodhandler(what,first,...) - local method=registered[what] - if method then - local how,namespace=method.how,method.namespace - if how=="uri" or how=="url" then - local specification=splitmethod(first) - local scheme=specification.scheme - local resolver=namespace and namespace[scheme] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) - end - return resolver(specification,...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) - end - return resolver(specification,...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") - end - end - elseif how=="tag" then - local resolver=namespace and namespace[first] - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,first) - end - return resolver(...) - else - resolver=namespace.default or namespace.file - if resolver then - if trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"default") - end - return resolver(...) - elseif trace_methods then - report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") - end - end + local method=registered[what] + if method then + local how,namespace=method.how,method.namespace + if how=="uri" or how=="url" then + local specification=splitmethod(first) + local scheme=specification.scheme + local resolver=namespace and namespace[scheme] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,scheme,first) + end + return resolver(specification,...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"default",first) + end + return resolver(specification,...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, handler %a, argument %a",what,how,"unset") end - else - report_methods("resolving, invalid method %a") + end + elseif how=="tag" then + local resolver=namespace and namespace[first] + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,first) + end + return resolver(...) + else + resolver=namespace.default or namespace.file + if resolver then + if trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"default") + end + return resolver(...) + elseif trace_methods then + report_methods("resolving, method %a, how %a, tag %a",what,how,"unset") + end + end end + else + report_methods("resolving, invalid method %a") + end end resolvers.methodhandler=methodhandler function resolvers.registermethod(name,namespace,how) - registered[name]={ how=how or "tag",namespace=namespace } - namespace["byscheme"]=function(scheme,filename,...) - if scheme=="file" then - return methodhandler(name,filename,...) - else - return methodhandler(name,addurlscheme(filename,scheme),...) - end + registered[name]={ how=how or "tag",namespace=namespace } + namespace["byscheme"]=function(scheme,filename,...) + if scheme=="file" then + return methodhandler(name,filename,...) + else + return methodhandler(name,addurlscheme(filename,scheme),...) end + end end -local concatinators=allocate { notfound=file.join } -local locators=allocate { notfound=function() end } -local hashers=allocate { notfound=function() end } -local generators=allocate { notfound=function() end } +local concatinators=allocate { notfound=file.join } +local locators=allocate { notfound=function() end } +local hashers=allocate { notfound=function() end } +local generators=allocate { notfound=function() end } resolvers.concatinators=concatinators resolvers.locators=locators resolvers.hashers=hashers @@ -17695,17 +21269,17 @@ do -- create closure to overcome 200 locals limit package.loaded["data-res"] = package.loaded["data-res"] or true --- original size: 68263, stripped down to: 47789 +-- original size: 68195, stripped down to: 43680 if not modules then modules={} end modules ['data-res']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local gsub,find,lower,upper,match,gmatch=string.gsub,string.find,string.lower,string.upper,string.match,string.gmatch -local concat,insert,remove,sortedkeys,sortedhash=table.concat,table.insert,table.remove,table.sortedkeys,table.sortedhash +local concat,insert,remove=table.concat,table.insert,table.remove local next,type,rawget=next,type,rawget local os=os local P,S,R,C,Cc,Cs,Ct,Carg=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Carg @@ -17727,11 +21301,11 @@ local isfile=lfs.isfile local isdir=lfs.isdir local setmetatableindex=table.setmetatableindex local luasuffixes=utilities.lua.suffixes -local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) -local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) -local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) -local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) -local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) +local trace_locating=false trackers .register("resolvers.locating",function(v) trace_locating=v end) +local trace_detail=false trackers .register("resolvers.details",function(v) trace_detail=v end) +local trace_expansions=false trackers .register("resolvers.expansions",function(v) trace_expansions=v end) +local trace_paths=false trackers .register("resolvers.paths",function(v) trace_paths=v end) +local resolve_otherwise=true directives.register("resolvers.otherwise",function(v) resolve_otherwise=v end) local report_resolving=logs.reporter("resolvers","resolving") local resolvers=resolvers local expandedpathfromlist=resolvers.expandedpathfromlist @@ -17752,15 +21326,15 @@ resolvers.luacnfname="texmfcnf.lua" resolvers.luacnffallback="contextcnf.lua" resolvers.luacnfstate="unknown" if environment.default_texmfcnf then - resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf + resolvers.luacnfspec="home:texmf/web2c;"..environment.default_texmfcnf else - resolvers.luacnfspec=concat ({ - "home:texmf/web2c", - "selfautoparent:/texmf-local/web2c", - "selfautoparent:/texmf-context/web2c", - "selfautoparent:/texmf-dist/web2c", - "selfautoparent:/texmf/web2c", - },";") + resolvers.luacnfspec=concat ({ + "home:texmf/web2c", + "selfautoparent:/texmf-local/web2c", + "selfautoparent:/texmf-context/web2c", + "selfautoparent:/texmf-dist/web2c", + "selfautoparent:/texmf/web2c", + },";") end local unset_variable="unset" local formats=resolvers.formats @@ -17771,24 +21345,24 @@ local suffixmap=resolvers.suffixmap resolvers.defaultsuffixes={ "tex" } local instance=nil function resolvers.setenv(key,value,raw) - if instance then - instance.environment[key]=value - ossetenv(key,raw and value or resolveprefix(value)) - end + if instance then + instance.environment[key]=value + ossetenv(key,raw and value or resolveprefix(value)) + end end local function getenv(key) - local value=rawget(instance.environment,key) - if value and value~="" then - return value - else - local e=osgetenv(key) - return e~=nil and e~="" and checkedvariable(e) or "" - end + local value=rawget(instance.environment,key) + if value and value~="" then + return value + else + local e=osgetenv(key) + return e~=nil and e~="" and checkedvariable(e) or "" + end end resolvers.getenv=getenv resolvers.env=getenv local function resolvevariable(k) - return instance.expansions[k] + return instance.expansions[k] end local dollarstripper=lpeg.stripper("$") local inhibitstripper=P("!")^0*Cs(P(1)^0) @@ -17802,1506 +21376,1506 @@ local somevariable=R("az","AZ","09","__","--")^1/resolvevariable local variable=(P("$")/"")*(somevariable+(P("{")/"")*somevariable*(P("}")/"")) local variableresolver=Cs((variable+P(1))^0) local function expandedvariable(var) - return lpegmatch(variableexpander,var) or var + return lpegmatch(variableexpander,var) or var end function resolvers.reset() - if trace_locating then - report_resolving("creating instance") - end - local environment={} - local variables={} - local expansions={} - local order={} - instance={ - environment=environment, - variables=variables, - expansions=expansions, - order=order, - files={}, - setups={}, - found={}, - foundintrees={}, - hashes={}, - hashed={}, - pathlists=false, - specification={}, - lists={}, - data={}, - fakepaths={}, - remember=true, - diskcache=true, - renewcache=false, - renewtree=false, - loaderror=false, - savelists=true, - pattern=nil, - force_suffixes=true, - pathstack={}, - } - setmetatableindex(variables,function(t,k) - local v - for i=1,#order do - v=order[i][k] - if v~=nil then - t[k]=v - return v - end - end - if v==nil then - v="" - end - t[k]=v - return v - end) - setmetatableindex(environment,function(t,k) - local v=osgetenv(k) - if v==nil then - v=variables[k] - end - if v~=nil then - v=checkedvariable(v) or "" - end - v=resolvers.repath(v) - t[k]=v - return v - end) - setmetatableindex(expansions,function(t,k) - local v=environment[k] - if type(v)=="string" then - v=lpegmatch(variableresolver,v) - v=lpegmatch(variablecleaner,v) - end + if trace_locating then + report_resolving("creating instance") + end + local environment={} + local variables={} + local expansions={} + local order={} + instance={ + environment=environment, + variables=variables, + expansions=expansions, + order=order, + files={}, + setups={}, + found={}, + foundintrees={}, + hashes={}, + hashed={}, + pathlists=false, + specification={}, + lists={}, + data={}, + fakepaths={}, + remember=true, + diskcache=true, + renewcache=false, + renewtree=false, + loaderror=false, + savelists=true, + pattern=nil, + force_suffixes=true, + pathstack={}, + } + setmetatableindex(variables,function(t,k) + local v + for i=1,#order do + v=order[i][k] + if v~=nil then t[k]=v return v - end) + end + end + if v==nil then + v="" + end + t[k]=v + return v + end) + setmetatableindex(environment,function(t,k) + local v=osgetenv(k) + if v==nil then + v=variables[k] + end + if v~=nil then + v=checkedvariable(v) or "" + end + v=resolvers.repath(v) + t[k]=v + return v + end) + setmetatableindex(expansions,function(t,k) + local v=environment[k] + if type(v)=="string" then + v=lpegmatch(variableresolver,v) + v=lpegmatch(variablecleaner,v) + end + t[k]=v + return v + end) end function resolvers.initialized() - return instance~=nil + return instance~=nil end local function reset_hashes() - instance.lists={} - instance.pathlists=false - instance.found={} + instance.lists={} + instance.pathlists=false + instance.found={} end local function reset_caches() - instance.lists={} - instance.pathlists=false + instance.lists={} + instance.pathlists=false end local slash=P("/") local pathexpressionpattern=Cs ( - Cc("^")*( - Cc("%")*S(".-")+slash^2*P(-1)/"/.*" + Cc("^")*( + Cc("%")*S(".-")+slash^2*P(-1)/"/.*" +slash^2/"/"+(1-slash)*P(-1)*Cc("/")+P(1) - )^1*Cc("$") + )^1*Cc("$") ) local cache={} local function makepathexpression(str) - if str=="." then - return "^%./$" - else - local c=cache[str] - if not c then - c=lpegmatch(pathexpressionpattern,str) - cache[str]=c - end - return c + if str=="." then + return "^%./$" + else + local c=cache[str] + if not c then + c=lpegmatch(pathexpressionpattern,str) + cache[str]=c end + return c + end end local function reportcriticalvariables(cnfspec) - if trace_locating then - for i=1,#resolvers.criticalvars do - local k=resolvers.criticalvars[i] - local v=resolvers.getenv(k) or "unknown" - report_resolving("variable %a set to %a",k,v) - end - report_resolving() - if cnfspec then - report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) - end - report_resolving() + if trace_locating then + for i=1,#resolvers.criticalvars do + local k=resolvers.criticalvars[i] + local v=resolvers.getenv(k) or "unknown" + report_resolving("variable %a set to %a",k,v) + end + report_resolving() + if cnfspec then + report_resolving("using configuration specification %a",type(cnfspec)=="table" and concat(cnfspec,",") or cnfspec) end - reportcriticalvariables=function() end + report_resolving() + end + reportcriticalvariables=function() end end local function identify_configuration_files() - local specification=instance.specification - if #specification==0 then - local cnfspec=getenv("TEXMFCNF") - if cnfspec=="" then - cnfspec=resolvers.luacnfspec - resolvers.luacnfstate="default" - else - resolvers.luacnfstate="environment" - end - reportcriticalvariables(cnfspec) - local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) - local function locatecnf(luacnfname,kind) - for i=1,#cnfpaths do - local filepath=cnfpaths[i] - local filename=collapsepath(filejoin(filepath,luacnfname)) - local realname=resolveprefix(filename) - if trace_locating then - local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") - local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) - report_resolving("looking for %s %a on %s path %a from specification %a", - kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) - end - if isfile(realname) then - specification[#specification+1]=filename - if trace_locating then - report_resolving("found %s configuration file %a",kind,realname) - end - end - end - end - locatecnf(resolvers.luacnfname,"regular") - if #specification==0 then - locatecnf(resolvers.luacnffallback,"fallback") - end + local specification=instance.specification + if #specification==0 then + local cnfspec=getenv("TEXMFCNF") + if cnfspec=="" then + cnfspec=resolvers.luacnfspec + resolvers.luacnfstate="default" + else + resolvers.luacnfstate="environment" + end + reportcriticalvariables(cnfspec) + local cnfpaths=expandedpathfromlist(resolvers.splitpath(cnfspec)) + local function locatecnf(luacnfname,kind) + for i=1,#cnfpaths do + local filepath=cnfpaths[i] + local filename=collapsepath(filejoin(filepath,luacnfname)) + local realname=resolveprefix(filename) if trace_locating then - report_resolving() + local fullpath=gsub(resolveprefix(collapsepath(filepath)),"//","/") + local weirdpath=find(fullpath,"/texmf.+/texmf") or not find(fullpath,"/web2c",1,true) + report_resolving("looking for %s %a on %s path %a from specification %a", + kind,luacnfname,weirdpath and "weird" or "given",fullpath,filepath) + end + if isfile(realname) then + specification[#specification+1]=filename + if trace_locating then + report_resolving("found %s configuration file %a",kind,realname) + end end - elseif trace_locating then - report_resolving("configuration files already identified") + end + end + locatecnf(resolvers.luacnfname,"regular") + if #specification==0 then + locatecnf(resolvers.luacnffallback,"fallback") + end + if trace_locating then + report_resolving() end + elseif trace_locating then + report_resolving("configuration files already identified") + end end local function load_configuration_files() - local specification=instance.specification - if #specification>0 then - local luacnfname=resolvers.luacnfname - for i=1,#specification do - local filename=specification[i] - local pathname=filedirname(filename) - local filename=filejoin(pathname,luacnfname) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local setups=instance.setups - local data=blob() - local parent=data and data.parent - if parent then - local filename=filejoin(pathname,parent) - local realname=resolveprefix(filename) - local blob=loadfile(realname) - if blob then - local parentdata=blob() - if parentdata then - report_resolving("loading configuration file %a",filename) - data=table.merged(parentdata,data) - end - end - end - data=data and data.content - if data then - if trace_locating then - report_resolving("loading configuration file %a",filename) - report_resolving() - end - local variables=data.variables or {} - local warning=false - for k,v in next,data do - local variant=type(v) - if variant=="table" then - initializesetter(filename,k,v) - elseif variables[k]==nil then - if trace_locating and not warning then - report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", - k,resolveprefix(filename)) - warning=true - end - variables[k]=v - end - end - setups[pathname]=variables - if resolvers.luacnfstate=="default" then - local cnfspec=variables["TEXMFCNF"] - if cnfspec then - if trace_locating then - report_resolving("reloading configuration due to TEXMF redefinition") - end - resolvers.setenv("TEXMFCNF",cnfspec) - instance.specification={} - identify_configuration_files() - load_configuration_files() - resolvers.luacnfstate="configuration" - break - end - end - else - if trace_locating then - report_resolving("skipping configuration file %a (no content)",filename) - end - setups[pathname]={} - instance.loaderror=true - end - elseif trace_locating then - report_resolving("skipping configuration file %a (no valid format)",filename) + local specification=instance.specification + if #specification>0 then + local luacnfname=resolvers.luacnfname + for i=1,#specification do + local filename=specification[i] + local pathname=filedirname(filename) + local filename=filejoin(pathname,luacnfname) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local setups=instance.setups + local data=blob() + local parent=data and data.parent + if parent then + local filename=filejoin(pathname,parent) + local realname=resolveprefix(filename) + local blob=loadfile(realname) + if blob then + local parentdata=blob() + if parentdata then + report_resolving("loading configuration file %a",filename) + data=table.merged(parentdata,data) end - instance.order[#instance.order+1]=instance.setups[pathname] - if instance.loaderror then - break + end + end + data=data and data.content + if data then + if trace_locating then + report_resolving("loading configuration file %a",filename) + report_resolving() + end + local variables=data.variables or {} + local warning=false + for k,v in next,data do + local variant=type(v) + if variant=="table" then + initializesetter(filename,k,v) + elseif variables[k]==nil then + if trace_locating and not warning then + report_resolving("variables like %a in configuration file %a should move to the 'variables' subtable", + k,resolveprefix(filename)) + warning=true + end + variables[k]=v + end + end + setups[pathname]=variables + if resolvers.luacnfstate=="default" then + local cnfspec=variables["TEXMFCNF"] + if cnfspec then + if trace_locating then + report_resolving("reloading configuration due to TEXMF redefinition") + end + resolvers.setenv("TEXMFCNF",cnfspec) + instance.specification={} + identify_configuration_files() + load_configuration_files() + resolvers.luacnfstate="configuration" + break end + end + else + if trace_locating then + report_resolving("skipping configuration file %a (no content)",filename) + end + setups[pathname]={} + instance.loaderror=true end - elseif trace_locating then - report_resolving("warning: no lua configuration files found") + elseif trace_locating then + report_resolving("skipping configuration file %a (no valid format)",filename) + end + instance.order[#instance.order+1]=instance.setups[pathname] + if instance.loaderror then + break + end end + elseif trace_locating then + report_resolving("warning: no lua configuration files found") + end end function resolvers.configurationfiles() - return instance.specification or {} + return instance.specification or {} end local function load_file_databases() - instance.loaderror=false - instance.files={} - if not instance.renewcache then - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - resolvers.hashers.byscheme(hash.type,hash.name) - if instance.loaderror then break end - end + instance.loaderror=false + instance.files={} + if not instance.renewcache then + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + resolvers.hashers.byscheme(hash.type,hash.name) + if instance.loaderror then break end end + end end local function locate_file_databases() - local texmfpaths=resolvers.expandedpathlist("TEXMF") - if #texmfpaths>0 then - for i=1,#texmfpaths do - local path=collapsepath(texmfpaths[i]) - path=gsub(path,"/+$","") - local stripped=lpegmatch(inhibitstripper,path) - if stripped~="" then - local runtime=stripped==path - path=cleanpath(path) - local spec=resolvers.splitmethod(stripped) - if runtime and (spec.noscheme or spec.scheme=="file") then - stripped="tree:///"..stripped - elseif spec.scheme=="cache" or spec.scheme=="file" then - stripped=spec.path - end - if trace_locating then - if runtime then - report_resolving("locating list of %a (runtime) (%s)",path,stripped) - else - report_resolving("locating list of %a (cached)",path) - end - end - methodhandler('locators',stripped) - end + local texmfpaths=resolvers.expandedpathlist("TEXMF") + if #texmfpaths>0 then + for i=1,#texmfpaths do + local path=collapsepath(texmfpaths[i]) + path=gsub(path,"/+$","") + local stripped=lpegmatch(inhibitstripper,path) + if stripped~="" then + local runtime=stripped==path + path=cleanpath(path) + local spec=resolvers.splitmethod(stripped) + if runtime and (spec.noscheme or spec.scheme=="file") then + stripped="tree:///"..stripped + elseif spec.scheme=="cache" or spec.scheme=="file" then + stripped=spec.path end if trace_locating then - report_resolving() + if runtime then + report_resolving("locating list of %a (runtime) (%s)",path,stripped) + else + report_resolving("locating list of %a (cached)",path) + end end - elseif trace_locating then - report_resolving("no texmf paths are defined (using TEXMF)") - end -end -local function generate_file_databases() - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - methodhandler('generators',hash.name) + methodhandler('locators',stripped) + end end if trace_locating then - report_resolving() + report_resolving() end + elseif trace_locating then + report_resolving("no texmf paths are defined (using TEXMF)") + end +end +local function generate_file_databases() + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + methodhandler('generators',hash.name) + end + if trace_locating then + report_resolving() + end end local function save_file_databases() - for i=1,#instance.hashes do - local hash=instance.hashes[i] - local cachename=hash.name - if hash.cache then - local content=instance.files[cachename] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",cachename) - end - caches.savecontent(cachename,"files",content) - elseif trace_locating then - report_resolving("not saving runtime tree %a",cachename) - end + for i=1,#instance.hashes do + local hash=instance.hashes[i] + local cachename=hash.name + if hash.cache then + local content=instance.files[cachename] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",cachename) + end + caches.savecontent(cachename,"files",content) + elseif trace_locating then + report_resolving("not saving runtime tree %a",cachename) end + end end function resolvers.renew(hashname) - if hashname and hashname~="" then - local expanded=resolvers.expansion(hashname) or "" - if expanded~="" then - if trace_locating then - report_resolving("identifying tree %a from %a",expanded,hashname) - end - hashname=expanded - else - if trace_locating then - report_resolving("identifying tree %a",hashname) - end - end - local realpath=resolveprefix(hashname) - if isdir(realpath) then - if trace_locating then - report_resolving("using path %a",realpath) - end - methodhandler('generators',hashname) - local content=instance.files[hashname] - caches.collapsecontent(content) - if trace_locating then - report_resolving("saving tree %a",hashname) - end - caches.savecontent(hashname,"files",content) - else - report_resolving("invalid path %a",realpath) - end + if hashname and hashname~="" then + local expanded=resolvers.expansion(hashname) or "" + if expanded~="" then + if trace_locating then + report_resolving("identifying tree %a from %a",expanded,hashname) + end + hashname=expanded + else + if trace_locating then + report_resolving("identifying tree %a",hashname) + end end + local realpath=resolveprefix(hashname) + if isdir(realpath) then + if trace_locating then + report_resolving("using path %a",realpath) + end + methodhandler('generators',hashname) + local content=instance.files[hashname] + caches.collapsecontent(content) + if trace_locating then + report_resolving("saving tree %a",hashname) + end + caches.savecontent(hashname,"files",content) + else + report_resolving("invalid path %a",realpath) + end + end end local function load_databases() - locate_file_databases() - if instance.diskcache and not instance.renewcache then - load_file_databases() - if instance.loaderror then - generate_file_databases() - save_file_databases() - end - else - generate_file_databases() - if instance.renewcache then - save_file_databases() - end + locate_file_databases() + if instance.diskcache and not instance.renewcache then + load_file_databases() + if instance.loaderror then + generate_file_databases() + save_file_databases() + end + else + generate_file_databases() + if instance.renewcache then + save_file_databases() end + end end function resolvers.appendhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a appended",name) - end - insert(instance.hashes,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a appended",name) end + insert(instance.hashes,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.prependhash(type,name,cache) - if not instance.hashed[name] then - if trace_locating then - report_resolving("hash %a prepended",name) - end - insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) - instance.hashed[name]=cache + if not instance.hashed[name] then + if trace_locating then + report_resolving("hash %a prepended",name) end + insert(instance.hashes,1,{ type=type,name=name,cache=cache } ) + instance.hashed[name]=cache + end end function resolvers.extendtexmfvariable(specification) - local t=resolvers.splitpath(getenv("TEXMF")) - insert(t,1,specification) - local newspec=concat(t,",") - if instance.environment["TEXMF"] then - instance.environment["TEXMF"]=newspec - elseif instance.variables["TEXMF"] then - instance.variables["TEXMF"]=newspec - else - end - reset_hashes() + local t=resolvers.splitpath(getenv("TEXMF")) + insert(t,1,specification) + local newspec=concat(t,",") + if instance.environment["TEXMF"] then + instance.environment["TEXMF"]=newspec + elseif instance.variables["TEXMF"] then + instance.variables["TEXMF"]=newspec + else + end + reset_hashes() end function resolvers.splitexpansions() - local ie=instance.expansions - for k,v in next,ie do - local t,tn,h,p={},0,{},splitconfigurationpath(v) - for kk=1,#p do - local vv=p[kk] - if vv~="" and not h[vv] then - tn=tn+1 - t[tn]=vv - h[vv]=true - end - end - if #t>1 then - ie[k]=t - else - ie[k]=t[1] - end + local ie=instance.expansions + for k,v in next,ie do + local t,tn,h,p={},0,{},splitconfigurationpath(v) + for kk=1,#p do + local vv=p[kk] + if vv~="" and not h[vv] then + tn=tn+1 + t[tn]=vv + h[vv]=true + end end + if #t>1 then + ie[k]=t + else + ie[k]=t[1] + end + end end function resolvers.datastate() - return caches.contentstate() + return caches.contentstate() end function resolvers.variable(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.variables[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.variables[name] + return result~=nil and result or "" end function resolvers.expansion(name) - local name=name and lpegmatch(dollarstripper,name) - local result=name and instance.expansions[name] - return result~=nil and result or "" + local name=name and lpegmatch(dollarstripper,name) + local result=name and instance.expansions[name] + return result~=nil and result or "" end function resolvers.unexpandedpathlist(str) - local pth=resolvers.variable(str) - local lst=resolvers.splitpath(pth) - return expandedpathfromlist(lst) + local pth=resolvers.variable(str) + local lst=resolvers.splitpath(pth) + return expandedpathfromlist(lst) end function resolvers.unexpandedpath(str) - return joinpath(resolvers.unexpandedpathlist(str)) + return joinpath(resolvers.unexpandedpathlist(str)) end function resolvers.pushpath(name) - local pathstack=instance.pathstack - local lastpath=pathstack[#pathstack] - local pluspath=filedirname(name) - if lastpath then - lastpath=collapsepath(filejoin(lastpath,pluspath)) - else - lastpath=collapsepath(pluspath) - end - insert(pathstack,lastpath) - if trace_paths then - report_resolving("pushing path %a",lastpath) - end + local pathstack=instance.pathstack + local lastpath=pathstack[#pathstack] + local pluspath=filedirname(name) + if lastpath then + lastpath=collapsepath(filejoin(lastpath,pluspath)) + else + lastpath=collapsepath(pluspath) + end + insert(pathstack,lastpath) + if trace_paths then + report_resolving("pushing path %a",lastpath) + end end function resolvers.poppath() - local pathstack=instance.pathstack - if trace_paths and #pathstack>0 then - report_resolving("popping path %a",pathstack[#pathstack]) - end - remove(pathstack) + local pathstack=instance.pathstack + if trace_paths and #pathstack>0 then + report_resolving("popping path %a",pathstack[#pathstack]) + end + remove(pathstack) end function resolvers.stackpath() - local pathstack=instance.pathstack - local currentpath=pathstack[#pathstack] - return currentpath~="" and currentpath or nil + local pathstack=instance.pathstack + local currentpath=pathstack[#pathstack] + return currentpath~="" and currentpath or nil end local done={} function resolvers.resetextrapaths() - local ep=instance.extra_paths - if not ep then - done={} - instance.extra_paths={} - elseif #ep>0 then - done={} - reset_caches() - end + local ep=instance.extra_paths + if not ep then + done={} + instance.extra_paths={} + elseif #ep>0 then + done={} + reset_caches() + end end function resolvers.getextrapaths() - return instance.extra_paths or {} + return instance.extra_paths or {} end function resolvers.registerextrapath(paths,subpaths) - if not subpaths or subpaths=="" then - if not paths or path=="" then - return - elseif done[paths] then - return - end - end - local paths=settings_to_array(paths) - local subpaths=settings_to_array(subpaths) - local ep=instance.extra_paths or {} - local oldn=#ep - local newn=oldn - local nofpaths=#paths - local nofsubpaths=#subpaths - if nofpaths>0 then - if nofsubpaths>0 then - for i=1,nofpaths do - local p=paths[i] - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=p.."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end - end - else - for i=1,nofpaths do - local p=paths[i] - if not done[p] then - newn=newn+1 - ep[newn]=cleanpath(p) - done[p]=true - end - end + if not subpaths or subpaths=="" then + if not paths or path=="" then + return + elseif done[paths] then + return + end + end + local paths=settings_to_array(paths) + local subpaths=settings_to_array(subpaths) + local ep=instance.extra_paths or {} + local oldn=#ep + local newn=oldn + local nofpaths=#paths + local nofsubpaths=#subpaths + if nofpaths>0 then + if nofsubpaths>0 then + for i=1,nofpaths do + local p=paths[i] + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=p.."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end end - elseif nofsubpaths>0 then - for i=1,oldn do - for j=1,nofsubpaths do - local s=subpaths[j] - local ps=ep[i].."/"..s - if not done[ps] then - newn=newn+1 - ep[newn]=cleanpath(ps) - done[ps]=true - end - end + end + else + for i=1,nofpaths do + local p=paths[i] + if not done[p] then + newn=newn+1 + ep[newn]=cleanpath(p) + done[p]=true end + end end - if newn>0 then - instance.extra_paths=ep - end - if newn~=oldn then - reset_caches() + elseif nofsubpaths>0 then + for i=1,oldn do + for j=1,nofsubpaths do + local s=subpaths[j] + local ps=ep[i].."/"..s + if not done[ps] then + newn=newn+1 + ep[newn]=cleanpath(ps) + done[ps]=true + end + end end + end + if newn>0 then + instance.extra_paths=ep + end + if newn~=oldn then + reset_caches() + end end function resolvers.pushextrapath(path) - local paths=settings_to_array(path) - if instance.extra_stack then - insert(instance.extra_stack,1,paths) - else - instance.extra_stack={ paths } - end - reset_caches() + local paths=settings_to_array(path) + if instance.extra_stack then + insert(instance.extra_stack,1,paths) + else + instance.extra_stack={ paths } + end + reset_caches() end function resolvers.popextrapath() - if instance.extra_stack then - reset_caches() - return remove(instance.extra_stack,1) - end + if instance.extra_stack then + reset_caches() + return remove(instance.extra_stack,1) + end end local function made_list(instance,list,extra_too) - local done={} - local new={} - local newn=0 - local function add(p) - for k=1,#p do - local v=p[k] - if not done[v] then - done[v]=true - newn=newn+1 - new[newn]=v - end - end + local done={} + local new={} + local newn=0 + local function add(p) + for k=1,#p do + local v=p[k] + if not done[v] then + done[v]=true + newn=newn+1 + new[newn]=v + end end - for k=1,#list do - local v=list[k] - if done[v] then - elseif find(v,"^[%.%/]$") then - done[v]=true - newn=newn+1 - new[newn]=v - else - break - end + end + for k=1,#list do + local v=list[k] + if done[v] then + elseif find(v,"^[%.%/]$") then + done[v]=true + newn=newn+1 + new[newn]=v + else + break + end + end + if extra_too then + local es=instance.extra_stack + if es and #es>0 then + for k=1,#es do + add(es[k]) + end end - if extra_too then - local es=instance.extra_stack - if es and #es>0 then - for k=1,#es do - add(es[k]) - end - end - local ep=instance.extra_paths - if ep and #ep>0 then - add(ep) - end + local ep=instance.extra_paths + if ep and #ep>0 then + add(ep) end - add(list) - return new + end + add(list) + return new end function resolvers.cleanpathlist(str) - local t=resolvers.expandedpathlist(str) - if t then - for i=1,#t do - t[i]=collapsepath(cleanpath(t[i])) - end + local t=resolvers.expandedpathlist(str) + if t then + for i=1,#t do + t[i]=collapsepath(cleanpath(t[i])) end - return t + end + return t end function resolvers.expandpath(str) - return joinpath(resolvers.expandedpathlist(str)) + return joinpath(resolvers.expandedpathlist(str)) end function resolvers.expandedpathlist(str,extra_too) - if not str then - return {} - elseif instance.savelists then - str=lpegmatch(dollarstripper,str) - local lists=instance.lists - local lst=lists[str] - if not lst then - local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) - lst=expandedpathfromlist(l) - lists[str]=lst - end - return lst - else - local lst=resolvers.splitpath(resolvers.expansion(str)) - return made_list(instance,expandedpathfromlist(lst),extra_too) + if not str then + return {} + elseif instance.savelists then + str=lpegmatch(dollarstripper,str) + local lists=instance.lists + local lst=lists[str] + if not lst then + local l=made_list(instance,resolvers.splitpath(resolvers.expansion(str)),extra_too) + lst=expandedpathfromlist(l) + lists[str]=lst end + return lst + else + local lst=resolvers.splitpath(resolvers.expansion(str)) + return made_list(instance,expandedpathfromlist(lst),extra_too) + end end function resolvers.expandedpathlistfromvariable(str) - str=lpegmatch(dollarstripper,str) - local tmp=resolvers.variableofformatorsuffix(str) - return resolvers.expandedpathlist(tmp~="" and tmp or str) + str=lpegmatch(dollarstripper,str) + local tmp=resolvers.variableofformatorsuffix(str) + return resolvers.expandedpathlist(tmp~="" and tmp or str) end function resolvers.expandpathfromvariable(str) - return joinpath(resolvers.expandedpathlistfromvariable(str)) + return joinpath(resolvers.expandedpathlistfromvariable(str)) end function resolvers.cleanedpathlist(v) - local t=resolvers.expandedpathlist(v) - for i=1,#t do - t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) - end - return t + local t=resolvers.expandedpathlist(v) + for i=1,#t do + t[i]=resolvers.resolve(resolvers.cleanpath(t[i])) + end + return t end function resolvers.expandbraces(str) - local pth=expandedpathfromlist(resolvers.splitpath(str)) - return joinpath(pth) + local pth=expandedpathfromlist(resolvers.splitpath(str)) + return joinpath(pth) end function resolvers.registerfilehash(name,content,someerror) - if content then - instance.files[name]=content - else - instance.files[name]={} - if somerror==true then - instance.loaderror=someerror - end + if content then + instance.files[name]=content + else + instance.files[name]={} + if somerror==true then + instance.loaderror=someerror end + end end function resolvers.getfilehashes() - return instance and instance.files or {} + return instance and instance.files or {} end function resolvers.gethashes() - return instance and instance.hashes or {} + return instance and instance.hashes or {} end function resolvers.renewcache() - if instance then - instance.renewcache=true - end + if instance then + instance.renewcache=true + end end local function isreadable(name) - local readable=isfile(name) - if trace_detail then - if readable then - report_resolving("file %a is readable",name) - else - report_resolving("file %a is not readable",name) - end + local readable=isfile(name) + if trace_detail then + if readable then + report_resolving("file %a is readable",name) + else + report_resolving("file %a is not readable",name) end - return readable + end + return readable end local function collect_files(names) - local filelist={} - local noffiles=0 - local function check(hash,root,pathname,path,basename,name) - if not pathname or find(path,pathname) then - local variant=hash.type - local search=filejoin(root,path,name) - local result=methodhandler('concatinators',variant,root,path,name) - if trace_detail then - report_resolving("match: variant %a, search %a, result %a",variant,search,result) - end - noffiles=noffiles+1 - filelist[noffiles]={ variant,search,result } - end + local filelist={} + local noffiles=0 + local function check(hash,root,pathname,path,basename,name) + if not pathname or find(path,pathname) then + local variant=hash.type + local search=filejoin(root,path,name) + local result=methodhandler('concatinators',variant,root,path,name) + if trace_detail then + report_resolving("match: variant %a, search %a, result %a",variant,search,result) + end + noffiles=noffiles+1 + filelist[noffiles]={ variant,search,result } end - for k=1,#names do - local filename=names[k] + end + for k=1,#names do + local filename=names[k] + if trace_detail then + report_resolving("checking name %a",filename) + end + local basename=filebasename(filename) + local pathname=filedirname(filename) + if pathname=="" or find(pathname,"^%.") then + pathname=false + else + pathname=gsub(pathname,"%*",".*") + pathname="/"..pathname.."$" + end + local hashes=instance.hashes + for h=1,#hashes do + local hash=hashes[h] + local hashname=hash.name + local content=hashname and instance.files[hashname] + if content then if trace_detail then - report_resolving("checking name %a",filename) + report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) end - local basename=filebasename(filename) - local pathname=filedirname(filename) - if pathname=="" or find(pathname,"^%.") then - pathname=false - else - pathname=gsub(pathname,"%*",".*") - pathname="/"..pathname.."$" - end - local hashes=instance.hashes - for h=1,#hashes do - local hash=hashes[h] - local hashname=hash.name - local content=hashname and instance.files[hashname] - if content then - if trace_detail then - report_resolving("deep checking %a, base %a, pattern %a",hashname,basename,pathname) - end - local path,name=lookup(content,basename) - if path then - local metadata=content.metadata - local realroot=metadata and metadata.path or hashname - if type(path)=="string" then - check(hash,realroot,pathname,path,basename,name) - else - for i=1,#path do - check(hash,realroot,pathname,path[i],basename,name) - end - end - end - elseif trace_locating then - report_resolving("no match in %a (%s)",hashname,basename) + local path,name=lookup(content,basename) + if path then + local metadata=content.metadata + local realroot=metadata and metadata.path or hashname + if type(path)=="string" then + check(hash,realroot,pathname,path,basename,name) + else + for i=1,#path do + check(hash,realroot,pathname,path[i],basename,name) end + end end + elseif trace_locating then + report_resolving("no match in %a (%s)",hashname,basename) + end end - return noffiles>0 and filelist or nil + end + return noffiles>0 and filelist or nil end local fit={} function resolvers.registerintrees(filename,format,filetype,usedmethod,foundname) - local foundintrees=instance.foundintrees - if usedmethod=="direct" and filename==foundname and fit[foundname] then - else - local collapsed=collapsepath(foundname,true) - local t={ - filename=filename, - format=format~="" and format or nil, - filetype=filetype~="" and filetype or nil, - usedmethod=usedmethod, - foundname=foundname, - fullname=collapsed, - } - fit[foundname]=t - foundintrees[#foundintrees+1]=t - end + local foundintrees=instance.foundintrees + if usedmethod=="direct" and filename==foundname and fit[foundname] then + else + local collapsed=collapsepath(foundname,true) + local t={ + filename=filename, + format=format~="" and format or nil, + filetype=filetype~="" and filetype or nil, + usedmethod=usedmethod, + foundname=foundname, + fullname=collapsed, + } + fit[foundname]=t + foundintrees[#foundintrees+1]=t + end end function resolvers.foundintrees() - return instance.foundintrees or {} + return instance.foundintrees or {} end function resolvers.foundintree(fullname) - local f=fit[fullname] - return f and f.usedmethod=="database" + local f=fit[fullname] + return f and f.usedmethod=="database" end local function can_be_dir(name) - local fakepaths=instance.fakepaths - if not fakepaths[name] then - if isdir(name) then - fakepaths[name]=1 - else - fakepaths[name]=2 - end + local fakepaths=instance.fakepaths + if not fakepaths[name] then + if isdir(name) then + fakepaths[name]=1 + else + fakepaths[name]=2 end - return fakepaths[name]==1 + end + return fakepaths[name]==1 end local preparetreepattern=Cs((P(".")/"%%."+P("-")/"%%-"+P(1))^0*Cc("$")) local collect_instance_files local function find_analyze(filename,askedformat,allresults) - local filetype='' - local filesuffix=suffixonly(filename) - local wantedfiles={} - wantedfiles[#wantedfiles+1]=filename - if askedformat=="" then - if filesuffix=="" or not suffixmap[filesuffix] then - local defaultsuffixes=resolvers.defaultsuffixes - local formatofsuffix=resolvers.formatofsuffix - for i=1,#defaultsuffixes do - local forcedname=filename..'.'..defaultsuffixes[i] - wantedfiles[#wantedfiles+1]=forcedname - filetype=formatofsuffix(forcedname) - if trace_locating then - report_resolving("forcing filetype %a",filetype) - end - end - else - filetype=resolvers.formatofsuffix(filename) - if trace_locating then - report_resolving("using suffix based filetype %a",filetype) - end + local filetype='' + local filesuffix=suffixonly(filename) + local wantedfiles={} + wantedfiles[#wantedfiles+1]=filename + if askedformat=="" then + if filesuffix=="" or not suffixmap[filesuffix] then + local defaultsuffixes=resolvers.defaultsuffixes + local formatofsuffix=resolvers.formatofsuffix + for i=1,#defaultsuffixes do + local forcedname=filename..'.'..defaultsuffixes[i] + wantedfiles[#wantedfiles+1]=forcedname + filetype=formatofsuffix(forcedname) + if trace_locating then + report_resolving("forcing filetype %a",filetype) end + end else - if filesuffix=="" or not suffixmap[filesuffix] then - local format_suffixes=suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] - end - end - end - filetype=askedformat - if trace_locating then - report_resolving("using given filetype %a",filetype) + filetype=resolvers.formatofsuffix(filename) + if trace_locating then + report_resolving("using suffix based filetype %a",filetype) + end + end + else + if filesuffix=="" or not suffixmap[filesuffix] then + local format_suffixes=suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + wantedfiles[#wantedfiles+1]=filename.."."..format_suffixes[i] end + end end - return filetype,wantedfiles + filetype=askedformat + if trace_locating then + report_resolving("using given filetype %a",filetype) + end + end + return filetype,wantedfiles end local function find_direct(filename,allresults) - if not dangerous[askedformat] and isreadable(filename) then - if trace_detail then - report_resolving("file %a found directly",filename) - end - return "direct",{ filename } + if not dangerous[askedformat] and isreadable(filename) then + if trace_detail then + report_resolving("file %a found directly",filename) end + return "direct",{ filename } + end end local function find_wildcard(filename,allresults) - if find(filename,'*',1,true) then - if trace_locating then - report_resolving("checking wildcard %a",filename) - end - local result=resolvers.findwildcardfiles(filename) - if result then - return "wildcard",result - end - end -end -local function find_qualified(filename,allresults,askedformat,alsostripped) - if not is_qualified_path(filename) then - return - end + if find(filename,'*',1,true) then if trace_locating then - report_resolving("checking qualified name %a",filename) + report_resolving("checking wildcard %a",filename) end - if isreadable(filename) then - if trace_detail then - report_resolving("qualified file %a found",filename) - end - return "qualified",{ filename } + local result=resolvers.findwildcardfiles(filename) + if result then + return "wildcard",result end + end +end +local function find_qualified(filename,allresults,askedformat,alsostripped) + if not is_qualified_path(filename) then + return + end + if trace_locating then + report_resolving("checking qualified name %a",filename) + end + if isreadable(filename) then if trace_detail then - report_resolving("locating qualified file %a",filename) - end - local forcedname,suffix="",suffixonly(filename) - if suffix=="" then - local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] - if format_suffixes then - for i=1,#format_suffixes do - local s=format_suffixes[i] - forcedname=filename.."."..s - if isreadable(forcedname) then - if trace_locating then - report_resolving("no suffix, forcing format filetype %a",s) - end - return "qualified",{ forcedname } - end - end + report_resolving("qualified file %a found",filename) + end + return "qualified",{ filename } + end + if trace_detail then + report_resolving("locating qualified file %a",filename) + end + local forcedname,suffix="",suffixonly(filename) + if suffix=="" then + local format_suffixes=askedformat=="" and resolvers.defaultsuffixes or suffixes[askedformat] + if format_suffixes then + for i=1,#format_suffixes do + local s=format_suffixes[i] + forcedname=filename.."."..s + if isreadable(forcedname) then + if trace_locating then + report_resolving("no suffix, forcing format filetype %a",s) + end + return "qualified",{ forcedname } end + end end - if alsostripped and suffix and suffix~="" then - local basename=filebasename(filename) - local pattern=lpegmatch(preparetreepattern,filename) - local savedformat=askedformat - local format=savedformat or "" - if format=="" then - askedformat=resolvers.formatofsuffix(suffix) + end + if alsostripped and suffix and suffix~="" then + local basename=filebasename(filename) + local pattern=lpegmatch(preparetreepattern,filename) + local savedformat=askedformat + local format=savedformat or "" + if format=="" then + askedformat=resolvers.formatofsuffix(suffix) + end + if not format then + askedformat="othertextfiles" + end + if basename~=filename then + local resolved=collect_instance_files(basename,askedformat,allresults) + if #resolved==0 then + local lowered=lower(basename) + if filename~=lowered then + resolved=collect_instance_files(lowered,askedformat,allresults) end - if not format then - askedformat="othertextfiles" + end + resolvers.format=savedformat + if #resolved>0 then + local result={} + for r=1,#resolved do + local rr=resolved[r] + if find(rr,pattern) then + result[#result+1]=rr + end end - if basename~=filename then - local resolved=collect_instance_files(basename,askedformat,allresults) - if #resolved==0 then - local lowered=lower(basename) - if filename~=lowered then - resolved=collect_instance_files(lowered,askedformat,allresults) - end - end - resolvers.format=savedformat - if #resolved>0 then - local result={} - for r=1,#resolved do - local rr=resolved[r] - if find(rr,pattern) then - result[#result+1]=rr - end - end - if #result>0 then - return "qualified",result - end - end + if #result>0 then + return "qualified",result end + end end + end end local function check_subpath(fname) - if isreadable(fname) then - if trace_detail then - report_resolving("found %a by deep scanning",fname) - end - return fname + if isreadable(fname) then + if trace_detail then + report_resolving("found %a by deep scanning",fname) end + return fname + end end local function makepathlist(list,filetype) - local typespec=resolvers.variableofformat(filetype) - local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) - local entry={} - if pathlist and #pathlist>0 then - for k=1,#pathlist do - local path=pathlist[k] - local prescanned=find(path,'^!!') - local resursive=find(path,'//$') - local pathname=lpegmatch(inhibitstripper,path) - local expression=makepathexpression(pathname) - local barename=gsub(pathname,"/+$","") - barename=resolveprefix(barename) - local scheme=url.hasscheme(barename) - local schemename=gsub(barename,"%.%*$",'') - entry[k]={ - path=path, - pathname=pathname, - prescanned=prescanned, - recursive=recursive, - expression=expression, - barename=barename, - scheme=scheme, - schemename=schemename, - } - end - entry.typespec=typespec - list[filetype]=entry - else - list[filetype]=false - end - return entry + local typespec=resolvers.variableofformat(filetype) + local pathlist=resolvers.expandedpathlist(typespec,filetype and usertypes[filetype]) + local entry={} + if pathlist and #pathlist>0 then + for k=1,#pathlist do + local path=pathlist[k] + local prescanned=find(path,'^!!') + local resursive=find(path,'//$') + local pathname=lpegmatch(inhibitstripper,path) + local expression=makepathexpression(pathname) + local barename=gsub(pathname,"/+$","") + barename=resolveprefix(barename) + local scheme=url.hasscheme(barename) + local schemename=gsub(barename,"%.%*$",'') + entry[k]={ + path=path, + pathname=pathname, + prescanned=prescanned, + recursive=recursive, + expression=expression, + barename=barename, + scheme=scheme, + schemename=schemename, + } + end + entry.typespec=typespec + list[filetype]=entry + else + list[filetype]=false + end + return entry end local function find_intree(filename,filetype,wantedfiles,allresults) - local pathlists=instance.pathlists - if not pathlists then - pathlists=setmetatableindex({},makepathlist) - instance.pathlists=pathlists - end - local pathlist=pathlists[filetype] - if pathlist then - local method="intree" - local filelist=collect_files(wantedfiles) - local dirlist={} - local result={} - if filelist then - for i=1,#filelist do - dirlist[i]=filedirname(filelist[i][3]).."/" + local pathlists=instance.pathlists + if not pathlists then + pathlists=setmetatableindex({},makepathlist) + instance.pathlists=pathlists + end + local pathlist=pathlists[filetype] + if pathlist then + local method="intree" + local filelist=collect_files(wantedfiles) + local dirlist={} + local result={} + if filelist then + for i=1,#filelist do + dirlist[i]=filedirname(filelist[i][3]).."/" + end + end + if trace_detail then + report_resolving("checking filename %a in tree",filename) + end + for k=1,#pathlist do + local entry=pathlist[k] + local path=entry.path + local pathname=entry.pathname + local done=false + if filelist then + local expression=entry.expression + if trace_detail then + report_resolving("using pattern %a for path %a",expression,pathname) + end + for k=1,#filelist do + local fl=filelist[k] + local f=fl[2] + local d=dirlist[k] + if find(d,expression) or find(resolveprefix(d),expression) then + result[#result+1]=resolveprefix(fl[3]) + done=true + if allresults then + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) + end + else + if trace_detail then + report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) + end + break end + elseif trace_detail then + report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + end end - if trace_detail then - report_resolving("checking filename %a in tree",filename) - end - for k=1,#pathlist do - local entry=pathlist[k] - local path=entry.path - local pathname=entry.pathname - local done=false - if filelist then - local expression=entry.expression + end + if done then + method="database" + else + method="filesystem" + local scheme=entry.scheme + if not scheme or scheme=="file" then + local pname=entry.schemename + if not find(pname,"*",1,true) then + if can_be_dir(pname) then + if not done and not entry.prescanned then if trace_detail then - report_resolving("using pattern %a for path %a",expression,pathname) - end - for k=1,#filelist do - local fl=filelist[k] - local f=fl[2] - local d=dirlist[k] - if find(d,expression) or find(resolveprefix(d),expression) then - result[#result+1]=resolveprefix(fl[3]) - done=true - if allresults then - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, continue scanning",expression,f,d) - end - else - if trace_detail then - report_resolving("match to %a in hash for file %a and path %a, quit scanning",expression,f,d) - end - break - end - elseif trace_detail then - report_resolving("no match to %a in hash for file %a and path %a",expression,f,d) + report_resolving("quick root scan for %a",pname) + end + for k=1,#wantedfiles do + local w=wantedfiles[k] + local fname=check_subpath(filejoin(pname,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end - end - end - if done then - method="database" - else - method="filesystem" - local scheme=entry.scheme - if not scheme or scheme=="file" then - local pname=entry.schemename - if not find(pname,"*",1,true) then - if can_be_dir(pname) then - if not done and not entry.prescanned then - if trace_detail then - report_resolving("quick root scan for %a",pname) - end - for k=1,#wantedfiles do - local w=wantedfiles[k] - local fname=check_subpath(filejoin(pname,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - if not done and entry.recursive then - if trace_detail then - report_resolving("scanning filesystem for %a",pname) - end - local files=resolvers.simplescanfiles(pname,false,true) - for k=1,#wantedfiles do - local w=wantedfiles[k] - local subpath=files[w] - if not subpath or subpath=="" then - elseif type(subpath)=="string" then - local fname=check_subpath(filejoin(pname,subpath,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - else - for i=1,#subpath do - local sp=subpath[i] - if sp=="" then - else - local fname=check_subpath(filejoin(pname,sp,w)) - if fname then - result[#result+1]=fname - done=true - if not allresults then - break - end - end - end - end - if done and not allresults then - break - end - end - end - end - end + end + end + if not done and entry.recursive then + if trace_detail then + report_resolving("scanning filesystem for %a",pname) + end + local files=resolvers.simplescanfiles(pname,false,true) + for k=1,#wantedfiles do + local w=wantedfiles[k] + local subpath=files[w] + if not subpath or subpath=="" then + elseif type(subpath)=="string" then + local fname=check_subpath(filejoin(pname,subpath,w)) + if fname then + result[#result+1]=fname + done=true + if not allresults then + break end + end else - end - else - for k=1,#wantedfiles do - local pname=entry.barename - local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) - if fname then + for i=1,#subpath do + local sp=subpath[i] + if sp=="" then + else + local fname=check_subpath(filejoin(pname,sp,w)) + if fname then result[#result+1]=fname done=true if not allresults then - break + break end + end end + end + if done and not allresults then + break + end end + end end + end end - if done and not allresults then + else + end + else + for k=1,#wantedfiles do + local pname=entry.barename + local fname=methodhandler('finders',pname.."/"..wantedfiles[k]) + if fname then + result[#result+1]=fname + done=true + if not allresults then break + end end + end end - if #result>0 then - return method,result - end + end + if done and not allresults then + break + end + end + if #result>0 then + return method,result end + end end local function find_onpath(filename,filetype,wantedfiles,allresults) - if trace_detail then - report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) - end - local result={} - for k=1,#wantedfiles do - local fname=wantedfiles[k] - if fname and isreadable(fname) then - filename=fname - result[#result+1]=filejoin('.',fname) - if not allresults then - break - end - end - end - if #result>0 then - return "onpath",result + if trace_detail then + report_resolving("checking filename %a, filetype %a, wanted files %a",filename,filetype,concat(wantedfiles," | ")) + end + local result={} + for k=1,#wantedfiles do + local fname=wantedfiles[k] + if fname and isreadable(fname) then + filename=fname + result[#result+1]=filejoin('.',fname) + if not allresults then + break + end end + end + if #result>0 then + return "onpath",result + end end local function find_otherwise(filename,filetype,wantedfiles,allresults) - local filelist=collect_files(wantedfiles) - local fl=filelist and filelist[1] - if fl then - return "otherwise",{ resolveprefix(fl[3]) } - end + local filelist=collect_files(wantedfiles) + local fl=filelist and filelist[1] + if fl then + return "otherwise",{ resolveprefix(fl[3]) } + end end collect_instance_files=function(filename,askedformat,allresults) - if not filename or filename=="" then - return {} - end - askedformat=askedformat or "" - filename=collapsepath(filename,".") - filename=gsub(filename,"^%./",getcurrentdir().."/") - if allresults then - local filetype,wantedfiles=find_analyze(filename,askedformat) - local results={ - { find_direct (filename,true) }, - { find_wildcard (filename,true) }, - { find_qualified(filename,true,askedformat) }, - { find_intree (filename,filetype,wantedfiles,true) }, - { find_onpath (filename,filetype,wantedfiles,true) }, - { find_otherwise(filename,filetype,wantedfiles,true) }, - } - local result,status,done={},{},{} - for k,r in next,results do - local method,list=r[1],r[2] - if method and list then - for i=1,#list do - local c=collapsepath(list[i]) - if not done[c] then - result[#result+1]=c - done[c]=true - end - status[#status+1]=formatters["%-10s: %s"](method,c) - end - end - end - if trace_detail then - report_resolving("lookup status: %s",table.serialize(status,filename)) + if not filename or filename=="" then + return {} + end + askedformat=askedformat or "" + filename=collapsepath(filename,".") + filename=gsub(filename,"^%./",getcurrentdir().."/") + if allresults then + local filetype,wantedfiles=find_analyze(filename,askedformat) + local results={ + { find_direct (filename,true) }, + { find_wildcard (filename,true) }, + { find_qualified(filename,true,askedformat) }, + { find_intree (filename,filetype,wantedfiles,true) }, + { find_onpath (filename,filetype,wantedfiles,true) }, + { find_otherwise(filename,filetype,wantedfiles,true) }, + } + local result,status,done={},{},{} + for k,r in next,results do + local method,list=r[1],r[2] + if method and list then + for i=1,#list do + local c=collapsepath(list[i]) + if not done[c] then + result[#result+1]=c + done[c]=true + end + status[#status+1]=formatters["%-10s: %s"](method,c) end - return result,status - else - local method,result,stamp,filetype,wantedfiles - if instance.remember then - if askedformat=="" then - stamp=formatters["%s::%s"](suffixonly(filename),filename) - else - stamp=formatters["%s::%s"](askedformat,filename) - end - result=stamp and instance.found[stamp] - if result then - if trace_locating then - report_resolving("remembered file %a",filename) - end - return result - end + end + end + if trace_detail then + report_resolving("lookup status: %s",table.serialize(status,filename)) + end + return result,status + else + local method,result,stamp,filetype,wantedfiles + if instance.remember then + if askedformat=="" then + stamp=formatters["%s::%s"](suffixonly(filename),filename) + else + stamp=formatters["%s::%s"](askedformat,filename) + end + result=stamp and instance.found[stamp] + if result then + if trace_locating then + report_resolving("remembered file %a",filename) end - method,result=find_direct(filename) + return result + end + end + method,result=find_direct(filename) + if not result then + method,result=find_wildcard(filename) + if not result then + method,result=find_qualified(filename,false,askedformat) if not result then - method,result=find_wildcard(filename) - if not result then - method,result=find_qualified(filename,false,askedformat) - if not result then - filetype,wantedfiles=find_analyze(filename,askedformat) - method,result=find_intree(filename,filetype,wantedfiles) - if not result then - method,result=find_onpath(filename,filetype,wantedfiles) - if resolve_otherwise and not result then - method,result=find_otherwise(filename,filetype,wantedfiles) - end - end - end - end - end - if result and #result>0 then - local foundname=collapsepath(result[1]) - resolvers.registerintrees(filename,askedformat,filetype,method,foundname) - result={ foundname } - else - result={} - end - if stamp then - if trace_locating then - report_resolving("remembering file %a using hash %a",filename,stamp) + filetype,wantedfiles=find_analyze(filename,askedformat) + method,result=find_intree(filename,filetype,wantedfiles) + if not result then + method,result=find_onpath(filename,filetype,wantedfiles) + if resolve_otherwise and not result then + method,result=find_otherwise(filename,filetype,wantedfiles) end - instance.found[stamp]=result + end end - return result + end + end + if result and #result>0 then + local foundname=collapsepath(result[1]) + resolvers.registerintrees(filename,askedformat,filetype,method,foundname) + result={ foundname } + else + result={} end + if stamp then + if trace_locating then + report_resolving("remembering file %a using hash %a",filename,stamp) + end + instance.found[stamp]=result + end + return result + end end local function findfiles(filename,filetype,allresults) - if not filename or filename=="" then - return {} - end - local result,status=collect_instance_files(filename,filetype or "",allresults) - if not result or #result==0 then - local lowered=lower(filename) - if filename~=lowered then - result,status=collect_instance_files(lowered,filetype or "",allresults) - end + if not filename or filename=="" then + return {} + end + local result,status=collect_instance_files(filename,filetype or "",allresults) + if not result or #result==0 then + local lowered=lower(filename) + if filename~=lowered then + result,status=collect_instance_files(lowered,filetype or "",allresults) end - return result or {},status + end + return result or {},status end function resolvers.findfiles(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,true) - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,true) + end end function resolvers.findfile(filename,filetype) - if not filename or filename=="" then - return "" - else - return findfiles(filename,filetype,false)[1] or "" - end + if not filename or filename=="" then + return "" + else + return findfiles(filename,filetype,false)[1] or "" + end end function resolvers.findpath(filename,filetype) - return filedirname(findfiles(filename,filetype,false)[1] or "") + return filedirname(findfiles(filename,filetype,false)[1] or "") end local function findgivenfiles(filename,allresults) - local base=filebasename(filename) - local result={} - local hashes=instance.hashes - local function okay(hash,path,name) - local found=methodhandler('concatinators',hash.type,hash.name,path,name) - if found and found~="" then - result[#result+1]=resolveprefix(found) - return not allresults - end - end - for k=1,#hashes do - local hash=hashes[k] - local content=instance.files[hash.name] - if content then - local path,name=lookup(content,base) - if not path then - elseif type(path)=="string" then - if okay(hash,path,name) then - return result - end - else - for i=1,#path do - if okay(hash,path[i],name) then - return result - end - end - end + local base=filebasename(filename) + local result={} + local hashes=instance.hashes + local function okay(hash,path,name) + local found=methodhandler('concatinators',hash.type,hash.name,path,name) + if found and found~="" then + result[#result+1]=resolveprefix(found) + return not allresults + end + end + for k=1,#hashes do + local hash=hashes[k] + local content=instance.files[hash.name] + if content then + local path,name=lookup(content,base) + if not path then + elseif type(path)=="string" then + if okay(hash,path,name) then + return result + end + else + for i=1,#path do + if okay(hash,path[i],name) then + return result + end end + end end - return result + end + return result end function resolvers.findgivenfiles(filename) - return findgivenfiles(filename,true) + return findgivenfiles(filename,true) end function resolvers.findgivenfile(filename) - return findgivenfiles(filename,false)[1] or "" + return findgivenfiles(filename,false)[1] or "" end local makewildcard=Cs( - (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 + (P("^")^0*P("/")*P(-1)+P(-1))/".*"+(P("^")^0*P("/")/"")^0*(P("*")/".*"+P("-")/"%%-"+P(".")/"%%."+P("?")/"."+P("\\")/"/"+P(1))^0 ) function resolvers.wildcardpattern(pattern) - return lpegmatch(makewildcard,pattern) or pattern + return lpegmatch(makewildcard,pattern) or pattern end local function findwildcardfiles(filename,allresults,result) - local result=result or {} - local base=filebasename(filename) - local dirn=filedirname(filename) - local path=lower(lpegmatch(makewildcard,dirn) or dirn) - local name=lower(lpegmatch(makewildcard,base) or base) - local files=instance.files - if find(name,"*",1,true) then - local hashes=instance.hashes - local function okay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end - end + local result=result or {} + local base=filebasename(filename) + local dirn=filedirname(filename) + local path=lower(lpegmatch(makewildcard,dirn) or dirn) + local name=lower(lpegmatch(makewildcard,base) or base) + local files=instance.files + if find(name,"*",1,true) then + local hashes=instance.hashes + local function okay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults end - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - for found,base in filtered(files[hashname],name) do - if type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end - end + end + end + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + for found,base in filtered(files[hashname],name) do + if type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break end - end - else - local function okayokay(found,path,base,hashname,hashtype) - if find(found,path) then - local full=methodhandler('concatinators',hashtype,hashname,found,base) - if full and full~="" then - result[#result+1]=resolveprefix(full) - return not allresults - end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break + end end + end end - local hashes=instance.hashes - for k=1,#hashes do - local hash=hashes[k] - local hashname=hash.name - local hashtype=hash.type - if hashname and hashtype then - local found,base=lookup(content,base) - if not found then - elseif type(found)=='string' then - if okay(found,path,base,hashname,hashtype) then - break - end - else - for i=1,#found do - if okay(found[i],path,base,hashname,hashtype) then - break - end - end - end + end + end + else + local function okayokay(found,path,base,hashname,hashtype) + if find(found,path) then + local full=methodhandler('concatinators',hashtype,hashname,found,base) + if full and full~="" then + result[#result+1]=resolveprefix(full) + return not allresults + end + end + end + local hashes=instance.hashes + for k=1,#hashes do + local hash=hashes[k] + local hashname=hash.name + local hashtype=hash.type + if hashname and hashtype then + local found,base=lookup(content,base) + if not found then + elseif type(found)=='string' then + if okay(found,path,base,hashname,hashtype) then + break + end + else + for i=1,#found do + if okay(found[i],path,base,hashname,hashtype) then + break end + end end + end end - return result + end + return result end function resolvers.findwildcardfiles(filename,result) - return findwildcardfiles(filename,true,result) + return findwildcardfiles(filename,true,result) end function resolvers.findwildcardfile(filename) - return findwildcardfiles(filename,false)[1] or "" + return findwildcardfiles(filename,false)[1] or "" end function resolvers.automount() end function resolvers.starttiming() - statistics.starttiming(instance) + statistics.starttiming(instance) end function resolvers.stoptiming() - statistics.stoptiming(instance) + statistics.stoptiming(instance) end function resolvers.load(option) - resolvers.starttiming() - identify_configuration_files() - load_configuration_files() - if option~="nofiles" then - load_databases() - resolvers.automount() - end - resolvers.stoptiming() - local files=instance.files - return files and next(files) and true + resolvers.starttiming() + identify_configuration_files() + load_configuration_files() + if option~="nofiles" then + load_databases() + resolvers.automount() + end + resolvers.stoptiming() + local files=instance.files + return files and next(files) and true end function resolvers.loadtime() - return statistics.elapsedtime(instance) + return statistics.elapsedtime(instance) end local function report(str) - if trace_locating then - report_resolving(str) - else - print(str) - end + if trace_locating then + report_resolving(str) + else + print(str) + end end function resolvers.dowithfilesandreport(command,files,...) - if files and #files>0 then - if trace_locating then - report('') - end - if type(files)=="string" then - files={ files } - end - for f=1,#files do - local file=files[f] - local result=command(file,...) - if type(result)=='string' then - report(result) - else - for i=1,#result do - report(result[i]) - end - end + if files and #files>0 then + if trace_locating then + report('') + end + if type(files)=="string" then + files={ files } + end + for f=1,#files do + local file=files[f] + local result=command(file,...) + if type(result)=='string' then + report(result) + else + for i=1,#result do + report(result[i]) end + end end + end end -function resolvers.showpath(str) - return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) +function resolvers.showpath(str) + return joinpath(resolvers.expandedpathlist(resolvers.formatofvariable(str))) end function resolvers.registerfile(files,name,path) - if files[name] then - if type(files[name])=='string' then - files[name]={ files[name],path } - else - files[name]=path - end + if files[name] then + if type(files[name])=='string' then + files[name]={ files[name],path } else - files[name]=path + files[name]=path end + else + files[name]=path + end end function resolvers.dowithpath(name,func) - local pathlist=resolvers.expandedpathlist(name) - for i=1,#pathlist do - func("^"..cleanpath(pathlist[i])) - end + local pathlist=resolvers.expandedpathlist(name) + for i=1,#pathlist do + func("^"..cleanpath(pathlist[i])) + end end function resolvers.dowithvariable(name,func) - func(expandedvariable(name)) + func(expandedvariable(name)) end function resolvers.locateformat(name) - local engine=environment.ownmain or "luatex" - local barename=removesuffix(name) - local fullname=addsuffix(barename,"fmt") - local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" - if fmtname=="" then - fmtname=resolvers.findfile(fullname) - fmtname=cleanpath(fmtname) - end - if fmtname~="" then - local barename=removesuffix(fmtname) - local luaname=addsuffix(barename,luasuffixes.lua) - local lucname=addsuffix(barename,luasuffixes.luc) - local luiname=addsuffix(barename,luasuffixes.lui) - if isfile(luiname) then - return barename,luiname - elseif isfile(lucname) then - return barename,lucname - elseif isfile(luaname) then - return barename,luaname - end - end - return nil,nil + local engine=environment.ownmain or "luatex" + local barename=removesuffix(name) + local fullname=addsuffix(barename,"fmt") + local fmtname=caches.getfirstreadablefile(fullname,"formats",engine) or "" + if fmtname=="" then + fmtname=resolvers.findfile(fullname) + fmtname=cleanpath(fmtname) + end + if fmtname~="" then + local barename=removesuffix(fmtname) + local luaname=addsuffix(barename,luasuffixes.lua) + local lucname=addsuffix(barename,luasuffixes.luc) + local luiname=addsuffix(barename,luasuffixes.lui) + if isfile(luiname) then + return barename,luiname + elseif isfile(lucname) then + return barename,lucname + elseif isfile(luaname) then + return barename,luaname + end + end + return nil,nil end function resolvers.booleanvariable(str,default) - local b=resolvers.expansion(str) - if b=="" then - return default - else - b=toboolean(b) - return (b==nil and default) or b - end + local b=resolvers.expansion(str) + if b=="" then + return default + else + b=toboolean(b) + return (b==nil and default) or b + end end function resolvers.dowithfilesintree(pattern,handle,before,after) - local hashes=instance.hashes - for i=1,#hashes do - local hash=hashes[i] - local blobtype=hash.type - local blobpath=hash.name - if blobtype and blobpath then - local total=0 - local checked=0 - local done=0 - if before then - before(blobtype,blobpath,pattern) - end - for path,name in filtered(instance.files[blobpath],pattern) do - if type(path)=="string" then - checked=checked+1 - if handle(blobtype,blobpath,path,name) then - done=done+1 - end - else - checked=checked+#path - for i=1,#path do - if handle(blobtype,blobpath,path[i],name) then - done=done+1 - end - end - end - end - if after then - after(blobtype,blobpath,pattern,total,checked,done) + local hashes=instance.hashes + for i=1,#hashes do + local hash=hashes[i] + local blobtype=hash.type + local blobpath=hash.name + if blobtype and blobpath then + local total=0 + local checked=0 + local done=0 + if before then + before(blobtype,blobpath,pattern) + end + for path,name in filtered(instance.files[blobpath],pattern) do + if type(path)=="string" then + checked=checked+1 + if handle(blobtype,blobpath,path,name) then + done=done+1 + end + else + checked=checked+#path + for i=1,#path do + if handle(blobtype,blobpath,path[i],name) then + done=done+1 end + end end + end + if after then + after(blobtype,blobpath,pattern,checked,done) + end end + end end local obsolete=resolvers.obsolete or {} resolvers.obsolete=obsolete -resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile -resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles +resolvers.find_file=resolvers.findfile obsolete.find_file=resolvers.findfile +resolvers.find_files=resolvers.findfiles obsolete.find_files=resolvers.findfiles function resolvers.knownvariables(pattern) - if instance then - local environment=instance.environment - local variables=instance.variables - local expansions=instance.expansions - local order=instance.order - local pattern=upper(pattern or "") - local result={} - for i=1,#order do - for key in next,order[i] do - if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then - result[key]={ - environment=rawget(environment,key), - variable=key, - expansion=expansions[key], - resolved=resolveprefix(expansions[key]), - } - end - end + if instance then + local environment=instance.environment + local variables=instance.variables + local expansions=instance.expansions + local order=instance.order + local pattern=upper(pattern or "") + local result={} + for i=1,#order do + for key in next,order[i] do + if result[key]==nil and key~="" and (pattern=="" or find(upper(key),pattern)) then + result[key]={ + environment=rawget(environment,key), + variable=key, + expansion=expansions[key], + resolved=resolveprefix(expansions[key]), + } end - return result - else - return {} + end end + return result + else + return {} + end end @@ -19311,14 +22885,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-pre"] = package.loaded["data-pre"] or true --- original size: 4090, stripped down to: 3059 +-- original size: 4854, stripped down to: 2889 if not modules then modules={} end modules ['data-pre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local prefixes=resolvers.prefixes @@ -19331,64 +22905,64 @@ local dirname=file.dirname local joinpath=file.join local isfile=lfs.isfile prefixes.environment=function(str) - return cleanpath(expansion(str)) + return cleanpath(expansion(str)) end local function relative(str,n) - if not isfile(str) then - local pstr="./"..str + if not isfile(str) then + local pstr="./"..str + if isfile(pstr) then + str=pstr + else + local p="../" + for i=1,n or 2 do + local pstr=p..str if isfile(pstr) then - str=pstr + str=pstr + break else - local p="../" - for i=1,n or 2 do - local pstr=p..str - if isfile(pstr) then - str=pstr - break - else - p=p.."../" - end - end + p=p.."../" end + end end - return cleanpath(str) + end + return cleanpath(str) end local function locate(str) - local fullname=findgivenfile(str) or "" - return cleanpath(fullname~="" and fullname or str) + local fullname=findgivenfile(str) or "" + return cleanpath(fullname~="" and fullname or str) end prefixes.relative=relative prefixes.locate=locate prefixes.auto=function(str) - local fullname=relative(str) - if not isfile(fullname) then - fullname=locate(str) - end - return fullname + local fullname=relative(str) + if not isfile(fullname) then + fullname=locate(str) + end + return fullname end prefixes.filename=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(basename((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(basename((fullname~="" and fullname) or str)) end prefixes.pathname=function(str) - local fullname=findgivenfile(str) or "" - return cleanpath(dirname((fullname~="" and fullname) or str)) + local fullname=findgivenfile(str) or "" + return cleanpath(dirname((fullname~="" and fullname) or str)) end prefixes.selfautoloc=function(str) - local pth=getenv('SELFAUTOLOC') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOLOC') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautoparent=function(str) - local pth=getenv('SELFAUTOPARENT') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTOPARENT') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.selfautodir=function(str) - local pth=getenv('SELFAUTODIR') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('SELFAUTODIR') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.home=function(str) - local pth=getenv('HOME') - return cleanpath(str and joinpath(pth,str) or pth) + local pth=getenv('HOME') + return cleanpath(str and joinpath(pth,str) or pth) end prefixes.env=prefixes.environment prefixes.rel=prefixes.relative @@ -19398,24 +22972,24 @@ prefixes.full=prefixes.locate prefixes.file=prefixes.filename prefixes.path=prefixes.pathname local function toppath() - local inputstack=resolvers.inputstack - if not inputstack then - return "." - end - local pathname=dirname(inputstack[#inputstack] or "") - if pathname=="" then - return "." - else - return pathname - end + local inputstack=resolvers.inputstack + if not inputstack then + return "." + end + local pathname=dirname(inputstack[#inputstack] or "") + if pathname=="" then + return "." + else + return pathname + end end local function jobpath() - local path=resolvers.stackpath() - if not path or path=="" then - return "." - else - return path - end + local path=resolvers.stackpath() + if not path or path=="" then + return "." + else + return path + end end resolvers.toppath=toppath resolvers.jobpath=jobpath @@ -19423,8 +22997,6 @@ prefixes.toppath=function(str) return cleanpath(joinpath(toppath(),str)) end prefixes.jobpath=function(str) return cleanpath(joinpath(jobpath(),str)) end resolvers.setdynamic("toppath") resolvers.setdynamic("jobpath") -prefixes.jobfile=prefixes.jobpath -resolvers.setdynamic("jobfile") end -- of closure @@ -19433,14 +23005,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-inp"] = package.loaded["data-inp"] or true --- original size: 910, stripped down to: 823 +-- original size: 910, stripped down to: 818 if not modules then modules={} end modules ['data-inp']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19463,14 +23035,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-out"] = package.loaded["data-out"] or true --- original size: 530, stripped down to: 475 +-- original size: 530, stripped down to: 470 if not modules then modules={} end modules ['data-out']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local allocate=utilities.storage.allocate local resolvers=resolvers @@ -19486,16 +23058,16 @@ do -- create closure to overcome 200 locals limit package.loaded["data-fil"] = package.loaded["data-fil"] or true --- original size: 3863, stripped down to: 3310 +-- original size: 3863, stripped down to: 3170 if not modules then modules={} end modules ['data-fil']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_files=logs.reporter("resolvers","files") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -19503,88 +23075,88 @@ local finders,openers,loaders,savers=resolvers.finders,resolvers.openers,resolve local locators,hashers,generators,concatinators=resolvers.locators,resolvers.hashers,resolvers.generators,resolvers.concatinators local checkgarbage=utilities.garbagecollector and utilities.garbagecollector.check function locators.file(specification) - local filename=specification.filename - local realname=resolveprefix(filename) - if realname and realname~='' and lfs.isdir(realname) then - if trace_locating then - report_files("file locator %a found as %a",filename,realname) - end - resolvers.appendhash('file',filename,true) - elseif trace_locating then - report_files("file locator %a not found",filename) + local filename=specification.filename + local realname=resolveprefix(filename) + if realname and realname~='' and lfs.isdir(realname) then + if trace_locating then + report_files("file locator %a found as %a",filename,realname) end + resolvers.appendhash('file',filename,true) + elseif trace_locating then + report_files("file locator %a not found",filename) + end end function hashers.file(specification) - local pathname=specification.filename - local content=caches.loadcontent(pathname,'files') - resolvers.registerfilehash(pathname,content,content==nil) + local pathname=specification.filename + local content=caches.loadcontent(pathname,'files') + resolvers.registerfilehash(pathname,content,content==nil) end function generators.file(specification) - local pathname=specification.filename - local content=resolvers.scanfiles(pathname,false,true) - resolvers.registerfilehash(pathname,content,true) + local pathname=specification.filename + local content=resolvers.scanfiles(pathname,false,true) + resolvers.registerfilehash(pathname,content,true) end concatinators.file=file.join function finders.file(specification,filetype) - local filename=specification.filename - local foundname=resolvers.findfile(filename,filetype) - if foundname and foundname~="" then - if trace_locating then - report_files("file finder: %a found",filename) - end - return foundname - else - if trace_locating then - report_files("file finder: %a not found",filename) - end - return finders.notfound() + local filename=specification.filename + local foundname=resolvers.findfile(filename,filetype) + if foundname and foundname~="" then + if trace_locating then + report_files("file finder: %a found",filename) + end + return foundname + else + if trace_locating then + report_files("file finder: %a not found",filename) end + return finders.notfound() + end end function openers.helpers.textopener(tag,filename,f) - return { - reader=function() return f:read () end, - close=function() logs.show_close(filename) return f:close() end, - } + return { + reader=function() return f:read () end, + close=function() logs.show_close(filename) return f:close() end, + } end function openers.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"r") - if f then - if trace_locating then - report_files("file opener: %a opened",filename) - end - return openers.helpers.textopener("file",filename,f) - end - end - if trace_locating then - report_files("file opener: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"r") + if f then + if trace_locating then + report_files("file opener: %a opened",filename) + end + return openers.helpers.textopener("file",filename,f) end - return openers.notfound() + end + if trace_locating then + report_files("file opener: %a not found",filename) + end + return openers.notfound() end function loaders.file(specification,filetype) - local filename=specification.filename - if filename and filename~="" then - local f=io.open(filename,"rb") - if f then - logs.show_load(filename) - if trace_locating then - report_files("file loader: %a loaded",filename) - end - local s=f:read("*a") - if checkgarbage then - checkgarbage(#s) - end - f:close() - if s then - return true,s,#s - end - end - end - if trace_locating then - report_files("file loader: %a not found",filename) + local filename=specification.filename + if filename and filename~="" then + local f=io.open(filename,"rb") + if f then + logs.show_load(filename) + if trace_locating then + report_files("file loader: %a loaded",filename) + end + local s=f:read("*a") + if checkgarbage then + checkgarbage(#s) + end + f:close() + if s then + return true,s,#s + end end - return loaders.notfound() + end + if trace_locating then + report_files("file loader: %a not found",filename) + end + return loaders.notfound() end @@ -19594,116 +23166,116 @@ do -- create closure to overcome 200 locals limit package.loaded["data-con"] = package.loaded["data-con"] or true --- original size: 5029, stripped down to: 3607 +-- original size: 5029, stripped down to: 3432 if not modules then modules={} end modules ['data-con']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.100, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) -local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) -local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) +local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) +local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) +local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) containers=containers or {} local containers=containers containers.usecache=true local report_containers=logs.reporter("resolvers","containers") local allocated={} local mt={ - __index=function(t,k) - if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } - t.writable=writable - return writable - elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } - t.readables=readables - return readables - end - end, - __storage__=true + __index=function(t,k) + if k=="writable" then + local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } + t.writable=writable + return writable + elseif k=="readables" then + local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } + t.readables=readables + return readables + end + end, + __storage__=true } function containers.define(category,subcategory,version,enabled) - if category and subcategory then - local c=allocated[category] - if not c then - c={} - allocated[category]=c - end - local s=c[subcategory] - if not s then - s={ - category=category, - subcategory=subcategory, - storage={}, - enabled=enabled, - version=version or math.pi, - trace=false, - } - setmetatable(s,mt) - c[subcategory]=s - end - return s + if category and subcategory then + local c=allocated[category] + if not c then + c={} + allocated[category]=c + end + local s=c[subcategory] + if not s then + s={ + category=category, + subcategory=subcategory, + storage={}, + enabled=enabled, + version=version or math.pi, + trace=false, + } + setmetatable(s,mt) + c[subcategory]=s end + return s + end end function containers.is_usable(container,name) - return container.enabled and caches and caches.is_writable(container.writable,name) + return container.enabled and caches and caches.is_writable(container.writable,name) end function containers.is_valid(container,name) - if name and name~="" then - local storage=container.storage[name] - return storage and storage.cache_version==container.version - else - return false - end + if name and name~="" then + local storage=container.storage[name] + return storage and storage.cache_version==container.version + else + return false + end end function containers.read(container,name) - local storage=container.storage - local stored=storage[name] - if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name,container.writable) - if stored and stored.cache_version==container.version then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","load",container.subcategory,name) - end - else - stored=nil - end - storage[name]=stored - elseif stored then - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) - end + local storage=container.storage + local stored=storage[name] + if not stored and container.enabled and caches and containers.usecache then + stored=caches.loaddata(container.readables,name,container.writable) + if stored and stored.cache_version==container.version then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","load",container.subcategory,name) + end + else + stored=nil end - return stored + storage[name]=stored + elseif stored then + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","reuse",container.subcategory,name) + end + end + return stored end function containers.write(container,name,data) - if data then - data.cache_version=container.version - if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","save",container.subcategory,name) - end - data.unique,data.shared=unique,shared - end - if trace_cache or trace_containers then - report_containers("action %a, category %a, name %a","store",container.subcategory,name) - end - container.storage[name]=data + if data then + data.cache_version=container.version + if container.enabled and caches then + local unique,shared=data.unique,data.shared + data.unique,data.shared=nil,nil + caches.savedata(container.writable,name,data) + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","save",container.subcategory,name) + end + data.unique,data.shared=unique,shared end - return data + if trace_cache or trace_containers then + report_containers("action %a, category %a, name %a","store",container.subcategory,name) + end + container.storage[name]=data + end + return data end function containers.content(container,name) - return container.storage[name] + return container.storage[name] end function containers.cleanname(name) - return (gsub(lower(name),"[^%w\128-\255]+","-")) + return (gsub(lower(name),"[^%w\128-\255]+","-")) end @@ -19713,97 +23285,101 @@ do -- create closure to overcome 200 locals limit package.loaded["data-use"] = package.loaded["data-use"] or true --- original size: 4272, stripped down to: 3289 +-- original size: 4434, stripped down to: 3180 if not modules then modules={} end modules ['data-use']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,lower,gsub,find=string.format,string.lower,string.gsub,string.find -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_mounts=logs.reporter("resolvers","mounts") local resolvers=resolvers resolvers.automounted=resolvers.automounted or {} function resolvers.automount(usecache) - local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) - if (not mountpaths or #mountpaths==0) and usecache then - mountpaths=caches.getreadablepaths("mount") - end - if mountpaths and #mountpaths>0 then - resolvers.starttiming() - for k=1,#mountpaths do - local root=mountpaths[k] - local f=io.open(root.."/url.tmi") - if f then - for line in f:lines() do - if line then - if find(line,"^[%%#%-]") then - elseif find(line,"^zip://") then - if trace_locating then - report_mounts("mounting %a",line) - end - table.insert(resolvers.automounted,line) - resolvers.usezipfile(line) - end - end - end - f:close() + local mountpaths=resolvers.cleanpathlist(resolvers.expansion('TEXMFMOUNT')) + if (not mountpaths or #mountpaths==0) and usecache then + mountpaths=caches.getreadablepaths("mount") + end + if mountpaths and #mountpaths>0 then + resolvers.starttiming() + for k=1,#mountpaths do + local root=mountpaths[k] + local f=io.open(root.."/url.tmi") + if f then + for line in f:lines() do + if line then + if find(line,"^[%%#%-]") then + elseif find(line,"^zip://") then + if trace_locating then + report_mounts("mounting %a",line) + end + table.insert(resolvers.automounted,line) + resolvers.usezipfile(line) end + end end - resolvers.stoptiming() + f:close() + end end + resolvers.stoptiming() + end 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,kind,banner) - local enginebanner=status.banner - if formatbanner and enginebanner and sourcefile then - local luvname=file.replacesuffix(texname,"luv") - local luvdata={ - enginebanner=enginebanner, - formatbanner=formatbanner, - sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), - sourcefile=sourcefile, - luaversion=LUAVERSION, - } - io.savedata(luvname,table.serialize(luvdata,true)) - lua.registerfinalizer(function() - logs.report("format banner","%s",banner) - logs.newline() - end) - end + local enginebanner=status.banner + if formatbanner and enginebanner and sourcefile then + local luvname=file.replacesuffix(texname,"luv") + local luvdata={ + enginebanner=enginebanner, + formatbanner=formatbanner, + sourcehash=md5.hex(io.loaddata(resolvers.findfile(sourcefile)) or "unknown"), + sourcefile=sourcefile, + luaversion=LUAVERSION, + } + io.savedata(luvname,table.serialize(luvdata,true)) + lua.registerfinalizer(function() + if jit then + logs.report("format banner","%s lua: %s jit",banner,LUAVERSION) + else + logs.report("format banner","%s lua: %s",banner,LUAVERSION) + end + logs.newline() + end) + end end function statistics.checkfmtstatus(texname) - local enginebanner=status.banner - if enginebanner and texname then - local luvname=file.replacesuffix(texname,"luv") - if lfs.isfile(luvname) then - local luv=dofile(luvname) - if luv and luv.sourcefile then - local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") - local luvbanner=luv.enginebanner or "?" - if luvbanner~=enginebanner then - return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) - end - local luvhash=luv.sourcehash or "?" - if luvhash~=sourcehash then - return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) - end - local luvluaversion=luv.luaversion or 0 - if luvluaversion~=LUAVERSION then - return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) - end - else - return "invalid status file" - end - else - return "missing status file" - end + local enginebanner=status.banner + if enginebanner and texname then + local luvname=file.replacesuffix(texname,"luv") + if lfs.isfile(luvname) then + local luv=dofile(luvname) + if luv and luv.sourcefile then + local sourcehash=md5.hex(io.loaddata(resolvers.findfile(luv.sourcefile)) or "unknown") + local luvbanner=luv.enginebanner or "?" + if luvbanner~=enginebanner then + return format("engine mismatch (luv: %s <> bin: %s)",luvbanner,enginebanner) + end + local luvhash=luv.sourcehash or "?" + if luvhash~=sourcehash then + return format("source mismatch (luv: %s <> bin: %s)",luvhash,sourcehash) + end + local luvluaversion=luv.luaversion or 0 + if luvluaversion~=LUAVERSION then + return format("lua mismatch (luv: %s <> bin: %s)",luvluaversion,LUAVERSION) + end + else + return "invalid status file" + end + else + return "missing status file" end - return true + end + return true end @@ -19813,233 +23389,233 @@ do -- create closure to overcome 200 locals limit package.loaded["data-zip"] = package.loaded["data-zip"] or true --- original size: 8716, stripped down to: 6795 +-- original size: 8700, stripped down to: 6313 if not modules then modules={} end modules ['data-zip']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,find,match=string.format,string.find,string.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_zip=logs.reporter("resolvers","zip") local resolvers=resolvers zip=zip or {} local zip=zip -zip.archives=zip.archives or {} -local archives=zip.archives -zip.registeredfiles=zip.registeredfiles or {} -local registeredfiles=zip.registeredfiles +local archives=zip.archives or {} +zip.archives=archives +local registeredfiles=zip.registeredfiles or {} +zip.registeredfiles=registeredfiles local function validzip(str) - if not find(str,"^zip://") then - return "zip:///"..str - else - return str - end + if not find(str,"^zip://") then + return "zip:///"..str + else + return str + end end function zip.openarchive(name) - if not name or name=="" then - return nil - else - local arch=archives[name] - if not arch then - local full=resolvers.findfile(name) or "" - arch=full~="" and zip.open(full) or false - archives[name]=arch - end - return arch + if not name or name=="" then + return nil + else + local arch=archives[name] + if not arch then + local full=resolvers.findfile(name) or "" + arch=full~="" and zip.open(full) or false + archives[name]=arch end + return arch + end end function zip.closearchive(name) - if not name or (name=="" and archives[name]) then - zip.close(archives[name]) - archives[name]=nil - end + if not name or (name=="" and archives[name]) then + zip.close(archives[name]) + archives[name]=nil + end end function resolvers.locators.zip(specification) - local archive=specification.filename - local zipfile=archive and archive~="" and zip.openarchive(archive) - if trace_locating then - if zipfile then - report_zip("locator: archive %a found",archive) - else - report_zip("locator: archive %a not found",archive) - end + local archive=specification.filename + local zipfile=archive and archive~="" and zip.openarchive(archive) + if trace_locating then + if zipfile then + report_zip("locator: archive %a found",archive) + else + report_zip("locator: archive %a not found",archive) end + end end function resolvers.hashers.zip(specification) - local archive=specification.filename - if trace_locating then - report_zip("loading file %a",archive) - end - resolvers.usezipfile(specification.original) + local archive=specification.filename + if trace_locating then + report_zip("loading file %a",archive) + end + resolvers.usezipfile(specification.original) end function resolvers.concatinators.zip(zipfile,path,name) - if not path or path=="" then - return format('%s?name=%s',zipfile,name) - else - return format('%s?name=%s/%s',zipfile,path,name) - end + if not path or path=="" then + return format('%s?name=%s',zipfile,name) + else + return format('%s?name=%s/%s',zipfile,path,name) + end end function resolvers.finders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("finder: archive %a found",archive) - end - local dfile=zfile:open(queryname) - if dfile then - dfile=zfile:close() - if trace_locating then - report_zip("finder: file %a found",queryname) - end - return specification.original - elseif trace_locating then - report_zip("finder: file %a not found",queryname) - end - elseif trace_locating then - report_zip("finder: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("finder: archive %a found",archive) end + local dfile=zfile:open(queryname) + if dfile then + dfile:close() + if trace_locating then + report_zip("finder: file %a found",queryname) + end + return specification.original + elseif trace_locating then + report_zip("finder: file %a not found",queryname) + end + elseif trace_locating then + report_zip("finder: unknown archive %a",archive) + end end - if trace_locating then - report_zip("finder: %a not found",original) - end - return resolvers.finders.notfound() + end + if trace_locating then + report_zip("finder: %a not found",original) + end + return resolvers.finders.notfound() end function resolvers.openers.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("opener; archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - if trace_locating then - report_zip("opener: file %a found",queryname) - end - return resolvers.openers.helpers.textopener('zip',original,dfile) - elseif trace_locating then - report_zip("opener: file %a not found",queryname) - end - elseif trace_locating then - report_zip("opener: unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("opener; archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + if trace_locating then + report_zip("opener: file %a found",queryname) + end + return resolvers.openers.helpers.textopener('zip',original,dfile) + elseif trace_locating then + report_zip("opener: file %a not found",queryname) + end + elseif trace_locating then + report_zip("opener: unknown archive %a",archive) + end end - if trace_locating then - report_zip("opener: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("opener: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.loaders.zip(specification) - local original=specification.original - local archive=specification.filename - if archive then - local query=url.query(specification.query) - local queryname=query.name - if queryname then - local zfile=zip.openarchive(archive) - if zfile then - if trace_locating then - report_zip("loader: archive %a opened",archive) - end - local dfile=zfile:open(queryname) - if dfile then - logs.show_load(original) - if trace_locating then - report_zip("loader; file %a loaded",original) - end - local s=dfile:read("*all") - dfile:close() - return true,s,#s - elseif trace_locating then - report_zip("loader: file %a not found",queryname) - end - elseif trace_locating then - report_zip("loader; unknown archive %a",archive) - end + local original=specification.original + local archive=specification.filename + if archive then + local query=url.query(specification.query) + local queryname=query.name + if queryname then + local zfile=zip.openarchive(archive) + if zfile then + if trace_locating then + report_zip("loader: archive %a opened",archive) end + local dfile=zfile:open(queryname) + if dfile then + logs.show_load(original) + if trace_locating then + report_zip("loader; file %a loaded",original) + end + local s=dfile:read("*all") + dfile:close() + return true,s,#s + elseif trace_locating then + report_zip("loader: file %a not found",queryname) + end + elseif trace_locating then + report_zip("loader; unknown archive %a",archive) + end end - if trace_locating then - report_zip("loader: %a not found",original) - end - return resolvers.openers.notfound() + end + if trace_locating then + report_zip("loader: %a not found",original) + end + return resolvers.openers.notfound() end function resolvers.usezipfile(archive) - local specification=resolvers.splitmethod(archive) - local archive=specification.filename - if archive and not registeredfiles[archive] then - local z=zip.openarchive(archive) - if z then - local tree=url.query(specification.query).tree or "" - if trace_locating then - report_zip("registering: archive %a",archive) - end - resolvers.starttiming() - resolvers.prependhash('zip',archive) - resolvers.extendtexmfvariable(archive) - registeredfiles[archive]=z - resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) - resolvers.stoptiming() - elseif trace_locating then - report_zip("registering: unknown archive %a",archive) - end + local specification=resolvers.splitmethod(archive) + local archive=specification.filename + if archive and not registeredfiles[archive] then + local z=zip.openarchive(archive) + if z then + local tree=url.query(specification.query).tree or "" + if trace_locating then + report_zip("registering: archive %a",archive) + end + resolvers.starttiming() + resolvers.prependhash('zip',archive) + resolvers.extendtexmfvariable(archive) + registeredfiles[archive]=z + resolvers.registerfilehash(archive,resolvers.registerzipfile(z,tree)) + resolvers.stoptiming() elseif trace_locating then - report_zip("registering: archive %a not found",archive) + report_zip("registering: unknown archive %a",archive) end + elseif trace_locating then + report_zip("registering: archive %a not found",archive) + end end function resolvers.registerzipfile(z,tree) - local names={} - local files={} - local remap={} - local n=0 - local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) - local register=resolvers.registerfile - if trace_locating then - report_zip("registering: using filter %a",filter) - end - for i in z:files() do - local filename=i.filename - local path,name=match(filename,filter) - if not path then - n=n+1 - register(names,filename,"") - local usedname=lower(filename) - files[usedname]="" - if usedname~=filename then - remap[usedname]=filename - end - elseif name and name~="" then - n=n+1 - register(names,name,path) - local usedname=lower(name) - files[usedname]=path - if usedname~=name then - remap[usedname]=name - end - else - end + local names={} + local files={} + local remap={} + local n=0 + local filter=tree=="" and "^(.+)/(.-)$" or format("^%s/(.+)/(.-)$",tree) + local register=resolvers.registerfile + if trace_locating then + report_zip("registering: using filter %a",filter) + end + for i in z:files() do + local filename=i.filename + local path,name=match(filename,filter) + if not path then + n=n+1 + register(names,filename,"") + local usedname=lower(filename) + files[usedname]="" + if usedname~=filename then + remap[usedname]=filename + end + elseif name and name~="" then + n=n+1 + register(names,name,path) + local usedname=lower(name) + files[usedname]=path + if usedname~=name then + remap[usedname]=name + end + else end - report_zip("registering: %s files registered",n) - return { - files=files, - remap=remap, - } + end + report_zip("registering: %s files registered",n) + return { + files=files, + remap=remap, + } end @@ -20049,20 +23625,20 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tre"] = package.loaded["data-tre"] or true --- original size: 8479, stripped down to: 5580 +-- original size: 8478, stripped down to: 5223 if not modules then modules={} end modules ['data-tre']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find,gsub,lower=string.find,string.gsub,string.lower -local basename,dirname,joinname=file.basename,file.dirname,file .join +local basename,dirname,joinname=file.basename,file.dirname,file .join local globdir,isdir,isfile=dir.glob,lfs.isdir,lfs.isfile local P,lpegmatch=lpeg.P,lpeg.match -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) local report_trees=logs.reporter("resolvers","trees") local resolvers=resolvers local resolveprefix=resolvers.resolve @@ -20071,165 +23647,167 @@ local lookup=resolvers.get_from_content local collectors={} local found={} function resolvers.finders.tree(specification) - local spec=specification.filename - local okay=found[spec] - if okay==nil then - if spec~="" then - local path=dirname(spec) - local name=basename(spec) - if path=="" then - path="." - end - local names=collectors[path] - if not names then - local pattern=find(path,"/%*+$") and path or (path.."/*") - names=globdir(pattern) - collectors[path]=names - end - local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" - for i=1,#names do - local fullname=names[i] - if find(fullname,pattern) then - found[spec]=fullname - return fullname - end - end - local pattern=lower(pattern) - for i=1,#names do - local fullname=lower(names[i]) - if find(fullname,pattern) then - if isfile(fullname) then - found[spec]=fullname - return fullname - else - break - end - end - end + local spec=specification.filename + local okay=found[spec] + if okay==nil then + if spec~="" then + local path=dirname(spec) + local name=basename(spec) + if path=="" then + path="." + end + local names=collectors[path] + if not names then + local pattern=find(path,"/%*+$") and path or (path.."/*") + names=globdir(pattern) + collectors[path]=names + end + local pattern="/"..gsub(name,"([%.%-%+])","%%%1").."$" + for i=1,#names do + local fullname=names[i] + if find(fullname,pattern) then + found[spec]=fullname + return fullname + end + end + local pattern=lower(pattern) + for i=1,#names do + local fullname=lower(names[i]) + if find(fullname,pattern) then + if isfile(fullname) then + found[spec]=fullname + return fullname + else + break + end end - okay=notfound() - found[spec]=okay + end end - return okay + okay=notfound() + found[spec]=okay + end + return okay end function resolvers.locators.tree(specification) - local name=specification.filename - local realname=resolveprefix(name) - if realname and realname~='' and isdir(realname) then - if trace_locating then - report_trees("locator %a found",realname) - end - resolvers.appendhash('tree',name,false) - elseif trace_locating then - report_trees("locator %a not found",name) + local name=specification.filename + local realname=resolveprefix(name) + if realname and realname~='' and isdir(realname) then + if trace_locating then + report_trees("locator %a found",realname) end + resolvers.appendhash('tree',name,false) + elseif trace_locating then + report_trees("locator %a not found",name) + end end function resolvers.hashers.tree(specification) - local name=specification.filename - report_trees("analyzing %a",name) - resolvers.methodhandler("hashers",name) - resolvers.generators.file(specification) + local name=specification.filename + if trace_locating then + report_trees("analyzing %a",name) + end + resolvers.methodhandler("hashers",name) + resolvers.generators.file(specification) end local collectors={} local splitter=lpeg.splitat("/**/") local stripper=lpeg.replacer { [P("/")*P("*")^1*P(-1)]="" } table.setmetatableindex(collectors,function(t,k) - local rootname=lpegmatch(stripper,k) - local dataname=joinname(rootname,"dirlist") - local content=caches.loadcontent(dataname,"files",dataname) - if not content then - content=resolvers.scanfiles(rootname,nil,nil,false,true) - caches.savecontent(dataname,"files",content,dataname) - end - t[k]=content - return content + local rootname=lpegmatch(stripper,k) + local dataname=joinname(rootname,"dirlist") + local content=caches.loadcontent(dataname,"files",dataname) + if not content then + content=resolvers.scanfiles(rootname,nil,nil,false,true) + caches.savecontent(dataname,"files",content,dataname) + end + t[k]=content + return content end) local function checked(root,p,n) - if p then - if type(p)=="table" then - for i=1,#p do - local fullname=joinname(root,p[i],n) - if isfile(fullname) then - return fullname - end - end - else - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end + if p then + if type(p)=="table" then + for i=1,#p do + local fullname=joinname(root,p[i],n) + if isfile(fullname) then + return fullname end + end + else + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - return notfound() + end + return notfound() end local function resolve(specification) - local filename=specification.filename - if filename~="" then - local root,rest=lpegmatch(splitter,filename) - if root and rest then - local path,name=dirname(rest),basename(rest) - if name~=rest then - local content=collectors[root] - local p,n=lookup(content,name) - if not p then - return notfound() - end - local pattern=".*/"..path.."$" - local istable=type(p)=="table" - if istable then - for i=1,#p do - local pi=p[i] - if pi==path or find(pi,pattern) then - local fullname=joinname(root,pi,n) - if isfile(fullname) then - return fullname - end - end - end - elseif p==path or find(p,pattern) then - local fullname=joinname(root,p,n) - if isfile(fullname) then - return fullname - end - end - local queries=specification.queries - if queries and queries.option=="fileonly" then - return checked(root,p,n) - else - return notfound() - end + local filename=specification.filename + if filename~="" then + local root,rest=lpegmatch(splitter,filename) + if root and rest then + local path,name=dirname(rest),basename(rest) + if name~=rest then + local content=collectors[root] + local p,n=lookup(content,name) + if not p then + return notfound() + end + local pattern=".*/"..path.."$" + local istable=type(p)=="table" + if istable then + for i=1,#p do + local pi=p[i] + if pi==path or find(pi,pattern) then + local fullname=joinname(root,pi,n) + if isfile(fullname) then + return fullname + end end + end + elseif p==path or find(p,pattern) then + local fullname=joinname(root,p,n) + if isfile(fullname) then + return fullname + end end - local path,name=dirname(filename),basename(filename) - local root=lpegmatch(stripper,path) - local content=collectors[path] - local p,n=lookup(content,name) - if p then - return checked(root,p,n) + local queries=specification.queries + if queries and queries.option=="fileonly" then + return checked(root,p,n) + else + return notfound() end + end end - return notfound() + local path,name=dirname(filename),basename(filename) + local root=lpegmatch(stripper,path) + local content=collectors[path] + local p,n=lookup(content,name) + if p then + return checked(root,p,n) + end + end + return notfound() end -resolvers.finders .dirlist=resolve -resolvers.locators .dirlist=resolvers.locators .tree -resolvers.hashers .dirlist=resolvers.hashers .tree +resolvers.finders .dirlist=resolve +resolvers.locators .dirlist=resolvers.locators .tree +resolvers.hashers .dirlist=resolvers.hashers .tree resolvers.generators.dirlist=resolvers.generators.file -resolvers.openers .dirlist=resolvers.openers .file -resolvers.loaders .dirlist=resolvers.loaders .file +resolvers.openers .dirlist=resolvers.openers .file +resolvers.loaders .dirlist=resolvers.loaders .file function resolvers.finders.dirfile(specification) - local queries=specification.queries - if queries then - queries.option="fileonly" - else - specification.queries={ option="fileonly" } - end - return resolve(specification) -end -resolvers.locators .dirfile=resolvers.locators .dirlist -resolvers.hashers .dirfile=resolvers.hashers .dirlist + local queries=specification.queries + if queries then + queries.option="fileonly" + else + specification.queries={ option="fileonly" } + end + return resolve(specification) +end +resolvers.locators .dirfile=resolvers.locators .dirlist +resolvers.hashers .dirfile=resolvers.hashers .dirlist resolvers.generators.dirfile=resolvers.generators.dirlist -resolvers.openers .dirfile=resolvers.openers .dirlist -resolvers.loaders .dirfile=resolvers.loaders .dirlist +resolvers.openers .dirfile=resolvers.openers .dirlist +resolvers.loaders .dirfile=resolvers.loaders .dirlist end -- of closure @@ -20238,19 +23816,19 @@ do -- create closure to overcome 200 locals limit package.loaded["data-sch"] = package.loaded["data-sch"] or true --- original size: 6753, stripped down to: 5511 +-- original size: 6753, stripped down to: 5268 if not modules then modules={} end modules ['data-sch']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local load,tonumber=load,tonumber local gsub,concat,format=string.gsub,table.concat,string.format local finders,openers,loaders=resolvers.finders,resolvers.openers,resolvers.loaders -local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) +local trace_schemes=false trackers.register("resolvers.schemes",function(v) trace_schemes=v end) local report_schemes=logs.reporter("resolvers","schemes") local http=require("socket.http") local ltn12=require("ltn12") @@ -20263,27 +23841,27 @@ schemes.cleaners=cleaners local threshold=24*60*60 directives.register("schemes.threshold",function(v) threshold=tonumber(v) or threshold end) function cleaners.none(specification) - return specification.original + return specification.original end function cleaners.strip(specification) - local path,name=file.splitbase(specification.original) - if path=="" then - return (gsub(name,"[^%a%d%.]+","-")) - else - return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) - end + local path,name=file.splitbase(specification.original) + if path=="" then + return (gsub(name,"[^%a%d%.]+","-")) + else + return (gsub((gsub(path,"%.","-").."-"..name),"[^%a%d%.]+","-")) + end end function cleaners.md5(specification) - return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) + return file.addsuffix(md5.hex(specification.original),file.suffix(specification.path)) end local cleaner=cleaners.strip directives.register("schemes.cleanmethod",function(v) cleaner=cleaners[v] or cleaners.strip end) function resolvers.schemes.cleanname(specification) - local hash=cleaner(specification) - if trace_schemes then - report_schemes("hashing %a to %a",specification.original,hash) - end - return hash + local hash=cleaner(specification) + if trace_schemes then + report_schemes("hashing %a to %a",specification.original,hash) + end + return hash end local cached={} local loaded={} @@ -20291,139 +23869,139 @@ local reused={} local thresholds={} local handlers={} local runner=sandbox.registerrunner { - name="curl resolver", - method="execute", - program="curl", - template="--silent --insecure --create-dirs --output %cachename% %original%", - checkers={ - cachename="cache", - original="url", - } + name="curl resolver", + method="execute", + program="curl", + template="--silent --insecure --create-dirs --output %cachename% %original%", + checkers={ + cachename="cache", + original="url", + } } local function fetch(specification) - local original=specification.original - local scheme=specification.scheme - local cleanname=schemes.cleanname(specification) - local cachename=caches.setfirstwritablefile(cleanname,"schemes") - if not cached[original] then - statistics.starttiming(schemes) - if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then - cached[original]=cachename - local handler=handlers[scheme] - if handler then - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") - end - logs.flush() - handler(specification,cachename) - else - if trace_schemes then - report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") - end - logs.flush() - runner { - original=original, - cachename=cachename, - } - end - end - if io.exists(cachename) then - cached[original]=cachename - if trace_schemes then - report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) - end - else - cached[original]="" - if trace_schemes then - report_schemes("using missing %a, protocol %a",original,scheme) - end + local original=specification.original + local scheme=specification.scheme + local cleanname=schemes.cleanname(specification) + local cachename=caches.setfirstwritablefile(cleanname,"schemes") + if not cached[original] then + statistics.starttiming(schemes) + if not io.exists(cachename) or (os.difftime(os.time(),lfs.attributes(cachename).modification)>(thresholds[protocol] or threshold)) then + cached[original]=cachename + local handler=handlers[scheme] + if handler then + if trace_schemes then + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"built-in") end - loaded[scheme]=loaded[scheme]+1 - statistics.stoptiming(schemes) - else + logs.flush() + handler(specification,cachename) + else if trace_schemes then - report_schemes("reusing %a, protocol %a",original,scheme) + report_schemes("fetching %a, protocol %a, method %a",original,scheme,"curl") end - reused[scheme]=reused[scheme]+1 + logs.flush() + runner { + original=original, + cachename=cachename, + } + end + end + if io.exists(cachename) then + cached[original]=cachename + if trace_schemes then + report_schemes("using cached %a, protocol %a, cachename %a",original,scheme,cachename) + end + else + cached[original]="" + if trace_schemes then + report_schemes("using missing %a, protocol %a",original,scheme) + end end - return cached[original] + loaded[scheme]=loaded[scheme]+1 + statistics.stoptiming(schemes) + else + if trace_schemes then + report_schemes("reusing %a, protocol %a",original,scheme) + end + reused[scheme]=reused[scheme]+1 + end + return cached[original] end local function finder(specification,filetype) - return resolvers.methodhandler("finders",fetch(specification),filetype) + return resolvers.methodhandler("finders",fetch(specification),filetype) end local opener=openers.file local loader=loaders.file local function install(scheme,handler,newthreshold) - handlers [scheme]=handler - loaded [scheme]=0 - reused [scheme]=0 - finders [scheme]=finder - openers [scheme]=opener - loaders [scheme]=loader - thresholds[scheme]=newthreshold or threshold + handlers [scheme]=handler + loaded [scheme]=0 + reused [scheme]=0 + finders [scheme]=finder + openers [scheme]=opener + loaders [scheme]=loader + thresholds[scheme]=newthreshold or threshold end schemes.install=install local function http_handler(specification,cachename) - local tempname=cachename..".tmp" - local f=io.open(tempname,"wb") - local status,message=http.request { - url=specification.original, - sink=ltn12.sink.file(f) - } - if not status then - os.remove(tempname) - else - os.remove(cachename) - os.rename(tempname,cachename) - end - return cachename + local tempname=cachename..".tmp" + local f=io.open(tempname,"wb") + local status,message=http.request { + url=specification.original, + sink=ltn12.sink.file(f) + } + if not status then + os.remove(tempname) + else + os.remove(cachename) + os.rename(tempname,cachename) + end + return cachename end install('http',http_handler) install('https') install('ftp') statistics.register("scheme handling time",function() - local l,r,nl,nr={},{},0,0 - for k,v in table.sortedhash(loaded) do - if v>0 then - nl=nl+1 - l[nl]=k..":"..v - end - end - for k,v in table.sortedhash(reused) do - if v>0 then - nr=nr+1 - r[nr]=k..":"..v - end - end - local n=nl+nr - if n>0 then - l=nl>0 and concat(l) or "none" - r=nr>0 and concat(r) or "none" - return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", - statistics.elapsedtime(schemes),n,threshold,l,r) - else - return nil - end + local l,r,nl,nr={},{},0,0 + for k,v in table.sortedhash(loaded) do + if v>0 then + nl=nl+1 + l[nl]=k..":"..v + end + end + for k,v in table.sortedhash(reused) do + if v>0 then + nr=nr+1 + r[nr]=k..":"..v + end + end + local n=nl+nr + if n>0 then + l=nl>0 and concat(l) or "none" + r=nr>0 and concat(r) or "none" + return format("%s seconds, %s processed, threshold %s seconds, loaded: %s, reused: %s", + statistics.elapsedtime(schemes),n,threshold,l,r) + else + return nil + end end) local httprequest=http.request local toquery=url.toquery local function fetchstring(url,data) - local q=data and toquery(data) - if q then - url=url.."?"..q - end - local reply=httprequest(url) - return reply + local q=data and toquery(data) + if q then + url=url.."?"..q + end + local reply=httprequest(url) + return reply end schemes.fetchstring=fetchstring function schemes.fetchtable(url,data) - local reply=fetchstring(url,data) - if reply then - local s=load("return "..reply) - if s then - return s() - end + local reply=fetchstring(url,data) + if reply then + local s=load("return "..reply) + if s then + return s() end + end end @@ -20433,14 +24011,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lua"] = package.loaded["data-lua"] or true --- original size: 4207, stripped down to: 3137 +-- original size: 4207, stripped down to: 3041 if not modules then modules={} end modules ['data-lua']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local package,lpeg=package,lpeg local gsub=string.gsub @@ -20459,20 +24037,20 @@ helpers.report=logs.reporter("resolvers","libraries") trackers.register("resolvers.libraries",function(v) helpers.trace=v end) trackers.register("resolvers.locating",function(v) helpers.trace=v end) helpers.sequence={ - "already loaded", - "preload table", - "lua variable format", - "lib variable format", - "lua extra list", - "lib extra list", - "path specification", - "cpath specification", - "all in one fallback", - "not loaded", + "already loaded", + "preload table", + "lua variable format", + "lib variable format", + "lua extra list", + "lib extra list", + "path specification", + "cpath specification", + "all in one fallback", + "not loaded", } local pattern=Cs(P("!")^0/""*(P("/")*P(-1)/"/"+P("/")^1/"/"+1)^0) function helpers.cleanpath(path) - return resolveprefix(lpegmatch(pattern,path)) + return resolveprefix(lpegmatch(pattern,path)) end local loadedaslib=helpers.loadedaslib local registerpath=helpers.registerpath @@ -20480,56 +24058,56 @@ local lualibfile=helpers.lualibfile local luaformatpaths local libformatpaths local function getluaformatpaths() - if not luaformatpaths then - luaformatpaths={} - for i=1,#luaformats do - registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) - end + if not luaformatpaths then + luaformatpaths={} + for i=1,#luaformats do + registerpath("lua format","lua",luaformatpaths,resolvers.expandedpathlistfromvariable(luaformats[i])) end - return luaformatpaths + end + return luaformatpaths end local function getlibformatpaths() - if not libformatpaths then - libformatpaths={} - for i=1,#libformats do - registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) - end + if not libformatpaths then + libformatpaths={} + for i=1,#libformats do + registerpath("lib format","lib",libformatpaths,resolvers.expandedpathlistfromvariable(libformats[i])) end - return libformatpaths + end + return libformatpaths end local function loadedbyformat(name,rawname,suffixes,islib,what) - local trace=helpers.trace - local report=helpers.report - for i=1,#suffixes do - local format=suffixes[i] - local resolved=resolvers.findfile(name,format) or "" - if trace then - report("%s format, identifying %a using format %a",what,name,format) - end - if resolved~="" then - if trace then - report("%s format, %a found on %a",what,name,resolved) - end - if islib then - return loadedaslib(resolved,rawname) - else - return loadfile(resolved) - end - end + local trace=helpers.trace + local report=helpers.report + for i=1,#suffixes do + local format=suffixes[i] + local resolved=resolvers.findfile(name,format) or "" + if trace then + report("%s format, identifying %a using format %a",what,name,format) + end + if resolved~="" then + if trace then + report("%s format, %a found on %a",what,name,resolved) + end + if islib then + return loadedaslib(resolved,rawname) + else + return loadfile(resolved) + end end + end end helpers.loadedbyformat=loadedbyformat methods["lua variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") + if helpers.trace then + helpers.report("%s format, checking %s paths","lua",#getluaformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),"lua"),name,luasuffixes,false,"lua") end methods["lib variable format"]=function(name) - if helpers.trace then - helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) - end - return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") + if helpers.trace then + helpers.report("%s format, checking %s paths","lib",#getlibformatpaths()) + end + return loadedbyformat(addsuffix(lualibfile(name),os.libsuffix),name,libsuffixes,true,"lib") end resolvers.loadlualib=require @@ -20540,64 +24118,64 @@ do -- create closure to overcome 200 locals limit package.loaded["data-aux"] = package.loaded["data-aux"] or true --- original size: 2438, stripped down to: 2003 +-- original size: 2452, stripped down to: 1877 if not modules then modules={} end modules ['data-aux']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local find=string.find local type,next=type,next -local trace_locating=false trackers.register("resolvers.locating",function(v) trace_locating=v end) +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="context/lua" - newname=file.addsuffix(newname,"lua") - local oldscript=resolvers.cleanpath(oldname) + local scriptpath="context/lua" + newname=file.addsuffix(newname,"lua") + local oldscript=resolvers.cleanpath(oldname) + if trace_locating then + report_scripts("to be replaced old script %a",oldscript) + end + local newscripts=resolvers.findfiles(newname) or {} + if #newscripts==0 then if trace_locating then - report_scripts("to be replaced old script %a",oldscript) + report_scripts("unable to locate new script") end - local newscripts=resolvers.findfiles(newname) or {} - if #newscripts==0 then + else + for i=1,#newscripts do + local newscript=resolvers.cleanpath(newscripts[i]) + if trace_locating then + report_scripts("checking new script %a",newscript) + end + if oldscript==newscript then if trace_locating then - report_scripts("unable to locate new script") + report_scripts("old and new script are the same") end - else - for i=1,#newscripts do - local newscript=resolvers.cleanpath(newscripts[i]) - if trace_locating then - report_scripts("checking new script %a",newscript) - end - if oldscript==newscript then - if trace_locating then - report_scripts("old and new script are the same") - end - elseif not find(newscript,scriptpath,1,true) then - if trace_locating then - report_scripts("new script should come from %a",scriptpath) - end - elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then - if trace_locating then - report_scripts("invalid new script name") - end - else - local newdata=io.loaddata(newscript) - if newdata then - if trace_locating then - report_scripts("old script content replaced by new content") - end - io.savedata(oldscript,newdata) - break - elseif trace_locating then - report_scripts("unable to load new script") - end - end + elseif not find(newscript,scriptpath,1,true) then + if trace_locating then + report_scripts("new script should come from %a",scriptpath) end + elseif not (find(oldscript,file.removesuffix(newname).."$") or find(oldscript,newname.."$")) then + if trace_locating then + report_scripts("invalid new script name") + end + else + local newdata=io.loaddata(newscript) + if newdata then + if trace_locating then + report_scripts("old script content replaced by new content: %s",oldscript) + end + io.savedata(oldscript,newdata) + break + elseif trace_locating then + report_scripts("unable to load new script") + end + end end + end end @@ -20607,53 +24185,53 @@ do -- create closure to overcome 200 locals limit package.loaded["data-tmf"] = package.loaded["data-tmf"] or true --- original size: 2601, stripped down to: 1627 +-- original size: 2601, stripped down to: 1549 if not modules then modules={} end modules ['data-tmf']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local resolvers=resolvers local report_tds=logs.reporter("resolvers","tds") function resolvers.load_tree(tree,resolve) - if type(tree)=="string" and tree~="" then - local getenv,setenv=resolvers.getenv,resolvers.setenv - local texos="texmf-"..os.platform - local oldroot=environment.texroot - local newroot=file.collapsepath(tree) - local newtree=file.join(newroot,texos) - local newpath=file.join(newtree,"bin") - if not lfs.isdir(newtree) then - report_tds("no %a under tree %a",texos,tree) - os.exit() - end - if not lfs.isdir(newpath) then - report_tds("no '%s/bin' under tree %a",texos,tree) - os.exit() - end - local texmfos=newtree - environment.texroot=newroot - environment.texos=texos - environment.texmfos=texmfos - if resolve then - resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) - end - setenv('SELFAUTOPARENT',newroot) - setenv('SELFAUTODIR',newtree) - setenv('SELFAUTOLOC',newpath) - setenv('TEXROOT',newroot) - setenv('TEXOS',texos) - setenv('TEXMFOS',texmfos) - setenv('TEXMFCNF',resolvers.luacnfspec,true) - setenv('PATH',newpath..io.pathseparator..getenv('PATH')) - report_tds("changing from root %a to %a",oldroot,newroot) - report_tds("prepending %a to PATH",newpath) - report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) - report_tds() - end + if type(tree)=="string" and tree~="" then + local getenv,setenv=resolvers.getenv,resolvers.setenv + local texos="texmf-"..os.platform + local oldroot=environment.texroot + local newroot=file.collapsepath(tree) + local newtree=file.join(newroot,texos) + local newpath=file.join(newtree,"bin") + if not lfs.isdir(newtree) then + report_tds("no %a under tree %a",texos,tree) + os.exit() + end + if not lfs.isdir(newpath) then + report_tds("no '%s/bin' under tree %a",texos,tree) + os.exit() + end + local texmfos=newtree + environment.texroot=newroot + environment.texos=texos + environment.texmfos=texmfos + if resolve then + resolvers.luacnfspec=resolvers.resolve(resolvers.luacnfspec) + end + setenv('SELFAUTOPARENT',newroot) + setenv('SELFAUTODIR',newtree) + setenv('SELFAUTOLOC',newpath) + setenv('TEXROOT',newroot) + setenv('TEXOS',texos) + setenv('TEXMFOS',texmfos) + setenv('TEXMFCNF',resolvers.luacnfspec,true) + setenv('PATH',newpath..io.pathseparator..getenv('PATH')) + report_tds("changing from root %a to %a",oldroot,newroot) + report_tds("prepending %a to PATH",newpath) + report_tds("setting TEXMFCNF to %a",resolvers.luacnfspec) + report_tds() + end end @@ -20663,14 +24241,14 @@ do -- create closure to overcome 200 locals limit package.loaded["data-lst"] = package.loaded["data-lst"] or true --- original size: 1823, stripped down to: 1591 +-- original size: 1823, stripped down to: 1542 if not modules then modules={} end modules ['data-lst']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local type=type local concat,sortedhash=table.concat,table.sortedhash @@ -20681,37 +24259,37 @@ local resolveprefix=resolvers.resolve local report_lists=logs.reporter("resolvers","lists") local report_resolved=logs.reporter("system","resolved") local function tabstr(str) - if type(str)=='table' then - return concat(str," | ") - else - return str - end + if type(str)=='table' then + return concat(str," | ") + else + return str + end end function listers.variables(pattern) - local result=resolvers.knownvariables(pattern) - for key,value in sortedhash(result) do - report_lists(key) - report_lists(" env: %s",tabstr(value.environment or "unset")) - report_lists(" var: %s",tabstr(value.variable or "unset")) - report_lists(" exp: %s",tabstr(value.expansion or "unset")) - report_lists(" res: %s",tabstr(value.resolved or "unset")) - end + local result=resolvers.knownvariables(pattern) + for key,value in sortedhash(result) do + report_lists(key) + report_lists(" env: %s",tabstr(value.environment or "unset")) + report_lists(" var: %s",tabstr(value.variable or "unset")) + report_lists(" exp: %s",tabstr(value.expansion or "unset")) + report_lists(" res: %s",tabstr(value.resolved or "unset")) + end end function listers.configurations() - local configurations=resolvers.configurationfiles() - for i=1,#configurations do - report_resolved("file : %s",resolveprefix(configurations[i])) - end - report_resolved("") - local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) - for i=1,#list do - local li=resolveprefix(list[i]) - if lfs.isdir(li) then - report_resolved("path - %s",li) - else - report_resolved("path + %s",li) - end + local configurations=resolvers.configurationfiles() + for i=1,#configurations do + report_resolved("file : %s",resolveprefix(configurations[i])) + end + report_resolved("") + local list=resolvers.expandedpathfromlist(resolvers.splitpath(resolvers.luacnfspec)) + for i=1,#list do + local li=resolveprefix(list[i]) + if lfs.isdir(li) then + report_resolved("path - %s",li) + else + report_resolved("path + %s",li) end + end end @@ -20721,14 +24299,14 @@ do -- create closure to overcome 200 locals limit package.loaded["util-lib"] = package.loaded["util-lib"] or true --- original size: 14943, stripped down to: 8305 +-- original size: 16094, stripped down to: 8443 if not modules then modules={} end modules ['util-lib']={ - version=1.001, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files", + version=1.001, + comment="companion to luat-lib.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files", } local type=type local next=next @@ -20748,256 +24326,291 @@ local qualifiedpath=file.is_qualified_path local isfile=lfs.isfile local done=false local function locate(required,version,trace,report,action) - if type(required)~="string" then - report("provide a proper library name") - return - end - if trace then - report("requiring library %a with version %a",required,version or "any") - end - local found_library=nil - local required_full=gsub(required,"%.","/") - local required_path=pathpart(required_full) - local required_base=nameonly(required_full) - if qualifiedpath(required) then - if isfile(addsuffix(required,os.libsuffix)) then - if trace then - report("qualified name %a found",required) - end - found_library=required - else - if trace then - report("qualified name %a not found",required) - end - end + if type(required)~="string" then + report("provide a proper library name") + return + end + if trace then + report("requiring library %a with version %a",required,version or "any") + end + local found_library=nil + local required_full=gsub(required,"%.","/") + local required_path=pathpart(required_full) + local required_base=nameonly(required_full) + if qualifiedpath(required) then + if isfile(addsuffix(required,os.libsuffix)) then + if trace then + report("qualified name %a found",required) + end + found_library=required else - local required_name=required_base.."."..os.libsuffix - local version=type(version)=="string" and version~="" and version or false - local engine="luatex" - if trace and not done then - local list=expandpaths("lib") - for i=1,#list do - report("tds path %i: %s",i,list[i]) - end + if trace then + report("qualified name %a not found",required) + end + end + else + local required_name=required_base.."."..os.libsuffix + local version=type(version)=="string" and version~="" and version or false + local engine="luatex" + if trace and not done then + local list=expandpaths("lib") + for i=1,#list do + report("tds path %i: %s",i,list[i]) + end + end + local function found(locate,asked_library,how,...) + if trace then + report("checking %s: %a",how,asked_library) + end + return locate(asked_library,...) + end + local function check(locate,...) + local found=nil + if version then + local asked_library=joinfile(required_path,version,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function found(locate,asked_library,how,...) - if trace then - report("checking %s: %a",how,asked_library) - end - return locate(asked_library,...) - end - local function check(locate,...) - local found=nil - if version then - local asked_library=joinfile(required_path,version,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - if not found or found=="" then - local asked_library=joinfile(required_path,required_name) - if trace then - report("checking %s: %a","with version",asked_library) - end - found=locate(asked_library,...) - end - return found and found~="" and found or false + found=locate(asked_library,...) + end + if not found or found=="" then + local asked_library=joinfile(required_path,required_name) + if trace then + report("checking %s: %a","with version",asked_library) end - local function attempt(checkpattern) - if trace then - report("checking tds lib paths strictly") - end - local found=findfile and check(findfile,"lib") - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - if trace then - report("checking tds lib paths with wildcard") - end - local asked_library=joinfile(required_path,".*",required_name) - if trace then - report("checking %s: %a","latest version",asked_library) - end - local list=findfiles(asked_library,"lib",true) - if list and #list>0 then - sort(list) - local found=list[#list] - if found and (not checkpattern or find(found,checkpattern)) then - return found - end - end - if trace then - report("checking lib paths") - end - package.extralibpath(environment.ownpath) - local paths=package.libpaths() - local pattern="/[^/]+%."..os.libsuffix.."$" - for i=1,#paths do - required_path=gsub(paths[i],pattern,"") - local found=check(lfs.isfound) - if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then - return found - end - end - return false + found=locate(asked_library,...) + end + return found and found~="" and found or false + end + local function attempt(checkpattern) + if trace then + report("checking tds lib paths strictly") + end + local found=findfile and check(findfile,"lib") + if found and (not checkpattern or find(found,checkpattern)) then + return found + end + if trace then + report("checking tds lib paths with wildcard") + end + local asked_library=joinfile(required_path,".*",required_name) + if trace then + report("checking %s: %a","latest version",asked_library) + end + local list=findfiles(asked_library,"lib",true) + if list and #list>0 then + sort(list) + local found=list[#list] + if found and (not checkpattern or find(found,checkpattern)) then + return found end - if engine then - if trace then - report("attemp 1, engine %a",engine) - end - found_library=attempt("/"..engine.."/") - if not found_library then - if trace then - report("attemp 2, no engine",asked_library) - end - found_library=attempt() - end - else - found_library=attempt() + end + if trace then + report("checking lib paths") + end + package.extralibpath(environment.ownpath) + local paths=package.libpaths() + local pattern="/[^/]+%."..os.libsuffix.."$" + for i=1,#paths do + required_path=gsub(paths[i],pattern,"") + local found=check(lfs.isfound) + if type(found)=="string" and (not checkpattern or find(found,checkpattern)) then + return found end + end + return false end - if not found_library then + if engine then + if trace then + report("attemp 1, engine %a",engine) + end + found_library=attempt("/"..engine.."/") + if not found_library then if trace then - report("not found: %a",required) + report("attemp 2, no engine",asked_library) end - library=false + found_library=attempt() + end else - if trace then - report("found: %a",found_library) - end - local result,message=action(found_library,required_base) - if result then - library=result - else - library=false - report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") - end + found_library=attempt() end + end + if not found_library then if trace then - if not library then - report("unknown library: %a",required) - else - report("stored library: %a",required) - end + report("not found: %a",required) end - return library + library=false + else + if trace then + report("found: %a",found_library) + end + local result,message=action(found_library,required_base) + if result then + library=result + else + library=false + report("load error: message %a, library %a",tostring(message or "unknown"),found_library or "no library") + end + end + if trace then + if not library then + report("unknown library: %a",required) + else + report("stored library: %a",required) + end + end + return library or nil end do - local report_swiglib=logs.reporter("swiglib") - local trace_swiglib=false - local savedrequire=require - local loadedlibs={} - local loadlib=package.loadlib - local pushdir=dir.push - local popdir=dir.pop - trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) - function requireswiglib(required,version) - local library=loadedlibs[library] - if library==nil then - local trace_swiglib=trace_swiglib or package.helpers.trace - library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) - pushdir(pathpart(name)) - local opener="luaopen_"..base - if trace_swiglib then - report_swiglib("opening: %a with %a",name,opener) - end - local library,message=loadlib(name,opener) - local libtype=type(library) - if libtype=="function" then - library=library() - else - 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 - popdir() - return library - end) - loadedlibs[required]=library or false + local report_swiglib=logs.reporter("swiglib") + local trace_swiglib=false + local savedrequire=require + local loadedlibs={} + local loadlib=package.loadlib + local pushdir=dir.push + local popdir=dir.pop + trackers.register("resolvers.swiglib",function(v) trace_swiglib=v end) + function requireswiglib(required,version) + local library=loadedlibs[library] + if library==nil then + local trace_swiglib=trace_swiglib or package.helpers.trace + library=locate(required,version,trace_swiglib,report_swiglib,function(name,base) + pushdir(pathpart(name)) + local opener="luaopen_"..base + if trace_swiglib then + report_swiglib("opening: %a with %a",name,opener) + end + local library,message=loadlib(name,opener) + local libtype=type(library) + if libtype=="function" then + library=library() + else + 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 + popdir() return library + end) + loadedlibs[required]=library or false end - function require(name,version) - if find(name,"^swiglib%.") then - return requireswiglib(name,version) - else - return savedrequire(name) - end + return library + end + function require(name,version) + if find(name,"^swiglib%.") then + return requireswiglib(name,version) + else + return savedrequire(name) + end + end + local swiglibs={} + local initializer="core" + function swiglib(name,version) + local library=swiglibs[name] + if not library then + statistics.starttiming(swiglibs) + if trace_swiglib then + report_swiglib("loading %a",name) + end + 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 - local swiglibs={} - local initializer="core" - function swiglib(name,version) - local library=swiglibs[name] - if not library then - statistics.starttiming(swiglibs) - if trace_swiglib then - report_swiglib("loading %a",name) - end - 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 - return library + return library + end + statistics.register("used swiglibs",function() + if next(swiglibs) then + return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) end - statistics.register("used swiglibs",function() - if next(swiglibs) then - return string.format("%s, initial load time %s seconds",table.concat(table.sortedkeys(swiglibs)," "),statistics.elapsedtime(swiglibs)) - end - end) + end) end if FFISUPPORTED and ffi and ffi.load then - local report_ffilib=logs.reporter("ffilib") - local trace_ffilib=false - local savedffiload=ffi.load - trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) - local loaded={} - local function locateindeed(name) - name=removesuffix(name) - local l=loaded[name] - if l==nil then - local message,library=pcall(savedffiload,name) - if type(message)=="userdata" then - l=message - elseif type(library)=="userdata" then - l=library - else - l=false - end - loaded[name]=l - elseif trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l + local report_ffilib=logs.reporter("ffilib") + local trace_ffilib=false + local savedffiload=ffi.load + trackers.register("resolvers.ffilib",function(v) trace_ffilib=v end) + local loaded={} + local function locateindeed(name) + name=removesuffix(name) + local l=loaded[name] + if l==nil then + local state,library=pcall(savedffiload,name) + if type(library)=="userdata" then + l=library + elseif type(state)=="userdata" then + l=state + else + l=false + end + loaded[name]=l + elseif trace_ffilib then + report_ffilib("reusing already loaded %a",name) end - function ffilib(name,version) - name=removesuffix(name) - local l=loaded[name] - if l~=nil then - if trace_ffilib then - report_ffilib("reusing already loaded %a",name) - end - return l - elseif version=="system" then - return locateindeed(name) - else - return locate(name,version,trace_ffilib,report_ffilib,locateindeed) + return l + end + local function getlist(required) + local list=directives.value("system.librarynames" ) + if type(list)=="table" then + list=list[required] + if type(list)=="table" then + if trace then + report("using lookup list for library %a: % | t",required,list) end + return list + end end - function ffi.load(name) - local library=ffilib(name) + return { required } + end + function ffilib(name,version) + name=removesuffix(name) + local l=loaded[name] + if l~=nil then + if trace_ffilib then + report_ffilib("reusing already loaded %a",name) + end + return l + end + local list=getlist(name) + if version=="system" then + for i=1,#list do + local library=locateindeed(list[i]) if type(library)=="userdata" then - return library + return library end - if trace_ffilib then - report_ffilib("trying to load %a using normal loader",name) + end + else + for i=1,#list do + local library=locate(list[i],version,trace_ffilib,report_ffilib,locateindeed) + if type(library)=="userdata" then + return library end - return savedffiload(name) + end end + end + function ffi.load(name) + local list=getlist(name) + for i=1,#list do + local library=ffilib(list[i]) + if type(library)=="userdata" then + return library + end + end + if trace_ffilib then + report_ffilib("trying to load %a using normal loader",name) + end + for i=1,#list do + local state,library=pcall(savedffiload,list[i]) + if type(library)=="userdata" then + return library + elseif type(state)=="userdata" then + return library + end + end + end end @@ -21007,13 +24620,13 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-sta"] = package.loaded["luat-sta"] or true --- original size: 5703, stripped down to: 2507 +-- original size: 5703, stripped down to: 2321 if not modules then modules={} end modules ['luat-sta']={ - version=1.001, - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local gmatch,match=string.gmatch,string.match local type=type @@ -21026,81 +24639,81 @@ local hash=states.hash states.tag=states.tag or "" states.filename=states.filename or "" function states.save(filename,tag) - tag=tag or states.tag - filename=file.addsuffix(filename or states.filename,'lus') - io.savedata(filename, - "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) - ) + tag=tag or states.tag + filename=file.addsuffix(filename or states.filename,'lus') + io.savedata(filename, + "-- generator : luat-sta.lua\n".."-- state tag : "..tag.."\n\n"..table.serialize(data[tag or states.tag] or {},true) + ) end function states.load(filename,tag) - states.filename=filename - states.tag=tag or "whatever" - states.filename=file.addsuffix(states.filename,'lus') - data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} + states.filename=filename + states.tag=tag or "whatever" + states.filename=file.addsuffix(states.filename,'lus') + data[states.tag],hash[states.tag]=(io.exists(filename) and dofile(filename)) or {},{} end local function set_by_tag(tag,key,value,default,persistent) - local d,h=data[tag],hash[tag] - if d then - if type(d)=="table" then - local dkey,hkey=key,key - local pre,post=match(key,"(.+)%.([^%.]+)$") - if pre and post then - for k in gmatch(pre,"[^%.]+") do - local dk=d[k] - if not dk then - dk={} - d[k]=dk - elseif type(dk)=="string" then - break - end - d=dk - end - dkey,hkey=post,key - end - if value==nil then - value=default - elseif value==false then - elseif persistent then - value=value or d[dkey] or default - else - value=value or default - end - d[dkey],h[hkey]=value,value - elseif type(d)=="string" then - data[tag],hash[tag]=value,value + local d,h=data[tag],hash[tag] + if d then + if type(d)=="table" then + local dkey,hkey=key,key + local pre,post=match(key,"(.+)%.([^%.]+)$") + if pre and post then + for k in gmatch(pre,"[^%.]+") do + local dk=d[k] + if not dk then + dk={} + d[k]=dk + elseif type(dk)=="string" then + break + end + d=dk end + dkey,hkey=post,key + end + if value==nil then + value=default + elseif value==false then + elseif persistent then + value=value or d[dkey] or default + else + value=value or default + end + d[dkey],h[hkey]=value,value + elseif type(d)=="string" then + data[tag],hash[tag]=value,value end + end end local function get_by_tag(tag,key,default) - local h=hash[tag] - if h and h[key] then - return h[key] - else - local d=data[tag] - if d then - for k in gmatch(key,"[^%.]+") do - local dk=d[k] - if dk~=nil then - d=dk - else - return default - end - end - if d==false then - return false - else - return d or default - end + local h=hash[tag] + if h and h[key] then + return h[key] + else + local d=data[tag] + if d then + for k in gmatch(key,"[^%.]+") do + local dk=d[k] + if dk~=nil then + d=dk + else + return default end + end + if d==false then + return false + else + return d or default + end end + end end states.set_by_tag=set_by_tag states.get_by_tag=get_by_tag function states.set(key,value,default,persistent) - set_by_tag(states.tag,key,value,default,persistent) + set_by_tag(states.tag,key,value,default,persistent) end function states.get(key,default) - return get_by_tag(states.tag,key,default) + return get_by_tag(states.tag,key,default) end @@ -21110,14 +24723,14 @@ do -- create closure to overcome 200 locals limit package.loaded["luat-fmt"] = package.loaded["luat-fmt"] or true --- original size: 9268, stripped down to: 7401 +-- original size: 9418, stripped down to: 7087 if not modules then modules={} end modules ['luat-fmt']={ - version=1.001, - comment="companion to mtxrun", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="companion to mtxrun", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format=string.format local concat=table.concat @@ -21125,229 +24738,232 @@ local quoted=string.quoted local luasuffixes=utilities.lua.suffixes local report_format=logs.reporter("resolvers","formats") local function primaryflags() - local arguments=environment.arguments - local flags={} - if arguments.silent then - flags[#flags+1]="--interaction=batchmode" - end - if arguments.jit then - flags[#flags+1]="--jiton" - end - return concat(flags," ") + local arguments=environment.arguments + local flags={} + if arguments.silent then + flags[#flags+1]="--interaction=batchmode" + end + return concat(flags," ") end local function secondaryflags() - local arguments=environment.arguments - local trackers=arguments.trackers - local directives=arguments.directives - local flags={} - if trackers and trackers~="" then - flags[#flags+1]="--c:trackers="..quoted(trackers) - end - if directives and directives~="" then - flags[#flags+1]="--c:directives="..quoted(directives) - end - if arguments.silent then - flags[#flags+1]="--c:silent" - end - if arguments.errors then - flags[#flags+1]="--c:errors" - end - if arguments.jit then - flags[#flags+1]="--c:jiton" - end - if arguments.ansi then - flags[#flags+1]="--c:ansi" - end - return concat(flags," ") + local arguments=environment.arguments + local trackers=arguments.trackers + local directives=arguments.directives + local flags={} + if trackers and trackers~="" then + flags[#flags+1]="--c:trackers="..quoted(trackers) + end + if directives and directives~="" then + flags[#flags+1]="--c:directives="..quoted(directives) + end + if arguments.silent then + flags[#flags+1]="--c:silent" + end + if arguments.errors then + flags[#flags+1]="--c:errors" + end + if arguments.jit then + flags[#flags+1]="--c:jiton" + end + if arguments.ansi then + flags[#flags+1]="--c:ansi" + end + if arguments.strip then + flags[#flags+1]="--c:strip" + end + if arguments.lmtx then + flags[#flags+1]="--c:lmtx" + end + return concat(flags," ") end local template=[[--ini %primaryflags% --lua=%luafile% %texfile% %secondaryflags% %dump% %redirect%]] local checkers={ - primaryflags="string", - secondaryflags="string", - luafile="readable", - texfile="readable", - redirect="string", - dump="string", + primaryflags="string", + secondaryflags="string", + luafile="readable", + texfile="readable", + redirect="string", + dump="string", } local runners={ - luatex=sandbox.registerrunner { - name="make luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="make luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="make luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="make luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.make_format(name,arguments) - local engine=environment.ownmain or "luatex" - local silent=environment.arguments.silent - local errors=environment.arguments.errors - local olddir=dir.current() - local path=caches.getwritablepath("formats",engine) or "" - if path~="" then - lfs.chdir(path) - end - report_format("using format path %a",dir.current()) - local texsourcename=file.addsuffix(name,"mkiv") - local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - if fulltexsourcename=="" then - texsourcename=file.addsuffix(name,"tex") - fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" - end - if fulltexsourcename=="" then - report_format("no tex source file with name %a (mkiv or tex)",name) - lfs.chdir(olddir) - return - else - report_format("using tex source file %a",fulltexsourcename) - end - local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) - local specificationname=file.replacesuffix(fulltexsourcename,"lus") - local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - if fullspecificationname=="" then - specificationname=file.join(texsourcepath,"context.lus") - fullspecificationname=resolvers.findfile(specificationname,"tex") or "" - end - if fullspecificationname=="" then - report_format("unknown stub specification %a",specificationname) - lfs.chdir(olddir) - return - end - local specificationpath=file.dirname(fullspecificationname) - local usedluastub=nil - local usedlualibs=dofile(fullspecificationname) - if type(usedlualibs)=="string" then - usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) - elseif type(usedlualibs)=="table" then - report_format("using stub specification %a",fullspecificationname) - local texbasename=file.basename(name) - local luastubname=file.addsuffix(texbasename,luasuffixes.lua) - local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) - report_format("creating initialization file %a",luastubname) - utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) - if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then - report_format("using compiled initialization file %a",lucstubname) - usedluastub=lucstubname - else - report_format("using uncompiled initialization file %a",luastubname) - usedluastub=luastubname - end - else - report_format("invalid stub specification %a",fullspecificationname) - lfs.chdir(olddir) - return - end - local specification={ - primaryflags=primaryflags(), - secondaryflags=secondaryflags(), - luafile=quoted(usedluastub), - texfile=quoted(fulltexsourcename), - dump=os.platform=="unix" and "\\\\dump" or "\\dump", - } - local runner=runners[engine] - if not runner then - report_format("format %a cannot be generated, no runner available for engine %a",name,engine) - elseif silent then - statistics.starttiming() - specification.redirect="> temp.log" - local result=runner(specification) - local runtime=statistics.stoptiming() - if result~=0 then - print(format("%s silent make > fatal error when making format %q",engine,name)) - else - print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) - end - os.remove("temp.log") - else - runner(specification) - end - local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" - local mp=dir.glob(pattern) - if mp then - for i=1,#mp do - local name=mp[i] - report_format("removing related mplib format %a",file.basename(name)) - os.remove(name) - end - end + local engine=environment.ownmain or "luatex" + local silent=environment.arguments.silent + local errors=environment.arguments.errors + local olddir=dir.current() + local path=caches.getwritablepath("formats",engine) or "" + if path~="" then + lfs.chdir(path) + end + report_format("using format path %a",dir.current()) + local texsourcename=file.addsuffix(name,"mkiv") + local fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + if fulltexsourcename=="" then + texsourcename=file.addsuffix(name,"tex") + fulltexsourcename=resolvers.findfile(texsourcename,"tex") or "" + end + if fulltexsourcename=="" then + report_format("no tex source file with name %a (mkiv or tex)",name) + lfs.chdir(olddir) + return + else + report_format("using tex source file %a",fulltexsourcename) + end + local texsourcepath=dir.expandname(file.dirname(fulltexsourcename)) + local specificationname=file.replacesuffix(fulltexsourcename,"lus") + local fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + if fullspecificationname=="" then + specificationname=file.join(texsourcepath,"context.lus") + fullspecificationname=resolvers.findfile(specificationname,"tex") or "" + end + if fullspecificationname=="" then + report_format("unknown stub specification %a",specificationname) + lfs.chdir(olddir) + return + end + local specificationpath=file.dirname(fullspecificationname) + local usedluastub=nil + local usedlualibs=dofile(fullspecificationname) + if type(usedlualibs)=="string" then + usedluastub=file.join(file.dirname(fullspecificationname),usedlualibs) + elseif type(usedlualibs)=="table" then + report_format("using stub specification %a",fullspecificationname) + local texbasename=file.basename(name) + local luastubname=file.addsuffix(texbasename,luasuffixes.lua) + local lucstubname=file.addsuffix(texbasename,luasuffixes.luc) + report_format("creating initialization file %a",luastubname) + utilities.merger.selfcreate(usedlualibs,specificationpath,luastubname) + if utilities.lua.compile(luastubname,lucstubname) and lfs.isfile(lucstubname) then + report_format("using compiled initialization file %a",lucstubname) + usedluastub=lucstubname + else + report_format("using uncompiled initialization file %a",luastubname) + usedluastub=luastubname + end + else + report_format("invalid stub specification %a",fullspecificationname) lfs.chdir(olddir) + return + end + local specification={ + primaryflags=primaryflags(), + secondaryflags=secondaryflags(), + luafile=quoted(usedluastub), + texfile=quoted(fulltexsourcename), + dump=os.platform=="unix" and "\\\\dump" or "\\dump", + } + local runner=runners[engine] + if not runner then + report_format("format %a cannot be generated, no runner available for engine %a",name,engine) + elseif silent then + statistics.starttiming() + specification.redirect="> temp.log" + local result=runner(specification) + local runtime=statistics.stoptiming() + if result~=0 then + print(format("%s silent make > fatal error when making format %q",engine,name)) + else + print(format("%s silent make > format %q made in %.3f seconds",engine,name,runtime)) + end + os.remove("temp.log") + else + runner(specification) + end + local pattern=file.removesuffix(file.basename(usedluastub)).."-*.mem" + local mp=dir.glob(pattern) + if mp then + for i=1,#mp do + local name=mp[i] + report_format("removing related mplib format %a",file.basename(name)) + os.remove(name) + end + end + lfs.chdir(olddir) end local template=[[%flags% --fmt=%fmtfile% --lua=%luafile% %texfile% %more%]] local checkers={ - flags="string", - more="string", - fmtfile="readable", - luafile="readable", - texfile="readable", + flags="string", + more="string", + fmtfile="readable", + luafile="readable", + texfile="readable", } local runners={ - luatex=sandbox.registerrunner { - name="run luatex format", - program="luatex", - template=template, - checkers=checkers, - reporter=report_format, - }, - luajittex=sandbox.registerrunner { - name="run luajittex format", - program="luajittex", - template=template, - checkers=checkers, - reporter=report_format, - }, + luatex=sandbox.registerrunner { + name="run luatex format", + program="luatex", + template=template, + checkers=checkers, + reporter=report_format, + }, + luajittex=sandbox.registerrunner { + name="run luajittex format", + program="luajittex", + template=template, + checkers=checkers, + reporter=report_format, + }, } function environment.run_format(name,data,more) - if name and name~="" then - local engine=environment.ownmain or "luatex" - local barename=file.removesuffix(name) - local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) - if fmtname=="" then - fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" - end - fmtname=resolvers.cleanpath(fmtname) - if fmtname=="" then - report_format("no format with name %a",name) + if name and name~="" then + local engine=environment.ownmain or "luatex" + local barename=file.removesuffix(name) + local fmtname=caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats",engine) + if fmtname=="" then + fmtname=resolvers.findfile(file.addsuffix(barename,"fmt")) or "" + end + fmtname=resolvers.cleanpath(fmtname) + if fmtname=="" then + report_format("no format with name %a",name) + else + local barename=file.removesuffix(name) + local luaname=file.addsuffix(barename,"luc") + if not lfs.isfile(luaname) then + luaname=file.addsuffix(barename,"lua") + end + if not lfs.isfile(luaname) then + report_format("using format name %a",fmtname) + report_format("no luc/lua file with name %a",barename) + else + local runner=runners[engine] + if not runner then + report_format("format %a cannot be run, no runner available for engine %a",name,engine) else - local barename=file.removesuffix(name) - local luaname=file.addsuffix(barename,"luc") - if not lfs.isfile(luaname) then - luaname=file.addsuffix(barename,"lua") - end - if not lfs.isfile(luaname) then - report_format("using format name %a",fmtname) - report_format("no luc/lua file with name %a",barename) - else - local runner=runners[engine] - if not runner then - report_format("format %a cannot be run, no runner available for engine %a",name,engine) - else - runner { - flags=primaryflags(), - fmtfile=quoted(barename), - luafile=quoted(luaname), - texfile=quoted(data), - more=more, - } - end - end + runner { + flags=primaryflags(), + fmtfile=quoted(barename), + luafile=quoted(luaname), + texfile=quoted(data), + more=more, + } end + end end + end end end -- of closure --- used libraries : l-lua.lua l-macro.lua l-sandbox.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-fil.lua util-sac.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-tpl.lua util-sbx.lua util-mrg.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 +-- used libraries : l-bit32.lua l-lua.lua l-macro.lua l-sandbox.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-sha.lua l-url.lua l-dir.lua l-boolean.lua l-unicode.lua l-math.lua util-str.lua util-tab.lua util-fil.lua util-sac.lua util-sto.lua util-prs.lua util-fmt.lua util-soc-imp-reset.lua util-soc-imp-socket.lua util-soc-imp-copas.lua util-soc-imp-ltn12.lua util-soc-imp-mime.lua util-soc-imp-url.lua util-soc-imp-headers.lua util-soc-imp-tp.lua util-soc-imp-http.lua util-soc-imp-ftp.lua util-soc-imp-smtp.lua trac-set.lua trac-log.lua trac-inf.lua trac-pro.lua util-lua.lua util-deb.lua util-tpl.lua util-sbx.lua util-mrg.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 : 877962 --- stripped bytes : 317771 +-- original bytes : 994864 +-- stripped bytes : 395007 -- end library merge @@ -21370,6 +24986,7 @@ local owntree = environment and environment.ownpath or ownpath local ownlibs = { -- order can be made better + 'l-bit32.lua', 'l-lua.lua', 'l-macro.lua', 'l-sandbox.lua', @@ -21385,6 +25002,7 @@ local ownlibs = { -- order can be made better 'l-file.lua', 'l-gzip.lua', 'l-md5.lua', + 'l-sha.lua', 'l-url.lua', 'l-dir.lua', 'l-boolean.lua', @@ -21399,6 +25017,19 @@ local ownlibs = { -- order can be made better 'util-prs.lua', 'util-fmt.lua', + 'util-soc-imp-reset.lua', + 'util-soc-imp-socket.lua', + 'util-soc-imp-copas.lua', + 'util-soc-imp-ltn12.lua', + -- 'util-soc-imp-mbox.lua', + 'util-soc-imp-mime.lua', + 'util-soc-imp-url.lua', + 'util-soc-imp-headers.lua', + 'util-soc-imp-tp.lua', + 'util-soc-imp-http.lua', + 'util-soc-imp-ftp.lua', + 'util-soc-imp-smtp.lua', + 'trac-set.lua', 'trac-log.lua', 'trac-inf.lua', -- was before trac-set @@ -21601,9 +25232,7 @@ local helpinfo = [[ <flag name="locate"><short>locate given filename in database (default) or system (<ref name="first"/> <ref name="all"/> <ref name="detail"/>)</short></flag> </subcategory> <subcategory> - <flag name="autotree"><short>use texmf tree cf. env texmfstart_tree or texmfstarttree</short></flag> <flag name="tree" value="pathtotree"><short>use given texmf tree (default file: setuptex.tmf)</short></flag> - <flag name="environment" value="name"><short>use given (tmf) environment file</short></flag> <flag name="path" value="runpath"><short>go to given path before execution</short></flag> <flag name="ifchanged" value="filename"><short>only execute when given file has changed (md checksum)</short></flag> <flag name="iftouched" value="old,new"><short>only execute when given file has changed (time stamp)</short></flag> @@ -21623,7 +25252,7 @@ local helpinfo = [[ </subcategory> <subcategory> <flag name="edit"><short>launch editor with found file</short></flag> - <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>)</short></flag> + <flag name="launch"><short>launch files like manuals, assumes os support (<ref name="all"/>,<ref name="list"/>)</short></flag> </subcategory> <subcategory> <flag name="timedrun"><short>run a script and time its run</short></flag> @@ -22022,9 +25651,9 @@ function resolvers.launch(str) end function runners.launch_file(filename) - trackers.enable("resolvers.locating") local allresults = environment.arguments["all"] - local pattern = environment.arguments["pattern"] + local pattern = environment.arguments["pattern"] + local listonly = environment.arguments["list"] if not pattern or pattern == "" then pattern = filename end @@ -22039,14 +25668,32 @@ function runners.launch_file(filename) t = resolvers.findfiles("*/" .. pattern .. "*",nil,allresults) end if t and #t > 0 then - if allresults then - for _, v in pairs(t) do - report("launching %s", v) - resolvers.launch(v) + for i=1,#t do + local name = t[i] + if listonly then + report("% 3i: %-30s %s",i,file.basename(name),file.dirname(name)) + else + report("launching: %s",name) + resolvers.launch(name) + if not allresults then + break + end + end + end + if listonly then + io.write("\n") + io.write("\n[select number]\n\n>> ") + local answer = tonumber(io.read()) + if answer then + io.write("\n") + local name = t[answer] + if name then + report("launching: %s",name) + resolvers.launch(name) + else + report("invalid number") + end end - else - report("launching %s", t[1]) - resolvers.launch(t[1]) end else report("no match for %s", pattern) @@ -22166,12 +25813,9 @@ function runners.execute_ctx_script(filename,...) dofile(fullname) local savename = environment.arguments['save'] if savename then - local save_list = runners.save_list - if save_list and next(save_list) then - if type(savename) ~= "string" then savename = file.basename(fullname) end - savename = file.replacesuffix(savename,"cfg") - runners.save_script_session(savename,save_list) - end + if type(savename) ~= "string" then savename = file.basename(fullname) end + savename = file.replacesuffix(savename,"cfg") + runners.save_script_session(savename,save_list) end return true end @@ -22188,22 +25832,22 @@ function runners.execute_ctx_script(filename,...) local scriptbase = match(scriptname,".*mtx%-([^%-]-)%.lua") if scriptbase then local data = io.loaddata(scriptname) -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 + 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 @@ -22243,7 +25887,7 @@ function runners.timedrun(filename) -- just for me end function runners.timed(action) - statistics.timed(action) + statistics.timed(action,true) end function runners.associate(filename) |