diff options
author | Karl Berry <karl@freefriends.org> | 2019-02-08 23:01:17 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2019-02-08 23:01:17 +0000 |
commit | 3b0cc990de05db69e604e690e76754217a5a759b (patch) | |
tree | ce99efc6326a6cad266fa8e6beb59b3d68f93022 | |
parent | ab1456ac100fab623d9d9e62c3ba878930d944aa (diff) |
lualibs (7feb19)
git-svn-id: svn://tug.org/texlive/trunk@49982 c570f23f-e606-0410-a88d-b1316a301751
15 files changed, 6846 insertions, 6767 deletions
diff --git a/Master/texmf-dist/doc/luatex/lualibs/NEWS b/Master/texmf-dist/doc/luatex/lualibs/NEWS index 376ce105b7c..87c4136cf24 100644 --- a/Master/texmf-dist/doc/luatex/lualibs/NEWS +++ b/Master/texmf-dist/doc/luatex/lualibs/NEWS @@ -1,6 +1,9 @@ History of the lualibs package -2018-12-19 v2.62/ (upload 2019-01-16) - * sync with Context beta as of 2018-12-19 +2019/01/28 v2.63/ + * sync with Context beta as of 2019/01/28 + +2019/01/28 v2.62/ + * sync with Context beta as of 2018/12/19 2018/10/18 v2.61/ * sync with Context beta as of 2018-10-18 diff --git a/Master/texmf-dist/doc/luatex/lualibs/README b/Master/texmf-dist/doc/luatex/lualibs/README index 20351af8f2f..865560d628e 100644 --- a/Master/texmf-dist/doc/luatex/lualibs/README +++ b/Master/texmf-dist/doc/luatex/lualibs/README @@ -11,8 +11,8 @@ for use independent of ConTeXt. This package has been developed by the LuaLaTeX development team on <http://github.com/lualatex/lualibs>. -The current verson 2.62 has been build by Ulrike Fischer on -<https://github.com/u-fischer/lualibs> from context 2018-12-19. +The current verson 2.63 has been build by Ulrike Fischer on +<https://github.com/u-fischer/lualibs> from context 2019-01-28. See the 'NEWS' file for version history. diff --git a/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf b/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf Binary files differindex beedbe0ff9f..4fbc060379c 100644 --- a/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf +++ b/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf diff --git a/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx b/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx index 607b51338f6..e469a4b8b39 100644 --- a/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx +++ b/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx @@ -37,7 +37,7 @@ \input docstrip.tex \Msg{************************************************************************} \Msg{* Installation} -\Msg{* Package: lualibs 2018-12-19 v2.62 Lua additional functions.} +\Msg{* Package: lualibs 2019-01-28 v2.63 Lua additional functions.} \Msg{************************************************************************} \keepsilent @@ -107,7 +107,7 @@ and lualibs-extended.lua. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{lualibs.drv} - [2018/12/07 v2.62 Lua Libraries.] + [2010/01/28 v2.63 Lua Libraries.] \documentclass{ltxdoc} \usepackage{fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -208,7 +208,7 @@ and lualibs-extended.lua. % \GetFileInfo{lualibs.drv} % % \title{The \identifier{lualibs} package} -% \date{2018/12/07 v2.62} +% \date{2019/01/28 v2.63} % \author{Élie Roux · \email{elie.roux@telecom-bretagne.eu}\\ % Philipp Gesang · \email{phg@phi-gamma.net}\\ % Ulrike Fischer · \email{fischer@troubleshooting-tex.de}\\ @@ -429,8 +429,8 @@ lualibs = lualibs or { } lualibs.module_info = { name = "lualibs", - version = 2.62, - date = "2018-12-19", + version = 2.63, + date = "2019-01-28", description = "ConTeXt Lua standard libraries.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -584,8 +584,8 @@ local loadmodule = lualibs.loadmodule local lualibs_basic_module = { name = "lualibs-basic", - version = 2.62, - date = "2018-12-19", + version = 2.63, + date = "2019-01-28", description = "ConTeXt Lua libraries -- basic collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -666,8 +666,8 @@ lualibs = lualibs or { } local lualibs_extended_module = { name = "lualibs-extended", - version = 2.62, - date = "2018-12-19", + version = 2.63, + date = "2019-01-28", description = "ConTeXt Lua libraries -- extended collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua index d94b696b3d9..3ae4cba02fd 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua @@ -1,15 +1,15 @@ -- merged file : lualibs-basic-merged.lua -- parent file : lualibs-basic.lua --- merge date : Tue Dec 25 16:21:45 2018 +-- merge date : Wed Jan 30 23:25:49 2019 do -- begin closure to overcome local limits and interference 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+).*$") @@ -17,111 +17,110 @@ 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") + bit32=require("l-bit32") end end -- closure @@ -129,11 +128,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -141,40 +140,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 @@ -190,255 +189,255 @@ 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="" + package.path="" end end -- closure @@ -446,11 +445,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -461,7 +460,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 @@ -484,7 +483,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('"') @@ -493,9 +492,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") @@ -527,7 +526,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 @@ -536,7 +535,7 @@ 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) @@ -613,82 +612,82 @@ patterns.somecontent=(anything-newline-space)^1 patterns.beginline=#(1-newline) patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0)) function anywhere(pattern) - return (1-P(pattern))^0*P(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 + 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 + 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("") @@ -698,463 +697,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 + 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 - pattern=Cs((P(one)/(two or "")+u)^0) + 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 + 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 + 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 - 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 + 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 + 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 + 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 })) + 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 + 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 @@ -1173,47 +1172,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 + 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) + return lpegmatch(patterns[what] or containsws(what),str) end end -- closure @@ -1221,11 +1220,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -1235,11 +1234,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -1247,25 +1246,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 @@ -1273,81 +1272,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 end -- closure @@ -1355,11 +1354,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -1370,147 +1369,147 @@ 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,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,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 + elseif ta=="string" then + local tb=type(b) + if ta==tb then + return a<b + else + return a<tostring(b) end - return tostring(a)<tostring(b) + 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,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 - 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,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,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,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 @@ -1518,927 +1517,927 @@ 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 + t=t or {} + 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,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 + 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 - 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,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,last=nil,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 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 + 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 + 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 - 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 + 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 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 + 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 - if level>0 then - handle(format("%s},",depth)) - 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 - end + 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 - 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 + handle(name.."={") + end + elseif tname=="number" then + if hexify then + handle(format("[0x%X]={",name)) else - handle("t={") + handle("["..name.."]={") 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 + 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 - handle("}") + if next(root)~=nil then + do_serialize(root,name,"",0) + end + end + handle("}") end function table.serialize(root,name,specification) - local t,n={},0 - local function flush(s) - n=n+1 - t[n]=s - end - serialize(flush,root,name,specification) - return concat(t,"\n") + local t,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,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 - end - return f + 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 + 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 - end - return true - else + 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 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 - end - for k,v in next,t do - n[v]=k + local n={} + if s then + for k,v in next,s do + n[k]=v 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,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 - 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 + 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 local function sequenced(t,sep,simple) - if not t then - return "" - elseif type(t)=="string" then - return t + 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 - local v=t[i] - if type(v)=="table" then - s[i]="{"..sequenced(v,sep,simple).."}" - else - s[i]=tostring(t[i]) - 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 - if type(v)=="table" then - s[n]=k.."={"..sequenced(v,sep,simple).."}" - else - s[n]=k.."="..tostring(v) - end - 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 + 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=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,keys,v={},{},0 + for key,value in next,t do + if not keys[value] then + v=v+1 + values[v]=value + keys[k]=key + end end + if s then + sort(values) + end + return values + else + return {} + end end 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 + end + return kv,s else - return nothing + 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 end -- closure @@ -2446,66 +2445,66 @@ end -- closure do -- begin closure to overcome local limits and interference 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 end -- closure @@ -2513,11 +2512,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -2527,107 +2526,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,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 + 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) + return floor(i/d) end end -- closure @@ -2635,90 +2634,90 @@ end -- closure do -- begin closure to overcome local limits and interference 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 end -- closure @@ -2726,11 +2725,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -2738,334 +2737,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)) + 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 - 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 + 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 end -- closure @@ -3073,11 +3072,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -3086,433 +3085,433 @@ 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 do - local selfdir=os.selfdir - if selfdir=="" then - selfdir=nil + 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 + end 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 + 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 - 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 - for p in gmatch(path,patt) do - if isfile(p.."/"..name) then - selfdir=p - break - end - end - end + for p in gmatch(path,patt) do + if isfile(p.."/"..name) then + selfdir=p + break + end end - os.selfdir=selfdir or "." + 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 } ) + 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="xdg-open %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 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 + 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 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 + 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 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 + 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 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 + 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 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 + 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 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 + 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 + if not fullname then + fullname=false end - return fullname + 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 + 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() + if exitcode~=nil then + return osexit(exitcode) + end + if c~=nil then + return osexit(c) + end + return osexit() end end -- closure @@ -3520,16 +3519,16 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -3539,20 +3538,20 @@ 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 attributes=lfs.attributes function lfs.isdir(name) - return attributes(name,"mode")=="directory" + return attributes(name,"mode")=="directory" end function lfs.isfile(name) - local a=attributes(name,"mode") - return a=="file" or a=="link" or nil + local a=attributes(name,"mode") + return a=="file" or a=="link" or nil end function lfs.isfound(name) - local a=attributes(name,"mode") - return (a=="file" or a=="link") 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") + 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(".") @@ -3566,27 +3565,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 @@ -3595,7 +3594,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) @@ -3611,142 +3610,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) @@ -3756,30 +3755,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) + 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 - 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 + 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 lpegmatch(deslasher,concat({ one,two,three,... },"/")) + return "/"..two end + else + return lpegmatch(deslasher,concat({ one,two,three,... },"/")) + end end local drivespec=R("az","AZ")^1*colon local anchors=fwslash+drivespec @@ -3789,56 +3788,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 + 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) @@ -3846,26 +3845,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("://") @@ -3874,44 +3873,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 - 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 - end - return true + 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 + if l<0 then + return false + end + end + return true end local symlinkattributes=lfs.symlinkattributes function lfs.readlink(name) - return symlinkattributes(name,"target") or nil + return symlinkattributes(name,"target") or nil end end -- closure @@ -3919,48 +3918,48 @@ end -- closure do -- begin closure to overcome local limits and interference 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 end -- closure @@ -3968,84 +3967,84 @@ end -- closure do -- begin closure to overcome local limits and interference 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 + 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 false + 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 -- closure @@ -4053,11 +4052,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -4069,478 +4068,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" - end - lfs.isdir=isdir - lfs.isfile=isfile + 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" + 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 - 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="/." + usedpath="/." elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" + usedpath=path.."/." + path=path.."/" else - usedpath=path + 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 - nofdirs=nofdirs+1 - dirs[nofdirs]=full - else - nofdirs=1 - dirs={ full } - end - end + 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_table(dirs[i],patt,recurse,result) - end + for i=1,nofdirs do + glob_pattern_function(dirs[i],patt,recurse,action) + end end - return result + end end -local function globpattern(path,patt,recurse,method) - local kind=type(method) - if patt and sub(patt,1,-3)==path then - patt=false +local function glob_pattern_table(path,patt,recurse,result) + 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 + nofdirs=nofdirs+1 + dirs[nofdirs]=full + else + nofdirs=1 + dirs={ full } + end + end 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 + 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 + 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 - 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) + 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 + 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 @@ -4549,18 +4548,18 @@ end -- closure do -- begin closure to overcome local limits and interference 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 {} if not string.utfcharacters then - local gmatch=string.gmatch - function string.characters(str) - return gmatch(str,".[\128-\191]*") - end + local gmatch=string.gmatch + function string.characters(str) + return gmatch(str,".[\128-\191]*") + end end utf.characters=string.utfcharacters local type=type @@ -4583,304 +4582,304 @@ local p_utfbom=patterns.utfbom local p_newline=patterns.newline local p_whitespace=patterns.whitespace 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 - function utf.byte(c) - return lpegmatch(p_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_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 - 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_utf8character)^0) - end - return lpegmatch(pattern,str) - end - end - elseif option=="pattern" then - return Cs((tabletopattern(mapping)/action+p_utf8character)^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_utf8character)^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_utf8character/mapping+p_utf8character)^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_utf8character/mapping+p_utf8character)^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_utf8character)^0) @@ -4888,25 +4887,25 @@ 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 @@ -4920,36 +4919,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) @@ -4960,88 +4959,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 @@ -5052,225 +5051,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 + 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 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 + 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 + 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 + 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 + 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 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 + 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 + 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 - 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 + first,last=lpegmatch(range,str) + if not last then + return P(str) + 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 + 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 end -- closure @@ -5278,11 +5277,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -5295,14 +5294,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("?") @@ -5321,21 +5320,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 @@ -5353,19 +5352,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("://") @@ -5375,161 +5374,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 end -- closure @@ -5537,11 +5536,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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={} @@ -5550,54 +5549,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 end -- closure diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua index 32024f47147..87b793b9b4e 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua @@ -29,8 +29,8 @@ local loadmodule = lualibs.loadmodule local lualibs_basic_module = { name = "lualibs-basic", - version = 2.62, - date = "2018-12-19", + version = 2.63, + date = "2019-01-28", description = "ConTeXt Lua libraries -- basic collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua index 2d973be3b95..d9b3cc8a212 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua @@ -1,15 +1,15 @@ -- merged file : lualibs-extended-merged.lua -- parent file : lualibs-extended.lua --- merge date : Tue Dec 25 16:21:26 2018 +-- merge date : Wed Jan 30 23:25:40 2019 do -- begin closure to overcome local limits and interference 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 {} @@ -22,20 +22,12 @@ 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 stripzero=patterns.stripzero @@ -53,32 +45,32 @@ local period=patterns.period local ptf=1/65536 local bpf=(7200/7227)/65536 local function points(n) - 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)) + 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) - 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)) + 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 @@ -90,65 +82,65 @@ 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 + extra,start=0,position end+anything - )^1) + )^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 + 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/"" @@ -166,130 +158,130 @@ 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_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, - ["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, + ["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 + 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 + 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))*prefix+C((1-period)^1))*(anything/""*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 + three*prefix*endofstring+two*prefix*endofstring+digit*prefix*endofstring+three+two+digit ) patterns.formattednumber=splitter function number.formatted(n,sep1,sep2) - if sep1==false then - if type(n)=="number" then - n=tostring(n) - end - return lpegmatch(splitter3,n,1,sep2 or ".") + 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,n,1,".",",") + elseif sep1=="." then + return lpegmatch(splitter,n,1,sep1,sep2 or ",") + elseif sep1=="," then + return lpegmatch(splitter,n,1,sep1,sep2 or ".") else - if type(n)=="number" then - n=format("%0.2f",n) - end - if sep1==true then - return lpegmatch(splitter,n,1,".",",") - elseif sep1=="." then - return lpegmatch(splitter,n,1,sep1,sep2 or ",") - elseif sep1=="," then - return lpegmatch(splitter,n,1,sep1,sep2 or ".") - else - return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".") - end + return lpegmatch(splitter,n,1,sep1 or ",",sep2 or ".") end + end end local p=Cs( - P("-")^0*(P("0")^1/"")^0*(1-period)^0*(period*P("0")^1*endofstring/""+period^0)*P(1-P("0")^1*endofstring)^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("+")/"" @@ -300,408 +292,382 @@ local exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(e local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) 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 -local stripzero=lpeg.patterns.stripzero -local stripzeros=lpeg.patterns.stripzeros - ]] -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, - stripzero=lpeg.patterns.stripzero, - stripzeros=lpeg.patterns.stripzeros, - } -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, +} 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((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("((a%s %% 1 == 0) and format('%%i',a%s) or tostring(a%s))",n,n,n) + 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) + 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 - if f=="0" then - return format([[formattednumber(a%s,false)]],n) - else - return format([[formattednumber(a%s,%q,".")]],n,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 - if f=="0" then - return format([[formattednumber(a%s,false)]],n) - else - return format([[formattednumber(a%s,%q,",")]],n,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)) - end + 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") @@ -717,164 +683,156 @@ local builder=Cs { "start", +V("z") +V(">") +V("<") - )+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, + )+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("%")*(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('"')/"""+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 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) + return f_16_16(n/65536.0) end end -- closure @@ -882,11 +840,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 byte=string.byte local char=string.char @@ -895,280 +853,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 + return (a-0x100)+b/0x100 + else + return (a )+b/0x100 + 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 + return (0x100*a+b-0x10000)+(0x100*c+d)/0x10000 + else + return (0x100*a+b )+(0x100*c+d)/0x10000 + 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 + 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 + 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 end -- closure @@ -1176,11 +1134,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 {} @@ -1195,219 +1153,219 @@ 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,t=nil,{} + 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 - 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 - end - end - if protect then - for key,value in next,core do - core[key]=nil + rawset(t,key,value) 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,"] @@ -1421,157 +1379,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 - 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 + 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 - m=m+1 - if outer then - r[m]="}" - else - r[m]="}," + 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 - return r + 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 - 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 - end - setmetatable(t,selfmapper) - return t +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 + end + setmetatable(t,selfmapper) + return t end local f_start_key_idx=formatters["%w{"] local f_start_key_num=formatters["%w[%s]={"] @@ -1609,187 +1567,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 + 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 - 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 + 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 - n=n+1 - t[n]=f_table_finish() - return concat(t,"\n") + 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 + 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 end -- closure @@ -1797,165 +1791,165 @@ end -- closure do -- begin closure to overcome local limits and interference 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 + 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 end -- closure @@ -1963,11 +1957,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -2009,8 +2003,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 } @@ -2018,9 +2012,9 @@ 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=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0) @@ -2032,7 +2026,7 @@ 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 @@ -2043,300 +2037,300 @@ 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 - else - hash=existing or {} - lpegmatch(pattern_a_s,str) - return hash - 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 + 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 + 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 - else - hash=existing or {} - lpegmatch(pattern_b_s,str) - return hash - 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 + 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 - end + 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=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 + 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=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 + 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 - 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,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,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 - end - parsers.settings_to_hash(settings,sc) + 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 + 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) @@ -2350,75 +2344,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) - end + 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 @@ -2426,89 +2420,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 - 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("->") @@ -2516,11 +2510,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 end -- closure @@ -2528,11 +2522,11 @@ end -- closure do -- begin closure to overcome local limits and interference if not modules then modules={} end modules ['util-dim']={ - version=1.001, - comment="support for dimensions", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" + version=1.001, + comment="support for dimensions", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local format,match,gsub,type,setmetatable=string.format,string.match,string.gsub,type,setmetatable local P,S,R,Cc,C,lpegmatch=lpeg.P,lpeg.S,lpeg.R,lpeg.Cc,lpeg.C,lpeg.match @@ -2546,34 +2540,34 @@ local number=number number.tonumberf=function(n) return lpegmatch(p_stripzeros,format("%.20f",n)) end number.tonumberg=function(n) return format("%.20g",n) end local dimenfactors=allocate { - ["pt"]=1/65536, - ["in"]=(100/7227)/65536, - ["cm"]=(254/7227)/65536, - ["mm"]=(2540/7227)/65536, - ["sp"]=1, - ["bp"]=(7200/7227)/65536, - ["pc"]=(1/12)/65536, - ["dd"]=(1157/1238)/65536, - ["cc"]=(1157/14856)/65536, - ["nd"]=(20320/21681)/65536, - ["nc"]=(5080/65043)/65536 + ["pt"]=1/65536, + ["in"]=(100/7227)/65536, + ["cm"]=(254/7227)/65536, + ["mm"]=(2540/7227)/65536, + ["sp"]=1, + ["bp"]=(7200/7227)/65536, + ["pc"]=(1/12)/65536, + ["dd"]=(1157/1238)/65536, + ["cc"]=(1157/14856)/65536, + ["nd"]=(20320/21681)/65536, + ["nc"]=(5080/65043)/65536 } local f_none=formatters["%s%s"] local f_true=formatters["%0.5F%s"] local function numbertodimen(n,unit,fmt) - if type(n)=='string' then - return n + if type(n)=='string' then + return n + else + unit=unit or 'pt' + n=n*dimenfactors[unit] + if not fmt then + fmt=f_none(n,unit) + elseif fmt==true then + fmt=f_true(n,unit) else - unit=unit or 'pt' - n=n*dimenfactors[unit] - if not fmt then - fmt=f_none(n,unit) - elseif fmt==true then - fmt=f_true(n,unit) - else - return formatters[fmt](n,unit) - end + return formatters[fmt](n,unit) end + end end number.maxdimen=1073741823 number.todimen=numbertodimen @@ -2583,23 +2577,23 @@ function number.toinches (n,fmt) return numbertodimen(n,"in",fmt) end function number.tocentimeters (n,fmt) return numbertodimen(n,"cm",fmt) end function number.tomillimeters (n,fmt) return numbertodimen(n,"mm",fmt) end function number.toscaledpoints(n,fmt) return numbertodimen(n,"sp",fmt) end -function number.toscaledpoints(n) return n.."sp" end -function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end +function number.toscaledpoints(n) return n.."sp" end +function number.tobasepoints (n,fmt) return numbertodimen(n,"bp",fmt) end function number.topicas (n,fmt) return numbertodimen(n "pc",fmt) end function number.todidots (n,fmt) return numbertodimen(n,"dd",fmt) end -function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end -function number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end -function number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end +function number.tociceros (n,fmt) return numbertodimen(n,"cc",fmt) end +function number.tonewdidots (n,fmt) return numbertodimen(n,"nd",fmt) end +function number.tonewciceros (n,fmt) return numbertodimen(n,"nc",fmt) end local amount=(S("+-")^0*R("09")^0*P(".")^0*R("09")^0)+Cc("0") local unit=R("az")^1+P("%") local dimenpair=amount/tonumber*(unit^1/dimenfactors+Cc(1)) lpeg.patterns.dimenpair=dimenpair local splitter=amount/tonumber*C(unit^1) function number.splitdimen(str) - return lpegmatch(splitter,str) + return lpegmatch(splitter,str) end setmetatableindex(dimenfactors,function(t,s) - return false + return false end) local stringtodimen local amount=S("+-")^0*R("09")^0*S(".,")^0*R("09")^0 @@ -2608,106 +2602,106 @@ local validdimen=amount*unit lpeg.patterns.validdimen=validdimen local dimensions={} function dimensions.__add(a,b) - local ta,tb=type(a),type(b) - if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end - if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end - return setmetatable({ a+b },dimensions) + local ta,tb=type(a),type(b) + if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end + if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end + return setmetatable({ a+b },dimensions) end function dimensions.__sub(a,b) - local ta,tb=type(a),type(b) - if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end - if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end - return setmetatable({ a-b },dimensions) + local ta,tb=type(a),type(b) + if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end + if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end + return setmetatable({ a-b },dimensions) end function dimensions.__mul(a,b) - local ta,tb=type(a),type(b) - if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end - if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end - return setmetatable({ a*b },dimensions) + local ta,tb=type(a),type(b) + if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end + if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end + return setmetatable({ a*b },dimensions) end function dimensions.__div(a,b) - local ta,tb=type(a),type(b) - if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end - if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end - return setmetatable({ a/b },dimensions) + local ta,tb=type(a),type(b) + if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end + if tb=="string" then b=stringtodimen(b) elseif tb=="table" then b=b[1] end + return setmetatable({ a/b },dimensions) end function dimensions.__unm(a) - local ta=type(a) - if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end - return setmetatable({-a },dimensions) + local ta=type(a) + if ta=="string" then a=stringtodimen(a) elseif ta=="table" then a=a[1] end + return setmetatable({-a },dimensions) end function dimensions.__lt(a,b) - return a[1]<b[1] + return a[1]<b[1] end function dimensions.__eq(a,b) - return a[1]==b[1] + return a[1]==b[1] end function dimensions.__tostring(a) - return a[1]/65536 .."pt" + return a[1]/65536 .."pt" end function dimensions.__index(tab,key) - local d=dimenfactors[key] - if not d then - error("illegal property of dimen: "..key) - d=1 - end - return 1/d -end - dimenfactors["ex"]=4*1/65536 - dimenfactors["em"]=10*1/65536 + local d=dimenfactors[key] + if not d then + error("illegal property of dimen: "..key) + d=1 + end + return 1/d +end + dimenfactors["ex"]=4*1/65536 + dimenfactors["em"]=10*1/65536 local known={} setmetatable(known,{ __mode="v" }) function dimen(a) - if a then - local ta=type(a) - if ta=="string" then - local k=known[a] - if k then - a=k - else - local value,unit=lpegmatch(dimenpair,a) - if value and unit then - k=value/unit - else - k=0 - end - known[a]=k - a=k - end - elseif ta=="table" then - a=a[1] + if a then + local ta=type(a) + if ta=="string" then + local k=known[a] + if k then + a=k + else + local value,unit=lpegmatch(dimenpair,a) + if value and unit then + k=value/unit + else + k=0 end - return setmetatable({ a },dimensions) - else - return setmetatable({ 0 },dimensions) + known[a]=k + a=k + end + elseif ta=="table" then + a=a[1] end + return setmetatable({ a },dimensions) + else + return setmetatable({ 0 },dimensions) + end end function string.todimen(str) - if type(str)=="number" then - return str - else - local k=known[str] - if not k then - local value,unit=lpegmatch(dimenpair,str) - if value and unit then - k=value/unit - else - k=0 - end - known[str]=k - end - return k + if type(str)=="number" then + return str + else + local k=known[str] + if not k then + local value,unit=lpegmatch(dimenpair,str) + if value and unit then + k=value/unit + else + k=0 + end + known[str]=k end + return k + end end stringtodimen=string.todimen function number.toscaled(d) - return format("%0.5f",d/0x10000) + return format("%0.5f",d/0x10000) end function number.percent(n,d) - d=d or texget("hsize") - if type(d)=="string" then - d=stringtodimen(d) - end - return (n/100)*d + d=d or texget("hsize") + if type(d)=="string" then + d=stringtodimen(d) + end + return (n/100)*d end number["%"]=number.percent @@ -2716,15 +2710,15 @@ end -- closure do -- begin closure to overcome local limits and interference if not modules then modules={} end modules ['util-jsn']={ - version=1.001, - comment="companion to m-json.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 m-json.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local P,V,R,S,C,Cc,Cs,Ct,Cf,Cg=lpeg.P,lpeg.V,lpeg.R,lpeg.S,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Cf,lpeg.Cg local lpegmatch=lpeg.match -local format=string.format +local format,gsub=string.format,string.gsub local utfchar=utf.char local concat=table.concat local tonumber,tostring,rawset,type,next=tonumber,tostring,rawset,type,next @@ -2740,13 +2734,15 @@ local dquote=P('"') local whitespace=lpeg.patterns.whitespace local optionalws=whitespace^0 local escapes={ - ["b"]="\010", - ["f"]="\014", - ["n"]="\n", - ["r"]="\r", - ["t"]="\t", + ["b"]="\010", + ["f"]="\014", + ["n"]="\n", + ["r"]="\r", + ["t"]="\t", } -local escape_un=C(P("\\u")/"0x"*S("09","AF","af"))/function(s) return utfchar(tonumber(s)) end +local escape_un=P("\\u")/""*(C(R("09","AF","af")^-4)/function(s) + return utfchar(tonumber(s,16)) +end) local escape_bs=P([[\]])/""*(P(1)/escapes) local jstring=dquote*Cs((escape_un+escape_bs+(1-dquote))^0)*dquote local jtrue=P("true")*Cc(true) @@ -2755,75 +2751,90 @@ local jnull=P("null")*Cc(nil) local jnumber=(1-whitespace-rparent-rbrace-comma)^1/tonumber local key=jstring local jsonconverter={ "value", - hash=lbrace*Cf(Ct("")*(V("pair")*(comma*V("pair"))^0+optionalws),rawset)*rbrace, - pair=Cg(optionalws*key*optionalws*colon*V("value")), - array=Ct(lparent*(V("value")*(comma*V("value"))^0+optionalws)*rparent), - value=optionalws*(jstring+V("hash")+V("array")+jtrue+jfalse+jnull+jnumber)*optionalws, + hash=lbrace*Cf(Ct("")*(V("pair")*(comma*V("pair"))^0+optionalws),rawset)*rbrace, + pair=Cg(optionalws*key*optionalws*colon*V("value")), + array=Ct(lparent*(V("value")*(comma*V("value"))^0+optionalws)*rparent), + value=optionalws*(jstring+V("hash")+V("array")+jtrue+jfalse+jnull+jnumber)*optionalws, } function json.tolua(str) - return lpegmatch(jsonconverter,str) -end -local function tojson(value,t) - local kind=type(value) - if kind=="table" then - local done=false - local size=#value - if size==0 then - for k,v in next,value do - if done then - t[#t+1]="," - else - t[#t+1]="{" - done=true - end - t[#t+1]=format("%q:",k) - tojson(v,t) - end - if done then - t[#t+1]="}" - else - t[#t+1]="{}" - end - elseif size==1 then - t[#t+1]="[" - tojson(value[1],t) - t[#t+1]="]" + return lpegmatch(jsonconverter,str) +end +local escaper +local function tojson(value,t,n) + local kind=type(value) + if kind=="table" then + local done=false + local size=#value + if size==0 then + for k,v in next,value do + if done then + n=n+1;t[n]="," else - for i=1,size do - if done then - t[#t+1]="," - else - t[#t+1]="[" - done=true - end - tojson(value[i],t) - end - t[#t+1]="]" - end - elseif kind=="string" then - t[#t+1]=format("%q",value) - elseif kind=="number" then - t[#t+1]=value - elseif kind=="boolean" then - t[#t+1]=tostring(value) - end - return t + n=n+1;t[n]="{" + done=true + end + n=n+1;t[n]=format("%q:",k) + t,n=tojson(v,t,n) + end + if done then + n=n+1;t[n]="}" + else + n=n+1;t[n]="{}" + end + elseif size==1 then + n=n+1;t[n]="[" + t,n=tojson(value[1],t,n) + n=n+1;t[n]="]" + else + for i=1,size do + if done then + n=n+1;t[n]="," + else + n=n+1;t[n]="[" + done=true + end + t,n=tojson(value[i],t,n) + end + n=n+1;t[n]="]" + end + elseif kind=="string" then + n=n+1;t[n]='"' + n=n+1;t[n]=lpegmatch(escaper,value) or value + n=n+1;t[n]='"' + elseif kind=="number" then + n=n+1;t[n]=value + elseif kind=="boolean" then + n=n+1;t[n]=tostring(value) + end + return t,n end function json.tostring(value) - local kind=type(value) - if kind=="table" then - return concat(tojson(value,{}),"") - elseif kind=="string" or kind=="number" then - return value - else - return tostring(value) - end + local kind=type(value) + if kind=="table" then + if not escaper then + local escapes={ + ["\\"]="\\u005C", + ["\""]="\\u0022", + } + for i=0,0x20 do + escapes[utfchar(i)]=format("\\u%04X",i) + end + escaper=Cs(( + (R('\0\x20')+S('\"\\'))/escapes+P(1) + )^1 ) + end + return concat((tojson(value,{},0))) + elseif kind=="string" or kind=="number" then + return lpegmatch(escaper,value) or value + else + return tostring(value) + end end function json.load(filename) - local data=io.loaddata(filename) - if data then - return lpegmatch(jsonconverter,data) - end + local data=io.loaddata(filename) + if data then + return lpegmatch(jsonconverter,data) + end end return json @@ -2832,11 +2843,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -2851,86 +2862,86 @@ 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,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 + 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 + 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 + 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 + if type(instance)=="number" then + return instance + else + local timer=timers[instance or "notimer"] + local it=timer.timing + if it>1 then else - local timer=timers[instance or "notimer"] - local it=timer.timing - if it>1 then - else - local starttime=timer.starttime - if starttime and starttime>0 then - return seconds(timer.loadtime+ticks()-starttime) - end - end - return 0 + local starttime=timer.starttime + if starttime and starttime>0 then + return seconds(timer.loadtime+ticks()-starttime) + end end + return 0 + 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 @@ -2942,91 +2953,100 @@ 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 - end - statistics.enable=false - 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 + 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 end -- closure @@ -3034,12 +3054,12 @@ end -- closure do -- begin closure to overcome local limits and interference 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 @@ -3050,150 +3070,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 %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 - end - return current + 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 + end + return current end end -- closure @@ -3201,11 +3222,11 @@ end -- closure do -- begin closure to overcome local limits and interference 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 type,next,tostring,tonumber=type,next,tostring,tonumber local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub @@ -3224,266 +3245,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,nesting=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 - 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 + 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 + 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 - 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 + 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 + 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] - 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))) + return b[3]<a[3] + end + 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 + 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() - 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 + 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 sethook and getinfo and 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 - end - end + 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 + end + end end debugger.showtraceback=showtraceback @@ -3492,88 +3513,88 @@ end -- closure do -- begin closure to overcome local limits and interference 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("]%") @@ -3590,41 +3611,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 end -- closure @@ -3632,235 +3653,235 @@ end -- closure do -- begin closure to overcome local limits and interference if not modules then modules={} end modules ['util-sta']={ - version=1.001, - comment="companion to util-ini.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 util-ini.mkiv", + author="Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright="PRAGMA ADE / ConTeXt Development Team", + license="see context related readme files" } local insert,remove,fastcopy,concat=table.insert,table.remove,table.fastcopy,table.concat local format=string.format local select,tostring=select,tostring -local trace_stacker=false trackers.register("stacker.resolve",function(v) trace_stacker=v end) +local trace_stacker=false trackers.register("stacker.resolve",function(v) trace_stacker=v end) local stacker=stacker or {} utilities.stacker=stacker local function start(s,t,first,last) - if s.mode=="switch" then - local n=tostring(t[last]) - if trace_stacker then - s.report("start: %s",n) - end - return n - else - local r={} - for i=first,last do - r[#r+1]=tostring(t[i]) - end - local n=concat(r," ") - if trace_stacker then - s.report("start: %s",n) - end - return n + if s.mode=="switch" then + local n=tostring(t[last]) + if trace_stacker then + s.report("start: %s",n) end + return n + else + local r={} + for i=first,last do + r[#r+1]=tostring(t[i]) + end + local n=concat(r," ") + if trace_stacker then + s.report("start: %s",n) + end + return n + end end local function stop(s,t,first,last) - if s.mode=="switch" then - local n=tostring(false) - if trace_stacker then - s.report("stop: %s",n) - end - return n - else - local r={} - for i=last,first,-1 do - r[#r+1]=tostring(false) - end - local n=concat(r," ") - if trace_stacker then - s.report("stop: %s",n) - end - return n + if s.mode=="switch" then + local n=tostring(false) + if trace_stacker then + s.report("stop: %s",n) + end + return n + else + local r={} + for i=last,first,-1 do + r[#r+1]=tostring(false) + end + local n=concat(r," ") + if trace_stacker then + s.report("stop: %s",n) end + return n + end end local function change(s,t1,first1,last1,t2,first2,last2) - if s.mode=="switch" then - local n=tostring(t2[last2]) - if trace_stacker then - s.report("change: %s",n) - end - return n - else - local r={} - for i=last1,first1,-1 do - r[#r+1]=tostring(false) - end - local n=concat(r," ") - for i=first2,last2 do - r[#r+1]=tostring(t2[i]) - end - if trace_stacker then - s.report("change: %s",n) - end - return n + if s.mode=="switch" then + local n=tostring(t2[last2]) + if trace_stacker then + s.report("change: %s",n) + end + return n + else + local r={} + for i=last1,first1,-1 do + r[#r+1]=tostring(false) + end + local n=concat(r," ") + for i=first2,last2 do + r[#r+1]=tostring(t2[i]) + end + if trace_stacker then + s.report("change: %s",n) end + return n + end end function stacker.new(name) - local report=logs.reporter("stacker",name or nil) - local s - local stack={} - local list={} - local ids={} - local hash={} - local hashing=true - local function push(...) - for i=1,select("#",...) do - insert(stack,(select(i,...))) - end - if hashing then - local c=concat(stack,"|") - local n=hash[c] - if not n then - n=#list+1 - hash[c]=n - list[n]=fastcopy(stack) + local report=logs.reporter("stacker",name or nil) + local s + local stack={} + local list={} + local ids={} + local hash={} + local hashing=true + local function push(...) + for i=1,select("#",...) do + insert(stack,(select(i,...))) + end + if hashing then + local c=concat(stack,"|") + local n=hash[c] + if not n then + n=#list+1 + hash[c]=n + list[n]=fastcopy(stack) + end + insert(ids,n) + return n + else + local n=#list+1 + list[n]=fastcopy(stack) + insert(ids,n) + return n + end + end + local function pop() + remove(stack) + remove(ids) + return ids[#ids] or s.unset or -1 + end + local function clean() + if #stack==0 then + if trace_stacker then + s.report("%s list entries, %s stack entries",#list,#stack) + end + end + end + local tops={} + local top=nil + local switch=nil + local function resolve_reset(mode) + if #tops>0 then + report("resetting %s left-over states of %a",#tops,name) + end + tops={} + top=nil + switch=nil + end + local function resolve_begin(mode) + if mode then + switch=mode=="switch" + else + switch=s.mode=="switch" + end + top={ switch=switch } + insert(tops,top) + end + local function resolve_step(ti) + local result=nil + local noftop=top and #top or 0 + if ti>0 then + local current=list[ti] + if current then + local noflist=#current + local nofsame=0 + if noflist>noftop then + for i=1,noflist do + if current[i]==top[i] then + nofsame=i + else + break end - insert(ids,n) - return n + end else - local n=#list+1 - list[n]=fastcopy(stack) - insert(ids,n) - return n - end - end - local function pop() - remove(stack) - remove(ids) - return ids[#ids] or s.unset or -1 - end - local function clean() - if #stack==0 then - if trace_stacker then - s.report("%s list entries, %s stack entries",#list,#stack) + for i=1,noflist do + if current[i]==top[i] then + nofsame=i + else + break end + end end - end - local tops={} - local top=nil - local switch=nil - local function resolve_reset(mode) - if #tops>0 then - report("resetting %s left-over states of %a",#tops,name) - end - tops={} - top=nil - switch=nil - end - local function resolve_begin(mode) - if mode then - switch=mode=="switch" - else - switch=s.mode=="switch" - end - top={ switch=switch } - insert(tops,top) - end - local function resolve_step(ti) - local result=nil - local noftop=top and #top or 0 - if ti>0 then - local current=list[ti] - if current then - local noflist=#current - local nofsame=0 - if noflist>noftop then - for i=1,noflist do - if current[i]==top[i] then - nofsame=i - else - break - end - end - else - for i=1,noflist do - if current[i]==top[i] then - nofsame=i - else - break - end - end - end - local plus=nofsame+1 - if plus<=noftop then - if plus<=noflist then - if switch then - result=s.change(s,top,plus,noftop,current,nofsame,noflist) - else - result=s.change(s,top,plus,noftop,current,plus,noflist) - end - else - if switch then - result=s.change(s,top,plus,noftop,current,nofsame,noflist) - else - result=s.stop(s,top,plus,noftop) - end - end - elseif plus<=noflist then - if switch then - result=s.start(s,current,nofsame,noflist) - else - result=s.start(s,current,plus,noflist) - end - end - top=current + local plus=nofsame+1 + if plus<=noftop then + if plus<=noflist then + if switch then + result=s.change(s,top,plus,noftop,current,nofsame,noflist) else - if 1<=noftop then - result=s.stop(s,top,1,noftop) - end - top={} + result=s.change(s,top,plus,noftop,current,plus,noflist) end - return result - else - if 1<=noftop then - result=s.stop(s,top,1,noftop) + else + if switch then + result=s.change(s,top,plus,noftop,current,nofsame,noflist) + else + result=s.stop(s,top,plus,noftop) end - top={} - return result - end - end - local function resolve_end() - if #tops>0 then - local result=s.stop(s,top,1,#top) - remove(tops) - top=tops[#tops] - switch=top and top.switch - return result - end - end - local function resolve(t) - resolve_begin() - for i=1,#t do - resolve_step(t[i]) + end + elseif plus<=noflist then + if switch then + result=s.start(s,current,nofsame,noflist) + else + result=s.start(s,current,plus,noflist) + end end - resolve_end() - end - s={ - name=name or "unknown", - unset=-1, - report=report, - start=start, - stop=stop, - change=change, - push=push, - pop=pop, - clean=clean, - resolve=resolve, - resolve_begin=resolve_begin, - resolve_step=resolve_step, - resolve_end=resolve_end, - resolve_reset=resolve_reset, - } - return s + top=current + else + if 1<=noftop then + result=s.stop(s,top,1,noftop) + end + top={} + end + return result + else + if 1<=noftop then + result=s.stop(s,top,1,noftop) + end + top={} + return result + end + end + local function resolve_end() + if #tops>0 then + local result=s.stop(s,top,1,#top) + remove(tops) + top=tops[#tops] + switch=top and top.switch + return result + end + end + local function resolve(t) + resolve_begin() + for i=1,#t do + resolve_step(t[i]) + end + resolve_end() + end + s={ + name=name or "unknown", + unset=-1, + report=report, + start=start, + stop=stop, + change=change, + push=push, + pop=pop, + clean=clean, + resolve=resolve, + resolve_begin=resolve_begin, + resolve_step=resolve_step, + resolve_end=resolve_end, + resolve_reset=resolve_reset, + } + return s end end -- closure diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua index fda759cc1df..0bf956ec536 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua @@ -30,8 +30,8 @@ lualibs = lualibs or { } local lualibs_extended_module = { name = "lualibs-extended", - version = 2.62, - date = "2018-12-19", + version = 2.63, + date = "2019-01-28", description = "ConTeXt Lua libraries -- extended collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua index c0a787a5c43..ddd499022fa 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua @@ -35,8 +35,6 @@ if LUAVERSION < 5.2 and jit then LUAVERSION = 5.2 end -_LUAVERSION = LUAVERSION -- for old times sake, will go away - -- lpeg if not lpeg then diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua index 6c08f34f6e7..7a5c35fd5fa 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua @@ -253,16 +253,25 @@ end function statistics.runtime() stoptiming(statistics) -- stoptiming(statistics) -- somehow we can start the timer twice, but where - return statistics.formatruntime(elapsedtime(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) +function statistics.timed(action,all) starttiming("run") action() stoptiming("run") - report("total runtime: %s seconds",elapsedtime("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 -- goodie diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua index e5f83e06c47..acbf160904d 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua @@ -14,10 +14,12 @@ if not modules then modules = { } end modules ['util-jsn'] = { -- -- Reminder for me: check usage in framework and extend when needed. Also document -- it in the cld lib documentation. +-- +-- Upgraded for handling the somewhat more fax server templates. local P, V, R, S, C, Cc, Cs, Ct, Cf, Cg = lpeg.P, lpeg.V, lpeg.R, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cs, lpeg.Ct, lpeg.Cf, lpeg.Cg local lpegmatch = lpeg.match -local format = string.format +local format, gsub = string.format, string.gsub local utfchar = utf.char local concat = table.concat @@ -26,9 +28,6 @@ local tonumber, tostring, rawset, type, next = tonumber, tostring, rawset, type, local json = utilities.json or { } utilities.json = json --- moduledata = moduledata or { } --- moduledata.json = json - -- \\ \/ \b \f \n \r \t \uHHHH local lbrace = P("{") @@ -43,16 +42,19 @@ local whitespace = lpeg.patterns.whitespace local optionalws = whitespace^0 local escapes = { - -- ["\\"] = "\\", -- lua will escape these - -- ["/"] = "/", -- no need to escape this one - ["b"] = "\010", - ["f"] = "\014", - ["n"] = "\n", - ["r"] = "\r", - ["t"] = "\t", + ["b"] = "\010", + ["f"] = "\014", + ["n"] = "\n", + ["r"] = "\r", + ["t"] = "\t", } -local escape_un = C(P("\\u") / "0x" * S("09","AF","af")) / function(s) return utfchar(tonumber(s)) end +-- todo: also handle larger utf16 + +local escape_un = P("\\u")/"" * (C(R("09","AF","af")^-4) / function(s) + return utfchar(tonumber(s,16)) +end) + local escape_bs = P([[\]]) / "" * (P(1) / escapes) -- if not found then P(1) is returned i.e. the to be escaped char local jstring = dquote * Cs((escape_un + escape_bs + (1-dquote))^0) * dquote @@ -85,7 +87,9 @@ function json.tolua(str) return lpegmatch(jsonconverter,str) end -local function tojson(value,t) -- we could optimize #t +local escaper + +local function tojson(value,t,n) -- we could optimize #t local kind = type(value) if kind == "table" then local done = false @@ -93,60 +97,75 @@ local function tojson(value,t) -- we could optimize #t if size == 0 then for k, v in next, value do if done then - t[#t+1] = "," + n = n + 1 ; t[n] = "," else - t[#t+1] = "{" + n = n + 1 ; t[n] = "{" done = true end - t[#t+1] = format("%q:",k) - tojson(v,t) + n = n + 1 ; t[n] = format("%q:",k) + t, n = tojson(v,t,n) end if done then - t[#t+1] = "}" + n = n + 1 ; t[n] = "}" else - t[#t+1] = "{}" + n = n + 1 ; t[n] = "{}" end elseif size == 1 then -- we can optimize for non tables - t[#t+1] = "[" - tojson(value[1],t) - t[#t+1] = "]" + n = n + 1 ; t[n] = "[" + t, n = tojson(value[1],t,n) + n = n + 1 ; t[n] = "]" else for i=1,size do if done then - t[#t+1] = "," + n = n + 1 ; t[n] = "," else - t[#t+1] = "[" + n = n + 1 ; t[n] = "[" done = true end - tojson(value[i],t) + t, n = tojson(value[i],t,n) end - t[#t+1] = "]" + n = n + 1 ; t[n] = "]" end elseif kind == "string" then - t[#t+1] = format("%q",value) + n = n + 1 ; t[n] = '"' + n = n + 1 ; t[n] = lpegmatch(escaper,value) or value + n = n + 1 ; t[n] = '"' elseif kind == "number" then - t[#t+1] = value + n = n + 1 ; t[n] = value elseif kind == "boolean" then - t[#t+1] = tostring(value) + n = n + 1 ; t[n] = tostring(value) end - return t + return t, n end function json.tostring(value) -- todo optimize for non table local kind = type(value) if kind == "table" then - return concat(tojson(value,{}),"") + if not escaper then + local escapes = { + ["\\"] = "\\u005C", + ["\""] = "\\u0022", + } + for i=0,0x20 do + escapes[utfchar(i)] = format("\\u%04X",i) + end + escaper = Cs( ( + (R('\0\x20') + S('\"\\')) / escapes + + P(1) + )^1 ) + + end + return concat((tojson(value,{},0))) elseif kind == "string" or kind == "number" then - return value + return lpegmatch(escaper,value) or value else return tostring(value) end end --- local tmp = [[ { "a" : true, "b" : [ 123 , 456E-10, { "a" : true, "b" : [ 123 , 456 ] } ] } ]] - +-- local tmp = [[ { "t" : "foobar", "a" : true, "b" : [ 123 , 456E-10, { "a" : true, "b" : [ 123 , 456 ] } ] } ]] -- tmp = json.tolua(tmp) -- inspect(tmp) -- tmp = json.tostring(tmp) @@ -155,7 +174,6 @@ end -- inspect(tmp) -- tmp = json.tostring(tmp) -- inspect(tmp) - -- inspect(json.tostring(true)) function json.load(filename) @@ -165,4 +183,11 @@ function json.load(filename) end end +-- local s = [[\foo"bar"]] +-- local j = json.tostring { s = s } +-- local l = json.tolua(j) +-- inspect(j) +-- inspect(l) +-- print(s==l.s) + return json diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua index 1f531ef48e2..1199301f42f 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua @@ -88,6 +88,7 @@ function luautilities.loadedluacode(fullname,forcestrip,name,macros) 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 diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua index 508d32d71cf..410a4a547e4 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua @@ -22,25 +22,12 @@ local utfchar, utfbyte, utflen = utf.char, utf.byte, utf.len ----- loadstripped = utilities.lua.loadstripped ----- setmetatableindex = table.setmetatableindex -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 +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 -- todo: make a special namespace for the formatter @@ -598,66 +585,34 @@ local template = [[ 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 -local stripzero=lpeg.patterns.stripzero -local stripzeros=lpeg.patterns.stripzeros - ]] - -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, - stripzero = lpeg.patterns.stripzero, - stripzeros = lpeg.patterns.stripzeros, - } - -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, +} -- -- -- @@ -1036,44 +991,86 @@ end -- strip = true -- end +-- add(formatters,"texexp", [[texexp(...)]], "local texexp = metapost.texexp") -- +-- add(formatters,"foo:bar",[[foo(...)]], { foo = function(...) print(...) return "!" end }) +-- print(string.formatters["foo %3!foo:bar! bar"](1,2,3)) + local format_rest = function(s) return format("%q",s) -- catches " and \n and such 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,"%.%.%.") +-- if f == 0 then +-- if w then +-- extension = gsub(extension,"%.%.%.","") +-- end +-- 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) -- maybe more times? +-- elseif f < 0 then +-- local a = "a" .. (n + f + 1) +-- return format(extension,a,a) +-- else +-- if w then +-- extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") +-- end +-- -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we +-- -- cache we don't save much and there are hardly any extensions anyway +-- local t = { } +-- for i=1,f do +-- n = n + 1 +-- -- t[#t+1] = "a" .. n +-- t[i] = "a" .. n +-- end +-- return format(extension,unpack(t)) +-- end +-- 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,"%.%.%.") - if f == 0 then - if w then + if w then + -- we have a wildcard + if f == 0 then extension = gsub(extension,"%.%.%.","") - end - return extension - elseif f == 1 then - if w then + return extension + elseif f == 1 then extension = gsub(extension,"%.%.%.","%%s") - end - n = n + 1 - local a = "a" .. n - return format(extension,a,a) -- maybe more times? - elseif f < 0 then - local a = "a" .. (n + f + 1) - return format(extension,a,a) - else - if w then + n = n + 1 + local a = "a" .. n + return format(extension,a,a) -- maybe more times? + elseif f < 0 then + local a = "a" .. (n + f + 1) + return format(extension,a,a) + else extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we + -- cache we don't save much and there are hardly any extensions anyway + local t = { } + for i=1,f do + n = n + 1 + -- t[#t+1] = "a" .. n + t[i] = "a" .. n + end + return format(extension,unpack(t)) end - -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we - -- cache we don't save much and there are hardly any extensions anyway - local t = { } - for i=1,f do + else + extension = gsub(extension,"%%s",function() n = n + 1 - -- t[#t+1] = "a" .. n - t[i] = "a" .. n - end - return format(extension,unpack(t)) + return "a" .. n + end) + return extension end end @@ -1273,36 +1270,22 @@ strings.formatters = { } -- _connector_ is an experiment -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 = { } -- better make a copy as we can overload - 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 +function strings.formatters.new(noconcat) + local e = { } -- better make a copy as we can overload + 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() --- local t = { _extensions_ = { }, _preamble_ = "", _type_ = "formatter", _n_ = 0 } --- local m = { _t_ = t } --- setmetatable(t, { __index = m, __call = use }) --- setmetatable(m, { __index = make }) --- return t --- end - local formatters = strings.formatters.new() -- the default instance string.formatters = formatters -- in the main string namespace @@ -1333,19 +1316,9 @@ patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n" -- escaping by lpeg is faster for strings without quotes, slower on a string with quotes, but -- faster again when other q-escapables are found (the ones we don't need to escape) -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 }) -- -- yes or no: -- diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua index f395f43defc..ed4cef9967c 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua @@ -820,3 +820,53 @@ if setinspector then end) end +-- ordered hashes (for now here but in the table namespace): + +-- local t = table.orderedhash() +-- +-- t["1"] = { "a", "b" } +-- t["2"] = { } +-- t["2a"] = { "a", "c", "d" } +-- +-- for k, v in table.ordered(t) do +-- ... +-- 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 diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua index 21d2a122c81..6ed21b7f404 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua @@ -25,8 +25,8 @@ lualibs = lualibs or { } lualibs.module_info = { name = "lualibs", - version = 2.62, - date = "2018-12-19", + version = 2.63, + date = "2019-01-28", description = "ConTeXt Lua standard libraries.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", |