summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2018-09-26 20:49:48 +0000
committerKarl Berry <karl@freefriends.org>2018-09-26 20:49:48 +0000
commit3a0140d05a7e481750ec23a30ed5cf3cdef61eb7 (patch)
tree8fac1dc16795d22db3b45205fa55db220a9beed4 /Master/texmf-dist/tex/luatex
parentb573c63f79c24b5c8dff312e023c2745b49f6089 (diff)
lualibs (26sep18)
git-svn-id: svn://tug.org/texlive/trunk@48770 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua5552
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua10
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua82
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua3834
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua10
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua62
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua266
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-lpeg.lua300
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua69
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-math.lua119
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-md5.lua3
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua166
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-os.lua106
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-package.lua44
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua28
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua175
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua98
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-unicode.lua395
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-url.lua123
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-deb.lua275
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-dim.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua243
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua9
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua49
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua37
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sta.lua16
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sto.lua110
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua493
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua176
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tpl.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/lualibs/lualibs.lua8
31 files changed, 11869 insertions, 993 deletions
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua
new file mode 100644
index 00000000000..8d3f87b9d66
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua
@@ -0,0 +1,5552 @@
+-- merged file : lualibs-basic-merged.lua
+-- parent file : lualibs-basic.lua
+-- merge date : Fri Sep 21 15:12:31 2018
+
+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"
+}
+local next,type,tonumber=next,type,tonumber
+LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
+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
+end
+_LUAVERSION=LUAVERSION
+if not lpeg then
+ 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
+ end
+else
+ 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
+ end
+end
+if not pairs then
+ function pairs(t)
+ return next,t
+ end
+end
+if not table.unpack then
+ table.unpack=_G.unpack
+elseif not unpack then
+ _G.unpack=table.unpack
+end
+if not package.loaders then
+ package.loaders=package.searchers
+end
+local print,select,tostring=print,select,tostring
+local inspectors={}
+function setinspector(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
+ end
+ end
+end
+local dummy=function() end
+function optionalrequire(...)
+ local ok,result=xpcall(require,dummy,...)
+ if ok then
+ return result
+ end
+end
+if lua then
+ 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
+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
+end
+if not FFISUPPORTED then
+ ffi=nil
+elseif not ffi.number then
+ ffi.number=tonumber
+end
+if not bit32 then
+ bit32=require("l-bit32")
+end
+
+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"
+}
+local type=type
+local gsub,format,find=string.gsub,string.format,string.find
+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 function cleanpath(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
+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",
+ }
+}
+package.helpers=helpers
+local methods=helpers.methods
+local builtin=helpers.builtin
+local extraluapaths={}
+local extralibpaths={}
+local luapaths=nil
+local libpaths=nil
+local oldluapath=nil
+local oldlibpath=nil
+local nofextralua=-1
+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)
+ end
+ return nofpaths
+end
+local function getextraluapaths()
+ 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
+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
+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
+end
+package.luapaths=getluapaths
+package.libpaths=getlibpaths
+package.extraluapaths=getextraluapaths
+package.extralibpaths=getextralibpaths
+local hashes={
+ 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
+ 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
+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
+ end
+end
+helpers.registerpath=registerpath
+function package.extraluapath(...)
+ registerpath("extra lua","lua",extraluapaths,...)
+end
+function package.pushluapath(path)
+ pushpath("extra lua","lua",extraluapaths,path)
+end
+function package.popluapath()
+ poppath("extra lua","lua",extraluapaths)
+end
+function package.extralibpath(...)
+ registerpath("extra lib","lib",extralibpaths,...)
+end
+function package.pushlibpath(path)
+ pushpath("extra lib","lib",extralibpaths,path)
+end
+function package.poplibpath()
+ 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)
+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
+ end
+end
+helpers.loadedbypath=loadedbypath
+local function loadedbyname(name,rawname)
+ if find(name,"^/") or find(name,"^[a-zA-Z]:/") then
+ local trace=helpers.trace
+ if trace then
+ helpers.report("qualified name, identifying '%s'",what,name)
+ end
+ if isreadable(name) then
+ if trace then
+ helpers.report("qualified name, '%s' found",what,name)
+ end
+ return loadfile(name)
+ end
+ end
+end
+helpers.loadedbyname=loadedbyname
+methods["already loaded"]=function(name)
+ return package.loaded[name]
+end
+methods["preload table"]=function(name)
+ return builtin["preload table"](name)
+end
+methods["qualified path"]=function(name)
+ return loadedbyname(addsuffix(lualibfile(name),"lua"),name)
+end
+methods["lua extra list"]=function(name)
+ return loadedbypath(addsuffix(lualibfile(name),"lua"),name,getextraluapaths(),false,"lua")
+end
+methods["lib extra list"]=function(name)
+ return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib")
+end
+methods["path specification"]=function(name)
+ getluapaths()
+ return builtin["path specification"](name)
+end
+methods["cpath specification"]=function(name)
+ getlibpaths()
+ return builtin["cpath specification"](name)
+end
+methods["all in one fallback"]=function(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
+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
+ 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
+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
+ end
+ package.loaded[name]=nil
+end
+table.insert(searchers,1,helpers.loaded)
+if context then
+ package.path=""
+end
+
+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"
+}
+lpeg=require("lpeg")
+local lpeg=lpeg
+if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
+local type,next,tostring=type,next,tostring
+local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
+local floor=math.floor
+local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt
+local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print
+if setinspector then
+ setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end)
+end
+lpeg.patterns=lpeg.patterns or {}
+local patterns=lpeg.patterns
+local anything=P(1)
+local endofstring=P(-1)
+local alwaysmatched=P(true)
+patterns.anything=anything
+patterns.endofstring=endofstring
+patterns.beginofstring=alwaysmatched
+patterns.alwaysmatched=alwaysmatched
+local sign=S('+-')
+local zero=P('0')
+local digit=R('09')
+local digits=digit^1
+local octdigit=R("07")
+local octdigits=octdigit^1
+local lowercase=R("az")
+local uppercase=R("AZ")
+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 escaped=P("\\")*anything
+local squote=P("'")
+local dquote=P('"')
+local space=P(" ")
+local period=P(".")
+local comma=P(",")
+local utfbom_32_be=P('\000\000\254\255')
+local utfbom_32_le=P('\255\254\000\000')
+local utfbom_16_be=P('\254\255')
+local utfbom_16_le=P('\255\254')
+local utfbom_8=P('\239\187\191')
+local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
+local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8")
+local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")
+local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0)
+local utf8next=R("\128\191")
+patterns.utfbom_32_be=utfbom_32_be
+patterns.utfbom_32_le=utfbom_32_le
+patterns.utfbom_16_be=utfbom_16_be
+patterns.utfbom_16_le=utfbom_16_le
+patterns.utfbom_8=utfbom_8
+patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n")
+patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000")
+patterns.utf_32_be_nl=P("\000\000\000\r\000\000\000\n")+P("\000\000\000\r")+P("\000\000\000\n")
+patterns.utf_32_le_nl=P("\r\000\000\000\n\000\000\000")+P("\r\000\000\000")+P("\n\000\000\000")
+patterns.utf8one=R("\000\127")
+patterns.utf8two=R("\194\223")*utf8next
+patterns.utf8three=R("\224\239")*utf8next*utf8next
+patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
+patterns.utfbom=utfbom
+patterns.utftype=utftype
+patterns.utfstricttype=utfstricttype
+patterns.utfoffset=utfoffset
+local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
+local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false)
+local utf8character=P(1)*R("\128\191")^0
+patterns.utf8=utf8char
+patterns.utf8char=utf8char
+patterns.utf8character=utf8character
+patterns.validutf8=validutf8char
+patterns.validutf8char=validutf8char
+local eol=S("\n\r")
+local spacer=S(" \t\f\v")
+local whitespace=eol+spacer
+local nonspacer=1-spacer
+local nonwhitespace=1-whitespace
+patterns.eol=eol
+patterns.spacer=spacer
+patterns.whitespace=whitespace
+patterns.nonspacer=nonspacer
+patterns.nonwhitespace=nonwhitespace
+local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)
+local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
+local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
+local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
+local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
+local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
+local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
+local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
+local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
+local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
+patterns.stripper=stripper
+patterns.fullstripper=fullstripper
+patterns.collapser=collapser
+patterns.nospacer=nospacer
+patterns.b_collapser=b_collapser
+patterns.m_collapser=m_collapser
+patterns.e_collapser=e_collapser
+patterns.b_stripper=b_stripper
+patterns.m_stripper=m_stripper
+patterns.e_stripper=e_stripper
+patterns.lowercase=lowercase
+patterns.uppercase=uppercase
+patterns.letter=patterns.lowercase+patterns.uppercase
+patterns.space=space
+patterns.tab=P("\t")
+patterns.spaceortab=patterns.space+patterns.tab
+patterns.newline=newline
+patterns.emptyline=newline^1
+patterns.equal=P("=")
+patterns.comma=comma
+patterns.commaspacer=comma*spacer^0
+patterns.period=period
+patterns.colon=P(":")
+patterns.semicolon=P(";")
+patterns.underscore=underscore
+patterns.escaped=escaped
+patterns.squote=squote
+patterns.dquote=dquote
+patterns.nosquote=(escaped+(1-squote))^0
+patterns.nodquote=(escaped+(1-dquote))^0
+patterns.unsingle=(squote/"")*patterns.nosquote*(squote/"")
+patterns.undouble=(dquote/"")*patterns.nodquote*(dquote/"")
+patterns.unquoted=patterns.undouble+patterns.unsingle
+patterns.unspacer=((patterns.spacer^1)/"")^0
+patterns.singlequoted=squote*patterns.nosquote*squote
+patterns.doublequoted=dquote*patterns.nodquote*dquote
+patterns.quoted=patterns.doublequoted+patterns.singlequoted
+patterns.digit=digit
+patterns.digits=digits
+patterns.octdigit=octdigit
+patterns.octdigits=octdigits
+patterns.hexdigit=hexdigit
+patterns.hexdigits=hexdigits
+patterns.sign=sign
+patterns.cardinal=digits
+patterns.integer=sign^-1*digits
+patterns.unsigned=digit^0*period*digits
+patterns.float=sign^-1*patterns.unsigned
+patterns.cunsigned=digit^0*comma*digits
+patterns.cpunsigned=digit^0*(period+comma)*digits
+patterns.cfloat=sign^-1*patterns.cunsigned
+patterns.cpfloat=sign^-1*patterns.cpunsigned
+patterns.number=patterns.float+patterns.integer
+patterns.cnumber=patterns.cfloat+patterns.integer
+patterns.cpnumber=patterns.cpfloat+patterns.integer
+patterns.oct=zero*octdigits
+patterns.octal=patterns.oct
+patterns.HEX=zero*P("X")*(digit+uppercase)^1
+patterns.hex=zero*P("x")*(digit+lowercase)^1
+patterns.hexadecimal=zero*S("xX")*hexdigits
+patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigits+hexdigits*period*hexdigit^0+hexdigits)*(S("pP")*sign^-1*hexdigits)^-1
+patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)*S("eE")*sign^-1*digits
+patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
+patterns.somecontent=(anything-newline-space)^1
+patterns.beginline=#(1-newline)
+patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0))
+function anywhere(pattern)
+ return (1-P(pattern))^0*P(pattern)
+end
+lpeg.anywhere=anywhere
+function lpeg.instringchecker(p)
+ p=anywhere(p)
+ return function(str)
+ return lpegmatch(p,str) and true or false
+ end
+end
+function lpeg.splitter(pattern,action)
+ return (((1-P(pattern))^1)/action+1)^0
+end
+function lpeg.tsplitter(pattern,action)
+ return Ct((((1-P(pattern))^1)/action+1)^0)
+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
+ 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
+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)
+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
+ end
+ return lpegmatch(c,str)
+ else
+ return { str }
+ end
+end
+local spacing=patterns.spacer^0*newline
+local empty=spacing*Cc("")
+local nonempty=Cs((1-spacing)^1)*spacing^-1
+local content=(empty+nonempty)^1
+patterns.textline=content
+local linesplitter=tsplitat(newline)
+patterns.linesplitter=linesplitter
+function string.splitlines(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)
+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 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)
+ 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)
+ end
+end
+function lpeg.frontstripper(str)
+ return (P(str)+P(true))*Cs(anything^0)
+end
+function lpeg.endstripper(str)
+ return Cs((1-P(str)*endofstring)^0)
+end
+function lpeg.replacer(one,two,makefunction,isutf)
+ local pattern
+ local u=isutf and utf8char or 1
+ if type(one)=="table" then
+ local no=#one
+ local p=P(false)
+ if no==0 then
+ for k,v in next,one do
+ p=p+P(k)/v
+ end
+ pattern=Cs((p+u)^0)
+ elseif no==1 then
+ local o=one[1]
+ one,two=P(o[1]),o[2]
+ pattern=Cs((one/two+u)^0)
+ else
+ for i=1,no do
+ local o=one[i]
+ p=p+P(o[1])/o[2]
+ end
+ pattern=Cs((p+u)^0)
+ end
+ else
+ pattern=Cs((P(one)/(two or "")+u)^0)
+ 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
+ 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
+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
+end
+local splitters_s,splitters_p={},{}
+function lpeg.beforesuffix(separator)
+ local splitter=splitters_s[separator]
+ if not splitter then
+ local pattern=P(separator)
+ splitter=C((1-pattern)^0)*pattern*endofstring
+ splitters_s[separator]=splitter
+ end
+ return splitter
+end
+function lpeg.afterprefix(separator)
+ local splitter=splitters_p[separator]
+ if not splitter then
+ local pattern=P(separator)
+ splitter=pattern*C(anything^0)
+ splitters_p[separator]=splitter
+ end
+ return splitter
+end
+function lpeg.balancer(left,right)
+ left,right=P(left),P(right)
+ return P { left*((1-left-right)+V(1))^0*right }
+end
+function lpeg.counter(pattern,action)
+ local n=0
+ local pattern=(P(pattern)/function() n=n+1 end+anything)^0
+ if action then
+ return function(str) n=0;lpegmatch(pattern,str);action(n) end
+ else
+ return function(str) n=0;lpegmatch(pattern,str);return n end
+ end
+end
+utf=utf or (unicode and unicode.utf8) or {}
+local utfcharacters=utf and utf.characters or string.utfcharacters
+local utfgmatch=utf and utf.gmatch
+local utfchar=utf and utf.char
+lpeg.UP=lpeg.P
+if utfcharacters then
+ function lpeg.US(str)
+ local p=P(false)
+ for uc in utfcharacters(str) do
+ p=p+P(uc)
+ end
+ return p
+ end
+elseif utfgmatch then
+ function lpeg.US(str)
+ local p=P(false)
+ for uc in utfgmatch(str,".") do
+ p=p+P(uc)
+ end
+ return p
+ end
+else
+ function lpeg.US(str)
+ local p=P(false)
+ local f=function(uc)
+ p=p+P(uc)
+ end
+ lpegmatch((utf8char/f)^0,str)
+ return p
+ end
+end
+local range=utf8byte*utf8byte+Cc(false)
+function lpeg.UR(str,more)
+ local first,last
+ if type(str)=="number" then
+ first=str
+ last=more or first
+ else
+ first,last=lpegmatch(range,str)
+ if not last then
+ return P(str)
+ end
+ end
+ if first==last then
+ return P(str)
+ elseif utfchar and (last-first<8) then
+ local p=P(false)
+ for i=first,last do
+ p=p+P(utfchar(i))
+ end
+ return p
+ else
+ local f=function(b)
+ return b>=first and b<=last
+ end
+ return utf8byte/f
+ end
+end
+function lpeg.is_lpeg(p)
+ 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
+end
+local sort=table.sort
+local function copyindexed(old)
+ 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
+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)
+ 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
+ p=P(k)+p
+ else
+ p=P(k)
+ 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
+ if k==v then
+ p=P(k)
+ else
+ p=P(k)/v
+ end
+ end
+ 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
+ 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
+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
+ 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
+ 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
+ end
+ return (insensitive and make2 or make1)(tree)
+end
+lpeg.utfchartabletopattern=utfchartabletopattern
+function lpeg.utfreplacer(list,insensitive)
+ local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0)
+ return function(str)
+ return lpegmatch(pattern,str) or str
+ end
+end
+patterns.containseol=lpeg.finder(eol)
+local function nextstep(n,step,result)
+ local m=n%step
+ local d=floor(n/step)
+ if d>0 then
+ local v=V(tostring(step))
+ local s=result.start
+ for i=1,d do
+ if s then
+ s=v*s
+ else
+ s=v
+ end
+ end
+ result.start=s
+ end
+ if step>1 and result.start then
+ local v=V(tostring(step/2))
+ result[tostring(step)]=v*v
+ end
+ if step>0 then
+ return nextstep(m,step/2,result)
+ else
+ return result
+ end
+end
+function lpeg.times(pattern,n)
+ return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
+end
+do
+ local trailingzeros=zero^0*-digit
+ local stripper=Cs((
+ digits*(
+ period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"")
+ )+1
+ )^0)
+ lpeg.patterns.stripzeros=stripper
+ local nonzero=digit-zero
+ local trailingzeros=zero^1*endofstring
+ local stripper=Cs((1-period)^0*(
+ period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring
+ ))
+ lpeg.patterns.stripzero=stripper
+end
+local byte_to_HEX={}
+local byte_to_hex={}
+local byte_to_dec={}
+local hex_to_byte={}
+for i=0,255 do
+ local H=format("%02X",i)
+ local h=format("%02x",i)
+ local d=format("%03i",i)
+ local c=char(i)
+ byte_to_HEX[c]=H
+ byte_to_hex[c]=h
+ byte_to_dec[c]=d
+ hex_to_byte[h]=c
+ hex_to_byte[H]=c
+end
+local hextobyte=P(2)/hex_to_byte
+local bytetoHEX=P(1)/byte_to_HEX
+local bytetohex=P(1)/byte_to_hex
+local bytetodec=P(1)/byte_to_dec
+local hextobytes=Cs(hextobyte^0)
+local bytestoHEX=Cs(bytetoHEX^0)
+local bytestohex=Cs(bytetohex^0)
+local bytestodec=Cs(bytetodec^0)
+patterns.hextobyte=hextobyte
+patterns.bytetoHEX=bytetoHEX
+patterns.bytetohex=bytetohex
+patterns.bytetodec=bytetodec
+patterns.hextobytes=hextobytes
+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
+end
+function string.tohex(s)
+ 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
+end
+function string.tobytes(s)
+ if not s or s=="" then
+ return s
+ else
+ return lpegmatch(hextobytes,s)
+ end
+end
+local patterns={}
+local function containsws(what)
+ local p=patterns[what]
+ if not p then
+ local p1=P(what)*(whitespace+endofstring)*Cc(true)
+ local p2=whitespace*P(p1)
+ p=P(p1)+P(1-p2)^0*p2+Cc(false)
+ patterns[what]=p
+ end
+ return p
+end
+lpeg.containsws=containsws
+function string.containsws(str,what)
+ return lpegmatch(patterns[what] or containsws(what),str)
+end
+
+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"
+}
+functions=functions or {}
+function functions.dummy() end
+
+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"
+}
+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
+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
+end
+function string.quoted(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
+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
+end
+local stripper=patterns.stripper
+local fullstripper=patterns.fullstripper
+local collapser=patterns.collapser
+local nospacer=patterns.nospacer
+local longtostring=patterns.longtostring
+function string.strip(str)
+ return str and lpegmatch(stripper,str) or ""
+end
+function string.fullstrip(str)
+ return str and lpegmatch(fullstripper,str) or ""
+end
+function string.collapsespaces(str)
+ return str and lpegmatch(collapser,str) or ""
+end
+function string.nospaces(str)
+ return str and lpegmatch(nospacer,str) or ""
+end
+function string.longtostring(str)
+ 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
+end
+local anything=patterns.anything
+local allescapes=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)
+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
+end
+function string.valid(str,default)
+ 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)
+end
+local replacer=lpeg.replacer("@","%%")
+function string.tformat(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
+ end
+end
+
+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"
+}
+local type,next,tostring,tonumber,select=type,next,tostring,tonumber,select
+local table,string=table,string
+local concat,sort,insert,remove=table.concat,table.sort,table.insert,table.remove
+local format,lower,dump=string.format,string.lower,string.dump
+local getmetatable,setmetatable=getmetatable,setmetatable
+local getinfo=debug.getinfo
+local lpegmatch,patterns=lpeg.match,lpeg.patterns
+local floor=math.floor
+local stripper=patterns.stripper
+function table.getn(t)
+ return t and #t
+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
+ 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 {}
+ 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
+ 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)
+ else
+ 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 {}
+ 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 {}
+ 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 {}
+ 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
+ end
+ return sortedkeys(keys)
+end
+table.sortedkeys=sortedkeys
+table.sortedhashonly=sortedhashonly
+table.sortedindexonly=sortedindexonly
+table.sortedhashkeys=sortedhashkeys
+local function nothing() end
+local function sortedhash(t,cmp)
+ 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
+ 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
+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
+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
+ 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
+ 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
+ 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
+ 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 {}
+ 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
+ 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
+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
+ 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
+ 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',
+}
+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
+ 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
+ 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))
+ 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
+ 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
+ local sk=sortedkeys(root)
+ for i=1,#sk do
+ local k=sk[i]
+ local v=root[k]
+ local tv=type(v)
+ local tk=type(k)
+ if compact and first and tk=="number" and k>=first and k<=last then
+ if tv=="number" then
+ if hexify then
+ handle(format("%s 0x%X,",depth,v))
+ else
+ handle(format("%s %s,",depth,v))
+ end
+ elseif tv=="string" then
+ handle(format("%s %q,",depth,v))
+ elseif tv=="table" then
+ if next(v)==nil then
+ handle(format("%s {},",depth))
+ elseif inline then
+ local st=is_simple_table(v,hexify)
+ if st then
+ handle(format("%s { %s },",depth,concat(st,", ")))
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ else
+ do_serialize(v,k,depth,level+1,true)
+ end
+ elseif tv=="boolean" then
+ handle(format("%s %s,",depth,v and "true" or "false"))
+ elseif tv=="function" then
+ if functions then
+ handle(format('%s load(%q),',depth,dump(v)))
+ else
+ handle(format('%s "function",',depth))
+ end
+ else
+ handle(format("%s %q,",depth,tostring(v)))
+ end
+ elseif k=="__p__" then
+ if false then
+ handle(format("%s __p__=nil,",depth))
+ end
+ elseif tv=="number" then
+ if tk=="number" then
+ if hexify then
+ handle(format("%s [0x%X]=0x%X,",depth,k,v))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v))
+ end
+ elseif tk=="boolean" then
+ if hexify then
+ handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))
+ else
+ handle(format("%s [%s]=%s,",depth,k and "true" or "false",v))
+ end
+ elseif tk~="string" then
+ elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+ if hexify then
+ handle(format("%s %s=0x%X,",depth,k,v))
+ else
+ handle(format("%s %s=%s,",depth,k,v))
+ end
+ else
+ if hexify then
+ handle(format("%s [%q]=0x%X,",depth,k,v))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v))
+ end
+ end
+ elseif tv=="string" then
+ if tk=="number" then
+ if hexify then
+ handle(format("%s [0x%X]=%q,",depth,k,v))
+ else
+ handle(format("%s [%s]=%q,",depth,k,v))
+ end
+ elseif tk=="boolean" then
+ handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
+ elseif tk~="string" then
+ elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+ handle(format("%s %s=%q,",depth,k,v))
+ else
+ handle(format("%s [%q]=%q,",depth,k,v))
+ end
+ elseif tv=="table" then
+ if next(v)==nil then
+ if tk=="number" then
+ if hexify then
+ handle(format("%s [0x%X]={},",depth,k))
+ else
+ handle(format("%s [%s]={},",depth,k))
+ end
+ elseif tk=="boolean" then
+ handle(format("%s [%s]={},",depth,k and "true" or "false"))
+ elseif tk~="string" then
+ elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+ handle(format("%s %s={},",depth,k))
+ else
+ handle(format("%s [%q]={},",depth,k))
+ end
+ elseif inline then
+ local st=is_simple_table(v,hexify)
+ if st then
+ if tk=="number" then
+ if hexify then
+ handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
+ end
+ elseif tk=="boolean" then
+ handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
+ elseif tk~="string" then
+ elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+ handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
+ else
+ handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ else
+ do_serialize(v,k,depth,level+1)
+ end
+ elseif tv=="boolean" then
+ if tk=="number" then
+ if hexify then
+ handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
+ else
+ handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
+ end
+ elseif tk=="boolean" then
+ handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
+ elseif tk~="string" then
+ elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+ handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
+ else
+ handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
+ end
+ elseif tv=="function" then
+ if functions then
+ local f=getinfo(v).what=="C" and dump(dummy) or dump(v)
+ if tk=="number" then
+ if hexify then
+ handle(format("%s [0x%X]=load(%q),",depth,k,f))
+ else
+ handle(format("%s [%s]=load(%q),",depth,k,f))
+ end
+ elseif tk=="boolean" then
+ handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
+ elseif tk~="string" then
+ elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
+ handle(format("%s %s=load(%q),",depth,k,f))
+ else
+ handle(format("%s [%q]=load(%q),",depth,k,f))
+ end
+ end
+ 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
+ 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
+ else
+ noquotes=false
+ hexify=false
+ handle=_handle or print
+ compact=true
+ inline=true
+ functions=true
+ metacheck=true
+ end
+ if tname=="string" then
+ if name=="return" then
+ handle("return {")
+ else
+ handle(name.."={")
+ end
+ elseif tname=="number" then
+ if hexify then
+ handle(format("[0x%X]={",name))
+ else
+ handle("["..name.."]={")
+ end
+ elseif tname=="boolean" then
+ if name then
+ handle("return {")
+ else
+ handle("{")
+ end
+ else
+ handle("t={")
+ end
+ if root then
+ if metacheck and getmetatable(root) then
+ local dummy=root._w_h_a_t_e_v_e_r_
+ root._w_h_a_t_e_v_e_r_=nil
+ end
+ if next(root)~=nil then
+ do_serialize(root,name,"",0)
+ end
+ 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")
+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)
+ 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
+ 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
+ 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
+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
+ end
+ return h
+end
+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
+ end
+ return f
+end
+function table.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
+ 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
+ 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
+ end
+ return new
+end
+table.sparse=sparse
+function table.compact(t)
+ 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
+ end
+ return false
+end
+function table.count(t)
+ 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
+ end
+ return n
+end
+function table.hashed(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
+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
+ 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
+ end
+end
+local function sequenced(t,sep,simple)
+ if not t then
+ return ""
+ elseif type(t)=="string" then
+ return t
+ end
+ local n=#t
+ local s={}
+ if n>0 then
+ for i=1,n do
+ local v=t[i]
+ if type(v)=="table" then
+ s[i]="{"..sequenced(v,sep,simple).."}"
+ else
+ s[i]=tostring(t[i])
+ end
+ end
+ 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
+ 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
+end
+if setinspector then
+ 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) }
+end
+function table.is_empty(t)
+ return not t or next(t)==nil
+end
+function table.has_one_entry(t)
+ 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
+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
+end
+function table.sorted(t,...)
+ sort(t,...)
+ return t
+end
+function table.values(t,s)
+ if t then
+ local values,keys,v={},{},0
+ for key,value in next,t do
+ if not keys[value] then
+ v=v+1
+ values[v]=value
+ keys[k]=key
+ end
+ end
+ if s then
+ sort(values)
+ end
+ return values
+ else
+ return {}
+ end
+end
+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
+ 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
+ end
+end
+
+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"
+}
+local type,tonumber=type,tonumber
+boolean=boolean or {}
+local boolean=boolean
+function boolean.tonumber(b)
+ 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
+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
+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
+ end
+ return default
+end
+
+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"
+}
+local tostring,tonumber=tostring,tonumber
+local format,floor,match,rep=string.format,math.floor,string.match,string.rep
+local concat,insert=table.concat,table.insert
+local lpegmatch=lpeg.match
+local floor=math.floor
+number=number or {}
+local number=number
+if bit32 then
+ local bextract=bit32.extract
+ local t={
+ "0","0","0","0","0","0","0","0",
+ "0","0","0","0","0","0","0","0",
+ "0","0","0","0","0","0","0","0",
+ "0","0","0","0","0","0","0","0",
+ }
+ function number.tobitstring(b,m)
+ local n=32
+ for i=0,31 do
+ local v=bextract(b,i)
+ local k=32-i
+ if v==1 then
+ n=k
+ t[k]="1"
+ else
+ t[k]="0"
+ end
+ end
+ if m then
+ m=33-m*8
+ if m<1 then
+ m=1
+ end
+ return concat(t,"",m)
+ elseif n<8 then
+ return concat(t)
+ elseif n<16 then
+ return concat(t,"",9)
+ elseif n<24 then
+ return concat(t,"",17)
+ else
+ return concat(t,"",25)
+ end
+ 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"
+ end
+ end
+end
+function number.valid(str,default)
+ 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
+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
+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
+end
+
+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"
+}
+if not math.ceiling then
+ math.ceiling=math.ceil
+end
+if not math.round then
+ 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
+end
+if not math.mod then
+ 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
+end
+if not math.odd then
+ 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
+end
+if not math.pow then
+ function math.pow(x,y)
+ return x^y
+ end
+end
+if not math.atan2 then
+ math.atan2=math.atan
+end
+if not math.ldexp then
+ 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
+end
+if not math.type then
+ 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
+end
+if not math.ult then
+ local floor=math.floor
+ function math.tointeger(m,n)
+ return floor(m)<floor(n)
+ end
+end
+
+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"
+}
+local io=io
+local open,flush,write,read=io.open,io.flush,io.write,io.read
+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="\\",";"
+else
+ 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
+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
+ 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()
+ 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
+ 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
+ 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
+ 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
+ end
+end
+function io.exists(filename)
+ 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
+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
+ 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
+}
+function io.characters(f,n)
+ 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
+ end
+}
+function io.bytes(f,n)
+ if f then
+ return nextbyte[n or 1],f
+ else
+ return nil,nil
+ end
+end
+function io.ask(question,default,options)
+ while true do
+ write(question)
+ if options then
+ write(format(" [%s]",concat(options,"|")))
+ end
+ if default then
+ write(format(" [%s]",default))
+ end
+ write(format(" "))
+ flush()
+ local answer=read()
+ answer=gsub(answer,"^%s*(.*)%s*$","%1")
+ if answer=="" and default then
+ return default
+ elseif not options then
+ return answer
+ else
+ for k=1,#options do
+ if options[k]==answer then
+ return answer
+ end
+ end
+ local pattern="^"..answer
+ for k=1,#options do
+ local v=options[k]
+ if find(v,pattern) then
+ return v
+ end
+ end
+ 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
+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
+end
+
+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"
+}
+local os=os
+local date,time=os.date,os.time
+local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string.upper,string.gmatch
+local concat=table.concat
+local random,ceil,randomseed=math.random,math.ceil,math.randomseed
+local rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring=rawget,rawset,type,getmetatable,setmetatable,tonumber,tostring
+math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6))
+randomseed(math.initialseed)
+if not os.__getenv__ then
+ os.__getenv__=os.getenv
+ os.__setenv__=os.setenv
+ if os.env then
+ local osgetenv=os.getenv
+ local ossetenv=os.setenv
+ local osenv=os.env local _=osenv.PATH
+ function os.setenv(k,v)
+ if v==nil then
+ v=""
+ end
+ local K=upper(k)
+ osenv[K]=v
+ if type(v)=="table" then
+ v=concat(v,";")
+ end
+ ossetenv(K,v)
+ end
+ function os.getenv(k)
+ local K=upper(k)
+ local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k)
+ if v=="" then
+ return nil
+ else
+ return v
+ end
+ 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
+end
+os.resultof=resultof
+function os.pipeto(command)
+ 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
+end
+os.type=os.type or (io.pathseparator==";" and "windows") or "unix"
+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' }
+else
+ os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' }
+end
+local launchers={
+ 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))
+end
+if not os.times then
+ 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
+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
+end })
+local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or ""
+if platform~="" then
+ 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
+ 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
+ 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
+ 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
+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
+ 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
+ end
+else
+ 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
+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)
+ )
+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
+ 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
+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
+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
+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
+ end
+ memory[filename]=fullname
+ end
+ return fullname
+end
+os.which=which
+os.where=which
+function os.today()
+ return date("!*t")
+end
+function os.now()
+ 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)
+ end
+end
+local function isleapyear(year)
+ 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
+end
+os.nofdays=nofdays
+function os.weekday(day,month,year)
+ return date("%w",time { year=year,month=month,day=day })+1
+end
+function os.validdate(year,month,day)
+ if month<1 then
+ month=1
+ elseif month>12 then
+ month=12
+ end
+ if day<1 then
+ day=1
+ else
+ local max=nofdays(year,month)
+ if day>max then
+ day=max
+ end
+ end
+ return year,month,day
+end
+local osexit=os.exit
+local exitcode=nil
+function os.setexitcode(code)
+ exitcode=code
+end
+function os.exit(c)
+ if exitcode~=nil then
+ return osexit(exitcode)
+ end
+ if c~=nil then
+ return osexit(c)
+ end
+ return osexit()
+end
+
+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"
+}
+file=file or {}
+local file=file
+if not lfs then
+ lfs=optionalrequire("lfs")
+end
+local insert,concat=table.insert,table.concat
+local match,find,gmatch=string.match,string.find,string.gmatch
+local lpegmatch=lpeg.match
+local getcurrentdir,attributes=lfs.currentdir,lfs.attributes
+local checkedsplit=string.checkedsplit
+local P,R,S,C,Cs,Cp,Cc,Ct=lpeg.P,lpeg.R,lpeg.S,lpeg.C,lpeg.Cs,lpeg.Cp,lpeg.Cc,lpeg.Ct
+local attributes=lfs.attributes
+function lfs.isdir(name)
+ return attributes(name,"mode")=="directory"
+end
+function lfs.isfile(name)
+ 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
+end
+if sandbox then
+ sandbox.redefine(lfs.isfile,"lfs.isfile")
+ sandbox.redefine(lfs.isdir,"lfs.isdir")
+ sandbox.redefine(lfs.isfound,"lfs.isfound")
+end
+local colon=P(":")
+local period=P(".")
+local periods=P("..")
+local fwslash=P("/")
+local bwslash=P("\\")
+local slashes=S("\\/")
+local noperiod=1-period
+local noslashes=1-slashes
+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 ""
+end
+local pattern=(noslashes^0*slashes)^1*C(noslashes^1)*-1
+local function basename(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
+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 ""
+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
+end
+file.pathpart=pathpart
+file.basename=basename
+file.nameonly=nameonly
+file.suffixonly=suffixonly
+file.suffix=suffixonly
+file.suffixesonly=suffixesonly
+file.suffixes=suffixesonly
+file.dirname=pathpart
+file.extname=suffixonly
+local drive=C(R("az","AZ"))*colon
+local path=C((noslashes^0*slashes)^0)
+local suffix=period*C(P(1-period)^0*P(-1))
+local base=C((1-suffix)^0)
+local rest=C(P(1)^0)
+drive=drive+Cc("")
+path=path+Cc("")
+base=base+Cc("")
+suffix=suffix+Cc("")
+local pattern_a=drive*path*base*suffix
+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
+end
+function file.splitbase(str)
+ 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
+ end
+end
+local pattern=Cs(((period*(1-period-slashes)^1*-1)/""+1)^1)
+function file.removesuffix(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
+ 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
+ elseif t=="string" then
+ if s==criterium then
+ return filename
+ end
+ 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
+end
+local reslasher=lpeg.replacer(P("\\"),"/")
+function file.reslash(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
+ 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
+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
+end
+function file.splitpath(str,separator)
+ 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)
+end
+local someslash=S("\\/")
+local stripper=Cs(P(fwslash)^0/""*reslasher)
+local isnetwork=someslash*someslash*(1-someslash)+(1-fwslash-colon)^1*colon
+local isroot=fwslash^1*-1
+local hasroot=fwslash^1
+local reslasher=lpeg.replacer(S("\\/"),"/")
+local deslasher=lpeg.replacer(S("\\/")^1,"/")
+function file.join(one,two,three,...)
+ if not two then
+ return one=="" and one or lpegmatch(reslasher,one)
+ end
+ if one=="" then
+ return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
+ end
+ if lpegmatch(isnetwork,one) then
+ local one=lpegmatch(reslasher,one)
+ local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
+ if lpegmatch(hasroot,two) then
+ return one..two
+ else
+ return one.."/"..two
+ end
+ elseif lpegmatch(isroot,one) then
+ local two=lpegmatch(deslasher,three and concat({ two,three,... },"/") or two)
+ if lpegmatch(hasroot,two) then
+ return two
+ else
+ return "/"..two
+ end
+ else
+ return lpegmatch(deslasher,concat({ one,two,three,... },"/"))
+ end
+end
+local drivespec=R("az","AZ")^1*colon
+local anchors=fwslash+drivespec
+local untouched=periods+(1-period)^1*P(-1)
+local mswindrive=Cs(drivespec*(bwslash/"/"+fwslash)^0)
+local mswinuncpath=(bwslash+fwslash)*(bwslash+fwslash)*Cc("//")
+local splitstarter=(mswindrive+mswinuncpath+Cc(false))*Ct(lpeg.splitat(S("/\\")^1))
+local absolute=fwslash
+function file.collapsepath(str,anchor)
+ if not str then
+ 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
+ else
+ return newelements
+ end
+ end
+end
+local validchars=R("az","09","AZ","--","..")
+local pattern_a=lpeg.replacer(1-validchars)
+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
+ 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
+ end
+end
+local letter=R("az","AZ")+S("_-+")
+local separator=P("://")
+local qualified=period^0*fwslash+letter*colon+letter^1*separator+letter^1*fwslash
+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
+end
+function file.is_rootbased_path(filename)
+ 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
+end
+function lfs.mkdirs(path)
+ 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
+end
+local symlinkattributes=lfs.symlinkattributes
+function lfs.readlink(name)
+ return symlinkattributes(name,"target") or nil
+end
+
+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"
+}
+if not gzip then
+ 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
+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
+end
+function gzip.suffix(filename)
+ local suffix,extra=suffixes(filename)
+ local gzipped=extra=="gz"
+ return suffix,gzipped
+end
+
+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"
+}
+if not md5 then
+ 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,
+ }
+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
+end
+function file.needsupdating(oldname,newname,threshold)
+ local oldtime=lfs.attributes(oldname,"modification")
+ if oldtime then
+ local newtime=lfs.attributes(newname,"modification")
+ if not newtime then
+ return true
+ elseif newtime>=oldtime then
+ return false
+ elseif oldtime-newtime<(threshold or 1) then
+ return false
+ else
+ return true
+ end
+ else
+ return false
+ end
+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
+end
+function file.checksum(name)
+ if md5 then
+ local data=io.loaddata(name)
+ if data then
+ return md5.HEX(data)
+ end
+ 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
+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
+end
+
+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"
+}
+local type,select=type,select
+local find,gmatch,match,gsub,sub=string.find,string.gmatch,string.match,string.gsub,string.sub
+local concat,insert,remove,unpack=table.concat,table.insert,table.remove,table.unpack
+local lpegmatch=lpeg.match
+local P,S,R,C,Cc,Cs,Ct,Cv,V=lpeg.P,lpeg.S,lpeg.R,lpeg.C,lpeg.Cc,lpeg.Cs,lpeg.Ct,lpeg.Cv,lpeg.V
+dir=dir or {}
+local dir=dir
+local lfs=lfs
+local attributes=lfs.attributes
+local walkdir=lfs.dir
+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
+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
+end
+function dir.current()
+ 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
+ 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
+ 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
+ end
+ 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)
+ }
+else
+ 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)
+)^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
+ 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
+ end
+ 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
+ end
+ end
+ return files
+end
+dir.globdirs=globdirs
+function dir.ls(pattern)
+ 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
+ else
+ str=""
+ for i=1,n do
+ local s=select(i,...)
+ if s=="" then
+ elseif str=="" then
+ str=s
+ else
+ str=str.."/"..s
+ end
+ end
+ end
+ local 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
+ 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
+ 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
+ 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
+ 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
+ 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
+end
+function dir.pop()
+ 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
+ end
+end
+dir.found=found
+
+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"
+}
+utf=utf or (unicode and unicode.utf8) or {}
+utf.characters=utf.characters or string.utfcharacters
+utf.values=utf.values or string.utfvalues
+local type=type
+local char,byte,format,sub,gmatch=string.char,string.byte,string.format,string.sub,string.gmatch
+local concat=table.concat
+local P,C,R,Cs,Ct,Cmt,Cc,Carg,Cp=lpeg.P,lpeg.C,lpeg.R,lpeg.Cs,lpeg.Ct,lpeg.Cmt,lpeg.Cc,lpeg.Carg,lpeg.Cp
+local lpegmatch=lpeg.match
+local patterns=lpeg.patterns
+local tabletopattern=lpeg.utfchartabletopattern
+local bytepairs=string.bytepairs
+local finder=lpeg.finder
+local replacer=lpeg.replacer
+local utfvalues=utf.values
+local utfgmatch=utf.gmatch
+local p_utftype=patterns.utftype
+local p_utfstricttype=patterns.utfstricttype
+local p_utfoffset=patterns.utfoffset
+local p_utf8char=patterns.utf8character
+local p_utf8byte=patterns.utf8byte
+local p_utfbom=patterns.utfbom
+local p_newline=patterns.newline
+local p_whitespace=patterns.whitespace
+if not unicode then
+ unicode={ utf=utf }
+end
+if not utf.char then
+ utf.char=string.utfcharacter or (utf8 and utf8.char)
+ if not utf.char then
+ local char=string.char
+ if bit32 then
+ local rshift=bit32.rshift
+ function utf.char(n)
+ if n<0x80 then
+ return char(n)
+ elseif n<0x800 then
+ return char(
+ 0xC0+rshift(n,6),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x10000 then
+ return char(
+ 0xE0+rshift(n,12),
+ 0x80+(rshift(n,6)%0x40),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x200000 then
+ return char(
+ 0xF0+rshift(n,18),
+ 0x80+(rshift(n,12)%0x40),
+ 0x80+(rshift(n,6)%0x40),
+ 0x80+(n%0x40)
+ )
+ else
+ return ""
+ end
+ end
+ else
+ local floor=math.floor
+ function utf.char(n)
+ if n<0x80 then
+ return char(n)
+ elseif n<0x800 then
+ return char(
+ 0xC0+floor(n/0x40),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x10000 then
+ return char(
+ 0xE0+floor(n/0x1000),
+ 0x80+(floor(n/0x40)%0x40),
+ 0x80+(n%0x40)
+ )
+ elseif n<0x200000 then
+ return char(
+ 0xF0+floor(n/0x40000),
+ 0x80+(floor(n/0x1000)%0x40),
+ 0x80+(floor(n/0x40)%0x40),
+ 0x80+(n%0x40)
+ )
+ else
+ return ""
+ end
+ end
+ end
+ end
+end
+if not utf.byte then
+ utf.byte=string.utfvalue or (utf8 and utf8.codepoint)
+ if not utf.byte then
+ local utf8byte=patterns.utf8byte
+ function utf.byte(c)
+ return lpegmatch(utf8byte,c)
+ end
+ end
+end
+local utfchar,utfbyte=utf.char,utf.byte
+function utf.filetype(data)
+ 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.toentities=toentities
+function utf.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 )
+function string.toutf(s)
+ return lpegmatch(pattern,s) or s
+end
+local validatedutf=Cs (
+ (
+ 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
+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
+ 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
+ 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_two(s,p)
+ n=n+1
+ if n==first then
+ b=p
+ else
+ return true
+ end
+ end
+ local pattern_zero=Cmt(p_utf8char,slide_zero)^0
+ local pattern_one=Cmt(p_utf8char,slide_one )^0
+ local pattern_two=Cmt(p_utf8char,slide_two )^0
+ local pattern_first=C(patterns.utf8character)
+ function utf.sub(str,start,stop)
+ if not start then
+ return str
+ end
+ if start==0 then
+ start=1
+ end
+ if not stop then
+ if start<0 then
+ local l=utflength(str)
+ start=l+start
+ else
+ start=start-1
+ end
+ b,n,first=0,0,start
+ lpegmatch(pattern_two,str)
+ if n>=first then
+ return sub(str,b)
+ else
+ return ""
+ end
+ end
+ if start<0 or stop<0 then
+ local l=utf.length(str)
+ if start<0 then
+ start=l+start
+ if start<=0 then
+ start=1
+ else
+ start=start+1
+ end
+ end
+ if stop<0 then
+ stop=l+stop
+ if stop==0 then
+ stop=1
+ else
+ stop=stop+1
+ end
+ end
+ end
+ if start==1 and stop==1 then
+ return lpegmatch(pattern_first,str) or ""
+ elseif start>stop then
+ return ""
+ elseif start>1 then
+ b,e,n,first,last=0,0,0,start-1,stop
+ lpegmatch(pattern_one,str)
+ if n>=first and e==0 then
+ e=#str
+ end
+ return sub(str,b,e)
+ else
+ b,e,n,last=1,0,0,stop
+ lpegmatch(pattern_zero,str)
+ if e==0 then
+ e=#str
+ end
+ return sub(str,b,e)
+ end
+ end
+end
+function utf.remapper(mapping,option,action)
+ local variant=type(mapping)
+ if variant=="table" then
+ action=action or mapping
+ if option=="dynamic" then
+ local pattern=false
+ table.setmetatablenewindex(mapping,function(t,k,v) rawset(t,k,v) pattern=false end)
+ return function(str)
+ if not str or str=="" then
+ return ""
+ else
+ if not pattern then
+ pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0)
+ end
+ return lpegmatch(pattern,str)
+ end
+ end
+ elseif option=="pattern" then
+ return Cs((tabletopattern(mapping)/action+p_utf8char)^0)
+ else
+ local pattern=Cs((tabletopattern(mapping)/action+p_utf8char)^0)
+ return function(str)
+ if not str or str=="" then
+ return ""
+ else
+ return lpegmatch(pattern,str)
+ end
+ end,pattern
+ end
+ elseif variant=="function" then
+ if option=="pattern" then
+ return Cs((p_utf8char/mapping+p_utf8char)^0)
+ else
+ local pattern=Cs((p_utf8char/mapping+p_utf8char)^0)
+ return function(str)
+ if not str or str=="" then
+ return ""
+ else
+ return lpegmatch(pattern,str)
+ end
+ end,pattern
+ end
+ else
+ return function(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
+ end
+end
+local utflinesplitter=p_utfbom^-1*lpeg.tsplitat(p_newline)
+local utfcharsplitter_ows=p_utfbom^-1*Ct(C(p_utf8char)^0)
+local utfcharsplitter_iws=p_utfbom^-1*Ct((p_whitespace^1+C(p_utf8char))^0)
+local utfcharsplitter_raw=Ct(C(p_utf8char)^0)
+patterns.utflinesplitter=utflinesplitter
+function utf.splitlines(str)
+ 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
+end
+function utf.totable(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)
+end
+local utf16_to_utf8_be,utf16_to_utf8_le
+local utf32_to_utf8_be,utf32_to_utf8_le
+local utf_16_be_getbom=patterns.utfbom_16_be^-1
+local utf_16_le_getbom=patterns.utfbom_16_le^-1
+local utf_32_be_getbom=patterns.utfbom_32_be^-1
+local utf_32_le_getbom=patterns.utfbom_32_le^-1
+local utf_16_be_linesplitter=utf_16_be_getbom*lpeg.tsplitat(patterns.utf_16_be_nl)
+local utf_16_le_linesplitter=utf_16_le_getbom*lpeg.tsplitat(patterns.utf_16_le_nl)
+local utf_32_be_linesplitter=utf_32_be_getbom*lpeg.tsplitat(patterns.utf_32_be_nl)
+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
+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
+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))
+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))
+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)
+p_utf32_to_utf8_be=P(true)/function() more=0 end*utf_32_be_getbom*Cs(p_utf32_to_utf8_be^0)
+p_utf32_to_utf8_le=P(true)/function() more=0 end*utf_32_le_getbom*Cs(p_utf32_to_utf8_le^0)
+patterns.utf16_to_utf8_be=p_utf16_to_utf8_be
+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
+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
+ 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
+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
+ 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
+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
+ 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
+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
+ 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
+utf.utf32_to_utf8_le_t=utf32_to_utf8_le_t
+utf.utf32_to_utf8_be_t=utf32_to_utf8_be_t
+utf.utf16_to_utf8_le=utf16_to_utf8_le
+utf.utf16_to_utf8_be=utf16_to_utf8_be
+utf.utf32_to_utf8_le=utf32_to_utf8_le
+utf.utf32_to_utf8_be=utf32_to_utf8_be
+function utf.utf8_to_utf8_t(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
+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
+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
+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
+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
+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
+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
+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
+)
+function utf.tocodes(str,separator)
+ return lpegmatch(pattern,str,1,separator or " ")
+end
+function utf.ustring(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))
+end
+function utf.toeight(str)
+ if not str or str=="" then
+ return nil
+ end
+ local utftype=lpegmatch(p_utfstricttype,str)
+ if utftype=="utf-8" then
+ return sub(str,4)
+ elseif utftype=="utf-16-be" then
+ return utf16_to_utf8_be(str)
+ elseif utftype=="utf-16-le" then
+ return utf16_to_utf8_le(str)
+ else
+ return str
+ end
+end
+local p_nany=p_utf8char/""
+if utfgmatch then
+ function utf.count(str,what)
+ if type(what)=="string" then
+ local n=0
+ for _ in utfgmatch(str,what) do
+ n=n+1
+ end
+ return n
+ else
+ return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str)
+ end
+ end
+else
+ local cache={}
+ function utf.count(str,what)
+ if type(what)=="string" then
+ local p=cache[what]
+ if not p then
+ p=Cs((P(what)/" "+p_nany)^0)
+ cache[p]=p
+ end
+ return #lpegmatch(p,str)
+ else
+ return #lpegmatch(Cs((P(what)/" "+p_nany)^0),str)
+ end
+ end
+end
+if not utf.characters then
+ function utf.characters(str)
+ return gmatch(str,".[\128-\191]*")
+ end
+ string.utfcharacters=utf.characters
+end
+if not utf.values then
+ local find=string.find
+ local dummy=function()
+ end
+ function utf.values(str)
+ local n=#str
+ if n==0 then
+ return dummy
+ elseif n==1 then
+ return function() return utfbyte(str) end
+ else
+ local p=1
+ return function()
+ local b,e=find(str,".[\128-\191]*",p)
+ if b then
+ p=e+1
+ return utfbyte(sub(str,b,e))
+ end
+ end
+ end
+ end
+ string.utfvalues=utf.values
+end
+function utf.chrlen(u)
+ return
+ (u<0x80 and 1) or
+ (u<0xE0 and 2) or
+ (u<0xF0 and 3) or
+ (u<0xF8 and 4) or
+ (u<0xFC and 5) or
+ (u<0xFE and 6) or 0
+end
+if bit32 then
+ local extract=bit32.extract
+ local char=string.char
+ function unicode.toutf32string(n)
+ if n<=0xFF then
+ return
+ char(n).."\000\000\000"
+ elseif n<=0xFFFF then
+ return
+ char(extract(n,0,8))..char(extract(n,8,8)).."\000\000"
+ elseif n<=0xFFFFFF then
+ return
+ char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8)).."\000"
+ else
+ return
+ char(extract(n,0,8))..char(extract(n,8,8))..char(extract(n,16,8))..char(extract(n,24,8))
+ end
+ end
+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
+ end
+ return s
+end
+
+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"
+}
+local char,format,byte=string.char,string.format,string.byte
+local concat=table.concat
+local tonumber,type,next=tonumber,type,next
+local P,C,R,S,Cs,Cc,Ct,Cf,Cg,V=lpeg.P,lpeg.C,lpeg.R,lpeg.S,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Cf,lpeg.Cg,lpeg.V
+local lpegmatch,lpegpatterns,replacer=lpeg.match,lpeg.patterns,lpeg.replacer
+local sortedhash=table.sortedhash
+url=url or {}
+local url=url
+local unescapes={}
+local escapes={}
+setmetatable(unescapes,{ __index=function(t,k)
+ 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
+end })
+local colon=P(":")
+local qmark=P("?")
+local hash=P("#")
+local slash=P("/")
+local atsign=P("@")
+local percent=P("%")
+local endofstring=P(-1)
+local hexdigit=R("09","AF","af")
+local plus=P("+")
+local nothing=Cc("")
+local okay=R("09","AZ","az")+S("-_.,:=+*~!'()@&$")
+local escapedchar=(percent*C(hexdigit*hexdigit))/unescapes
+local unescapedchar=P(1)/escapes
+local escaped=(plus/" ")+escapedchar
+local noslash=P("/")/""
+local plustospace=P("+")/" "
+local decoder=Cs((
+ 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 )
+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.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 scheme=schemestr*colon+nothing
+local authority=slash*slash*authoritystr+nothing
+local path=slash*pathstr+nothing
+local query=qmark*querystr+nothing
+local fragment=hash*fragmentstr+nothing
+local validurl=scheme*authority*path*query*fragment
+local parser=Ct(validurl)
+lpegpatterns.url=validurl
+lpegpatterns.urlsplitter=parser
+local escaper=Cs((R("09","AZ","az")^1+P(" ")/"%%20"+S("-./_:")^1+P(1)/escapes)^0)
+local unescaper=Cs((escapedchar+1)^0)
+local getcleaner=Cs((P("+++")/"%%2B"+P("+")/"%%20"+P(1))^1)
+lpegpatterns.urlunescaped=escapedchar
+lpegpatterns.urlescaper=escaper
+lpegpatterns.urlunescaper=unescaper
+lpegpatterns.urlgetcleaner=getcleaner
+function url.unescapeget(str)
+ return lpegmatch(getcleaner,str)
+end
+local function split(str)
+ return (type(str)=="string" and lpegmatch(parser,str)) or str
+end
+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
+end
+local rootletter=R("az","AZ")+S("_-+")
+local separator=P("://")
+local qualified=P(".")^0*P("/")+rootletter*P(":")+rootletter^1*separator+rootletter^1*P("/")
+local rootbased=P("/")+rootletter*P(":")
+local barswapper=replacer("|",":")
+local backslashswapper=replacer("\\","/")
+local equal=P("=")
+local amp=P("&")
+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),
+},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
+ 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
+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)
+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
+end
+local function escapestring(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
+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
+ 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
+end
+
+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"
+}
+set=set or {}
+local nums={}
+local tabs={}
+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
+ end
+end
+function set.totable(n)
+ 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," ")
+ 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
+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 4b302285523..0fed125d393 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic.lua
@@ -7,7 +7,7 @@
-- lualibs.dtx (with options: `basic')
-- This is a generated file.
--
--- Copyright (C) 2009--2017 by
+-- Copyright (C) 2009--2018 by
-- PRAGMA ADE / ConTeXt Development Team
-- The LuaLaTeX Dev Team
--
@@ -29,8 +29,8 @@ local loadmodule = lualibs.loadmodule
local lualibs_basic_module = {
name = "lualibs-basic",
- version = 2.5,
- date = "2017-02-01",
+ version = 2.6,
+ date = "2018-09-21",
description = "ConTeXt Lua libraries -- basic collection.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -40,11 +40,11 @@ local lualibs_basic_module = {
local loaded = false --- track success of package loading
if lualibs.prefer_merged then
- info"Loading merged package for collection “basic”."
+ info"Loading merged package for collection ^^e2^^80^^9cbasic^^e2^^80^^9d."
loaded = loadmodule('lualibs-basic-merged.lua')
else
info"Ignoring merged packages."
- info"Falling back to individual libraries from collection “basic”."
+ info"Falling back to individual libraries from collection ^^e2^^80^^9cbasic^^e2^^80^^9d."
end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua
index bc691d53635..b0b2c52836a 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua
@@ -75,7 +75,8 @@ function dir.current()
return (gsub(currentdir(),"\\","/"))
end
--- somewhat optimized
+-- The next one is somewhat optimized but still slow but it's a pitty that the iterator
+-- doesn't return a mode too.
local function glob_pattern_function(path,patt,recurse,action)
if isdir(path) then
@@ -89,6 +90,7 @@ local function glob_pattern_function(path,patt,recurse,action)
usedpath = path
end
local dirs
+ local nofdirs = 0
for name in walkdir(usedpath) do
if name ~= "." and name ~= ".." then
local full = path .. name
@@ -98,16 +100,18 @@ local function glob_pattern_function(path,patt,recurse,action)
action(full)
end
elseif recurse and mode == "directory" then
- if not dirs then
- dirs = { full }
+ if dirs then
+ nofdirs = nofdirs + 1
+ dirs[nofdirs] = full
else
- dirs[#dirs+1] = full
+ nofdirs = 1
+ dirs = { full }
end
end
end
end
if dirs then
- for i=1,#dirs do
+ for i=1,nofdirs do
glob_pattern_function(dirs[i],patt,recurse,action)
end
end
@@ -118,38 +122,41 @@ local function glob_pattern_table(path,patt,recurse,result)
if not result then
result = { }
end
- if isdir(path) then
- local usedpath
- if path == "/" then
- usedpath = "/."
- elseif not find(path,"/$") then
- usedpath = path .. "/."
- path = path .. "/"
- else
- usedpath = path
- end
- local dirs
- for name in walkdir(usedpath) do
- if name ~= "." and name ~= ".." then
- local full = path .. name
- local mode = attributes(full,'mode')
- if mode == 'file' then
- if not patt or find(full,patt) then
- result[#result+1] = full
- end
- elseif recurse and mode == "directory" then
- if not dirs then
- dirs = { full }
- else
- dirs[#dirs+1] = full
- end
+ 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
- if dirs then
- for i=1,#dirs do
- glob_pattern_table(dirs[i],patt,recurse,result)
- end
+ end
+ if dirs then
+ for i=1,nofdirs do
+ glob_pattern_table(dirs[i],patt,recurse,result)
end
end
return result
@@ -160,12 +167,13 @@ local function globpattern(path,patt,recurse,method)
if patt and sub(patt,1,-3) == path then
patt = false
end
+ local okay = isdir(path)
if kind == "function" then
- return glob_pattern_function(path,patt,recurse,method)
+ return okay and glob_pattern_function(path,patt,recurse,method) or { }
elseif kind == "table" then
- return glob_pattern_table(path,patt,recurse,method)
+ return okay and glob_pattern_table(path,patt,recurse,method) or method
else
- return glob_pattern_table(path,patt,recurse,{ })
+ return okay and glob_pattern_table(path,patt,recurse,{ }) or { }
end
end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua
new file mode 100644
index 00000000000..0175b8d8747
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua
@@ -0,0 +1,3834 @@
+-- merged file : lualibs-extended-merged.lua
+-- parent file : lualibs-extended.lua
+-- merge date : Fri Sep 21 15:12:38 2018
+
+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"
+}
+utilities=utilities or {}
+utilities.strings=utilities.strings or {}
+local strings=utilities.strings
+local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,string.find
+local load,dump=load,string.dump
+local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
+local unpack,concat=table.unpack,table.concat
+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
+end
+if not number then number={} end
+local stripzero=patterns.stripzero
+local stripzeros=patterns.stripzeros
+local newline=patterns.newline
+local endofstring=patterns.endofstring
+local anything=patterns.anything
+local whitespace=patterns.whitespace
+local space=patterns.space
+local spacer=patterns.spacer
+local spaceortab=patterns.spaceortab
+local digit=patterns.digit
+local sign=patterns.sign
+local period=patterns.period
+local ptf=1/65536
+local bpf=(7200/7227)/65536
+local function points(n)
+ 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))
+end
+number.points=points
+number.basepoints=basepoints
+local rubish=spaceortab^0*newline
+local anyrubish=spaceortab+newline
+local stripped=(spaceortab^1/"")*newline
+local leading=rubish^0/""
+local trailing=(anyrubish^1*endofstring)/""
+local redundant=rubish^3/"\n"
+local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0)
+function strings.collapsecrlf(str)
+ return lpegmatch(pattern,str)
+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
+ 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((
+ 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
+ end+newline*Cp()/function(position)
+ extra,start=0,position
+ end+anything
+ )^1)
+function strings.tabtospace(str,tab)
+ return lpegmatch(pattern,str,1,tab or 7)
+end
+function string.utfpadding(s,n)
+ if not n or n==0 then
+ return ""
+ end
+ local l=utflen(s)
+ if n>0 then
+ return nspaces[n-l]
+ else
+ return nspaces[-n-l]
+ end
+end
+local optionalspace=spacer^0
+local nospace=optionalspace/""
+local endofline=nospace*newline
+local stripend=(whitespace^1*endofstring)/""
+local normalline=(nospace*((1-optionalspace*(newline+endofstring))^1)*nospace)
+local stripempty=endofline^1/""
+local normalempty=endofline^1
+local singleempty=endofline*(endofline^0/"")
+local doubleempty=endofline*endofline^-1*(endofline^0/"")
+local stripstart=stripempty^0
+local intospace=whitespace^1/" "
+local noleading=whitespace^1/""
+local notrailing=noleading*endofstring
+local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 )
+local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 )
+local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 )
+local p_prune_intospace=Cs (noleading*(notrailing+intospace+1 )^0 )
+local p_retain_normal=Cs ((normalline+normalempty )^0 )
+local p_retain_collapse=Cs ((normalline+doubleempty )^0 )
+local p_retain_noempty=Cs ((normalline+singleempty )^0 )
+local striplinepatterns={
+ ["prune"]=p_prune_normal,
+ ["prune and collapse"]=p_prune_collapse,
+ ["prune and no empty"]=p_prune_noempty,
+ ["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
+end
+function strings.collapse(str)
+ return str and lpegmatch(p_prune_intospace,str) or str
+end
+strings.striplong=strings.striplines
+function strings.nice(str)
+ str=gsub(str,"[:%-+_]+"," ")
+ return str
+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)..'"')
+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).."'")
+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]",
+}
+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
+end
+function number.signed(i)
+ 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)
+)
+local splitter3=Cs (
+ 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 ".")
+ 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
+ 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
+ )
+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
+end
+local zero=P("0")^1/""
+local plus=P("+")/""
+local minus=P("-")
+local separator=period
+local trailing=zero^1*#S("eE")
+local exponent=(S("eE")*(plus+Cs((minus*zero^0*endofstring)/"")+minus)*zero^0*(endofstring*Cc("0")+anything^1))
+local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent)
+local pattern_b=Cs((exponent+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))
+ end
+ return tostring(n)
+end
+local hf={}
+local hs={}
+setmetatable(hf,{ __index=function(t,k)
+ 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
+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
+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 arguments={ "a1" }
+setmetatable(arguments,{ __index=function(t,k)
+ 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
+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
+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
+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
+end
+local format_q=function()
+ 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)
+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
+end
+local format_d=format_i
+local format_I=function(f)
+ 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)
+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
+end
+local format_k=function(b,a)
+ 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)
+end
+local format_G=function(f)
+ 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)
+end
+local format_E=function(f)
+ n=n+1
+ return format("format('%%%sE',a%s)",f,n)
+end
+local format_j=function(f)
+ n=n+1
+ return format("sparseexponent('%%%se',a%s)",f,n)
+end
+local format_J=function(f)
+ n=n+1
+ return format("sparseexponent('%%%sE',a%s)",f,n)
+end
+local format_x=function(f)
+ n=n+1
+ return format("format('%%%sx',a%s)",f,n)
+end
+local format_X=function(f)
+ 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)
+end
+local format_c=function()
+ n=n+1
+ return format("utfchar(a%s)",n)
+end
+local format_C=function()
+ 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)
+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
+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
+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
+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
+end
+local format_p=function()
+ n=n+1
+ return format("points(a%s)",n)
+end
+local format_b=function()
+ 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
+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
+end
+local format_l=function()
+ 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)
+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)
+end
+local format_N=function(f)
+ n=n+1
+ if not f or f=="" then
+ f=".9"
+ end
+ return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+end
+local format_a=function(f)
+ n=n+1
+ if f and f~="" then
+ return format("autosingle(a%s,%q)",n,f)
+ else
+ return format("autosingle(a%s)",n)
+ end
+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
+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
+end
+local format_W=function(f)
+ 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
+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
+end
+local format_z=function(f)
+ n=n+(tonumber(f) or 1)
+ return "''"
+end
+local format_rest=function(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,"%.%.%.")
+ 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)
+ 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
+ local t={}
+ for i=1,f do
+ n=n+1
+ t[i]="a"..n
+ end
+ return format(extension,unpack(t))
+ end
+end
+local builder=Cs { "start",
+ start=(
+ (
+ P("%")/""*(
+ V("!")
++V("s")+V("q")+V("i")+V("d")+V("f")+V("F")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o")
++V("c")+V("C")+V("S")
++V("Q")
++V("n")
++V("N")
++V("k")
++V("r")+V("h")+V("H")+V("u")+V("U")+V("p")+V("b")+V("t")+V("T")+V("l")+V("L")+V("I")+V("w")
++V("W")
++V("a")
++V("A")
++V("j")+V("J")
++V("m")+V("M")
++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,
+}
+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,
+}
+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)()
+ 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
+ end
+ t[str]=f
+ return f
+end
+local function use(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
+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
+ end
+end
+strings.formatters.add=add
+patterns.xmlescape=Cs((P("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;"+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
+local dquote=patterns.dquote
+local equote=patterns.escaped+dquote/'\\"'+1
+local cquote=Cc('"')
+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
+end
+local pattern=Cs((newline/(os.newline or "\r")+1)^0)
+function string.replacenewlines(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
+end
+
+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"
+}
+local byte=string.byte
+local char=string.char
+utilities=utilities or {}
+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
+end
+function files.close(f)
+ 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
+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
+end
+function files.getposition(f)
+ 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
+end
+function files.skip(f,n)
+ 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))
+end
+function files.readbytes(f,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) }
+end
+function files.readchar(f)
+ return f:read(1)
+end
+function files.readstring(f,n)
+ 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
+end
+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
+end
+function files.readcardinal2le(f)
+ 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
+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
+end
+function files.readcardinal3(f)
+ 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
+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
+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
+end
+function files.readcardinal4(f)
+ 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
+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
+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
+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
+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
+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
+ end
+end
+function files.skipshort(f,n)
+ f:read(2*(n or 1))
+end
+function files.skiplong(f,n)
+ 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 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)))
+end
+function files.writebyte(f,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
+end
+if fio and fio.readcardinaltable then
+ files.readcardinaltable=fio.readcardinaltable
+ files.readintegertable=fio.readintegertable
+else
+ local readcardinal1=files.readcardinal1
+ local readcardinal2=files.readcardinal2
+ local readcardinal3=files.readcardinal3
+ local readcardinal4=files.readcardinal4
+ function files.readcardinaltable(f,n,b)
+ local t={}
+ if b==1 then for i=1,n do t[i]=readcardinal1(f) end
+ elseif b==2 then for i=1,n do t[i]=readcardinal2(f) end
+ elseif b==3 then for i=1,n do t[i]=readcardinal3(f) end
+ elseif b==4 then for i=1,n do t[i]=readcardinal4(f) end end
+ return t
+ end
+ local readinteger1=files.readinteger1
+ local readinteger2=files.readinteger2
+ local readinteger3=files.readinteger3
+ local readinteger4=files.readinteger4
+ function files.readintegertable(f,n,b)
+ local t={}
+ if b==1 then for i=1,n do t[i]=readinteger1(f) end
+ elseif b==2 then for i=1,n do t[i]=readinteger2(f) end
+ elseif b==3 then for i=1,n do t[i]=readinteger3(f) end
+ elseif b==4 then for i=1,n do t[i]=readinteger4(f) end end
+ return t
+ end
+end
+
+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"
+}
+utilities=utilities or {}
+utilities.tables=utilities.tables or {}
+local tables=utilities.tables
+local format,gmatch,gsub,sub=string.format,string.gmatch,string.gsub,string.sub
+local concat,insert,remove,sort=table.concat,table.insert,table.remove,table.sort
+local setmetatable,getmetatable,tonumber,tostring,rawget=setmetatable,getmetatable,tonumber,tostring,rawget
+local type,next,rawset,tonumber,tostring,load,select=type,next,rawset,tonumber,tostring,load,select
+local lpegmatch,P,Cs,Cc=lpeg.match,lpeg.P,lpeg.Cs,lpeg.Cc
+local sortedkeys,sortedpairs=table.sortedkeys,table.sortedpairs
+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
+ 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
+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
+ 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
+ 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
+ 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
+ end
+end
+function tables.insertbeforevalue(t,value,extra)
+ for i=1,#t do
+ if t[i]==extra then
+ remove(t,i)
+ end
+ end
+ for i=1,#t do
+ if t[i]==value then
+ insert(t,i,extra)
+ return
+ end
+ 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
+ end
+ for i=1,#t do
+ if t[i]==value then
+ insert(t,i+1,extra)
+ return
+ end
+ 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)
+ 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
+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")
+end
+function tables.encapsulate(core,capsule,protect)
+ 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"]("overload",key,core))
+ os.exit()
+ else
+ rawset(t,key,value)
+ end
+ end
+ } )
+ end
+end
+local f_hashed_string=formatters["[%q]=%q,"]
+local f_hashed_number=formatters["[%q]=%s,"]
+local f_hashed_boolean=formatters["[%q]=%l,"]
+local f_hashed_table=formatters["[%q]="]
+local f_indexed_string=formatters["[%s]=%q,"]
+local f_indexed_number=formatters["[%s]=%s,"]
+local f_indexed_boolean=formatters["[%s]=%l,"]
+local f_indexed_table=formatters["[%s]="]
+local f_ordered_string=formatters["%q,"]
+local f_ordered_number=formatters["%s,"]
+local f_ordered_boolean=formatters["%l,"]
+function table.fastserialize(t,prefix)
+ local r={ type(prefix)=="string" and prefix or "return" }
+ local m=1
+ local function fastserialize(t,outer)
+ local n=#t
+ m=m+1
+ r[m]="{"
+ if n>0 then
+ for i=0,n do
+ local v=t[i]
+ local tv=type(v)
+ if tv=="string" then
+ m=m+1 r[m]=f_ordered_string(v)
+ elseif tv=="number" then
+ m=m+1 r[m]=f_ordered_number(v)
+ elseif tv=="table" then
+ fastserialize(v)
+ elseif tv=="boolean" then
+ m=m+1 r[m]=f_ordered_boolean(v)
+ end
+ end
+ end
+ for k,v in next,t do
+ local tk=type(k)
+ if tk=="number" then
+ if k>n or k<0 then
+ local tv=type(v)
+ if tv=="string" then
+ m=m+1 r[m]=f_indexed_string(k,v)
+ elseif tv=="number" then
+ m=m+1 r[m]=f_indexed_number(k,v)
+ elseif tv=="table" then
+ m=m+1 r[m]=f_indexed_table(k)
+ fastserialize(v)
+ elseif tv=="boolean" then
+ m=m+1 r[m]=f_indexed_boolean(k,v)
+ end
+ end
+ else
+ local tv=type(v)
+ if tv=="string" then
+ m=m+1 r[m]=f_hashed_string(k,v)
+ elseif tv=="number" then
+ m=m+1 r[m]=f_hashed_number(k,v)
+ elseif tv=="table" then
+ m=m+1 r[m]=f_hashed_table(k)
+ fastserialize(v)
+ elseif tv=="boolean" then
+ m=m+1 r[m]=f_hashed_boolean(k,v)
+ end
+ end
+ end
+ 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
+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
+ end
+ end
+end
+function table.save(filename,t,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)
+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)
+end
+function table.drop(t,slow)
+ 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
+end
+local f_start_key_idx=formatters["%w{"]
+local f_start_key_num=formatters["%w[%s]={"]
+local f_start_key_str=formatters["%w[%q]={"]
+local f_start_key_boo=formatters["%w[%l]={"]
+local f_start_key_nop=formatters["%w{"]
+local f_stop=formatters["%w},"]
+local f_key_num_value_num=formatters["%w[%s]=%s,"]
+local f_key_str_value_num=formatters["%w[%q]=%s,"]
+local f_key_boo_value_num=formatters["%w[%l]=%s,"]
+local f_key_num_value_str=formatters["%w[%s]=%q,"]
+local f_key_str_value_str=formatters["%w[%q]=%q,"]
+local f_key_boo_value_str=formatters["%w[%l]=%q,"]
+local f_key_num_value_boo=formatters["%w[%s]=%l,"]
+local f_key_str_value_boo=formatters["%w[%q]=%l,"]
+local f_key_boo_value_boo=formatters["%w[%l]=%l,"]
+local f_key_num_value_not=formatters["%w[%s]={},"]
+local f_key_str_value_not=formatters["%w[%q]={},"]
+local f_key_boo_value_not=formatters["%w[%l]={},"]
+local f_key_num_value_seq=formatters["%w[%s]={ %, t },"]
+local f_key_str_value_seq=formatters["%w[%q]={ %, t },"]
+local f_key_boo_value_seq=formatters["%w[%l]={ %, t },"]
+local f_val_num=formatters["%w%s,"]
+local f_val_str=formatters["%w%q,"]
+local f_val_boo=formatters["%w%l,"]
+local f_val_not=formatters["%w{},"]
+local f_val_seq=formatters["%w{ %, t },"]
+local f_fin_seq=formatters[" %, t }"]
+local f_table_return=formatters["return {"]
+local f_table_name=formatters["%s={"]
+local f_table_direct=formatters["{"]
+local f_table_entry=formatters["[%q]={"]
+local f_table_finish=formatters["}"]
+local spaces=utilities.strings.newrepeater(" ")
+local 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)
+ 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 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
+ end
+ end
+ if level>0 then
+ n=n+1 t[n]=f_stop(depth-1)
+ end
+ end
+ local tname=type(name)
+ if tname=="string" then
+ if name=="return" then
+ t={ f_table_return() }
+ else
+ t={ f_table_name(name) }
+ end
+ elseif tname=="number" then
+ t={ f_table_entry(name) }
+ elseif tname=="boolean" then
+ if name then
+ t={ f_table_return() }
+ else
+ t={ f_table_direct() }
+ end
+ else
+ t={ f_table_name("t") }
+ end
+ if root then
+ if getmetatable(root) then
+ local dummy=root._w_h_a_t_e_v_e_r_
+ root._w_h_a_t_e_v_e_r_=nil
+ end
+ if next(root)~=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)
+end
+
+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"
+}
+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
+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
+end
+function storage.marked(t)
+ 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
+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)
+end
+local keyisvalue={ __index=function(t,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
+local f_index={
+ ["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
+end
+local f_index={
+ ["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
+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
+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
+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
+end
+function table.getmetatablekey(t,key,value)
+ local m=getmetatable(t)
+ return m and m[key]
+end
+function table.makeweak(t)
+ if not t then
+ t={}
+ end
+ local m=getmetatable(t)
+ if m then
+ m.__mode="v"
+ else
+ setmetatable(t,{ __mode="v" })
+ end
+ return t
+end
+
+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"
+}
+local lpeg,table,string=lpeg,table,string
+local P,R,V,S,C,Ct,Cs,Carg,Cc,Cg,Cf,Cp=lpeg.P,lpeg.R,lpeg.V,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cs,lpeg.Carg,lpeg.Cc,lpeg.Cg,lpeg.Cf,lpeg.Cp
+local lpegmatch,lpegpatterns=lpeg.match,lpeg.patterns
+local concat,gmatch,find=table.concat,string.gmatch,string.find
+local tostring,type,next,rawset=tostring,type,next,rawset
+local mod,div=math.mod,math.div
+utilities=utilities or {}
+local parsers=utilities.parsers or {}
+utilities.parsers=parsers
+local patterns=parsers.patterns or {}
+parsers.patterns=patterns
+local setmetatableindex=table.setmetatableindex
+local sortedhash=table.sortedhash
+local sortedkeys=table.sortedkeys
+local tohash=table.tohash
+local hashes={}
+utilities.parsers.hashes=hashes
+local digit=R("09")
+local space=P(' ')
+local equal=P("=")
+local colon=P(":")
+local comma=P(",")
+local lbrace=P("{")
+local rbrace=P("}")
+local lparent=P("(")
+local rparent=P(")")
+local lbracket=P("[")
+local rbracket=P("]")
+local period=S(".")
+local punctuation=S(".,:;")
+local spacer=lpegpatterns.spacer
+local whitespace=lpegpatterns.whitespace
+local newline=lpegpatterns.newline
+local anything=lpegpatterns.anything
+local endofstring=lpegpatterns.endofstring
+local nobrace=1-(lbrace+rbrace )
+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
+}
+local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace }
+local nestedparents=P { lparent*(noparent+V(1))^0*rparent }
+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.nestedparents=nestedparents
+lpegpatterns.nested=nestedbraces
+lpegpatterns.argument=argument
+lpegpatterns.content=content
+local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0)
+local key=C((1-equal-comma)^1)
+local pattern_a=(space+comma)^0*(key*equal*value+key*C(""))
+local pattern_c=(space+comma)^0*(key*equal*value)
+local pattern_d=(space+comma)^0*(key*(equal+colon)*value+key*C(""))
+local key=C((1-space-equal-comma)^1)
+local pattern_b=spaces*comma^0*spaces*(key*((spaces*equal*spaces*value)+C("")))
+local hash={}
+local function set(key,value)
+ hash[key]=value
+end
+local pattern_a_s=(pattern_a/set)^1
+local pattern_b_s=(pattern_b/set)^1
+local pattern_c_s=(pattern_c/set)^1
+local pattern_d_s=(pattern_d/set)^1
+patterns.settings_to_hash_a=pattern_a_s
+patterns.settings_to_hash_b=pattern_b_s
+patterns.settings_to_hash_c=pattern_c_s
+patterns.settings_to_hash_d=pattern_d_s
+function parsers.make_settings_to_hash_pattern(set,how)
+ if how=="strict" then
+ return (pattern_c/set)^1
+ elseif how=="tolerant" then
+ return (pattern_b/set)^1
+ else
+ return (pattern_a/set)^1
+ end
+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
+end
+function parsers.settings_to_hash_colon_too(str)
+ if not str or str=="" then
+ return {}
+ elseif type(str)=="table" then
+ return str
+ else
+ hash={}
+ lpegmatch(pattern_d_s,str)
+ return hash
+ end
+end
+function parsers.settings_to_hash_tolerant(str,existing)
+ if not str or str=="" then
+ return {}
+ elseif type(str)=="table" then
+ if existing then
+ for k,v in next,str do
+ existing[k]=v
+ end
+ return exiting
+ else
+ return str
+ end
+ 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
+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)
+ else
+ return { str }
+ end
+end
+function parsers.settings_to_numbers(str)
+ if not str or str=="" then
+ return {}
+ end
+ if type(str)=="table" then
+ elseif find(str,",",1,true) then
+ str=lpegmatch(pattern,str)
+ else
+ return { tonumber(str) }
+ end
+ for i=1,#str do
+ str[i]=tonumber(str[i])
+ end
+ return str
+end
+local value=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)
+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
+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
+end
+function parsers.process_stripped_settings(str,action)
+ if not str or str=="" then
+ return {}
+ else
+ return lpegmatch(pattern_b,str,1,action)
+ end
+end
+local function set(t,v)
+ 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)
+end
+function parsers.hash_to_string(h,separator,yes,no,strict,omit)
+ if h then
+ local t,tn,s={},0,sortedkeys(h)
+ omit=omit and tohash(omit)
+ for i=1,#s do
+ local key=s[i]
+ if not omit or not omit[key] then
+ local value=h[key]
+ if type(value)=="boolean" then
+ if yes and no then
+ if value then
+ tn=tn+1
+ t[tn]=key..'='..yes
+ elseif not strict then
+ tn=tn+1
+ t[tn]=key..'='..no
+ end
+ elseif value or not strict then
+ tn=tn+1
+ t[tn]=key..'='..tostring(value)
+ end
+ else
+ tn=tn+1
+ t[tn]=key..'='..value
+ end
+ end
+ 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
+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 {}
+end
+hashes.settings_to_set=table.setmetatableindex(function(t,k)
+ 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
+ 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 {}
+end
+local splitter=lpeg.tsplitat(" ")
+function utilities.parsers.options_to_array(str)
+ 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
+ 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)
+ 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
+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)
+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)
+end
+function parsers.listitem(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"),
+}
+lpegpatterns.splitthousands=pattern
+function parsers.splitthousands(str)
+ return lpegmatch(pattern,str) or str
+end
+local optionalwhitespace=whitespace^0
+lpegpatterns.words=Ct((Cs((1-punctuation-whitespace)^1)+anything)^1)
+lpegpatterns.sentences=Ct((optionalwhitespace*Cs((1-period)^0*period))^1)
+lpegpatterns.paragraphs=Ct((optionalwhitespace*Cs((whitespace^1*endofstring/""+1-(spacer^0*newline*newline))^1))^1)
+local dquote=P('"')
+local equal=P('=')
+local escape=P('\\')
+local separator=S(' ,')
+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
+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
+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.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
+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)
+ end
+end
+local cardinal=lpegpatterns.cardinal/tonumber
+local spacers=lpegpatterns.spacer^0
+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
+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)
+end
+local pattern=Cs((P("^")/"<sup>"*lpegpatterns.integer*Cc("</sup>")+anything)^0)
+function parsers.unittoxml(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
+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
+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 {}
+ end
+end
+local function fetch(t,name)
+ return t[name] or {}
+end
+local function process(result,more)
+ 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)
+end
+function utilities.parsers.runtime(time)
+ if not time then
+ time=os.runtime()
+ end
+ local days=div(time,24*60*60)
+ time=mod(time,24*60*60)
+ local hours=div(time,60*60)
+ time=mod(time,60*60)
+ local minutes=div(time,60)
+ local seconds=mod(time,60)
+ return days,hours,minutes,seconds
+end
+local spacing=whitespace^0
+local apply=P("->")
+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
+end
+
+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"
+}
+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
+local allocate=utilities.storage.allocate
+local setmetatableindex=table.setmetatableindex
+local formatters=string.formatters
+local texget=tex and tex.get or function() return 65536*10*100 end
+local p_stripzeros=lpeg.patterns.stripzeros
+number=number or {}
+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
+}
+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
+ 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
+ end
+end
+number.maxdimen=1073741823
+number.todimen=numbertodimen
+number.dimenfactors=dimenfactors
+function number.topoints (n,fmt) return numbertodimen(n,"pt",fmt) end
+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.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
+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)
+end
+setmetatableindex(dimenfactors,function(t,s)
+ return false
+end)
+local stringtodimen
+local amount=S("+-")^0*R("09")^0*S(".,")^0*R("09")^0
+local unit=P("pt")+P("cm")+P("mm")+P("sp")+P("bp")+P("in")+P("pc")+P("dd")+P("cc")+P("nd")+P("nc")
+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)
+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)
+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)
+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)
+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)
+end
+function dimensions.__lt(a,b)
+ return a[1]<b[1]
+end
+function dimensions.__eq(a,b)
+ return a[1]==b[1]
+end
+function dimensions.__tostring(a)
+ 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 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]
+ 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
+ end
+end
+stringtodimen=string.todimen
+function number.toscaled(d)
+ 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
+end
+number["%"]=number.percent
+
+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"
+}
+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 utfchar=utf.char
+local concat=table.concat
+local tonumber,tostring,rawset,type,next=tonumber,tostring,rawset,type,next
+local json=utilities.json or {}
+utilities.json=json
+local lbrace=P("{")
+local rbrace=P("}")
+local lparent=P("[")
+local rparent=P("]")
+local comma=P(",")
+local colon=P(":")
+local dquote=P('"')
+local whitespace=lpeg.patterns.whitespace
+local optionalws=whitespace^0
+local escapes={
+ ["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_bs=P([[\]])/""*(P(1)/escapes)
+local jstring=dquote*Cs((escape_un+escape_bs+(1-dquote))^0)*dquote
+local jtrue=P("true")*Cc(true)
+local jfalse=P("false")*Cc(false)
+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,
+}
+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]="]"
+ 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
+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
+end
+function json.load(filename)
+ local data=io.loaddata(filename)
+ if data then
+ return lpegmatch(jsonconverter,data)
+ end
+end
+return json
+
+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"
+}
+local type,tonumber,select=type,tonumber,select
+local format,lower,find=string.format,string.lower,string.find
+local concat=table.concat
+local clock=os.gettimeofday or os.clock
+local setmetatableindex=table.setmetatableindex
+local serialize=table.serialize
+local formatters=string.formatters
+statistics=statistics or {}
+local statistics=statistics
+statistics.enable=true
+statistics.threshold=0.01
+local statusinfo,n,registered,timers={},0,{},{}
+setmetatableindex(timers,function(t,k)
+ local v={ timing=0,loadtime=0 }
+ t[k]=v
+ return v
+end)
+local function hastiming(instance)
+ return instance and timers[instance]
+end
+local function resettiming(instance)
+ timers[instance or "notimer"]={ timing=0,loadtime=0 }
+end
+local ticks=clock
+local seconds=function(n) return n or 0 end
+local function starttiming(instance)
+ local timer=timers[instance or "notimer"]
+ local it=timer.timing
+ if it==0 then
+ timer.starttime=ticks()
+ if not timer.loadtime then
+ timer.loadtime=0
+ end
+ end
+ timer.timing=it+1
+end
+local function stoptiming(instance)
+ local timer=timers[instance or "notimer"]
+ local it=timer.timing
+ if it>1 then
+ timer.timing=it-1
+ else
+ local starttime=timer.starttime
+ if starttime and starttime>0 then
+ local stoptime=ticks()
+ local loadtime=stoptime-starttime
+ timer.stoptime=stoptime
+ timer.loadtime=timer.loadtime+loadtime
+ timer.timing=0
+ timer.starttime=0
+ return loadtime
+ end
+ end
+ return 0
+end
+local function elapsed(instance)
+ if type(instance)=="number" then
+ return instance
+ else
+ local timer=timers[instance or "notimer"]
+ return timer and seconds(timer.loadtime) or 0
+ end
+end
+local function currenttime(instance)
+ if type(instance)=="number" then
+ return instance
+ else
+ local timer=timers[instance or "notimer"]
+ local it=timer.timing
+ if it>1 then
+ else
+ 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))
+end
+local function elapsedindeed(instance)
+ 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
+end
+statistics.hastiming=hastiming
+statistics.resettiming=resettiming
+statistics.starttiming=starttiming
+statistics.stoptiming=stoptiming
+statistics.currenttime=currenttime
+statistics.elapsed=elapsed
+statistics.elapsedtime=elapsedtime
+statistics.elapsedindeed=elapsedindeed
+statistics.elapsedseconds=elapsedseconds
+function statistics.register(tag,fnc)
+ if statistics.enable and type(fnc)=="function" then
+ local rt=registered[tag] or (#statusinfo+1)
+ statusinfo[rt]={ tag,fnc }
+ registered[tag]=rt
+ if #tag>n then n=#tag end
+ end
+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
+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))
+end
+starttiming(statistics)
+function statistics.formatruntime(runtime)
+ return format("%s seconds",runtime)
+end
+function statistics.runtime()
+ stoptiming(statistics)
+ return statistics.formatruntime(elapsedtime(statistics))
+end
+local report=logs.reporter("system")
+function statistics.timed(action)
+ starttiming("run")
+ action()
+ stoptiming("run")
+ report("total runtime: %s seconds",elapsedtime("run"))
+end
+function statistics.tracefunction(base,tag,...)
+ for i=1,select("#",...) do
+ local name=select(i,...)
+ local stat={}
+ local func=base[name]
+ setmetatableindex(stat,function(t,k) t[k]=0 return 0 end)
+ base[name]=function(n,k,v) stat[k]=stat[k]+1 return func(n,k,v) end
+ statistics.register(formatters["%s.%s"](tag,name),function() return serialize(stat,"calls") end)
+ end
+end
+
+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"
+}
+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
+utilities=utilities or {}
+utilities.lua=utilities.lua or {}
+local luautilities=utilities.lua
+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.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",
+}
+local function register(name)
+ if tracestripping then
+ report_lua("stripped bytecode from %a",name or "unknown")
+ end
+ strippedchunks[#strippedchunks+1]=name
+ luautilities.nofstrippedchunks=luautilities.nofstrippedchunks+1
+end
+local function stupidcompile(luafile,lucfile,strip)
+ local code=io.loaddata(luafile)
+ if code and code~="" then
+ code=load(code)
+ if code then
+ code=dump(code,strip and luautilities.stripcode or luautilities.alwaysstripcode)
+ if code and code~="" then
+ register(name)
+ io.savedata(lucfile,code)
+ return true,0
+ end
+ else
+ report_lua("fatal error %a in file %a",1,luafile)
+ end
+ else
+ report_lua("fatal error %a in file %a",2,luafile)
+ end
+ return false,0
+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")
+ 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
+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
+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
+end
+function luautilities.loadstripped(...)
+ 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
+ end
+} )
+function luautilities.registerfinalizer(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
+end
+
+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"
+}
+local debug=require "debug"
+local getinfo,sethook=debug.getinfo,debug.sethook
+local type,next,tostring,tonumber=type,next,tostring,tonumber
+local format,find,sub,gsub=string.format,string.find,string.sub,string.gsub
+local insert,remove,sort=table.insert,table.remove,table.sort
+local setmetatableindex=table.setmetatableindex
+utilities=utilities or {}
+local debugger=utilities.debugger or {}
+utilities.debugger=debugger
+local report=logs.reporter("debugger")
+local ticks=os.gettimeofday or os.clock
+local seconds=function(n) return n or 0 end
+local overhead=0
+local dummycalls=10*1000
+local nesting=0
+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[[
+ 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
+ end
+ initialize=false
+ end
+elseif os.type=="unix" then
+ 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
+ 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
+ end)
+ t[name]=v
+ return v
+end)
+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
+end
+function debugger.showstats(printer,threshold)
+ local printer=printer or report
+ local calls=0
+ local functions=0
+ local dataset={}
+ local length=0
+ local realtime=0
+ local totaltime=0
+ local threshold=threshold or 0
+ for name,sources in next,names do
+ for source,lines in next,sources do
+ for line,data in next,lines do
+ local count=data.count
+ if count>threshold then
+ if #name>length then
+ length=#name
+ end
+ local total=data.total
+ local real=total
+ if real>0 then
+ real=total-(count*overhead/dummycalls)
+ if real<0 then
+ real=0
+ end
+ realtime=realtime+real
+ end
+ totaltime=totaltime+total
+ if line<0 then
+ line=0
+ end
+ dataset[#dataset+1]={ real,total,count,name,source,line }
+ end
+ end
+ 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
+ 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
+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
+end
+function debugger.enable()
+ if nesting==0 then
+ running=true
+ if initialize then
+ initialize()
+ end
+ sethook(hook,"cr")
+ local function dummy() end
+ local t=ticks()
+ for i=1,dummycalls do
+ dummy()
+ end
+ overhead=ticks()-t
+ end
+ if nesting>0 then
+ nesting=nesting+1
+ end
+end
+function debugger.disable()
+ if nesting>0 then
+ nesting=nesting-1
+ end
+ if nesting==0 then
+ sethook()
+ end
+end
+local function showtraceback(rep)
+ 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
+debugger.showtraceback=showtraceback
+
+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"
+}
+utilities.templates=utilities.templates or {}
+local templates=utilities.templates
+local trace_template=false trackers.register("templates.trace",function(v) trace_template=v end)
+local report_template=logs.reporter("template")
+local tostring,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 ""
+ 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
+ end
+end
+local sqlescape=lpeg.replacer {
+ { "'","''" },
+ { "\\","\\\\" },
+ { "\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,
+}
+local quotedescapers={
+ 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
+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
+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 ""
+end
+local single=P("%")
+local double=P("%%")
+local lquoted=P("%[")
+local rquoted=P("]%")
+local lquotedq=P("%(")
+local rquotedq=P(")%")
+local escape=double/'%%'
+local nosingle=single/''
+local nodouble=double/''
+local nolquoted=lquoted/''
+local norquoted=rquoted/''
+local nolquotedq=lquotedq/''
+local norquotedq=rquotedq/''
+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 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
+end
+templates.replace=replace
+function templates.replacer(str,how,recurse)
+ return function(mapping)
+ return lpegmatch(replacer,str,1,mapping,how or "lua",recurse or false) or str
+ end
+end
+function templates.load(filename,mapping,how,recurse)
+ local data=io.loaddata(filename) or ""
+ if mapping and next(mapping) then
+ 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
+end
+
+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"
+}
+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 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
+ 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
+ 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
+ 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)
+ 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
+ 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
+ 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 9c55f8044ce..166f688ed65 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended.lua
@@ -7,7 +7,7 @@
-- lualibs.dtx (with options: `extended')
-- This is a generated file.
--
--- Copyright (C) 2009--2017 by
+-- Copyright (C) 2009--2018 by
-- PRAGMA ADE / ConTeXt Development Team
-- The LuaLaTeX Dev Team
--
@@ -30,8 +30,8 @@ lualibs = lualibs or { }
local lualibs_extended_module = {
name = "lualibs-extended",
- version = 2.5,
- date = "2017-02-01",
+ version = 2.6,
+ date = "2018-09-21",
description = "ConTeXt Lua libraries -- extended collection.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -111,11 +111,11 @@ fake_context()
local loaded = false
if lualibs.prefer_merged then
- info"Loading merged package for collection “extended”."
+ info"Loading merged package for collection ^^e2^^80^^9cextended^^e2^^80^^9d."
loaded = loadmodule('lualibs-extended-merged.lua')
else
info"Ignoring merged packages."
- info"Falling back to individual libraries from collection “extended”."
+ info"Falling back to individual libraries from collection ^^e2^^80^^9cextended^^e2^^80^^9d."
end
if loaded == false then
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua
index f2a27ad1832..46b6847d331 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua
@@ -69,31 +69,34 @@ local lpegmatch = lpeg.match
local getcurrentdir, attributes = lfs.currentdir, lfs.attributes
local checkedsplit = string.checkedsplit
--- local patterns = file.patterns or { }
--- file.patterns = patterns
-
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
-- better this way:
-local tricky = S("/\\") * P(-1)
+----- tricky = S("/\\") * P(-1)
local attributes = lfs.attributes
-if sandbox then
- sandbox.redefine(lfs.isfile,"lfs.isfile")
- sandbox.redefine(lfs.isdir, "lfs.isdir")
-end
-
function lfs.isdir(name)
- if lpegmatch(tricky,name) then
- return attributes(name,"mode") == "directory"
- else
- return attributes(name.."/.","mode") == "directory"
- end
+ -- if not lpegmatch(tricky,name) then
+ -- name = name .. "/."
+ -- end
+ return attributes(name,"mode") == "directory"
end
function lfs.isfile(name)
- return attributes(name,"mode") == "file"
+ local a = attributes(name,"mode")
+ return a == "file" or a == "link" or nil
+end
+
+function lfs.isfound(name)
+ local a = attributes(name,"mode")
+ return (a == "file" or a == "link") and name or nil
+end
+
+if sandbox then
+ sandbox.redefine(lfs.isfile,"lfs.isfile")
+ sandbox.redefine(lfs.isdir, "lfs.isdir")
+ sandbox.redefine(lfs.isfound, "lfs.isfound")
end
local colon = P(":")
@@ -699,3 +702,32 @@ function lfs.mkdirs(path)
lfs.mkdir(full)
end
end
+
+-- here is oen i ran into when messign around with xavante code (keppler project)
+-- where it's called in_base .. no gain in using lpeg here
+
+function file.withinbase(path) -- don't go beyond root
+ 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
+
+-- not used in context but was in luatex once:
+
+local symlinkattributes = lfs.symlinkattributes
+
+function lfs.readlink(name)
+ return symlinkattributes(name,"target") or nil
+end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua
index 2039017b25d..fa3ad3c4cda 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua
@@ -10,7 +10,7 @@ local io = io
local open, flush, write, read = io.open, io.flush, io.write, io.read
local byte, find, gsub, format = string.byte, string.find, string.gsub, string.format
local concat = table.concat
-local floor = math.floor
+----- floor = math.floor
local type = type
if string.find(os.getenv("PATH"),";",1,true) then
@@ -19,38 +19,48 @@ else
io.fileseparator, io.pathseparator = "/" , ":"
end
-local function readall(f)
- return f:read("*all")
-end
+-- local function readall(f)
+-- return f:read("*all")
+-- end
-- The next one is upto 50% faster on large files and less memory consumption due
-- to less intermediate large allocations. This phenomena was discussed on the
-- luatex dev list.
+local large = 0x01000000 -- 2^24 16.777.216
+local medium = 0x00100000 -- 2^20 1.048.576
+local small = 0x00020000 -- 2^17 131.072
+
+-- local function readall(f)
+-- local size = f:seek("end")
+-- if size == 0 then
+-- return ""
+-- end
+-- f:seek("set",0)
+-- if size < medium then
+-- return f:read('*all')
+-- else
+-- local step = (size > large) and large or (floor(size/(medium)) * small)
+-- local data = { }
+-- while true do
+-- local r = f:read(step)
+-- if not r then
+-- return concat(data)
+-- else
+-- data[#data+1] = r
+-- end
+-- end
+-- end
+-- end
+
local function readall(f)
+ -- return f:read("*all")
local size = f:seek("end")
- if size == 0 then
- return ""
- end
- f:seek("set",0)
- if size < 1024*1024 then
- return f:read('*all')
+ if size > 0 then
+ f:seek("set",0)
+ return f:read(size)
else
- local step
- if size > 16*1024*1024 then
- step = 16*1024*1024
- else
- step = floor(size/(1024*1024)) * 1024 * 1024 / 8
- end
- local data = { }
- while true do
- local r = f:read(step)
- if not r then
- return concat(data)
- else
- data[#data+1] = r
- end
- end
+ return ""
end
end
@@ -59,52 +69,75 @@ io.readall = readall
function io.loaddata(filename,textmode) -- return nil if empty
local f = open(filename,(textmode and 'r') or 'rb')
if f then
- local data = readall(f)
- f:close()
- if #data > 0 then
- return data
+ local size = f:seek("end")
+ local data = nil
+ if size > 0 then
+ -- data = f:read("*all")
+ 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
+-- -- empty
+-- else
+-- f:seek("set",0)
+-- if size < medium then
+-- local data = f:read('*all')
+-- if action then
+-- data = action(data)
+-- end
+-- if data then
+-- g:write(data)
+-- end
+-- else
+-- local step = (size > large) and large or (floor(size/(medium)) * small)
+-- while true do
+-- local data = f:read(step)
+-- if data then
+-- if action then
+-- data = action(data)
+-- end
+-- if data then
+-- g:write(data)
+-- end
+-- else
+-- break
+-- end
+-- end
+-- end
+-- end
+-- g:close()
+-- end
+-- f:close()
+-- flush()
+-- 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
- -- empty
- else
+ if size > 0 then
+ -- local data = f:read('*all')
f:seek("set",0)
- if size < 1024*1024 then
- local data = f:read('*all')
- if action then
- data = action(data)
- end
- if data then
- g:write(data)
- end
- else
- local step
- if size > 16*1024*1024 then
- step = 16*1024*1024
- else
- step = floor(size/(1024*1024)) * 1024 * 1024 / 8
- end
- while true do
- local data = f:read(step)
- if data then
- if action then
- data = action(data)
- end
- if data then
- g:write(data)
- end
- else
- break
- end
- end
+ local data = f:read(size)
+ if action then
+ data = action(data)
+ end
+ if data then
+ g:write(data)
end
end
g:close()
@@ -134,32 +167,70 @@ end
-- we can also chunk this one if needed: io.lines(filename,chunksize,"*l")
-function io.loadlines(filename,n) -- return nil if empty
- local f = open(filename,'r')
- if not f then
- -- no file
- elseif n then
- local lines = { }
- for i=1,n do
- local line = f:read("*lines")
- if line then
- lines[#lines+1] = line
- else
- break
+-- ffi.readline
+
+if fio and fio.readline then
+
+ local readline = fio.readline
+
+ function io.loadlines(filename,n) -- return nil if empty
+ local f = open(filename,'r')
+ if not f then
+ -- no file
+ 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
+ else
+ local line = readline(f)
+ f:close()
+ if line and #line > 0 then
+ return line
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
+
+else
+
+ function io.loadlines(filename,n) -- return nil if empty
+ local f = open(filename,'r')
+ if not f then
+ -- no file
+ 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
+ else
+ local line = f:read("*line") or ""
+ f:close()
+ if #line > 0 then
+ return line
+ end
end
end
+
end
function io.loadchunk(filename,n)
@@ -205,6 +276,7 @@ local function noflines(f)
return 0
end
else
+ -- todo: load and lpeg
local n = 0
for _ in f:lines() do
n = n + 1
@@ -216,7 +288,7 @@ end
io.noflines = noflines
--- inlined is faster
+-- inlined is faster ... beware, better use util-fil
local nextchar = {
[ 4] = function(f)
@@ -331,7 +403,7 @@ function io.ask(question,default,options)
end
end
-local function readnumber(f,n,m)
+local function readnumber(f,n,m) -- to be replaced
if m then
f:seek("set",n)
n = m
@@ -340,38 +412,32 @@ local function readnumber(f,n,m)
return byte(f:read(1))
elseif n == 2 then
local a, b = byte(f:read(2),1,2)
- return 256 * a + b
+ return 0x100 * a + b
elseif n == 3 then
local a, b, c = byte(f:read(3),1,3)
- return 256*256 * a + 256 * b + c
+ return 0x10000 * a + 0x100 * b + c
elseif n == 4 then
local a, b, c, d = byte(f:read(4),1,4)
- return 256*256*256 * a + 256*256 * b + 256 * c + d
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
elseif n == 8 then
local a, b = readnumber(f,4), readnumber(f,4)
- return 256 * a + b
+ return 0x100 * a + b
elseif n == 12 then
local a, b, c = readnumber(f,4), readnumber(f,4), readnumber(f,4)
- return 256*256 * a + 256 * b + c
+ return 0x10000 * a + 0x100 * b + c
elseif n == -2 then
local b, a = byte(f:read(2),1,2)
- return 256*a + b
+ return 0x100 * a + b
elseif n == -3 then
local c, b, a = byte(f:read(3),1,3)
- return 256*256 * a + 256 * b + c
+ return 0x10000 * a + 0x100 * b + c
elseif n == -4 then
local d, c, b, a = byte(f:read(4),1,4)
- return 256*256*256 * a + 256*256 * b + 256*c + d
+ 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 256*256*256*256*256*256*256 * a +
- 256*256*256*256*256*256 * b +
- 256*256*256*256*256 * c +
- 256*256*256*256 * d +
- 256*256*256 * e +
- 256*256 * f +
- 256 * g +
- h
+ return 0x100000000000000 * a + 0x1000000000000 * b + 0x10000000000 * c + 0x100000000 * d +
+ 0x1000000 * e + 0x10000 * f + 0x100 * g + h
else
return 0
end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lpeg.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lpeg.lua
index 959ca553eb8..750d5e698d7 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lpeg.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lpeg.lua
@@ -6,6 +6,10 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
license = "see context related readme files"
}
+-- we can get too many captures (e.g. on largexml files) which makes me wonder
+-- if P(foo)/"" can't be simplfied to N(foo) i.e. some direct instruction to the
+-- lpeg virtual machine to ignore it
+
-- lpeg 12 vs lpeg 10: slower compilation, similar parsing speed (i need to check
-- if i can use new features like capture / 2 and .B (at first sight the xml
-- parser is some 5% slower)
@@ -17,7 +21,13 @@ if not modules then modules = { } end modules ['l-lpeg'] = {
-- move utf -> l-unicode
-- move string -> l-string or keep it here
-lpeg = require("lpeg")
+-- lpeg.B : backward without consumption
+-- lpeg.F = getmetatable(lpeg.P(1)).__len : forward without consumption
+
+
+lpeg = require("lpeg") -- does lpeg register itself global?
+
+local lpeg = lpeg
-- The latest lpeg doesn't have print any more, and even the new ones are not
-- available by default (only when debug mode is enabled), which is a pitty as
@@ -103,11 +113,14 @@ patterns.alwaysmatched = alwaysmatched
local sign = S('+-')
local zero = P('0')
local digit = R('09')
+local digits = digit^1
local octdigit = R("07")
+local octdigits = octdigit^1
local lowercase = R("az")
local uppercase = R("AZ")
local underscore = P("_")
local hexdigit = digit + lowercase + uppercase
+local hexdigits = hexdigit^1
local cr, lf, crlf = P("\r"), P("\n"), P("\r\n")
----- newline = crlf + S("\r\n") -- cr + lf
local newline = P("\r") * (P("\n") + P(true)) + P("\n") -- P("\r")^-1 * P("\n")^-1
@@ -187,18 +200,20 @@ local fullstripper = whitespace^0 * C((whitespace^0 * nonwhitespace^1)^0)
----- collapser = Cs(spacer^0/"" * ((spacer^1 * endofstring / "") + (spacer^1/" ") + P(1))^0)
local collapser = Cs(spacer^0/"" * nonspacer^0 * ((spacer^0/" " * nonspacer^1)^0))
+local nospacer = Cs((whitespace^1/"" + nonwhitespace^1)^0)
-local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0)
-local e_collapser = Cs((whitespace^1 * P(-1)/"" + nonwhitespace^1 + whitespace^1/" ")^0)
-local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0)
+local b_collapser = Cs( whitespace^0 /"" * (nonwhitespace^1 + whitespace^1/" ")^0)
+local e_collapser = Cs((whitespace^1 * endofstring/"" + nonwhitespace^1 + whitespace^1/" ")^0)
+local m_collapser = Cs( (nonwhitespace^1 + whitespace^1/" ")^0)
-local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0)
-local e_stripper = Cs((spacer^1 * P(-1)/"" + nonspacer^1 + spacer^1/" ")^0)
-local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0)
+local b_stripper = Cs( spacer^0 /"" * (nonspacer^1 + spacer^1/" ")^0)
+local e_stripper = Cs((spacer^1 * endofstring/"" + nonspacer^1 + spacer^1/" ")^0)
+local m_stripper = Cs( (nonspacer^1 + spacer^1/" ")^0)
patterns.stripper = stripper
patterns.fullstripper = fullstripper
patterns.collapser = collapser
+patterns.nospacer = nospacer
patterns.b_collapser = b_collapser
patterns.m_collapser = m_collapser
@@ -238,43 +253,50 @@ patterns.doublequoted = dquote * patterns.nodquote * dquote
patterns.quoted = patterns.doublequoted + patterns.singlequoted
patterns.digit = digit
+patterns.digits = digits
patterns.octdigit = octdigit
+patterns.octdigits = octdigits
patterns.hexdigit = hexdigit
+patterns.hexdigits = hexdigits
patterns.sign = sign
-patterns.cardinal = digit^1
-patterns.integer = sign^-1 * digit^1
-patterns.unsigned = digit^0 * period * digit^1
+patterns.cardinal = digits
+patterns.integer = sign^-1 * digits
+patterns.unsigned = digit^0 * period * digits
patterns.float = sign^-1 * patterns.unsigned
-patterns.cunsigned = digit^0 * comma * digit^1
-patterns.cpunsigned = digit^0 * (period + comma) * digit^1
+patterns.cunsigned = digit^0 * comma * digits
+patterns.cpunsigned = digit^0 * (period + comma) * digits
patterns.cfloat = sign^-1 * patterns.cunsigned
patterns.cpfloat = sign^-1 * patterns.cpunsigned
patterns.number = patterns.float + patterns.integer
patterns.cnumber = patterns.cfloat + patterns.integer
patterns.cpnumber = patterns.cpfloat + patterns.integer
-patterns.oct = zero * octdigit^1
+patterns.oct = zero * octdigits -- hm is this ok
patterns.octal = patterns.oct
patterns.HEX = zero * P("X") * (digit+uppercase)^1
patterns.hex = zero * P("x") * (digit+lowercase)^1
-patterns.hexadecimal = zero * S("xX") * hexdigit^1
+patterns.hexadecimal = zero * S("xX") * hexdigits
patterns.hexafloat = sign^-1
* zero * S("xX")
- * (hexdigit^0 * period * hexdigit^1 + hexdigit^1 * period * hexdigit^0 + hexdigit^1)
- * (S("pP") * sign^-1 * hexdigit^1)^-1
+ * (hexdigit^0 * period * hexdigits + hexdigits * period * hexdigit^0 + hexdigits)
+ * (S("pP") * sign^-1 * hexdigits)^-1
patterns.decafloat = sign^-1
- * (digit^0 * period * digit^1 + digit^1 * period * digit^0 + digit^1)
- * S("eE") * sign^-1 * digit^1
+ * (digit^0 * period * digits + digits * period * digit^0 + digits)
+ * S("eE") * sign^-1 * digits
patterns.propername = (uppercase + lowercase + underscore) * (uppercase + lowercase + underscore + digit)^0 * endofstring
patterns.somecontent = (anything - newline - space)^1 -- (utf8char - newline - space)^1
patterns.beginline = #(1-newline)
-patterns.longtostring = Cs(whitespace^0/"" * ((patterns.quoted + nonwhitespace^1 + whitespace^1/"" * (P(-1) + Cc(" ")))^0))
+patterns.longtostring = Cs(whitespace^0/"" * ((patterns.quoted + nonwhitespace^1 + whitespace^1/"" * (endofstring + Cc(" ")))^0))
-local function anywhere(pattern) --slightly adapted from website
- return P { P(pattern) + 1 * V(1) }
+-- local function anywhere(pattern) -- slightly adapted from website
+-- return P { P(pattern) + 1 * V(1) }
+-- end
+
+function anywhere(pattern) -- faster
+ return (1-P(pattern))^0 * P(pattern)
end
lpeg.anywhere = anywhere
@@ -595,19 +617,27 @@ end
-- print(7,lpegmatch(lpeg.secondofsplit(":"),"bc"))
-- print(9,lpegmatch(lpeg.secondofsplit(":","123"),"bc"))
--- -- slower:
+-- this was slower but lpeg has been sped up in the meantime, so we no longer
+-- use this (still seems somewhat faster on long strings)
+--
+-- local nany = utf8char/""
--
-- function lpeg.counter(pattern)
--- local n, pattern = 0, (lpeg.P(pattern)/function() n = n + 1 end + lpeg.anything)^0
--- return function(str) n = 0 ; lpegmatch(pattern,str) ; return n end
+-- pattern = Cs((P(pattern)/" " + nany)^0)
+-- return function(str)
+-- return #lpegmatch(pattern,str)
+-- end
-- end
-local nany = utf8char/""
-
-function lpeg.counter(pattern)
- pattern = Cs((P(pattern)/" " + nany)^0)
- return function(str)
- return #lpegmatch(pattern,str)
+function lpeg.counter(pattern,action)
+ local n = 0
+ local pattern = (P(pattern) / function() n = n + 1 end + anything)^0
+ ----- pattern = (P(pattern) * (P(true) / function() n = n + 1 end) + anything)^0
+ ----- pattern = (P(pattern) * P(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
@@ -839,28 +869,42 @@ end
local p_false = P(false)
local p_true = P(true)
-local function make(t)
- local function making(t)
- 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
- -- can't happen
- else
- p = p + P(k) * making(v)
- end
- end
- end
- if t[""] then
- p = p + p_true
- end
- return p
- end
+-- local function collapse(t,x)
+-- if type(t) ~= "table" then
+-- return t, x
+-- else
+-- local n = next(t)
+-- if n == nil then
+-- return t, x
+-- elseif next(t,n) == nil then
+-- -- one entry
+-- local k = n
+-- local v = t[k]
+-- if type(v) == "table" then
+-- return collapse(v,x..k)
+-- else
+-- return v, x .. k
+-- end
+-- else
+-- local tt = { }
+-- for k, v in next, t do
+-- local vv, kk = collapse(v,k)
+-- tt[kk] = vv
+-- end
+-- return tt, x
+-- end
+-- end
+-- end
+
+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
+end
+
+local function make1(t,rest)
local p = p_false
local keys = sortedkeys(t)
for i=1,#keys do
@@ -872,41 +916,39 @@ local function make(t)
elseif v == false then
-- can't happen
else
- p = p + P(k) * making(v)
+ p = p + P(k) * make1(v,v[""])
end
end
end
+ if rest then
+ p = p + p_true
+ end
return p
end
-local function collapse(t,x)
- if type(t) ~= "table" then
- return t, x
- else
- local n = next(t)
- if n == nil then
- return t, x
- elseif next(t,n) == nil then
- -- one entry
- local k = n
+local function make2(t,rest) -- only ascii
+ 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 type(v) == "table" then
- return collapse(v,x..k)
+ if v == true then
+ p = p + (P(lower(k))+P(upper(k))) * p_true
+ elseif v == false then
+ -- can't happen
else
- return v, x .. k
+ p = p + (P(lower(k))+P(upper(k))) * make2(v,v[""])
end
- else
- local tt = { }
- for k, v in next, t do
- local vv, kk = collapse(v,k)
- tt[kk] = vv
- end
- return tt, x
end
end
+ if rest then
+ p = p + p_true
+ end
+ return p
end
-function lpeg.utfchartabletopattern(list) -- goes to util-lpg
+local function utfchartabletopattern(list,insensitive) -- goes to util-lpg
local tree = { }
local n = #list
if n == 0 then
@@ -979,32 +1021,42 @@ function lpeg.utfchartabletopattern(list) -- goes to util-lpg
end
end
end
--- collapse(tree,"") -- needs testing, maybe optional, slightly faster because P("x")*P("X") seems slower than P"(xX") (why)
--- inspect(tree)
- return make(tree)
+ -- collapse(tree,"") -- needs testing, maybe optional, slightly faster because P("x")*P("X") seems slower than P"(xX") (why)
+ -- inspect(tree)
+ return (insensitive and make2 or make1)(tree)
+end
+
+lpeg.utfchartabletopattern = utfchartabletopattern
+
+function lpeg.utfreplacer(list,insensitive)
+ local pattern = Cs((utfchartabletopattern(list,insensitive)/list + utf8character)^0)
+ return function(str)
+ return lpegmatch(pattern,str) or str
+ end
end
+
-- local t = { "start", "stoep", "staart", "paard" }
-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1)
-- local t = { "a", "abc", "ac", "abe", "abxyz", "xy", "bef","aa" }
-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/string.upper + 1)^1)
--- inspect(lpegmatch(p,"a"))
--- inspect(lpegmatch(p,"aa"))
--- inspect(lpegmatch(p,"aaaa"))
--- inspect(lpegmatch(p,"ac"))
--- inspect(lpegmatch(p,"bc"))
--- inspect(lpegmatch(p,"zzbczz"))
--- inspect(lpegmatch(p,"zzabezz"))
--- inspect(lpegmatch(p,"ab"))
--- inspect(lpegmatch(p,"abc"))
--- inspect(lpegmatch(p,"abe"))
--- inspect(lpegmatch(p,"xa"))
--- inspect(lpegmatch(p,"bx"))
--- inspect(lpegmatch(p,"bax"))
--- inspect(lpegmatch(p,"abxyz"))
--- inspect(lpegmatch(p,"foobarbefcrap"))
+-- inspect(lpegmatch(p,"a")=="A")
+-- inspect(lpegmatch(p,"aa")=="AA")
+-- inspect(lpegmatch(p,"aaaa")=="AAAA")
+-- inspect(lpegmatch(p,"ac")=="AC")
+-- inspect(lpegmatch(p,"bc")=="bc")
+-- inspect(lpegmatch(p,"zzbczz")=="zzbczz")
+-- inspect(lpegmatch(p,"zzabezz")=="zzABEzz")
+-- inspect(lpegmatch(p,"ab")=="Ab")
+-- inspect(lpegmatch(p,"abc")=="ABC")
+-- inspect(lpegmatch(p,"abe")=="ABE")
+-- inspect(lpegmatch(p,"xa")=="xA")
+-- inspect(lpegmatch(p,"bx")=="bx")
+-- inspect(lpegmatch(p,"bax")=="bAx")
+-- inspect(lpegmatch(p,"abxyz")=="ABXYZ")
+-- inspect(lpegmatch(p,"foobarbefcrap")=="foobArBEFcrAp")
-- local t = { ["^"] = 1, ["^^"] = 2, ["^^^"] = 3, ["^^^^"] = 4 }
-- local p = lpeg.Cs((lpeg.utfchartabletopattern(t)/t + 1)^1)
@@ -1081,25 +1133,38 @@ end
-- moved here (before util-str)
------ digit = R("09")
------ period = P(".")
------ zero = P("0")
-local trailingzeros = zero^0 * -digit -- suggested by Roberto R
-local case_1 = period * trailingzeros / ""
-local case_2 = period * (digit - trailingzeros)^1 * (trailingzeros / "")
-local number = digit^1 * (case_1 + case_2)
-local stripper = Cs((number + 1)^0)
+do
+
+ local trailingzeros = zero^0 * -digit -- suggested by Roberto
+ local stripper = Cs((
+ digits * (
+ period * trailingzeros / ""
+ + period * (digit - trailingzeros)^1 * (trailingzeros / "")
+ ) + 1
+ )^0)
+
+ lpeg.patterns.stripzeros = stripper -- multiple in string
-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
+ ))
--- local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
--- collectgarbage("collect")
--- str = string.rep(sample,10000)
--- local ts = os.clock()
--- lpegmatch(stripper,str)
--- print(#str, os.clock()-ts, lpegmatch(stripper,sample))
+ lpeg.patterns.stripzero = stripper -- slightly more efficient but expects a float !
--- for practical reasone we keep this here:
+ -- local sample = "bla 11.00 bla 11 bla 0.1100 bla 1.00100 bla 0.00 bla 0.001 bla 1.1100 bla 0.100100100 bla 0.00100100100"
+ -- collectgarbage("collect")
+ -- str = string.rep(sample,10000)
+ -- local ts = os.clock()
+ -- lpegmatch(stripper,str)
+ -- print(#str, os.clock()-ts, lpegmatch(stripper,sample))
+
+end
+
+-- for practical reasons we keep this here:
local byte_to_HEX = { }
local byte_to_hex = { }
@@ -1171,3 +1236,22 @@ end
-- local h = "ADFE0345"
-- local b = lpegmatch(patterns.hextobytes,h)
-- print(h,b,string.tohex(b),string.toHEX(b))
+
+local patterns = { } -- can be made weak
+
+local function containsws(what)
+ local p = patterns[what]
+ if not p then
+ local p1 = P(what) * (whitespace + endofstring) * Cc(true)
+ local p2 = whitespace * P(p1)
+ p = P(p1) + P(1-p2)^0 * p2 + Cc(false)
+ patterns[what] = p
+ end
+ return p
+end
+
+lpeg.containsws = containsws
+
+function string.containsws(str,what)
+ return lpegmatch(patterns[what] or containsws(what),str)
+end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua
index 35715383635..c0a787a5c43 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua
@@ -17,28 +17,37 @@ if not modules then modules = { } end modules ['l-lua'] = {
-- utf.*
-- bit32
--- compatibility hacksand helpers
+local next, type, tonumber = next, type, tonumber
-_MAJORVERSION, _MINORVERSION = string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
+-- compatibility hacks and helpers
-_MAJORVERSION = tonumber(_MAJORVERSION) or 5
-_MINORVERSION = tonumber(_MINORVERSION) or 1
-_LUAVERSION = _MAJORVERSION + _MINORVERSION/10
+LUAMAJORVERSION, LUAMINORVERSION = string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
-if _LUAVERSION < 5.2 and jit then
+LUAMAJORVERSION = tonumber(LUAMAJORVERSION) or 5
+LUAMINORVERSION = tonumber(LUAMINORVERSION) or 1
+LUAVERSION = LUAMAJORVERSION + LUAMINORVERSION/10
+
+if LUAVERSION < 5.2 and jit then
--
-- we want loadstring cum suis to behave like 5.2
--
- _MINORVERSION = 2
- _LUAVERSION = 5.2
+ MINORVERSION = 2
+ LUAVERSION = 5.2
end
+_LUAVERSION = LUAVERSION -- for old times sake, will go away
+
-- lpeg
if not lpeg then
lpeg = require("lpeg")
end
+-- if utf8 then
+-- utf8lua = utf8
+-- utf8 = nil
+-- end
+
-- basics:
if loadstring then
@@ -188,7 +197,7 @@ if lua then
lua.mask = load([[τεχ = 1]]) and "utf" or "ascii"
end
-local flush = io.flush
+local flush = io.flush
if flush then
@@ -199,3 +208,45 @@ if flush then
end
+-- new
+
+FFISUPPORTED = type(ffi) == "table" and ffi.os ~= "" and ffi.arch ~= "" and ffi.load
+
+if not FFISUPPORTED then
+
+ -- Maybe we should check for LUATEXENGINE but that's also a bti tricky as we still
+ -- can have a weird ffi library laying around. Checking for presence of 'jit' is
+ -- also not robust. So for now we hope for the best.
+
+ 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
+elseif not ffi.number then
+ ffi.number = tonumber
+end
+
+if not bit32 then -- and utf8 then
+ -- bit32 = load ( [[ -- replacement code with 5.3 syntax so that 5.2 doesn't bark on it ]] )
+ bit32 = require("l-bit32")
+end
+
+-- We need this due a bug in luatex socket loading:
+
+-- local loaded = package.loaded
+--
+-- if not loaded["socket"] then loaded["socket"] = loaded["socket.core"] end
+-- if not loaded["mime"] then loaded["mime"] = loaded["mime.core"] end
+--
+-- if not socket.mime then socket.mime = package.loaded["mime"] end
+--
+-- if not loaded["socket.mime"] then loaded["socket.mime"] = socket.mime end
+-- if not loaded["socket.http"] then loaded["socket.http"] = socket.http end
+-- if not loaded["socket.ftp"] then loaded["socket.ftp"] = socket.ftp end
+-- if not loaded["socket.smtp"] then loaded["socket.smtp"] = socket.smtp end
+-- if not loaded["socket.tp"] then loaded["socket.tp"] = socket.tp end
+-- if not loaded["socket.url"] then loaded["socket.url"] = socket.url end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-math.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-math.lua
index ec62919b46a..e5668a5db0a 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-math.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-math.lua
@@ -6,33 +6,144 @@ if not modules then modules = { } end modules ['l-math'] = {
license = "see context related readme files"
}
-local floor, sin, cos, tan = math.floor, math.sin, math.cos, math.tan
-
if not math.ceiling then
+
math.ceiling = math.ceil
+
end
if not math.round then
+
+ 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
+
end
if not math.mod then
+
function math.mod(n,m) return n % m end
-end
-local pipi = 2*math.pi/360
+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
+
end
if not math.odd then
+
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
+
+end
+
+if not math.pow then
+
+ function math.pow(x,y)
+ return x^y
+ end
+
+end
+
+if not math.atan2 then
+
+ math.atan2 = math.atan
+
+end
+
+if not math.ldexp then
+
+ function math.ldexp(x,e)
+ return x * 2.0^e
+ end
+
+end
+
+-- if not math.frexp then
+--
+-- -- not a oneliner so use a math library instead
+--
+-- function math.frexp(x,e)
+-- -- returns m and e such that x = m2e, e is an integer and the absolute
+-- -- value of m is in the range [0.5, 1) (or zero when x is zero)
+-- end
+--
+-- end
+
+if not math.log10 then
+
+ 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
+
+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
+
+end
+
+if not math.ult then
+
+ local floor = math.floor
+
+ function math.tointeger(m,n)
+ -- not ok but i'm not motivated to look into it now
+ return floor(m) < floor(n) -- unsigned comparison needed
+ end
+
end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-md5.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-md5.lua
index 00272c873f1..6758fa44441 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-md5.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-md5.lua
@@ -48,6 +48,9 @@ do
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
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua
index c6f1e33597b..a83e8f8f94a 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua
@@ -18,46 +18,50 @@ local floor = math.floor
number = number or { }
local number = number
-if bit32 then -- I wonder if this is faster
+-- begin obsolete code --
- local btest, bor = bit32.btest, bit32.bor
-
- function number.bit(p)
- return 2 ^ (p - 1) -- 1-based indexing
- end
-
- number.hasbit = btest
- number.setbit = bor
-
- function number.setbit(x,p) -- why not bor?
- return btest(x,p) and x or x + p
- end
-
- function number.clearbit(x,p)
- return btest(x,p) and x - p or x
- end
-
-else
-
- -- http://ricilake.blogspot.com/2007/10/iterating-bits-in-lua.html
-
- function number.bit(p)
- return 2 ^ (p - 1) -- 1-based indexing
- end
-
- function number.hasbit(x, p) -- typical call: if hasbit(x, bit(3)) then ...
- return x % (p + p) >= p
- end
-
- function number.setbit(x, p)
- return (x % (p + p) >= p) and x or x + p
- end
-
- function number.clearbit(x, p)
- return (x % (p + p) >= p) and x - p or x
- end
+-- if bit32 then
+--
+-- local btest, bor = bit32.btest, bit32.bor
+--
+-- function number.bit(p)
+-- return 2 ^ (p - 1) -- 1-based indexing
+-- end
+--
+-- number.hasbit = btest
+-- number.setbit = bor
+--
+-- function number.setbit(x,p) -- why not bor?
+-- return btest(x,p) and x or x + p
+-- end
+--
+-- function number.clearbit(x,p)
+-- return btest(x,p) and x - p or x
+-- end
+--
+-- else
+--
+-- -- http://ricilake.blogspot.com/2007/10/iterating-bits-in-lua.html
+--
+-- function number.bit(p)
+-- return 2 ^ (p - 1) -- 1-based indexing
+-- end
+--
+-- function number.hasbit(x, p) -- typical call: if hasbit(x, bit(3)) then ...
+-- return x % (p + p) >= p
+-- end
+--
+-- function number.setbit(x, p)
+-- return (x % (p + p) >= p) and x or x + p
+-- end
+--
+-- function number.clearbit(x, p)
+-- return (x % (p + p) >= p) and x - p or x
+-- end
+--
+-- end
-end
+-- end obsolete code --
-- print(number.tobitstring(8))
-- print(number.tobitstring(14))
@@ -152,60 +156,60 @@ function number.toevenhex(n)
end
end
--- a,b,c,d,e,f = number.toset(100101)
+-- -- a,b,c,d,e,f = number.toset(100101)
+-- --
+-- -- function number.toset(n)
+-- -- return match(tostring(n),"(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+-- -- end
+-- --
+-- -- -- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
+-- -- -- on
+-- --
+-- -- for i=1,1000000 do
+-- -- local a,b,c,d,e,f,g,h = number.toset(12345678)
+-- -- local a,b,c,d = number.toset(1234)
+-- -- local a,b,c = number.toset(123)
+-- -- local a,b,c = number.toset("123")
+-- -- end
+--
+-- local one = lpeg.C(1-lpeg.S('')/tonumber)^1
--
-- function number.toset(n)
--- return match(tostring(n),"(.?)(.?)(.?)(.?)(.?)(.?)(.?)(.?)")
+-- return lpegmatch(one,tostring(n))
-- end
--
--- -- the lpeg way is slower on 8 digits, but faster on 4 digits, some 7.5%
--- -- on
+-- -- function number.bits(n,zero)
+-- -- local t, i = { }, (zero and 0) or 1
+-- -- while n > 0 do
+-- -- local m = n % 2
+-- -- if m > 0 then
+-- -- insert(t,1,i)
+-- -- end
+-- -- n = floor(n/2)
+-- -- i = i + 1
+-- -- end
+-- -- return t
+-- -- end
+-- --
+-- -- -- a bit faster
--
--- for i=1,1000000 do
--- local a,b,c,d,e,f,g,h = number.toset(12345678)
--- local a,b,c,d = number.toset(1234)
--- local a,b,c = number.toset(123)
--- local a,b,c = number.toset("123")
--- end
-
-local one = lpeg.C(1-lpeg.S('')/tonumber)^1
-
-function number.toset(n)
- return lpegmatch(one,tostring(n))
-end
-
--- function number.bits(n,zero)
--- local t, i = { }, (zero and 0) or 1
--- while n > 0 do
+-- local function bits(n,i,...)
+-- if n > 0 then
-- local m = n % 2
+-- local n = floor(n/2)
-- if m > 0 then
--- insert(t,1,i)
+-- return bits(n, i+1, i, ...)
+-- else
+-- return bits(n, i+1, ...)
-- end
--- n = floor(n/2)
--- i = i + 1
+-- else
+-- return ...
-- end
--- return t
-- end
--
--- -- a bit faster
-
-local function bits(n,i,...)
- if n > 0 then
- local m = n % 2
- local n = floor(n/2)
- if m > 0 then
- return bits(n, i+1, i, ...)
- else
- return bits(n, i+1, ...)
- end
- else
- return ...
- end
-end
-
-function number.bits(n)
- return { bits(n,1) }
-end
+-- function number.bits(n)
+-- return { bits(n,1) }
+-- end
function number.bytetodecimal(b)
local d = floor(b * 100 / 255 + 0.5)
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-os.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-os.lua
index 0a86ea6d697..c2a903f5c3f 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-os.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-os.lua
@@ -32,11 +32,12 @@ 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
--- The following code permits traversing the environment table, at least
--- in luatex. Internally all environment names are uppercase.
+-- The following code permits traversing the environment table, at least in luatex. Internally all
+-- environment names are uppercase.
-- The randomseed in Lua is not that random, although this depends on the operating system as well
--- as the binary (Luatex is normally okay). But to be sure we set the seed anyway.
+-- as the binary (Luatex is normally okay). But to be sure we set the seed anyway. It will be better
+-- in Lua 5.4 (according to the announcements.)
math.initialseed = tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6))
@@ -119,7 +120,7 @@ end
local execute = os.execute
local iopopen = io.popen
-function os.resultof(command)
+local function resultof(command)
local handle = iopopen(command,"r") -- already has flush
if handle then
local result = handle:read("*all") or ""
@@ -130,9 +131,15 @@ function os.resultof(command)
end
end
+os.resultof = resultof
+
+function os.pipeto(command)
+ return iopopen(command,"w") -- already has flush
+end
+
if not io.fileseparator then
if find(os.getenv("PATH"),";",1,true) then
- io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "mswin"
+ io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "windows"
else
io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix"
end
@@ -150,7 +157,7 @@ end
local launchers = {
windows = "start %s",
macosx = "open %s",
- unix = "$BROWSER %s &> /dev/null &",
+ unix = "xdg-open %s &> /dev/null &",
}
function os.launch(str)
@@ -203,20 +210,27 @@ end })
local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or ""
-local function guess()
- local architecture = os.resultof("uname -m") or ""
- if architecture ~= "" then
- return architecture
- end
- architecture = os.getenv("HOSTTYPE") or ""
- if architecture ~= "" then
- return architecture
- end
- return os.resultof("echo $HOSTTYPE") or ""
-end
+-- local function guess()
+-- local architecture = resultof("uname -m") or ""
+-- if architecture ~= "" then
+-- return architecture
+-- end
+-- architecture = os.getenv("HOSTTYPE") or ""
+-- if architecture ~= "" then
+-- return architecture
+-- end
+-- return resultof("echo $HOSTTYPE") or ""
+-- end
-- os.bits = 32 | 64
+-- os.uname()
+-- sysname
+-- machine
+-- release
+-- version
+-- nodename
+
if platform ~= "" then
os.platform = platform
@@ -228,10 +242,12 @@ elseif os.type == "windows" then
-- PROCESSOR_ARCHITECTURE : binary platform
-- PROCESSOR_ARCHITEW6432 : OS platform
+ -- mswin-64 is now win64
+
function resolvers.platform(t,k)
- local platform, architecture = "", os.getenv("PROCESSOR_ARCHITECTURE") or ""
+ local architecture = os.getenv("PROCESSOR_ARCHITECTURE") or ""
+ local platform = ""
if find(architecture,"AMD64",1,true) then
- -- platform = "mswin-64"
platform = "win64"
else
platform = "mswin"
@@ -245,13 +261,17 @@ elseif name == "linux" then
function resolvers.platform(t,k)
-- we sometimes have HOSTTYPE set so let's check that first
- local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
- if find(architecture,"x86_64",1,true) then
- platform = "linux-64"
+ 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
+ -- we're done
+ 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 = "linux"
+ platform = musl and "linuxmusl" or "linux"
end
os.setenv("MTX_PLATFORM",platform)
os.platform = platform
@@ -271,11 +291,13 @@ elseif name == "macosx" then
]]--
function resolvers.platform(t,k)
- -- local platform, architecture = "", os.getenv("HOSTTYPE") or ""
+ -- local platform = ""
+ -- local architecture = os.getenv("HOSTTYPE") or ""
-- if architecture == "" then
- -- architecture = os.resultof("echo $HOSTTYPE") or ""
+ -- architecture = resultof("echo $HOSTTYPE") or ""
-- end
- local platform, architecture = "", os.resultof("echo $HOSTTYPE") or ""
+ local architecture = resultof("echo $HOSTTYPE") or ""
+ local platform = ""
if architecture == "" then
-- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n")
platform = "osx-intel"
@@ -294,7 +316,8 @@ elseif name == "macosx" then
elseif name == "sunos" then
function resolvers.platform(t,k)
- local platform, architecture = "", os.resultof("uname -m") or ""
+ local architecture = resultof("uname -m") or ""
+ local platform = ""
if find(architecture,"sparc",1,true) then
platform = "solaris-sparc"
else -- if architecture == 'i86pc'
@@ -308,7 +331,8 @@ elseif name == "sunos" then
elseif name == "freebsd" then
function resolvers.platform(t,k)
- local platform, architecture = "", os.resultof("uname -m") or ""
+ local architecture = resultof("uname -m") or ""
+ local platform = ""
if find(architecture,"amd64",1,true) then
platform = "freebsd-amd64"
else
@@ -323,7 +347,8 @@ elseif name == "kfreebsd" then
function resolvers.platform(t,k)
-- we sometimes have HOSTTYPE set so let's check that first
- local platform, architecture = "", os.getenv("HOSTTYPE") or os.resultof("uname -m") or ""
+ local architecture = os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+ local platform = ""
if find(architecture,"x86_64",1,true) then
platform = "kfreebsd-amd64"
else
@@ -502,8 +527,10 @@ end
-- These are moved from core-con.lua (as I needed them elsewhere).
-local function isleapyear(year)
- return (year % 400 == 0) or ((year % 100 ~= 0) and (year % 4 == 0))
+local function isleapyear(year) -- timed for bram's cs practicum
+ -- return (year % 400 == 0) or (year % 100 ~= 0 and year % 4 == 0) -- 3:4:1600:1900 = 9.9 : 8.2 : 5.0 : 6.8 (29.9)
+ return (year % 4 == 0) and (year % 100 ~= 0 or year % 400 == 0) -- 3:4:1600:1900 = 5.1 : 6.5 : 8.1 : 10.2 (29.9)
+ -- return (year % 4 == 0) and (year % 400 == 0 or year % 100 ~= 0) -- 3:4:1600:1900 = 5.2 : 8.5 : 6.8 : 10.1 (30.6)
end
os.isleapyear = isleapyear
@@ -556,3 +583,20 @@ function os.validdate(year,month,day)
end
return year, month, day
end
+
+local osexit = os.exit
+local exitcode = nil
+
+function os.setexitcode(code)
+ exitcode = code
+end
+
+function os.exit(c)
+ if exitcode ~= nil then
+ return osexit(exitcode)
+ end
+ if c ~= nil then
+ return osexit(c)
+ end
+ return osexit()
+end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-package.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-package.lua
index 075fcde25ae..0dd71e5eca8 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-package.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-package.lua
@@ -18,11 +18,15 @@ if not modules then modules = { } end modules ['l-package'] = {
local type = type
local gsub, format, find = string.gsub, string.format, string.find
+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 package = package
+local searchers = package.searchers or package.loaders
+
+-------.loaders = nil -- old stuff that we don't want
+-------.seeall = nil -- old stuff that we don't want
-- dummies
@@ -191,7 +195,25 @@ local function registerpath(tag,what,target,...)
add(path)
end
end
- return paths
+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
+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
+ end
end
helpers.registerpath = registerpath
@@ -199,10 +221,22 @@ helpers.registerpath = registerpath
function package.extraluapath(...)
registerpath("extra lua","lua",extraluapaths,...)
end
+function package.pushluapath(path)
+ pushpath("extra lua","lua",extraluapaths,path)
+end
+function package.popluapath()
+ poppath("extra lua","lua",extraluapaths)
+end
function package.extralibpath(...)
registerpath("extra lib","lib",extralibpaths,...)
end
+function package.pushlibpath(path)
+ pushpath("extra lib","lib",extralibpaths,path)
+end
+function package.poplibpath()
+ poppath("extra lib","lua",extralibpaths)
+end
-- lib loader (used elsewhere)
@@ -360,3 +394,7 @@ end
-- front ..
table.insert(searchers,1,helpers.loaded)
+
+if context then
+ package.path = ""
+end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua
index be8f397aee3..8ae8d8d1d76 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua
@@ -18,7 +18,7 @@ local P, S, C, Ct, Cc, Cs = lpeg.P, lpeg.S, lpeg.C, lpeg.Ct, lpeg.Cc, lpeg.Cs
--
-- function string.split(str,pattern)
-- local t = { }
--- if #str > 0 then
+-- if str ~= "" then
-- local n = 1
-- for s in gmatch(str..pattern,"(.-)"..pattern) do
-- t[n] = s
@@ -72,6 +72,7 @@ end
local stripper = patterns.stripper
local fullstripper = patterns.fullstripper
local collapser = patterns.collapser
+local nospacer = patterns.nospacer
local longtostring = patterns.longtostring
function string.strip(str)
@@ -86,6 +87,10 @@ function string.collapsespaces(str)
return str and lpegmatch(collapser,str) or ""
end
+function string.nospaces(str)
+ return str and lpegmatch(nospacer,str) or ""
+end
+
function string.longtostring(str)
return str and lpegmatch(longtostring,str) or ""
end
@@ -212,3 +217,24 @@ end
string.quote = string.quoted
string.unquote = string.unquoted
+
+-- new
+
+if not string.bytetable then -- used in font-cff.lua
+
+ local limit = 5000 -- we can go to 8000 in luajit and much higher in lua if needed
+
+ function string.bytetable(str) -- from a string
+ 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
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua
index 39357bd25e6..69f45d9b4cd 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['l-table'] = {
license = "see context related readme files"
}
-local type, next, tostring, tonumber, ipairs, select = type, next, tostring, tonumber, ipairs, select
+local type, next, tostring, tonumber, select = type, next, tostring, tonumber, select
local table, string = table, string
local concat, sort, insert, remove = table.concat, table.sort, table.insert, table.remove
local format, lower, dump = string.format, string.lower, string.dump
@@ -22,6 +22,10 @@ local floor = math.floor
local stripper = patterns.stripper
+function table.getn(t)
+ return t and #t -- for very old times sake
+end
+
function table.strip(tab)
local lst, l = { }, 0
for i=1,#tab do
@@ -416,7 +420,7 @@ end
-- todo : copy without metatable
-local function copy(t, tables) -- taken from lua wiki, slightly adapted
+local function copy(t,tables) -- taken from lua wiki, slightly adapted
tables = tables or { }
local tcopy = { }
if not tables[t] then
@@ -427,7 +431,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
if tables[i] then
i = tables[i]
else
- i = copy(i, tables)
+ i = copy(i,tables)
end
end
if type(v) ~= "table" then
@@ -435,7 +439,7 @@ local function copy(t, tables) -- taken from lua wiki, slightly adapted
elseif tables[v] then
tcopy[i] = tables[v]
else
- tcopy[i] = copy(v, tables)
+ tcopy[i] = copy(v,tables)
end
end
local mt = getmetatable(t)
@@ -460,7 +464,7 @@ function table.tohash(t,value)
local h = { }
if t then
if value == nil then value = true end
- for _, v in next, t do -- no ipairs here
+ for _, v in next, t do
h[v] = value
end
end
@@ -469,7 +473,7 @@ end
function table.fromhash(t)
local hsh, h = { }, 0
- for k, v in next, t do -- no ipairs here
+ for k, v in next, t do
if v then
h = h + 1
hsh[h] = k
@@ -486,7 +490,7 @@ local reserved = table.tohash { -- intercept a language inconvenience: no reserv
'NaN', 'goto',
}
--- local function simple_table(t)
+-- local function is_simple_table(t)
-- if #t > 0 then
-- local n = 0
-- for _,v in next, t do
@@ -520,29 +524,67 @@ local reserved = table.tohash { -- intercept a language inconvenience: no reserv
-- return nil
-- end
-local function simple_table(t)
+-- local function is_simple_table(t)
+-- 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
+-- 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] = tostring(v) -- tostring not needed
+-- 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
+-- end
+-- end
+-- return nil
+-- end
+
+local function is_simple_table(t,hexify) -- also used in util-tab so maybe public
local nt = #t
if nt > 0 then
local n = 0
- for _,v in next, t do
+ for _, v in next, t do
n = n + 1
- -- if type(v) == "table" then
- -- return nil
- -- end
+ if type(v) == "table" then
+ return nil
+ end
end
+ -- local haszero = t[0]
+ local haszero = rawget(t,0) -- don't trigger meta
if n == nt then
local tt = { }
for i=1,nt do
local v = t[i]
local tv = type(v)
if tv == "number" then
+ -- tt[i] = v -- not needed tostring(v)
if hexify then
tt[i] = format("0x%X",v)
else
- tt[i] = tostring(v) -- tostring not needed
+ tt[i] = v -- not needed tostring(v)
end
elseif tv == "string" then
- tt[i] = format("%q",v)
+ tt[i] = format("%q",v) -- f_string(v)
elseif tv == "boolean" then
tt[i] = v and "true" or "false"
else
@@ -550,11 +592,35 @@ local function simple_table(t)
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
+ -- tt[i+1] = v -- not needed tostring(v)
+ if hexify then
+ tt[i+1] = format("0x%X",v)
+ else
+ tt[i+1] = v -- not needed tostring(v)
+ end
+ elseif tv == "string" then
+ tt[i+1] = format("%q",v) -- f_string(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
end
return nil
end
+table.is_simple_table = is_simple_table
+
-- Because this is a core function of mkiv I moved some function calls
-- inline.
--
@@ -637,7 +703,7 @@ local function do_serialize(root,name,depth,level,indexed)
if next(v) == nil then
handle(format("%s {},",depth))
elseif inline then -- and #t > 0
- local st = simple_table(v)
+ local st = is_simple_table(v,hexify)
if st then
handle(format("%s { %s },",depth,concat(st,", ")))
else
@@ -723,7 +789,7 @@ local function do_serialize(root,name,depth,level,indexed)
handle(format("%s [%q]={},",depth,k))
end
elseif inline then
- local st = simple_table(v)
+ local st = is_simple_table(v,hexify)
if st then
if tk == "number" then
if hexify then
@@ -1030,7 +1096,9 @@ function table.unnest(t) -- bad name
end
local function are_equal(a,b,n,m) -- indexed
- if a and b and #a == #b then
+ 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
@@ -1052,16 +1120,18 @@ local function are_equal(a,b,n,m) -- indexed
end
local function identical(a,b) -- assumes same structure
- for ka, va in next, a do
- local vb = b[ka]
- if va == vb then
- -- same
- elseif type(va) == "table" and type(vb) == "table" then
- if not identical(va,vb) then
+ if a ~= b then
+ for ka, va in next, a do
+ local vb = b[ka]
+ if va == vb then
+ -- same
+ elseif type(va) == "table" and type(vb) == "table" then
+ if not identical(va,vb) then
+ return false
+ end
+ else
return false
end
- else
- return false
end
end
return true
@@ -1155,27 +1225,35 @@ function table.reversed(t)
end
end
-function table.reverse(t)
+function table.reverse(t) -- check with 5.3 ?
if t then
local n = #t
- for i=1,floor(n/2) do
- local j = n - i + 1
+ local m = n + 1
+ for i=1,floor(n/2) do -- maybe just n//2
+ local j = m - i
t[i], t[j] = t[j], t[i]
end
return t
end
end
-function table.sequenced(t,sep,simple) -- hash only
+local function sequenced(t,sep,simple)
if not t then
return ""
+ elseif type(t) == "string" then
+ return t -- handy fallback
end
local n = #t
local s = { }
if n > 0 then
-- indexed
for i=1,n do
- s[i] = tostring(t[i])
+ local v = t[i]
+ if type(v) == "table" then
+ s[i] = "{" .. sequenced(v,sep,simple) .. "}"
+ else
+ s[i] = tostring(t[i])
+ end
end
else
-- hashed
@@ -1187,17 +1265,27 @@ function table.sequenced(t,sep,simple) -- hash only
s[n] = k
elseif v and v~= "" then
n = n + 1
- s[n] = k .. "=" .. tostring(v)
+ if type(v) == "table" then
+ s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}"
+ else
+ s[n] = k .. "=" .. tostring(v)
+ end
end
else
n = n + 1
- s[n] = k .. "=" .. tostring(v)
+ if type(v) == "table" then
+ s[n] = k .. "={" .. sequenced(v,sep,simple) .. "}"
+ else
+ s[n] = k .. "=" .. tostring(v)
+ end
end
end
end
return concat(s,sep or " | ")
end
+table.sequenced = sequenced
+
function table.print(t,...)
if type(t) ~= "table" then
print(tostring(t))
@@ -1326,3 +1414,26 @@ function table.filtered(t,pattern,sort,cmp)
return nothing
end
end
+
+-- lua 5.3:
+
+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
+ end
+
+end
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 12a4f646ff4..51893d585fe 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua
@@ -42,11 +42,51 @@ local function resettiming(instance)
timers[instance or "notimer"] = { timing = 0, loadtime = 0 }
end
+local ticks = clock
+local seconds = function(n) return n or 0 end
+
+-- if FFISUPPORTED and ffi and os.type == "windows" then
+--
+-- local okay, kernel = pcall(ffi.load,"kernel32")
+--
+-- 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
+--
+-- end
+--
+-- end
+
local function starttiming(instance)
local timer = timers[instance or "notimer"]
- local it = timer.timing or 0
+ local it = timer.timing
if it == 0 then
- timer.starttime = clock()
+ timer.starttime = ticks()
if not timer.loadtime then
timer.loadtime = 0
end
@@ -62,7 +102,7 @@ local function stoptiming(instance)
else
local starttime = timer.starttime
if starttime and starttime > 0 then
- local stoptime = clock()
+ local stoptime = ticks()
local loadtime = stoptime - starttime
timer.stoptime = stoptime
timer.loadtime = timer.loadtime + loadtime
@@ -76,10 +116,28 @@ end
local function elapsed(instance)
if type(instance) == "number" then
- return instance or 0
+ return instance
+ else
+ local timer = timers[instance or "notimer"]
+ return timer and seconds(timer.loadtime) or 0
+ end
+end
+
+local function currenttime(instance)
+ if type(instance) == "number" then
+ return instance
else
local timer = timers[instance or "notimer"]
- return timer and timer.loadtime or 0
+ local it = timer.timing
+ if it > 1 then
+ -- whatever
+ else
+ local starttime = timer.starttime
+ if starttime and starttime > 0 then
+ return seconds(timer.loadtime + ticks() - starttime)
+ end
+ end
+ return 0
end
end
@@ -101,6 +159,7 @@ statistics.hastiming = hastiming
statistics.resettiming = resettiming
statistics.starttiming = starttiming
statistics.stoptiming = stoptiming
+statistics.currenttime = currenttime
statistics.elapsed = elapsed
statistics.elapsedtime = elapsedtime
statistics.elapsedindeed = elapsedindeed
@@ -127,20 +186,24 @@ function statistics.show()
return format("%s, type: %s, binary subtree: %s",
os.platform or "unknown",os.type or "unknown", environment.texos or "unknown")
end)
- register("luatex banner", function()
- return lower(status.banner)
+ -- register("luatex banner", function()
+ -- return lower(status.banner)
+ -- 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", function()
- local total, indirect = status.callbacks or 0, status.indirect_callbacks or 0
- return format("%s direct, %s indirect, %s total", total-indirect, indirect, total)
- end)
- if jit then
- local jitstatus = { jit.status() }
- if jitstatus[1] then
- register("luajit options", concat(jitstatus," ",2))
+ 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
-- so far
@@ -149,8 +212,9 @@ function statistics.show()
local hashchar = tonumber(status.luatex_hashchars)
local hashtype = status.luatex_hashtype
local mask = lua.mask or "ascii"
- return format("engine: %s, used memory: %s, hash type: %s, hash chars: min(%s,40), symbol mask: %s (%s)",
+ 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",
@@ -184,7 +248,7 @@ end
function statistics.runtime()
stoptiming(statistics)
- -- stoptiming(statistics) -- somehow we can start the timer twice, but where
+ -- stoptiming(statistics) -- somehow we can start the timer twice, but where
return statistics.formatruntime(elapsedtime(statistics))
end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-unicode.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-unicode.lua
index 3dec8001345..b5f52d3127c 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-unicode.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-unicode.lua
@@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['l-unicode'] = {
license = "see context related readme files"
}
+-- floor(b/256) => rshift(b, 8)
+-- floor(b/1024) => rshift(b,10)
+
-- in lua 5.3:
-- utf8.char(···) : concatinated
@@ -18,6 +21,9 @@ if not modules then modules = { } end modules ['l-unicode'] = {
-- todo: utf.sub replacement (used in syst-aux)
-- we put these in the utf namespace:
+-- used : byte char gmatch len lower sub upper
+-- not used : dump find format gfind gsub match rep reverse
+
utf = utf or (unicode and unicode.utf8) or { }
utf.characters = utf.characters or string.utfcharacters
@@ -29,6 +35,9 @@ utf.values = utf.values or string.utfvalues
-- string.characterpairs
-- string.bytes
-- string.bytepairs
+-- string.utflength
+-- string.utfvalues
+-- string.utfcharacters
local type = type
local char, byte, format, sub, gmatch = string.char, string.byte, string.format, string.sub, string.gmatch
@@ -64,53 +73,103 @@ end
if not utf.char then
- local floor, char = math.floor, string.char
-
- function utf.char(n)
- if n < 0x80 then
- -- 0aaaaaaa : 0x80
- return char(n)
- elseif n < 0x800 then
- -- 110bbbaa : 0xC0 : n >> 6
- -- 10aaaaaa : 0x80 : n & 0x3F
- return char(
- 0xC0 + floor(n/0x40),
- 0x80 + (n % 0x40)
- )
- elseif n < 0x10000 then
- -- 1110bbbb : 0xE0 : n >> 12
- -- 10bbbbaa : 0x80 : (n >> 6) & 0x3F
- -- 10aaaaaa : 0x80 : n & 0x3F
- return char(
- 0xE0 + floor(n/0x1000),
- 0x80 + (floor(n/0x40) % 0x40),
- 0x80 + (n % 0x40)
- )
- elseif n < 0x200000 then
- -- 11110ccc : 0xF0 : n >> 18
- -- 10ccbbbb : 0x80 : (n >> 12) & 0x3F
- -- 10bbbbaa : 0x80 : (n >> 6) & 0x3F
- -- 10aaaaaa : 0x80 : n & 0x3F
- -- dddd : ccccc - 1
- return char(
- 0xF0 + floor(n/0x40000),
- 0x80 + (floor(n/0x1000) % 0x40),
- 0x80 + (floor(n/0x40) % 0x40),
- 0x80 + (n % 0x40)
- )
+ utf.char = string.utfcharacter or (utf8 and utf8.char)
+
+ if not utf.char then
+
+ -- no multiples
+
+ local char = string.char
+
+ if bit32 then
+
+ local rshift = bit32.rshift
+
+ function utf.char(n)
+ if n < 0x80 then
+ -- 0aaaaaaa : 0x80
+ return char(n)
+ elseif n < 0x800 then
+ -- 110bbbaa : 0xC0 : n >> 6
+ -- 10aaaaaa : 0x80 : n & 0x3F
+ return char(
+ 0xC0 + rshift(n,6),
+ 0x80 + (n % 0x40)
+ )
+ elseif n < 0x10000 then
+ -- 1110bbbb : 0xE0 : n >> 12
+ -- 10bbbbaa : 0x80 : (n >> 6) & 0x3F
+ -- 10aaaaaa : 0x80 : n & 0x3F
+ return char(
+ 0xE0 + rshift(n,12),
+ 0x80 + (rshift(n,6) % 0x40),
+ 0x80 + (n % 0x40)
+ )
+ elseif n < 0x200000 then
+ -- 11110ccc : 0xF0 : n >> 18
+ -- 10ccbbbb : 0x80 : (n >> 12) & 0x3F
+ -- 10bbbbaa : 0x80 : (n >> 6) & 0x3F
+ -- 10aaaaaa : 0x80 : n & 0x3F
+ -- dddd : ccccc - 1
+ return char(
+ 0xF0 + rshift(n,18),
+ 0x80 + (rshift(n,12) % 0x40),
+ 0x80 + (rshift(n,6) % 0x40),
+ 0x80 + (n % 0x40)
+ )
+ else
+ return ""
+ end
+ end
+
else
- return ""
+
+ 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
- local utf8byte = patterns.utf8byte
+ utf.byte = string.utfvalue or (utf8 and utf8.codepoint)
+
+ if not utf.byte then
+
+ local utf8byte = patterns.utf8byte
+
+ function utf.byte(c)
+ return lpegmatch(utf8byte,c)
+ end
- function utf.byte(c)
- return lpegmatch(utf8byte,c)
end
end
@@ -171,43 +230,6 @@ local one = P(1)
local two = C(1) * C(1)
local four = C(R(utfchar(0xD8),utfchar(0xFF))) * C(1) * C(1) * C(1)
--- actually one of them is already utf ... sort of useless this one
-
--- 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 < 0x40000 then
--- return char(
--- 0xF0 + floor(n/0x40000),
--- 0x80 + floor(n/0x1000),
--- 0x80 + (floor(n/0x40) % 0x40),
--- 0x80 + (n % 0x40)
--- )
--- else
--- -- return char(
--- -- 0xF1 + floor(n/0x1000000),
--- -- 0x80 + floor(n/0x40000),
--- -- 0x80 + floor(n/0x1000),
--- -- 0x80 + (floor(n/0x40) % 0x40),
--- -- 0x80 + (n % 0x40)
--- -- )
--- return "?"
--- end
--- end
---
--- merge into:
-
local pattern = P("\254\255") * Cs( (
four / function(a,b,c,d)
local ab = 0xFF * byte(a) + byte(b)
@@ -253,83 +275,89 @@ end
if not utf.len then
- -- -- alternative 1: 0.77
- --
- -- local utfcharcounter = utfbom^-1 * Cs((p_utf8char/'!')^0)
- --
- -- function utf.len(str)
- -- return #lpegmatch(utfcharcounter,str or "")
- -- end
- --
- -- -- alternative 2: 1.70
- --
- -- local n = 0
- --
- -- local utfcharcounter = utfbom^-1 * (p_utf8char/function() n = n + 1 end)^0 -- slow
- --
- -- function utf.length(str)
- -- n = 0
- -- lpegmatch(utfcharcounter,str or "")
- -- return n
- -- end
- --
- -- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047)
-
- -- local n = 0
- --
- -- -- local utfcharcounter = lpeg.patterns.utfbom^-1 * P ( ( Cp() * (
- -- -- patterns.utf8one ^1 * Cc(1)
- -- -- + patterns.utf8two ^1 * Cc(2)
- -- -- + patterns.utf8three^1 * Cc(3)
- -- -- + patterns.utf8four ^1 * Cc(4) ) * Cp() / function(f,d,t) n = n + (t - f)/d end
- -- -- )^0 ) -- just as many captures as below
- --
- -- -- local utfcharcounter = lpeg.patterns.utfbom^-1 * P ( (
- -- -- (Cmt(patterns.utf8one ^1,function(_,_,s) n = n + #s return true end))
- -- -- + (Cmt(patterns.utf8two ^1,function(_,_,s) n = n + #s/2 return true end))
- -- -- + (Cmt(patterns.utf8three^1,function(_,_,s) n = n + #s/3 return true end))
- -- -- + (Cmt(patterns.utf8four ^1,function(_,_,s) n = n + #s/4 return true end))
- -- -- )^0 ) -- not interesting as it creates strings but sometimes faster
- --
- -- -- The best so far:
- --
- -- local utfcharcounter = utfbom^-1 * P ( (
- -- Cp() * (patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end
- -- + Cp() * (patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end
- -- + Cp() * (patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end
- -- + Cp() * (patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end
- -- )^0 )
-
- -- function utf.len(str)
- -- n = 0
- -- lpegmatch(utfcharcounter,str or "")
- -- return n
- -- end
-
- local n, f = 0, 1
+ utf.len = string.utflength or (utf8 and utf8.len)
+
+ if not utf.len then
+
+ -- -- alternative 1: 0.77
+ --
+ -- local utfcharcounter = utfbom^-1 * Cs((p_utf8char/'!')^0)
+ --
+ -- function utf.len(str)
+ -- return #lpegmatch(utfcharcounter,str or "")
+ -- end
+ --
+ -- -- alternative 2: 1.70
+ --
+ -- local n = 0
+ --
+ -- local utfcharcounter = utfbom^-1 * (p_utf8char/function() n = n + 1 end)^0 -- slow
+ --
+ -- function utf.length(str)
+ -- n = 0
+ -- lpegmatch(utfcharcounter,str or "")
+ -- return n
+ -- end
+ --
+ -- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047)
+
+ -- local n = 0
+ --
+ -- -- local utfcharcounter = lpeg.patterns.utfbom^-1 * P ( ( Cp() * (
+ -- -- patterns.utf8one ^1 * Cc(1)
+ -- -- + patterns.utf8two ^1 * Cc(2)
+ -- -- + patterns.utf8three^1 * Cc(3)
+ -- -- + patterns.utf8four ^1 * Cc(4) ) * Cp() / function(f,d,t) n = n + (t - f)/d end
+ -- -- )^0 ) -- just as many captures as below
+ --
+ -- -- local utfcharcounter = lpeg.patterns.utfbom^-1 * P ( (
+ -- -- (Cmt(patterns.utf8one ^1,function(_,_,s) n = n + #s return true end))
+ -- -- + (Cmt(patterns.utf8two ^1,function(_,_,s) n = n + #s/2 return true end))
+ -- -- + (Cmt(patterns.utf8three^1,function(_,_,s) n = n + #s/3 return true end))
+ -- -- + (Cmt(patterns.utf8four ^1,function(_,_,s) n = n + #s/4 return true end))
+ -- -- )^0 ) -- not interesting as it creates strings but sometimes faster
+ --
+ -- -- The best so far:
+ --
+ -- local utfcharcounter = utfbom^-1 * P ( (
+ -- Cp() * (patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end
+ -- + Cp() * (patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end
+ -- + Cp() * (patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end
+ -- + Cp() * (patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end
+ -- )^0 )
+
+ -- function utf.len(str)
+ -- n = 0
+ -- lpegmatch(utfcharcounter,str or "")
+ -- return n
+ -- end
+
+ 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) -- due to Cc no string captures, so faster
+ n = n + (t - f)/d
+ f = t
+ return true
+ end
+ )^0
- 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) -- due to Cc no string captures, so faster
- n = n + (t - f)/d
- f = t
- return true
+ function utf.len(str)
+ n, f = 0, 1
+ lpegmatch(utfcharcounter,str or "")
+ return n
end
- )^0
- function utf.len(str)
- n, f = 0, 1
- lpegmatch(utfcharcounter,str or "")
- return n
- end
+ -- -- these are quite a bit slower:
- -- -- these are quite a bit slower:
+ -- utfcharcounter = utfbom^-1 * (Cmt(P(1) * R("\128\191")^0, function() n = n + 1 return true end))^0 -- 50+ times slower
+ -- utfcharcounter = utfbom^-1 * (Cmt(P(1), function() n = n + 1 return true end) * R("\128\191")^0)^0 -- 50- times slower
- -- utfcharcounter = utfbom^-1 * (Cmt(P(1) * R("\128\191")^0, function() n = n + 1 return true end))^0 -- 50+ times slower
- -- utfcharcounter = utfbom^-1 * (Cmt(P(1), function() n = n + 1 return true end) * R("\128\191")^0)^0 -- 50- times slower
+ end
end
@@ -1041,21 +1069,23 @@ end
local function little(b)
if b < 0x10000 then
- return char(b%256,b/256)
+ return char(b%256,rshift(b,8))
else
b = b - 0x10000
- local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
- return char(b1%256,b1/256,b2%256,b2/256)
+ 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(b/256,b%256)
+ return char(rshift(b,8),b%256)
else
b = b - 0x10000
- local b1, b2 = b/1024 + 0xD800, b%1024 + 0xDC00
- return char(b1/256,b1%256,b2/256,b2%256)
+ 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
@@ -1270,3 +1300,62 @@ function utf.chrlen(u) -- u is number
(u < 0xFC and 5) or
(u < 0xFE and 6) or 0
end
+
+-- hashing saves a little but not that much in practice
+--
+-- local utf32 = table.setmetatableindex(function(t,k) local v = toutf32(k) t[k] = v return v end)
+
+if bit32 then
+
+ local extract = bit32.extract
+ local char = string.char
+
+ function unicode.toutf32string(n)
+ if n <= 0xFF then
+ return
+ char(n) ..
+ "\000\000\000"
+ elseif n <= 0xFFFF then
+ return
+ char(extract(n, 0,8)) ..
+ char(extract(n, 8,8)) ..
+ "\000\000"
+ elseif n <= 0xFFFFFF then
+ return
+ char(extract(n, 0,8)) ..
+ char(extract(n, 8,8)) ..
+ char(extract(n,16,8)) ..
+ "\000"
+ else
+ return
+ char(extract(n, 0,8)) ..
+ char(extract(n, 8,8)) ..
+ char(extract(n,16,8)) ..
+ char(extract(n,24,8))
+ end
+ end
+
+end
+
+-- goodie:
+
+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
+ end
+ return s
+end
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-url.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-url.lua
index b189ec5bba8..6f834d778d1 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-url.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-url.lua
@@ -8,9 +8,10 @@ if not modules then modules = { } end modules ['l-url'] = {
local char, format, byte = string.char, string.format, string.byte
local concat = table.concat
-local tonumber, type = tonumber, type
+local tonumber, type, next = tonumber, type, next
local P, C, R, S, Cs, Cc, Ct, Cf, Cg, V = lpeg.P, lpeg.C, lpeg.R, lpeg.S, lpeg.Cs, lpeg.Cc, lpeg.Ct, lpeg.Cf, lpeg.Cg, lpeg.V
local lpegmatch, lpegpatterns, replacer = lpeg.match, lpeg.patterns, lpeg.replacer
+local sortedhash = table.sortedhash
-- from wikipedia:
--
@@ -32,22 +33,61 @@ local lpegmatch, lpegpatterns, replacer = lpeg.match, lpeg.patterns, lpeg.replac
url = url or { }
local url = url
-local tochar = function(s) return char(tonumber(s,16)) end
+local unescapes = { }
+local escapes = { }
+
+setmetatable(unescapes, { __index = function(t,k)
+ 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
+end })
+
+-- okay:
local colon = P(":")
local qmark = P("?")
local hash = P("#")
local slash = P("/")
+local atsign = P("@")
local percent = P("%")
local endofstring = P(-1)
-
local hexdigit = R("09","AF","af")
local plus = P("+")
local nothing = Cc("")
-local escapedchar = (percent * C(hexdigit * hexdigit)) / tochar
-local escaped = (plus / " ") + escapedchar -- so no loc://foo++.tex
-
-local noslash = P("/") / ""
+local okay = R("09","AZ","az") + S("-_.,:=+*~!'()@&$")
+
+local escapedchar = (percent * C(hexdigit * hexdigit)) / unescapes
+local unescapedchar = P(1) / escapes
+local escaped = (plus / " ") + escapedchar -- so no loc://foo++.tex
+local noslash = P("/") / ""
+local plustospace = P("+")/" "
+
+local decoder = Cs( (
+ 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 )
+
+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.unescape(str) return str and lpegmatch(unescaper,str) or str end
-- we assume schemes with more than 1 character (in order to avoid problems with windows disks)
-- we also assume that when we have a scheme, we also have an authority
@@ -73,17 +113,9 @@ local parser = Ct(validurl)
lpegpatterns.url = validurl
lpegpatterns.urlsplitter = parser
-local escapes = { }
-
-setmetatable(escapes, { __index = function(t,k)
- local v = format("%%%02X",byte(k))
- t[k] = v
- return v
-end })
-
-local escaper = Cs((R("09","AZ","az")^1 + P(" ")/"%%20" + S("-./_")^1 + P(1) / escapes)^0) -- space happens most
+local escaper = Cs((R("09","AZ","az")^1 + P(" ")/"%%20" + S("-./_:")^1 + P(1) / escapes)^0) -- space happens most
local unescaper = Cs((escapedchar + 1)^0)
-local getcleaner = Cs((P("+++") / "%%2B" + P("+") / "%%20" + P(1))^1)
+local getcleaner = Cs((P("+++")/"%%2B" + P("+")/"%%20" + P(1))^1)
lpegpatterns.urlunescaped = escapedchar
lpegpatterns.urlescaper = escaper
@@ -134,8 +166,8 @@ local backslashswapper = replacer("\\","/")
local equal = P("=")
local amp = P("&")
-local key = Cs(((escapedchar+1)-equal )^0)
-local value = Cs(((escapedchar+1)-amp -endofstring)^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,
@@ -144,6 +176,11 @@ local splitquery = Cf ( Ct("") * P { "sequence",
-- hasher
+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) -- not yet ok (/test?test)
if not str or str == "" then
return {
@@ -177,12 +214,21 @@ local function hashed(str) -- not yet ok (/test?test)
-- not always a filename but handy anyway
local authority = detailed[2]
local path = detailed[3]
- local filename = nil
+ local filename -- = nil
+ local username -- = nil
+ local password -- = nil
+ local host -- = nil
+ local port -- = nil
+ if authority ~= "" then
+ -- these can be invalid
+ username, password, host, port = lpegmatch(splitauthority,authority)
+ end
if authority == "" then
filename = path
elseif path == "" then
filename = ""
else
+ -- this one can be can be invalid
filename = authority .. "/" .. path
end
return {
@@ -195,6 +241,11 @@ local function hashed(str) -- not yet ok (/test?test)
original = str,
noscheme = false,
filename = filename,
+ --
+ host = host,
+ port = port,
+ -- usename = username,
+ -- password = password,
}
end
@@ -236,24 +287,38 @@ function url.addscheme(str,scheme) -- no authority
end
function url.construct(hash) -- dodo: we need to escape !
- local fullurl, f = { }, 0
- local scheme, authority, path, query, fragment = hash.scheme, hash.authority, hash.path, hash.query, hash.fragment
+ 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
- f = f + 1 ; fullurl[f] = scheme .. "://"
+ r = r + 1 ; result[r] = lpegmatch(escaper,scheme)
+ r = r + 1 ; result[r] = "://"
end
if authority and authority ~= "" then
- f = f + 1 ; fullurl[f] = authority
+ r = r + 1 ; result[r] = lpegmatch(escaper,authority)
end
if path and path ~= "" then
- f = f + 1 ; fullurl[f] = "/" .. path
+ r = r + 1 ; result[r] = "/"
+ r = r + 1 ; result[r] = lpegmatch(escaper,path)
end
- if query and query ~= "" then
- f = f + 1 ; fullurl[f] = "?".. query
+ 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) -- is this escaped
+ r = r + 1 ; result[r] = "="
+ r = r + 1 ; result[r] = lpegmatch(escaper,v) -- is this escaped
+ done = true
+ end
end
if fragment and fragment ~= "" then
- f = f + 1 ; fullurl[f] = "#".. fragment
+ r = r + 1 ; result[r] = "#"
+ r = r + 1 ; result[r] = lpegmatch(escaper,fragment)
end
- return lpegmatch(escaper,concat(fullurl))
+ return concat(result)
end
local pattern = Cs(slash^-1/"" * R("az","AZ") * ((S(":|")/":") + P(":")) * slash * P(1)^0)
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-deb.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-deb.lua
index ee732b3b54c..9488a728b61 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-deb.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-deb.lua
@@ -12,87 +12,268 @@ if not modules then modules = { } end modules ['util-deb'] = {
local debug = require "debug"
-local getinfo = debug.getinfo
-local type, next, tostring = type, next, tostring
-local format, find = string.format, string.find
-local is_boolean = string.is_boolean
+local getinfo, sethook = debug.getinfo, debug.sethook
+local type, next, tostring, tonumber = type, next, tostring, tonumber
+local format, find, sub, gsub = string.format, string.find, string.sub, string.gsub
+local insert, remove, sort = table.insert, table.remove, table.sort
+local setmetatableindex = table.setmetatableindex
utilities = utilities or { }
local debugger = utilities.debugger or { }
utilities.debugger = debugger
-local counters = { }
+local report = logs.reporter("debugger")
+
+local ticks = os.gettimeofday or os.clock
+local seconds = function(n) return n or 0 end
+local overhead = 0
+local dummycalls = 10*1000
+local nesting = 0
local names = { }
-local report = logs.reporter("debugger")
+local initialize = false
+
+if not (FFISUPPORTED and ffi) then
+
+ -- we have no precise timer
+
+elseif os.type == "windows" then
+
+ initialize = function()
+ local kernel = ffilib("kernel32","system") -- no checking
+ 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
+ end
+ initialize = false
+ end
+
+elseif os.type == "unix" then
+
+ -- for the values: echo '#include <time.h>' > foo.h; gcc -dM -E foo.h
+
+ 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
+ end
+
+end
--- one
+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
+ end)
+ t[name] = v
+ return v
+end)
-local function hook()
- local f = getinfo(2) -- "nS"
+local function hook(where)
+ local f = getinfo(2,"nSl")
if f then
- local n = "unknown"
- if f.what == "C" then
- n = f.name or '<anonymous>'
- if not names[n] then
- names[n] = format("%42s",n)
+ 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
- else
- -- source short_src linedefined what name namewhat nups func
- n = f.name or f.namewhat or f.what
- if not n or n == "" then
- n = "?"
+ 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
- if not names[n] then
- names[n] = format("%42s : % 5i : %s",n,f.linedefined or 0,f.short_src or "unknown source")
+ 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
- counters[n] = (counters[n] or 0) + 1
end
end
-function debugger.showstats(printer,threshold) -- hm, something has changed, rubish now
- printer = printer or report
- threshold = threshold or 0
- local total, grandtotal, functions = 0, 0, 0
- local dataset = { }
- for name, count in next, counters do
- dataset[#dataset+1] = { name, count }
+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
+ -- if name = "a" then
+ -- -- weird name
+ -- end
+ dataset[#dataset+1] = { real, total, count, name, source, line }
+ end
+ end
+ end
end
- table.sort(dataset,function(a,b) return a[2] == b[2] and b[1] > a[1] or a[2] > b[2] end)
- for i=1,#dataset do
- local d = dataset[i]
- local name = d[1]
- local count = d[2]
- if count > threshold and not find(name,"for generator") then -- move up
- printer(format("%8i %s\n", count, names[name]))
- total = total + count
+ 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
+ else
+ return b[2] < a[2]
+ end
+ else
+ return b[1] < a[1]
end
- grandtotal = grandtotal + count
+ 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("\n")
- printer(format("functions : % 10i\n", functions))
- printer(format("total : % 10i\n", total))
- printer(format("grand total: % 10i\n", grandtotal))
- printer(format("threshold : % 10i\n", threshold))
+ printer("")
+ printer(format("functions : %i", functions))
+ printer(format("calls : %i", calls))
+ printer(format("overhead : %f", seconds(overhead/1000)))
+
+ -- table.save("luatex-profile.lua",names)
end
function debugger.savestats(filename,threshold)
local f = io.open(filename,'w')
if f then
- debugger.showstats(function(str) f:write(str) end,threshold)
+ debugger.showstats(function(str) f:write(str,"\n") end,threshold)
f:close()
end
end
function debugger.enable()
- debug.sethook(hook,"c")
+ if nesting == 0 then
+ running = true
+ if initialize then
+ initialize()
+ end
+ sethook(hook,"cr")
+ local function dummy() end
+ local t = ticks()
+ for i=1,dummycalls do
+ dummy()
+ end
+ overhead = ticks() - t
+ end
+ if nesting > 0 then
+ nesting = nesting + 1
+ end
end
function debugger.disable()
- debug.sethook()
- -- counters[debug.getinfo(2,"f").func] = nil
+ if nesting > 0 then
+ nesting = nesting - 1
+ end
+ if nesting == 0 then
+ sethook()
+ end
end
-- debugger.enable()
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-dim.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-dim.lua
index 2bdb870e7a4..fd9351a28fb 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-dim.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-dim.lua
@@ -429,7 +429,7 @@ end
stringtodimen = string.todimen -- local variable defined earlier
function number.toscaled(d)
- return format("%0.5f",d/2^16)
+ return format("%0.5f",d/0x10000) -- 2^16
end
--[[ldx--
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua
index 0f9731a2656..d568a2e1fd0 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua
@@ -6,10 +6,8 @@ if not modules then modules = { } end modules ['util-fil'] = {
license = "see context related readme files"
}
-local byte = string.byte
-local char = string.char
-local extract = bit32 and bit32.extract
-local floor = math.floor
+local byte = string.byte
+local char = string.char
-- Here are a few helpers (the starting point were old ones I used for parsing
-- flac files). In Lua 5.3 we can probably do this better. Some code will move
@@ -35,7 +33,10 @@ function files.close(f)
end
function files.size(f)
- return f:seek("end")
+ local current = f:seek()
+ local size = f:seek("end")
+ f:seek("set",current)
+ return size
end
files.getsize = files.size
@@ -83,6 +84,12 @@ function files.readbytes(f,n)
return byte(f:read(n),1,n)
end
+function files.readbytetable(f,n)
+ -- return { byte(f:read(n),1,n) }
+ local s = f:read(n or 1)
+ return { byte(s,1,#s) } -- best use the real length
+end
+
function files.readchar(f)
return f:read(1)
end
@@ -93,22 +100,23 @@ end
function files.readinteger1(f) -- one byte
local n = byte(f:read(1))
- if n >= 0x80 then
- -- return n - 0xFF - 1
+ if n >= 0x80 then
return n - 0x100
else
return n
end
end
-files.readcardinal1 = files.readbyte -- one byte
-files.readcardinal = files.readcardinal1
-files.readinteger = files.readinteger1
+files.readcardinal1 = files.readbyte -- one byte
+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
end
+
function files.readcardinal2le(f)
local b, a = byte(f:read(2),1,2)
return 0x100 * a + b
@@ -116,22 +124,19 @@ end
function files.readinteger2(f)
local a, b = byte(f:read(2),1,2)
- local n = 0x100 * a + b
- if n >= 0x8000 then
- -- return n - 0xFFFF - 1
- return n - 0x10000
+ if a >= 0x80 then
+ return 0x100 * a + b - 0x10000
else
- return n
+ return 0x100 * a + b
end
end
+
function files.readinteger2le(f)
local b, a = byte(f:read(2),1,2)
- local n = 0x100 * a + b
- if n >= 0x8000 then
- -- return n - 0xFFFF - 1
- return n - 0x10000
+ if a >= 0x80 then
+ return 0x100 * a + b - 0x10000
else
- return n
+ return 0x100 * a + b
end
end
@@ -139,6 +144,7 @@ function files.readcardinal3(f)
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
@@ -146,22 +152,19 @@ end
function files.readinteger3(f)
local a, b, c = byte(f:read(3),1,3)
- local n = 0x10000 * a + 0x100 * b + c
- if n >= 0x80000 then
- -- return n - 0xFFFFFF - 1
- return n - 0x1000000
+ if a >= 0x80 then
+ return 0x10000 * a + 0x100 * b + c - 0x1000000
else
- return n
+ return 0x10000 * a + 0x100 * b + c
end
end
+
function files.readinteger3le(f)
local c, b, a = byte(f:read(3),1,3)
- local n = 0x10000 * a + 0x100 * b + c
- if n >= 0x80000 then
- -- return n - 0xFFFFFF - 1
- return n - 0x1000000
+ if a >= 0x80 then
+ return 0x10000 * a + 0x100 * b + c - 0x1000000
else
- return n
+ return 0x10000 * a + 0x100 * b + c
end
end
@@ -169,6 +172,7 @@ function files.readcardinal4(f)
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
@@ -176,48 +180,75 @@ end
function files.readinteger4(f)
local a, b, c, d = byte(f:read(4),1,4)
- local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
- if n >= 0x8000000 then
- -- return n - 0xFFFFFFFF - 1
- return n - 0x100000000
+ if a >= 0x80 then
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
else
- return n
+ 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)
- local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d
- if n >= 0x8000000 then
- -- return n - 0xFFFFFFFF - 1
- return n - 0x100000000
+ if a >= 0x80 then
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
else
- return n
+ 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 (0x100 * a + b - 0x10000)/256.0
+-- else
+-- return (0x100 * a + b)/256.0
+-- 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
+end
+
+-- (real) (n>>16) + ((n&0xffff)/65536.0))
+
+-- function files.readfixed4(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)/65536.0
+-- else
+-- return (0x1000000 * a + 0x10000 * b + 0x100 * c + d)/65536.0
+-- end
+-- end
+
function files.readfixed4(f)
local a, b, c, d = byte(f:read(4),1,4)
- local n = 0x100 * a + b
- if n >= 0x8000 then
- -- return n - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF
- return n - 0x10000 + (0x100 * c + d)/0xFFFF
+ if a >= 0x80 then
+ return (0x100 * a + b - 0x10000) + (0x100 * c + d)/0x10000
else
- return n + (0x100 * c + d)/0xFFFF
+ return (0x100 * a + b ) + (0x100 * c + d)/0x10000
end
end
-if extract then
+-- (real) ((n<<16)>>(16+14)) + ((n&0x3fff)/16384.0))
+
+if bit32 then
+
+ local extract = bit32.extract
+ local band = bit32.band
function files.read2dot14(f)
local a, b = byte(f:read(2),1,2)
- local n = 0x100 * a + b
- local m = extract(n,0,30)
- if n > 0x7FFF then
- n = extract(n,30,2)
- return m/0x4000 - 4
+ if a >= 0x80 then
+ local n = -(0x100 * a + b)
+ return - (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
else
- n = extract(n,30,2)
- return n + m/0x4000
+ local n = 0x100 * a + b
+ return (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
end
end
@@ -233,20 +264,37 @@ end
-- writers (kind of slow)
-function files.writecardinal2(f,n)
- local a = char(n % 256)
- n = floor(n/256)
- local b = char(n % 256)
- f:write(b,a)
+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 a = char(n % 256)
- n = floor(n/256)
+ n = rshift(n,8)
local b = char(n % 256)
- n = floor(n/256)
+ n = rshift(n,8)
local c = char(n % 256)
- n = floor(n/256)
+ n = rshift(n,8)
local d = char(n % 256)
f:write(d,c,b,a)
end
@@ -259,3 +307,76 @@ function files.writebyte(f,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
+
+end
+
+if fio and fio.readcardinaltable then
+
+ files.readcardinaltable = fio.readcardinaltable
+ files.readintegertable = fio.readintegertable
+
+else
+
+ local readcardinal1 = files.readcardinal1
+ local readcardinal2 = files.readcardinal2
+ local readcardinal3 = files.readcardinal3
+ local readcardinal4 = files.readcardinal4
+
+ function files.readcardinaltable(f,n,b)
+ local t = { }
+ if b == 1 then for i=1,n do t[i] = readcardinal1(f) end
+ elseif b == 2 then for i=1,n do t[i] = readcardinal2(f) end
+ elseif b == 3 then for i=1,n do t[i] = readcardinal3(f) end
+ elseif b == 4 then for i=1,n do t[i] = readcardinal4(f) end end
+ return t
+ end
+
+ local readinteger1 = files.readinteger1
+ local readinteger2 = files.readinteger2
+ local readinteger3 = files.readinteger3
+ local readinteger4 = files.readinteger4
+
+ function files.readintegertable(f,n,b)
+ local t = { }
+ if b == 1 then for i=1,n do t[i] = readinteger1(f) end
+ elseif b == 2 then for i=1,n do t[i] = readinteger2(f) end
+ elseif b == 3 then for i=1,n do t[i] = readinteger3(f) end
+ elseif b == 4 then for i=1,n do t[i] = readinteger4(f) end end
+ return t
+ end
+
+end
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 e835c07d648..e5f83e06c47 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua
@@ -21,7 +21,7 @@ local format = string.format
local utfchar = utf.char
local concat = table.concat
-local tonumber, tostring, rawset, type = tonumber, tostring, rawset, type
+local tonumber, tostring, rawset, type, next = tonumber, tostring, rawset, type, next
local json = utilities.json or { }
utilities.json = json
@@ -158,4 +158,11 @@ end
-- inspect(json.tostring(true))
+function json.load(filename)
+ local data = io.loaddata(filename)
+ if data then
+ return lpegmatch(jsonconverter,data)
+ end
+end
+
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 b3346006c94..1f531ef48e2 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua
@@ -10,16 +10,17 @@ if not modules then modules = { } end modules ['util-lua'] = {
-- we will remove the 5.1 code some day soon
local rep, sub, byte, dump, format = string.rep, string.sub, string.byte, string.dump, string.format
-local load, loadfile, type = load, loadfile, type
+local load, loadfile, type, collectgarbage = load, loadfile, type, collectgarbage
utilities = utilities or {}
utilities.lua = utilities.lua or { }
local luautilities = utilities.lua
local report_lua = logs.reporter("system","lua")
+local report_mem = logs.reporter("system","lua memory")
local tracestripping = false
-local forcestupidcompile = true -- use internal bytecode compiler
+local tracememory = false
luautilities.stripcode = true -- support stripping when asked for
luautilities.alwaysstripcode = false -- saves 1 meg on 7 meg compressed format file (2012.08.12)
luautilities.nofstrippedchunks = 0
@@ -41,7 +42,7 @@ luautilities.suffixes = {
-- environment.loadpreprocessedfile can be set to a preprocessor
-local function register(name)
+local function register(name) -- makes no sense runtime
if tracestripping then
report_lua("stripped bytecode from %a",name or "unknown")
end
@@ -71,12 +72,15 @@ end
-- quite subtle ... doing this wrong incidentally can give more bytes
-function luautilities.loadedluacode(fullname,forcestrip,name)
+function luautilities.loadedluacode(fullname,forcestrip,name,macros)
-- quite subtle ... doing this wrong incidentally can give more bytes
name = name or fullname
+ if macros then
+ macros = lua.macros
+ end
local code, message
- if environment.loadpreprocessedfile then
- code, message = environment.loadpreprocessedfile(fullname)
+ if macros then
+ code, message = macros.loaded(fullname,true,false)
else
code, message = loadfile(fullname)
end
@@ -103,19 +107,27 @@ function luautilities.loadedluacode(fullname,forcestrip,name)
end
end
-function luautilities.strippedloadstring(code,forcestrip,name) -- not executed
+function luautilities.strippedloadstring(code,name,forcestrip) -- not executed
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 -- not yet executes
+ return load(dump(code,true)), 0 -- not yet executed
else
return code, 0
end
end
+function luautilities.loadstring(code,name) -- not executed
+ 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) -- defaults: cleanup=false strip=true
report_lua("compiling %a into %a",luafile,lucfile)
os.remove(lucfile)
@@ -176,3 +188,24 @@ setmetatable(finalizers, {
function luautilities.registerfinalizer(f)
finalizers[#finalizers+1] = f
end
+
+function luautilities.checkmemory(previous,threshold,trace) -- threshold in MB
+ 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
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua
index 650a7ead6ae..891f1096ac9 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua
@@ -31,6 +31,7 @@ utilities.parsers.hashes = hashes
local digit = R("09")
local space = P(' ')
local equal = P("=")
+local colon = P(":")
local comma = P(",")
local lbrace = P("{")
local rbrace = P("}")
@@ -72,11 +73,13 @@ lpegpatterns.nested = nestedbraces -- no capture
lpegpatterns.argument = argument -- argument after e.g. =
lpegpatterns.content = content -- rest after e.g =
-local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace) + C((nestedbraces + (1-comma))^0)
+local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace
+ + C((nestedbraces + (1-comma))^0)
local key = C((1-equal-comma)^1)
local pattern_a = (space+comma)^0 * (key * equal * value + key * C(""))
local pattern_c = (space+comma)^0 * (key * equal * value)
+local pattern_d = (space+comma)^0 * (key * (equal+colon) * value + key * C(""))
local key = C((1-space-equal-comma)^1)
local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * value) + C("")))
@@ -92,10 +95,12 @@ end
local pattern_a_s = (pattern_a/set)^1
local pattern_b_s = (pattern_b/set)^1
local pattern_c_s = (pattern_c/set)^1
+local pattern_d_s = (pattern_d/set)^1
patterns.settings_to_hash_a = pattern_a_s
patterns.settings_to_hash_b = pattern_b_s
patterns.settings_to_hash_c = pattern_c_s
+patterns.settings_to_hash_d = pattern_d_s
function parsers.make_settings_to_hash_pattern(set,how)
if how == "strict" then
@@ -126,6 +131,18 @@ function parsers.settings_to_hash(str,existing)
end
end
+function parsers.settings_to_hash_colon_too(str)
+ if not str or str == "" then
+ return { }
+ elseif type(str) == "table" then
+ return str
+ else
+ hash = { }
+ lpegmatch(pattern_d_s,str)
+ return hash
+ end
+end
+
function parsers.settings_to_hash_tolerant(str,existing)
if not str or str == "" then
return { }
@@ -165,7 +182,7 @@ function parsers.settings_to_hash_strict(str,existing)
end
local separator = comma * space^0
-local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace
+ C((nestedbraces + (1-comma))^0)
local pattern = spaces * Ct(value*(separator*value)^0)
@@ -210,7 +227,7 @@ function parsers.settings_to_numbers(str)
return str
end
-local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace
+ C((nestedbraces + nestedbrackets + nestedparents + (1-comma))^0)
local pattern = spaces * Ct(value*(separator*value)^0)
@@ -242,7 +259,7 @@ function parsers.groupedsplitat(symbol,withaction)
if not pattern then
local symbols = S(symbol)
local separator = space^0 * symbols * space^0
- local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace)
+ 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
@@ -566,14 +583,16 @@ function parsers.rfc4180splitter(specification)
local field = escaped + non_escaped + Cc("")
local record = Ct(field * (separator * field)^1)
local headerline = record * Cp()
- local wholeblob = Ct((newline^(specification.strict and -1 or 1) * record)^0)
+ 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(wholeblob,data,position)
+ local data = lpegmatch(headeryes,data,position)
return data, header
else
- return lpegmatch(wholeblob,data)
+ return lpegmatch(headernop,data)
end
end
end
@@ -604,10 +623,10 @@ local cardinal = lpegpatterns.cardinal / tonumber
local spacers = lpegpatterns.spacer^0
local endofstring = lpegpatterns.endofstring
-local stepper = spacers * ( C(cardinal) * ( spacers * S(":-") * spacers * ( C(cardinal) + Cc(true) ) + Cc(false) )
+local stepper = spacers * ( cardinal * ( spacers * S(":-") * spacers * ( cardinal + Cc(true) ) + Cc(false) )
* Carg(1) * Carg(2) / ranger * S(", ")^0 )^1
-local stepper = spacers * ( C(cardinal) * ( spacers * S(":-") * spacers * ( C(cardinal) + (P("*") + endofstring) * Cc(true) ) + Cc(false) )
+local stepper = spacers * ( cardinal * ( spacers * S(":-") * spacers * ( cardinal + (P("*") + endofstring) * Cc(true) ) + Cc(false) )
* Carg(1) * Carg(2) / ranger * S(", ")^0 )^1 * endofstring -- we're sort of strict (could do without endofstring)
function parsers.stepper(str,n,action)
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sta.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sta.lua
index 27ab5a624b6..d140cacdcd8 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sta.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sta.lua
@@ -154,7 +154,7 @@ function stacker.new(name)
local function resolve_step(ti) -- keep track of changes outside function !
-- todo: optimize for n=1 etc
local result = nil
- local noftop = #top
+ local noftop = top and #top or 0
if ti > 0 then
local current = list[ti]
if current then
@@ -289,24 +289,24 @@ end
--
-- local concat = table.concat
--
--- local pdfliteral = nodes.pool.pdfliteral
+-- local pdfpageliteral = nodes.pool.pdfpageliteral
--
-- function demostacker.start(s,t,first,last)
-- local n = whatever[t[last]]
-- -- s.report("start: %s",n)
--- return pdfliteral(n)
+-- return pdfpageliteral(n)
-- end
--
-- function demostacker.stop(s,t,first,last)
-- local n = whatever[false]
-- -- s.report("stop: %s",n)
--- return pdfliteral(n)
+-- return pdfpageliteral(n)
-- end
--
-- function demostacker.change(s,t1,first1,last1,t2,first2,last2)
-- local n = whatever[t2[last2]]
-- -- s.report("change: %s",n)
--- return pdfliteral(n)
+-- return pdfpageliteral(n)
-- end
--
-- demostacker.mode = "switch"
@@ -325,7 +325,7 @@ end
-- r[#r+1] = whatever[t[i]]
-- end
-- -- s.report("start: %s",concat(r," "))
--- return pdfliteral(concat(r," "))
+-- return pdfpageliteral(concat(r," "))
-- end
--
-- function demostacker.stop(s,t,first,last)
@@ -334,7 +334,7 @@ end
-- r[#r+1] = whatever[false]
-- end
-- -- s.report("stop: %s",concat(r," "))
--- return pdfliteral(concat(r," "))
+-- return pdfpageliteral(concat(r," "))
-- end
--
-- function demostacker.change(s,t1,first1,last1,t2,first2,last2)
@@ -346,7 +346,7 @@ end
-- r[#r+1] = whatever[t2[i]]
-- end
-- -- s.report("change: %s",concat(r," "))
--- return pdfliteral(concat(r," "))
+-- return pdfpageliteral(concat(r," "))
-- end
--
-- demostacker.mode = "stack"
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sto.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sto.lua
index d21267d7a8c..a08d25ced18 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sto.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-sto.lua
@@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['util-sto'] = {
license = "see context related readme files"
}
-local setmetatable, getmetatable, type = setmetatable, getmetatable, type
+local setmetatable, getmetatable, rawset, type = setmetatable, getmetatable, rawset, type
utilities = utilities or { }
utilities.storage = utilities.storage or { }
@@ -158,6 +158,29 @@ function table.setmetatablecall(t,f)
return t
end
+-- the manual is somewhat fuzzy about this but suggests that one can best
+-- set all fields before assigning a metatable
+
+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
+end
+
function table.setmetatablekey(t,key,value)
local m = getmetatable(t)
if not m then
@@ -172,3 +195,88 @@ function table.getmetatablekey(t,key,value)
local m = getmetatable(t)
return m and m[key]
end
+
+function table.makeweak(t)
+ if not t then
+ t = { }
+ end
+ local m = getmetatable(t)
+ if m then
+ m.__mode = "v"
+ else
+ setmetatable(t,{ __mode = "v" })
+ end
+ return t
+end
+
+-- Problem: we have no __next (which is ok as it would probably slow down lua) so
+-- we cannot loop over the keys.
+
+-- local parametersets = table.autokeys()
+--
+-- parametersets.foo.bar = function(t,k) return "OEPS" end
+-- parametersets.foo.foo = "SPEO"
+-- parametersets.crap = { a = "a", b = table.autokey { function() return "b" end } }
+--
+-- print(parametersets.foo.bar)
+-- print(parametersets.foo.foo)
+-- print(parametersets.crap.b)
+-- print(parametersets.crap.b[1])
+
+-- function table.autotables(t)
+-- local t = t or { }
+-- local m = getmetatable(t)
+-- if not m then
+-- m = { }
+-- setmetatable(t,m)
+-- end
+-- m.__newindex = function(t,k,p)
+-- local v = { }
+-- local m = {
+-- __index = function(t,k)
+-- local v = p[k]
+-- if type(v) == "function" then
+-- return v(t,k) -- so we can have multiple arguments
+-- else
+-- return v
+-- end
+-- end,
+-- __newindex = function(t,k,v)
+-- p[k] = v
+-- end,
+-- __len = function(t)
+-- return #p
+-- end,
+-- }
+-- setmetatable(v,m)
+-- rawset(t,k,v)
+-- return v
+-- end
+-- m.__index = function(t,k)
+-- local v = { }
+-- t[k] = v -- calls newindex
+-- return v
+-- end
+-- return t
+-- end
+--
+-- function table.autokeys(p)
+-- local t = { }
+-- setmetatable(t, {
+-- __newindex = function(t,k,v)
+-- p[k] = v
+-- end,
+-- __index = function(t,k)
+-- local v = p[k]
+-- if type(v) == "function" then
+-- return v(t,k) -- so we can have multiple arguments
+-- else
+-- return v
+-- end
+-- end,
+-- __len = function(t)
+-- return #p
+-- end,
+-- })
+-- return t
+-- end
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 fb510257a2f..48c265659ef 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua
@@ -12,17 +12,20 @@ local strings = utilities.strings
local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, string.sub, string.find
local load, dump = load, string.dump
-local tonumber, type, tostring = tonumber, type, tostring
+local tonumber, type, tostring, next, setmetatable = tonumber, type, tostring, next, setmetatable
+local unpack, concat = table.unpack, table.concat
local unpack, concat = table.unpack, table.concat
local P, V, C, S, R, Ct, Cs, Cp, Carg, Cc = lpeg.P, lpeg.V, lpeg.C, lpeg.S, lpeg.R, lpeg.Ct, lpeg.Cs, lpeg.Cp, lpeg.Carg, lpeg.Cc
local patterns, lpegmatch = lpeg.patterns, lpeg.match
-local utfchar, utfbyte = utf.char, utf.byte
+local 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 _LUAVERSION < 5.2 then
+if oldfashioned then
loadstripped = function(str,shortcuts)
return load(str)
@@ -44,21 +47,60 @@ end
if not number then number = { } end -- temp hack for luatex-fonts
-local stripper = patterns.stripzeros
+local stripzero = patterns.stripzero
+local stripzeros = patterns.stripzeros
local newline = patterns.newline
local endofstring = patterns.endofstring
+local anything = patterns.anything
local whitespace = patterns.whitespace
+local space = patterns.space
local spacer = patterns.spacer
local spaceortab = patterns.spaceortab
+local digit = patterns.digit
+local sign = patterns.sign
+local period = patterns.period
+
+-- local function points(n)
+-- n = tonumber(n)
+-- return (not n or n == 0) and "0pt" or lpegmatch(stripzeros,format("%.5fpt",n/65536))
+-- end
+
+-- local function basepoints(n)
+-- n = tonumber(n)
+-- return (not n or n == 0) and "0bp" or lpegmatch(stripzeros,format("%.5fbp", n*(7200/7227)/65536))
+-- end
+
+local ptf = 1 / 65536
+local bpf = (7200/7227) / 65536
local function points(n)
+ if n == 0 then
+ return "0pt"
+ end
n = tonumber(n)
- return (not n or n == 0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536))
+ 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)) -- plural as we need to keep the pt
end
local function basepoints(n)
+ if n == 0 then
+ return "0pt"
+ end
n = tonumber(n)
- return (not n or n == 0) and "0bp" or lpegmatch(stripper,format("%.5fbp", n*(7200/7227)/65536))
+ 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)) -- plural as we need to keep the pt
end
number.points = points
@@ -69,7 +111,6 @@ number.basepoints = basepoints
local rubish = spaceortab^0 * newline
local anyrubish = spaceortab + newline
-local anything = patterns.anything
local stripped = (spaceortab^1 / "") * newline
local leading = rubish^0 / ""
local trailing = (anyrubish^1 * endofstring) / ""
@@ -137,13 +178,26 @@ local pattern =
+ newline * Cp() / function(position)
extra, start = 0, position
end
- + patterns.anything
+ + anything
)^1)
function strings.tabtospace(str,tab)
+ -- no real gain in first checking if a \t is there
return lpegmatch(pattern,str,1,tab or 7)
end
+function string.utfpadding(s,n)
+ if not n or n == 0 then
+ return ""
+ end
+ local l = utflen(s)
+ if n > 0 then
+ return nspaces[n-l]
+ else
+ return nspaces[-n-l]
+ end
+end
+
-- local t = {
-- "1234567123456712345671234567",
-- "\tb\tc",
@@ -167,27 +221,31 @@ end
-- return str
-- end
-local space = spacer^0
-local nospace = space/""
-local endofline = nospace * newline
+local optionalspace = spacer^0
+local nospace = optionalspace/""
+local endofline = nospace * newline
-local stripend = (whitespace^1 * endofstring)/""
+local stripend = (whitespace^1 * endofstring)/""
-local normalline = (nospace * ((1-space*(newline+endofstring))^1) * nospace)
+local normalline = (nospace * ((1-optionalspace*(newline+endofstring))^1) * nospace)
-local stripempty = endofline^1/""
-local normalempty = endofline^1
-local singleempty = endofline * (endofline^0/"")
-local doubleempty = endofline * endofline^-1 * (endofline^0/"")
+local stripempty = endofline^1/""
+local normalempty = endofline^1
+local singleempty = endofline * (endofline^0/"")
+local doubleempty = endofline * endofline^-1 * (endofline^0/"")
+local stripstart = stripempty^0
-local stripstart = stripempty^0
+local intospace = whitespace^1/" "
+local noleading = whitespace^1/""
+local notrailing = noleading * endofstring
-local p_prune_normal = Cs ( stripstart * ( stripend + normalline + normalempty )^0 )
-local p_prune_collapse = Cs ( stripstart * ( stripend + normalline + doubleempty )^0 )
-local p_prune_noempty = Cs ( stripstart * ( stripend + normalline + singleempty )^0 )
-local p_retain_normal = Cs ( ( normalline + normalempty )^0 )
-local p_retain_collapse = Cs ( ( normalline + doubleempty )^0 )
-local p_retain_noempty = Cs ( ( normalline + singleempty )^0 )
+local p_prune_normal = Cs ( stripstart * ( stripend + normalline + normalempty )^0 )
+local p_prune_collapse = Cs ( stripstart * ( stripend + normalline + doubleempty )^0 )
+local p_prune_noempty = Cs ( stripstart * ( stripend + normalline + singleempty )^0 )
+local p_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 )
-- function striplines(str,prune,collapse,noempty)
-- if prune then
@@ -213,10 +271,11 @@ local striplinepatterns = {
["prune"] = p_prune_normal,
["prune and collapse"] = p_prune_collapse, -- default
["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, -- how about: stripper fullstripper
+ ["collapse"] = patterns.collapser,
}
setmetatable(striplinepatterns,{ __index = function(t,k) return p_prune_collapse end })
@@ -227,6 +286,10 @@ function strings.striplines(str,how)
return str and lpegmatch(striplinepatterns[how],str) or str
end
+function strings.collapse(str) -- maybe also in strings
+ return str and lpegmatch(p_prune_intospace,str) or str
+end
+
-- also see: string.collapsespaces
strings.striplong = strings.striplines -- for old times sake
@@ -242,13 +305,14 @@ strings.striplong = strings.striplines -- for old times sake
-- " zus wim jet",
-- " ",
-- }, "\n")
-
+--
-- local str = table.concat( {
-- " aaaa",
-- " bb",
-- " cccccc",
+-- " ",
-- }, "\n")
-
+--
-- for k, v in table.sortedhash(utilities.strings.striplinepatterns) do
-- logs.report("stripper","method: %s, result: [[%s]]",k,utilities.strings.striplines(str,k))
-- end
@@ -280,41 +344,49 @@ end
--
-- More info can be found in cld-mkiv.pdf so here I stick to a simple list.
--
--- integer %...i number
--- integer %...d number
--- unsigned %...u number
--- character %...c number
--- hexadecimal %...x number
--- HEXADECIMAL %...X number
--- octal %...o number
--- string %...s string number
--- float %...f number
--- checked float %...F number
--- exponential %...e number
--- exponential %...E number
--- autofloat %...g number
--- autofloat %...G number
--- utf character %...c number
--- force tostring %...S any
--- force tostring %Q any
--- force tonumber %N number (strip leading zeros)
--- signed number %I number
--- rounded number %r number
--- 0xhexadecimal %...h character number
--- 0xHEXADECIMAL %...H character number
--- U+hexadecimal %...u character number
--- U+HEXADECIMAL %...U character number
--- points %p number (scaled points)
--- basepoints %b number (scaled points)
--- table concat %...t table
--- table concat %{.}t table
--- serialize %...T sequenced (no nested tables)
--- serialize %{.}T sequenced (no nested tables)
--- boolean (logic) %l boolean
--- BOOLEAN %L boolean
--- whitespace %...w
--- automatic %...a 'whatever' (string, table, ...)
--- automatic %...A "whatever" (string, table, ...)
+-- integer %...i number
+-- integer %...d number
+-- unsigned %...u number -- not used
+-- character %...c number
+-- hexadecimal %...x number
+-- HEXADECIMAL %...X number
+-- octal %...o number
+-- string %...s string number
+-- float %...f number
+-- checked float %...F number
+-- exponential %...e number
+-- exponential %...E number
+-- stripped e %...j number
+-- stripped E %...J number
+-- autofloat %...g number
+-- autofloat %...G number
+-- utf character %...c number
+-- force tostring %...S any
+-- force tostring %Q any
+-- force tonumber %N number (strip leading zeros)
+-- signed number %I number
+-- rounded number %r number
+-- 0xhexadecimal %...h character number
+-- 0xHEXADECIMAL %...H character number
+-- U+hexadecimal %...u character number
+-- U+HEXADECIMAL %...U character number
+-- points %p number (scaled points)
+-- basepoints %b number (scaled points)
+-- table concat %...t table
+-- table concat %{.}t table
+-- serialize %...T sequenced (no nested tables)
+-- serialize %{.}T sequenced (no nested tables)
+-- boolean (logic) %l boolean
+-- BOOLEAN %L boolean
+-- whitespace %...w number
+-- whitespace %...W (fixed)
+-- automatic %...a 'whatever' (string, table, ...)
+-- automatic %...A "whatever" (string, table, ...)
+-- zap %...z skip
+-- stripped %...N %...N
+-- comma/period real %...m
+-- period/comma real %...M
+-- formatted float %...k n.m
local n = 0
@@ -387,27 +459,45 @@ end
-- maybe to util-num
-local digit = patterns.digit
-local period = patterns.period
-local three = digit * digit * digit
+local two = digit * digit
+local three = two * digit
+local prefix = (Carg(1) * three)^1
local splitter = Cs (
- (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1))
- * (P(1)/"" * Carg(2)) * C(2)
+ (((1 - (three^1 * period))^1 + C(three)) * prefix + C((1-period)^1))
+ * (anything/"" * Carg(2)) * C(2)
+)
+
+local splitter3 = Cs (
+ three * prefix * endofstring +
+ two * prefix * endofstring +
+ digit * prefix * endofstring +
+ three +
+ two +
+ digit
)
patterns.formattednumber = splitter
function number.formatted(n,sep1,sep2)
- local s = type(s) == "string" and n or format("%0.2f",n)
- if sep1 == true then
- return lpegmatch(splitter,s,1,".",",")
- elseif sep1 == "." then
- return lpegmatch(splitter,s,1,sep1,sep2 or ",")
- elseif sep1 == "," then
- return lpegmatch(splitter,s,1,sep1,sep2 or ".")
+ if sep1 == false then
+ if type(n) == "number" then
+ n = tostring(n)
+ end
+ return lpegmatch(splitter3,n,1,sep2 or ".")
else
- return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".")
+ 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
end
end
@@ -420,17 +510,45 @@ end
-- print(number.formatted(1234567))
-- print(number.formatted(12345678))
-- print(number.formatted(12345678,true))
+-- print(number.formatted(1,false))
+-- print(number.formatted(12,false))
+-- print(number.formatted(123,false))
+-- print(number.formatted(1234,false))
+-- print(number.formatted(12345,false))
+-- print(number.formatted(123456,false))
+-- print(number.formatted(1234567,false))
+-- print(number.formatted(12345678,false))
-- print(number.formatted(1234.56,"!","?"))
+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
+ )
+
+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
+end
+
local zero = P("0")^1 / ""
local plus = P("+") / ""
local minus = P("-")
-local separator = S(".")
-local digit = R("09")
+local separator = period
local trailing = zero^1 * #S("eE")
-local exponent = (S("eE") * (plus + Cs((minus * zero^0 * P(-1))/"") + minus) * zero^0 * (P(-1) * Cc("0") + P(1)^1))
+local exponent = (S("eE") * (plus + Cs((minus * zero^0 * endofstring)/"") + minus) * zero^0 * (endofstring * Cc("0") + anything^1))
local pattern_a = Cs(minus^0 * digit^1 * (separator/"" * trailing + separator * (trailing + digit)^0) * exponent)
-local pattern_b = Cs((exponent + P(1))^0)
+local pattern_b = Cs((exponent + anything)^0)
function number.sparseexponent(f,n)
if not n then
@@ -449,6 +567,31 @@ function number.sparseexponent(f,n)
return tostring(n)
end
+local hf = { }
+local hs = { }
+
+setmetatable(hf, { __index = function(t,k)
+ 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
+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
+end
+
local template = [[
%s
%s
@@ -457,7 +600,7 @@ return function(%s) return %s end
local preamble, environment = "", { }
-if _LUAVERSION < 5.2 then
+if oldfashioned then
preamble = [[
local lpeg=lpeg
@@ -473,12 +616,16 @@ 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
@@ -498,12 +645,16 @@ else
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
@@ -520,7 +671,10 @@ setmetatable(arguments, { __index =
end
})
-local prefix_any = C((S("+- .") + R("09"))^0)
+local prefix_any = C((sign + space + period + digit)^0)
+local prefix_sub = (C((sign + digit)^0) + Cc(0))
+ * period
+ * (C((sign + digit)^0) + Cc(0))
local prefix_tab = P("{") * C((1-P("}"))^0) * P("}") + C((1-R("az","AZ","09","%%"))^0)
-- we've split all cases as then we can optimize them (let's omit the fuzzy u)
@@ -545,9 +699,36 @@ local format_S = function(f) -- can be optimized
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
+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
+end
+
local format_q = function()
n = n + 1
- return format("(a%s and format('%%q',a%s) or '')",n,n) -- goodie: nil check (maybe separate lpeg, not faster)
+ -- lua 5.3 has a different q than lua 5.2 (which does a tostring on numbers)
+ -- return format("(a%s ~= nil and format('%%q',a%s) or '')",n,n)
+ return format("(a%s ~= nil and format('%%q',tostring(a%s)) or '')",n,n)
end
local format_Q = function() -- can be optimized
@@ -594,6 +775,11 @@ local format_F = function(f) -- beware, no cast to number
end
end
+local format_k = function(b,a) -- slow
+ 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)
@@ -732,9 +918,43 @@ local format_L = function()
return format("(a%s and 'TRUE' or 'FALSE')",n)
end
-local format_N = function() -- strips leading zeros
+local format_n = function() -- strips leading and trailing zeros and removes .0
+ 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() -- strips leading and trailing zeros (also accepts string)
+-- n = n + 1
+-- return format("tostring(tonumber(a%s) or a%s)",n,n)
+-- end
+
+-- local format_N = function(f) -- strips leading and trailing zeros
+-- n = n + 1
+-- -- stripzero (singular) as we only have a number
+-- if not f or f == "" then
+-- return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or ((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%.9f',a%s)))",n,n,n,n,n)
+-- else
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+-- end
+-- end
+
+-- local format_N = function(f) -- strips leading and trailing zeros
+-- n = n + 1
+-- -- stripzero (singular) as we only have a number
+-- if not f or f == "" then
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or ((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or lpegmatch(stripzero,format('%%.9f',a%s)))",n,n,n,n,n)
+-- else
+-- return format("(((a%s %% 1 == 0) and format('%%i',a%s)) or lpegmatch(stripzero,format('%%%sf',a%s)))",n,n,f,n)
+-- end
+-- end
+
+local format_N = function(f) -- strips leading and trailing zeros
n = n + 1
- return format("tostring(tonumber(a%s) or a%s)",n,n)
+ -- stripzero (singular) as we only have a number
+ if not f or f == "" then
+ f = ".9"
+ end -- always a leading number !
+ 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)
@@ -774,7 +994,11 @@ local format_m = function(f)
if not f or f == "" then
f = ","
end
- return format([[formattednumber(a%s,%q,".")]],n,f)
+ 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)
@@ -782,7 +1006,11 @@ local format_M = function(f)
if not f or f == "" then
f = "."
end
- return format([[formattednumber(a%s,%q,",")]],n,f)
+ if f == "0" then
+ return format([[formattednumber(a%s,false)]],n)
+ else
+ return format([[formattednumber(a%s,%q,",")]],n,f)
+ end
end
--
@@ -854,7 +1082,9 @@ local builder = Cs { "start",
+ V("C")
+ V("S") -- new
+ V("Q") -- new
+ + V("n") -- new
+ V("N") -- new
+ + V("k") -- new
--
+ V("r")
+ V("h") + V("H") + V("u") + V("U")
@@ -870,11 +1100,14 @@ local builder = Cs { "start",
+ V("m") + V("M") -- new (formatted number)
+ V("z") -- new
--
+ + V(">") -- left padding
+ + V("<") -- right padding
+ --
-- + V("?") -- ignored, probably messed up %
)
+ V("*")
)
- * (P(-1) + Carg(1))
+ * (endofstring + Carg(1))
)^0,
--
["s"] = (prefix_any * P("s")) / format_s, -- %s => regular %s (string)
@@ -892,8 +1125,10 @@ local builder = Cs { "start",
["o"] = (prefix_any * P("o")) / format_o, -- %o => regular %o (octal)
--
["S"] = (prefix_any * P("S")) / format_S, -- %S => %s (tostring)
- ["Q"] = (prefix_any * P("Q")) / format_S, -- %Q => %q (tostring)
- ["N"] = (prefix_any * P("N")) / format_N, -- %N => tonumber (strips leading zeros)
+ ["Q"] = (prefix_any * P("Q")) / format_Q, -- %Q => %q (tostring)
+ ["n"] = (prefix_any * P("n")) / format_n, -- %n => tonumber (strips leading and trailing zeros, as well as .0, expects number)
+ ["N"] = (prefix_any * P("N")) / format_N, -- %N => tonumber (strips leading and trailing zeros, also takes string)
+ ["k"] = (prefix_sub * P("k")) / format_k, -- %k => like f but with n.m
["c"] = (prefix_any * P("c")) / format_c, -- %c => utf character (extension to regular)
["C"] = (prefix_any * P("C")) / format_C, -- %c => U+.... utf character
--
@@ -916,48 +1151,48 @@ local builder = Cs { "start",
["j"] = (prefix_any * P("j")) / format_j, -- %j => %e (float) stripped exponent (irrational)
["J"] = (prefix_any * P("J")) / format_J, -- %J => %E (float) stripped exponent (irrational)
--
- ["m"] = (prefix_tab * P("m")) / format_m, -- %m => xxx.xxx.xxx,xx (optional prefix instead of .)
- ["M"] = (prefix_tab * P("M")) / format_M, -- %M => xxx,xxx,xxx.xx (optional prefix instead of ,)
+ ["m"] = (prefix_any * P("m")) / format_m, -- %m => xxx.xxx.xxx,xx (optional prefix instead of .)
+ ["M"] = (prefix_any * P("M")) / format_M, -- %M => xxx,xxx,xxx.xx (optional prefix instead of ,)
--
- ["z"] = (prefix_any * P("z")) / format_z, -- %M => xxx,xxx,xxx.xx (optional prefix instead of ,)
+ ["z"] = (prefix_any * P("z")) / format_z, -- %z => skip n arguments
--
["a"] = (prefix_any * P("a")) / format_a, -- %a => '...' (forces tostring)
["A"] = (prefix_any * P("A")) / format_A, -- %A => "..." (forces tostring)
--
+ ["<"] = (prefix_any * P("<")) / format_left,
+ [">"] = (prefix_any * P(">")) / format_right,
+ --
["*"] = Cs(((1-P("%"))^1 + P("%%")/"%%")^1) / format_rest, -- rest (including %%)
["?"] = Cs(((1-P("%"))^1 )^1) / format_rest, -- rest (including %%)
--
["!"] = Carg(2) * prefix_any * P("!") * C((1-P("!"))^1) * P("!") / format_extension,
}
--- we can be clever and only alias what is needed
-
--- local direct = Cs (
--- P("%")/""
--- * Cc([[local format = string.format return function(str) return format("%]])
--- * (S("+- .") + R("09"))^0
--- * S("sqidfgGeExXo")
--- * Cc([[",str) end]])
--- * P(-1)
--- )
-
-local direct = Cs (
- P("%")
- * (S("+- .") + R("09"))^0
- * S("sqidfgGeExXo")
- * P(-1) / [[local format = string.format return function(str) return format("%0",str) end]]
-)
+-- We can be clever and only alias what is needed:
+
+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,
+}
+
+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
- local p
+ local f = preset[str]
+ if f then
+ return f
+ end
local p = lpegmatch(direct,str)
if p then
- -- f = loadstripped(p)()
-- print("builder 1 >",p)
f = loadstripped(p)()
else
- n = 0
+ n = 0 -- used in patterns
-- p = lpegmatch(builder,str,1,"..",t._extensions_) -- after this we know n
p = lpegmatch(builder,str,1,t._connector_,t._extensions_) -- after this we know n
if n > 0 then
@@ -968,6 +1203,7 @@ local function make(t,str)
f = function() return str end
end
end
+ -- if jit then jit.on(f,true) end
t[str] = f
return f
end
@@ -1020,7 +1256,7 @@ strings.formatters = { }
-- _connector_ is an experiment
-if _LUAVERSION < 5.2 then
+if oldfashioned then
function strings.formatters.new(noconcat)
local t = { _type_ = "formatter", _connector_ = noconcat and "," or "..", _extensions_ = { }, _preamble_ = preamble, _environment_ = { } }
@@ -1072,19 +1308,15 @@ strings.formatters.add = add
-- registered in the default instance (should we fall back on this one?)
-patterns.xmlescape = Cs((P("<")/"&lt;" + P(">")/"&gt;" + P("&")/"&amp;" + P('"')/"&quot;" + P(1))^0)
-patterns.texescape = Cs((C(S("#$%\\{}"))/"\\%1" + P(1))^0)
+patterns.xmlescape = Cs((P("<")/"&lt;" + P(">")/"&gt;" + P("&")/"&amp;" + P('"')/"&quot;" + anything)^0)
+patterns.texescape = Cs((C(S("#$%\\{}"))/"\\%1" + anything)^0)
patterns.luaescape = Cs(((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"')^0) -- maybe also \0
patterns.luaquoted = Cs(Cc('"') * ((1-S('"\n'))^1 + P('"')/'\\"' + P('\n')/'\\n"')^0 * Cc('"'))
-- 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)
--- 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]])
-
-if _LUAVERSION < 5.2 then
+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")
@@ -1133,7 +1365,6 @@ end
local dquote = patterns.dquote -- P('"')
local equote = patterns.escaped + dquote / '\\"' + 1
-local space = patterns.space
local cquote = Cc('"')
local pattern =
@@ -1149,3 +1380,21 @@ local pattern = Cs((newline / (os.newline or "\r") + 1)^0)
function string.replacenewlines(str)
return lpegmatch(pattern,str)
end
+
+--
+
+function strings.newcollector()
+ local result, r = { }, 0
+ return
+ function(fmt,str,...) -- write
+ r = r + 1
+ result[r] = str == nil and fmt or formatters[fmt](str,...)
+ end,
+ function(connector) -- flush
+ if result then
+ local str = concat(result,connector)
+ result, r = { }, 0
+ return str
+ end
+ end
+end
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 0521a2a4f14..f395f43defc 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua
@@ -153,15 +153,16 @@ function table.tocsv(t,specification)
fields = sortedkeys(t[1])
end
local separator = specification.separator or ","
+ local noffields = #fields
if specification.preamble == true then
- for f=1,#fields do
+ 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,#fields do
+ for f=1,noffields do
local field = ti[fields[f]]
if type(field) == "string" then
r[f] = lpegmatch(escape,field)
@@ -215,30 +216,31 @@ 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] -- inlining this is somewhat faster but gives more formatters
local tk = type(k)
local tv = type(v)
if tv == "table" then
if tk == "number" then
- result[#result+1] = formatters["%s<entry n='%s'>"](s,k)
+ r = r + 1 result[r] = formatters["%s<entry n='%s'>"](s,k)
toxml(v,d+step,result,step)
- result[#result+1] = formatters["%s</entry>"](s,k)
+ r = r + 1 result[r] = formatters["%s</entry>"](s,k)
else
- result[#result+1] = formatters["%s<%s>"](s,k)
+ r = r + 1 result[r] = formatters["%s<%s>"](s,k)
toxml(v,d+step,result,step)
- result[#result+1] = formatters["%s</%s>"](s,k)
+ r = r + 1 result[r] = formatters["%s</%s>"](s,k)
end
elseif tv == "string" then
if tk == "number" then
- result[#result+1] = formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k)
+ r = r + 1 result[r] = formatters["%s<entry n='%s'>%!xml!</entry>"](s,k,v,k)
else
- result[#result+1] = formatters["%s<%s>%!xml!</%s>"](s,k,v,k)
+ r = r + 1 result[r] = formatters["%s<%s>%!xml!</%s>"](s,k,v,k)
end
elseif tk == "number" then
- result[#result+1] = formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k)
+ r = r + 1 result[r] = formatters["%s<entry n='%s'>%S</entry>"](s,k,v,k)
else
- result[#result+1] = formatters["%s<%s>%S</%s>"](s,k,v,k)
+ r = r + 1 result[r] = formatters["%s<%s>%S</%s>"](s,k,v,k)
end
end
end
@@ -478,11 +480,11 @@ end
-- inspect(table.drop({ { a=2 }, {a=3} }))
-- inspect(table.drop({ { a=2 }, {a=3} },true))
-function table.autokey(t,k)
- local v = { }
- t[k] = v
- return v
-end
+-- function table.autokey(t,k) -- replaced
+-- local v = { }
+-- t[k] = v
+-- return v
+-- end
local selfmapper = { __index = function(t,k) t[k] = k return k end }
@@ -564,99 +566,72 @@ local original_serialize = table.serialize -- the extensive one, the one we star
-- latest lua for the value of #n (with holes) .. anyway for tracing purposes we want
-- indices / keys being sorted, so it will never be real fast
-local function serialize(root,name,specification)
-
- if type(specification) == "table" then
- return original_serialize(root,name,specification) -- the original one
- end
-
- local t -- = { }
- local n = 1
- local unknown = false
+local is_simple_table = table.is_simple_table
--- local function simple_table(t)
--- local ts = #t
--- if ts > 0 then
--- local n = 0
--- for _, v in next, t do
--- n = n + 1
--- if type(v) == "table" then
+-- local function is_simple_table(t)
+-- 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 = t[0]
+-- local haszero = rawget(t,0) -- don't trigger meta
+-- if n == nt then
+-- local tt = { }
+-- for i=1,nt do
+-- local v = t[i]
+-- local tv = type(v)
+-- if tv == "number" then
+-- tt[i] = v -- not needed tostring(v)
+-- elseif tv == "string" then
+-- tt[i] = format("%q",v) -- f_string(v)
+-- elseif tv == "boolean" then
+-- tt[i] = v and "true" or "false"
+-- else
-- return nil
-- end
-- end
--- if n == ts then
--- local tt = { }
--- local nt = 0
--- for i=1,ts do
--- local v = t[i]
--- local tv = type(v)
--- nt = nt + 1
--- if tv == "number" then
--- tt[nt] = v
--- elseif tv == "string" then
--- tt[nt] = format("%q",v) -- f_string(v)
--- elseif tv == "boolean" then
--- tt[nt] = v and "true" or "false"
--- else
--- return nil
--- 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
+-- tt[i+1] = v -- not needed tostring(v)
+-- elseif tv == "string" then
+-- tt[i+1] = format("%q",v) -- f_string(v)
+-- elseif tv == "boolean" then
+-- tt[i+1] = v and "true" or "false"
+-- else
+-- return nil
-- end
--- return tt
-- end
+-- tt[1] = "[0] = " .. tt[1]
+-- return tt
-- end
--- return nil
-- end
+-- return nil
+-- end
- local function simple_table(t)
- 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 = t[0]
- local haszero = rawget(t,0) -- don't trigger meta
- if n == nt then
- local tt = { }
- for i=1,nt do
- local v = t[i]
- local tv = type(v)
- if tv == "number" then
- tt[i] = v -- not needed tostring(v)
- elseif tv == "string" then
- tt[i] = format("%q",v) -- f_string(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
- tt[i+1] = v -- not needed tostring(v)
- elseif tv == "string" then
- tt[i+1] = format("%q",v) -- f_string(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
- end
- return nil
+-- In order to overcome the luajit (65K constant) limitation I tried a split approach,
+-- i.e. outputting the first level tables as locals but that failed with large cjk
+-- fonts too so I removed that ... just use luatex instead.
+
+local function serialize(root,name,specification)
+
+ if type(specification) == "table" then
+ return original_serialize(root,name,specification) -- the original one
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
@@ -706,7 +681,7 @@ local function serialize(root,name,specification)
if next(v) == nil then -- tricky as next is unpredictable in a hash
n = n + 1 t[n] = f_val_not(depth)
else
- local st = simple_table(v)
+ local st = is_simple_table(v)
if st then
n = n + 1 t[n] = f_val_seq(depth,st)
else
@@ -750,7 +725,7 @@ local function serialize(root,name,specification)
n = n + 1 t[n] = f_key_str_value_not(depth,tostring(k))
end
else
- local st = simple_table(v)
+ local st = is_simple_table(v)
if not st then
do_serialize(v,k,depth,level+1)
elseif tk == "number" then
@@ -821,7 +796,7 @@ local function serialize(root,name,specification)
end
-- Let's forget about empty tables.
if next(root) ~= nil then
- local st = simple_table(root)
+ local st = is_simple_table(root)
if st then
return t[1] .. f_fin_seq(st) -- todo: move up and in one go
else
@@ -844,3 +819,4 @@ if setinspector then
end
end)
end
+
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tpl.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tpl.lua
index 468dd429c98..5e75a151b92 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tpl.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tpl.lua
@@ -16,7 +16,7 @@ local templates = utilities.templates
local trace_template = false trackers.register("templates.trace",function(v) trace_template = v end)
local report_template = logs.reporter("template")
-local tostring = tostring
+local 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
diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua
index 1181bd1d840..685d4228e3d 100644
--- a/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua
+++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua
@@ -7,7 +7,7 @@
-- lualibs.dtx (with options: `lualibs')
-- This is a generated file.
--
--- Copyright (C) 2009--2017 by
+-- Copyright (C) 2009--2018 by
-- PRAGMA ADE / ConTeXt Development Team
-- The LuaLaTeX Dev Team
--
@@ -25,8 +25,8 @@ lualibs = lualibs or { }
lualibs.module_info = {
name = "lualibs",
- version = 2.5,
- date = "2017-02-01",
+ version = 2.6,
+ date = "2018-09-21",
description = "ConTeXt Lua standard libraries.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -91,7 +91,7 @@ local loadmodule = loadmodule or function (name, t)
if not t then t = "library" end
local filepath = find_file(name, "lua")
if not filepath or filepath == "" then
- warn(stringformat("Could not locate %s “%s”.", t, name))
+ warn(stringformat("Could not locate %s ^^e2^^80^^9c%s^^e2^^80^^9d.", t, name))
return false
end
dofile(filepath)