diff options
author | Karl Berry <karl@freefriends.org> | 2017-02-05 23:22:36 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-02-05 23:22:36 +0000 |
commit | 7ef0c5b362e4df3e85449f3c397ca3b61edf15a0 (patch) | |
tree | ca33364f8dca69a80a40985834e5726448ba6746 | |
parent | 17efbb93c3c280ebec43438b10c53601758ef11e (diff) |
lualibs (4feb17)
git-svn-id: svn://tug.org/texlive/trunk@43153 c570f23f-e606-0410-a88d-b1316a301751
23 files changed, 517 insertions, 8464 deletions
diff --git a/Master/texmf-dist/doc/luatex/lualibs/NEWS b/Master/texmf-dist/doc/luatex/lualibs/NEWS index 0a5f935c2c5..a5164af8220 100644 --- a/Master/texmf-dist/doc/luatex/lualibs/NEWS +++ b/Master/texmf-dist/doc/luatex/lualibs/NEWS @@ -1,4 +1,7 @@ History of the lualibs package +2017/02/01 v2.5/ + * sync with Context beta as of 2017-02-01 + 2016/04/06 v2.4/ * sync with Context beta as of 2016-04-06 * basic maintenance diff --git a/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf b/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf Binary files differindex 1b097641b6b..b78891151de 100644 --- a/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf +++ b/Master/texmf-dist/doc/luatex/lualibs/lualibs.pdf diff --git a/Master/texmf-dist/source/luatex/lualibs/Makefile b/Master/texmf-dist/source/luatex/lualibs/Makefile index 5e0fd6135ad..5e0fd2a9b44 100644 --- a/Master/texmf-dist/source/luatex/lualibs/Makefile +++ b/Master/texmf-dist/source/luatex/lualibs/Makefile @@ -125,3 +125,14 @@ mrproper: clean @$(RM) -r $(DISTDIR) merge: $(MERGED) + +ifndef DESTDIR +install: + $(error "in order to install you need to provide $$DESTDIR") +else +install: $(TDS_ZIP) + $(info installing to destination “$(DESTDIR)”) + install -dm755 "$(DESTDIR)" + unzip "$(TDS_ZIP)" -d "$(DESTDIR)" +endif + diff --git a/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx b/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx index 291049d265d..fe9525e3ba8 100644 --- a/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx +++ b/Master/texmf-dist/source/luatex/lualibs/lualibs.dtx @@ -1,6 +1,6 @@ % \iffalse meta-comment % -% Copyright (C) 2009--2016 by +% Copyright (C) 2009--2017 by % % PRAGMA ADE / ConTeXt Development Team % The LuaLaTeX Dev Team @@ -37,7 +37,7 @@ \input docstrip.tex \Msg{************************************************************************} \Msg{* Installation} -\Msg{* Package: lualibs 2016-04-06 v2.4 Lua additional functions.} +\Msg{* Package: lualibs 2017-02-01 v2.5 Lua additional functions.} \Msg{************************************************************************} \keepsilent @@ -48,7 +48,7 @@ \preamble This is a generated file. -Copyright (C) 2009--2016 by +Copyright (C) 2009--2017 by PRAGMA ADE / ConTeXt Development Team The LuaLaTeX Dev Team @@ -107,7 +107,7 @@ and lualibs-extended.lua. %<*driver> \NeedsTeXFormat{LaTeX2e} \ProvidesFile{lualibs.drv} - [2016/04/06 v2.4 Lua Libraries.] + [2017/02/01 v2.5 Lua Libraries.] \documentclass{ltxdoc} \usepackage{fancyvrb,xspace} \usepackage[x11names]{xcolor} @@ -208,7 +208,7 @@ and lualibs-extended.lua. % \GetFileInfo{lualibs.drv} % % \title{The \identifier{lualibs} package} -% \date{2016/04/06 v2.4} +% \date{2017/02/01 v2.5} % \author{Élie Roux · \email{elie.roux@telecom-bretagne.eu}\\ % Philipp Gesang · \email{phg@phi-gamma.net}} % @@ -427,8 +427,8 @@ lualibs = lualibs or { } lualibs.module_info = { name = "lualibs", - version = 2.4, - date = "2016-04-06", + version = 2.5, + date = "2017-02-01", description = "ConTeXt Lua standard libraries.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -582,8 +582,8 @@ local loadmodule = lualibs.loadmodule local lualibs_basic_module = { name = "lualibs-basic", - version = 2.4, - date = "2016-04-06", + version = 2.5, + date = "2017-02-01", description = "ConTeXt Lua libraries -- basic collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", @@ -664,8 +664,8 @@ lualibs = lualibs or { } local lualibs_extended_module = { name = "lualibs-extended", - version = 2.4, - date = "2016-04-06", + version = 2.5, + date = "2017-02-01", description = "ConTeXt Lua libraries -- extended collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua deleted file mode 100644 index ec56b75dc70..00000000000 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-basic-merged.lua +++ /dev/null @@ -1,5072 +0,0 @@ --- merged file : lualibs-basic-merged.lua --- parent file : lualibs-basic.lua --- merge date : Wed Apr 6 23:53:30 2016 - -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" -} -_MAJORVERSION,_MINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$") -_MAJORVERSION=tonumber(_MAJORVERSION) or 5 -_MINORVERSION=tonumber(_MINORVERSION) or 1 -_LUAVERSION=_MAJORVERSION+_MINORVERSION/10 -if _LUAVERSION<5.2 and jit then - _MINORVERSION=2 - _LUAVERSION=5.2 -end -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 - -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 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 - return paths -end -helpers.registerpath=registerpath -function package.extraluapath(...) - registerpath("extra lua","lua",extraluapaths,...) -end -function package.extralibpath(...) - registerpath("extra lib","lib",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) - -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") -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 octdigit=R("07") -local lowercase=R("az") -local uppercase=R("AZ") -local underscore=P("_") -local hexdigit=digit+lowercase+uppercase -local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") -local newline=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 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_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) -patterns.stripper=stripper -patterns.fullstripper=fullstripper -patterns.collapser=collapser -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.octdigit=octdigit -patterns.hexdigit=hexdigit -patterns.sign=sign -patterns.cardinal=digit^1 -patterns.integer=sign^-1*digit^1 -patterns.unsigned=digit^0*period*digit^1 -patterns.float=sign^-1*patterns.unsigned -patterns.cunsigned=digit^0*comma*digit^1 -patterns.cpunsigned=digit^0*(period+comma)*digit^1 -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.octal=patterns.oct -patterns.HEX=zero*P("X")*(digit+uppercase)^1 -patterns.hex=zero*P("x")*(digit+lowercase)^1 -patterns.hexadecimal=zero*S("xX")*hexdigit^1 -patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigit^1+hexdigit^1*period*hexdigit^0+hexdigit^1)*(S("pP")*sign^-1*hexdigit^1)^-1 -patterns.decafloat=sign^-1*(digit^0*period*digit^1+digit^1*period*digit^0+digit^1)*S("eE")*sign^-1*digit^1 -patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring -patterns.somecontent=(anything-newline-space)^1 -patterns.beginline=#(1-newline) -patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(P(-1)+Cc(" ")))^0)) -local function anywhere(pattern) - return P { P(pattern)+1*V(1) } -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 -local nany=utf8char/"" -function lpeg.counter(pattern) - pattern=Cs((P(pattern)/" "+nany)^0) - return function(str) - return #lpegmatch(pattern,str) - 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 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 - else - p=p+P(k)*making(v) - end - end - end - if t[""] then - p=p+p_true - end - return p - end - 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)*making(v) - end - end - 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 - 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 -function lpeg.utfchartabletopattern(list) - 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 make(tree) -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 -local trailingzeros=zero^0*-digit -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) -lpeg.patterns.stripzeros=stripper -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 - -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 longtostring=patterns.longtostring -function string.strip(str) - return lpegmatch(stripper,str) or "" -end -function string.fullstrip(str) - return lpegmatch(fullstripper,str) or "" -end -function string.collapsespaces(str) - return lpegmatch(collapser,str) or "" -end -function string.longtostring(str) - return lpegmatch(longtostring,str) or "" -end -local pattern=P(" ")^0*P(-1) -function string.is_empty(str) - if 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 - -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,ipairs,select=type,next,tostring,tonumber,ipairs,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.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 -local reserved=table.tohash { - 'and','break','do','else','elseif','end','false','for','function','if', - 'in','local','nil','not','or','repeat','return','then','true','until','while', - 'NaN','goto', -} -local function simple_table(t) - local nt=#t - if nt>0 then - local n=0 - for _,v in next,t do - n=n+1 - 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) - 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 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 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=simple_table(v) - 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 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 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 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=simple_table(v) - 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 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 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 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 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 - if functions==nil then - functions=true - end - if compact==nil then - compact=true - end - if inline==nil then - inline=compact - end - else - noquotes=false - hexify=false - handle=_handle or print - compact=true - inline=true - functions=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 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 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 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) - for ka,va in next,a do - local vb=b[ka] - if va==vb then - elseif type(va)=="table" and type(vb)=="table" then - if not identical(va,vb) then - return false - end - else - return false - end - end - return true -end -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.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 - for i=1,floor(n/2) do - local j=n-i+1 - t[i],t[j]=t[j],t[i] - end - return t - end -end -function table.sequenced(t,sep,simple) - if not t then - return "" - end - local n=#t - local s={} - if n>0 then - for i=1,n do - s[i]=tostring(t[i]) - end - else - n=0 - for k,v in sortedhash(t) do - if simple then - if v==true then - n=n+1 - s[n]=k - elseif v and v~="" then - n=n+1 - s[n]=k.."="..tostring(v) - end - else - n=n+1 - s[n]=k.."="..tostring(v) - end - end - end - return concat(s,sep or " | ") -end -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 - -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 -number=number or {} -local number=number -if bit32 then - local btest,bor=bit32.btest,bit32.bor - function number.bit(p) - return 2^(p-1) - end - number.hasbit=btest - number.setbit=bor - function number.setbit(x,p) - 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 - function number.bit(p) - return 2^(p-1) - end - function number.hasbit(x,p) - 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 -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 -local one=lpeg.C(1-lpeg.S('')/tonumber)^1 -function number.toset(n) - return lpegmatch(one,tostring(n)) -end -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 - -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" -} -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 - function math.round(x) return floor(x+0.5) end -end -if not math.div then - 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 -if not math.sind then - 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 - -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 byte,find,gsub,format=string.byte,string.find,string.gsub,string.format -local concat=table.concat -local floor=math.floor -local type=type -if string.find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator="\\",";" -else - io.fileseparator,io.pathseparator="/",":" -end -local function readall(f) - return f:read("*all") -end -local function readall(f) - local size=f:seek("end") - if size==0 then - return "" - elseif size<1024*1024 then - f:seek("set",0) - return f:read('*all') - else - local done=f:seek("set",0) - local step - if size<1024*1024 then - step=1024*1024 - elseif size>16*1024*1024 then - 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 - end -end -io.readall=readall -function io.loaddata(filename,textmode) - local f=io.open(filename,(textmode and 'r') or 'rb') - if f then - local data=readall(f) - f:close() - if #data>0 then - return data - end - end -end -function io.savedata(filename,data,joiner) - local f=io.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() - io.flush() - return true - else - return false - end -end -function io.loadlines(filename,n) - local f=io.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[#lines+1]=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 -function io.loadchunk(filename,n) - local f=io.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=io.open(filename) - if f==nil then - return false - else - f:close() - return true - end -end -function io.size(filename) - local f=io.open(filename) - if f==nil then - return 0 - else - local s=f:seek("end") - f:close() - return s - end -end -function io.noflines(f) - if type(f)=="string" then - local f=io.open(filename) - if f then - local n=f and io.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 -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 - io.write(question) - if options then - io.write(format(" [%s]",concat(options,"|"))) - end - if default then - io.write(format(" [%s]",default)) - end - io.write(format(" ")) - io.flush() - local answer=io.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 256*a+b - elseif n==3 then - local a,b,c=byte(f:read(3),1,3) - return 256*256*a+256*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 - elseif n==8 then - local a,b=readnumber(f,4),readnumber(f,4) - return 256*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 - elseif n==-2 then - local b,a=byte(f:read(2),1,2) - return 256*a+b - elseif n==-3 then - local c,b,a=byte(f:read(3),1,3) - return 256*256*a+256*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 - 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 - 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 -function os.resultof(command) - local handle=iopopen(command,"r") - if handle then - local result=handle:read("*all") or "" - handle:close() - return result - else - return "" - end -end -if not io.fileseparator then - if find(os.getenv("PATH"),";",1,true) then - io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "mswin" - 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="$BROWSER %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 "" -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 -if platform~="" then - os.platform=platform -elseif os.type=="windows" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("PROCESSOR_ARCHITECTURE") or "" - if find(architecture,"AMD64",1,true) then - platform="win64" - else - platform="mswin" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end -elseif name=="linux" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="linux-64" - elseif find(architecture,"ppc",1,true) then - platform="linux-ppc" - else - platform="linux" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end -elseif name=="macosx" then - function resolvers.platform(t,k) - local platform,architecture="",os.resultof("echo $HOSTTYPE") or "" - if architecture=="" then - platform="osx-intel" - elseif find(architecture,"i386",1,true) then - platform="osx-intel" - elseif find(architecture,"x86_64",1,true) then - platform="osx-64" - else - platform="osx-ppc" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end -elseif name=="sunos" then - function resolvers.platform(t,k) - local platform,architecture="",os.resultof("uname -m") or "" - if find(architecture,"sparc",1,true) then - platform="solaris-sparc" - else - platform="solaris-intel" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end -elseif name=="freebsd" then - function resolvers.platform(t,k) - local platform,architecture="",os.resultof("uname -m") or "" - if find(architecture,"amd64",1,true) then - platform="freebsd-amd64" - else - platform="freebsd" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - end -elseif name=="kfreebsd" then - function resolvers.platform(t,k) - local platform,architecture="",os.getenv("HOSTTYPE") or os.resultof("uname -m") or "" - if find(architecture,"x86_64",1,true) then - platform="kfreebsd-amd64" - else - platform="kfreebsd-i386" - end - os.setenv("MTX_PLATFORM",platform) - os.platform=platform - return platform - 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%400==0) or ((year%100~=0) and (year%4==0)) -end -os.isleapyear=isleapyear -local days={ 31,28,31,30,31,30,31,31,30,31,30,31 } -local function nofdays(year,month) - if not month then - return isleapyear(year) and 365 or 364 - else - return month==2 and isleapyear(year) and 29 or days[month] - end -end -os.nofdays=nofdays -function os.weekday(day,month,year) - return date("%w",time { year=year,month=month,day=day })+1 -end -function os.validdate(year,month,day) - if month<1 then - month=1 - elseif month>12 then - month=12 - end - if day<1 then - day=1 - else - local max=nofdays(year,month) - if day>max then - day=max - end - end - return year,month,day -end - -end -- 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 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 -end -function lfs.isfile(name) - return attributes(name,"mode")=="file" -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(stripper,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 -file.readdata=io.loaddata -file.savedata=io.savedata -function file.copy(oldname,newname) - if oldname and newname then - local data=io.loaddata(oldname) - if data and data~="" then - file.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 - -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 - 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 - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - action(full) - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end - if dirs then - for i=1,#dirs do - glob_pattern_function(dirs[i],patt,recurse,action) - end - end - end -end -local function glob_pattern_table(path,patt,recurse,result) - if not result then - result={} - end - if isdir(path) then - local usedpath - if path=="/" then - usedpath="/." - elseif not find(path,"/$") then - usedpath=path.."/." - path=path.."/" - else - usedpath=path - end - local dirs - for name in walkdir(usedpath) do - if name~="." and name~=".." then - local full=path..name - local mode=attributes(full,'mode') - if mode=='file' then - if not patt or find(full,patt) then - result[#result+1]=full - end - elseif recurse and mode=="directory" then - if not dirs then - dirs={ full } - else - dirs[#dirs+1]=full - end - end - end - end - if dirs then - for i=1,#dirs do - glob_pattern_table(dirs[i],patt,recurse,result) - end - end - end - return result -end -local function globpattern(path,patt,recurse,method) - local kind=type(method) - if patt and sub(patt,1,-3)==path then - patt=false - end - if kind=="function" then - return glob_pattern_function(path,patt,recurse,method) - elseif kind=="table" then - return glob_pattern_table(path,patt,recurse,method) - else - return glob_pattern_table(path,patt,recurse,{}) - end -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 -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) - insert(stack,currentdir()) - if newdir and newdir~="" then - chdir(newdir) - 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 - local floor,char=math.floor,string.char - 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 -if not utf.byte then - local utf8byte=patterns.utf8byte - function utf.byte(c) - return lpegmatch(utf8byte,c) - 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 - 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 -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,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) - end -end -local function big(b) - if b<0x10000 then - return char(b/256,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) - 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 - -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=tonumber,type -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 -url=url or {} -local url=url -local tochar=function(s) return char(tonumber(s,16)) end -local colon=P(":") -local qmark=P("?") -local hash=P("#") -local slash=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 -local noslash=P("/")/"" -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 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) -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(((escapedchar+1)-equal )^0) -local value=Cs(((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 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=nil - 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, - } -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 fullurl,f={},0 - local scheme,authority,path,query,fragment=hash.scheme,hash.authority,hash.path,hash.query,hash.fragment - if scheme and scheme~="" then - f=f+1;fullurl[f]=scheme.."://" - end - if authority and authority~="" then - f=f+1;fullurl[f]=authority - end - if path and path~="" then - f=f+1;fullurl[f]="/"..path - end - if query and query~="" then - f=f+1;fullurl[f]="?"..query - end - if fragment and fragment~="" then - f=f+1;fullurl[f]="#"..fragment - end - return lpegmatch(escaper,concat(fullurl)) -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 1cd0c280c6e..4b302285523 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--2016 by +-- Copyright (C) 2009--2017 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.4, - date = "2016-04-06", + version = 2.5, + date = "2017-02-01", description = "ConTeXt Lua libraries -- basic collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua index 81ac65e506d..bc691d53635 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-dir.lua @@ -335,6 +335,36 @@ end dir.globfiles = globfiles +local function globdirs(path,recurse,func,files) -- func == pattern or function + 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 + --- skip + 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 + +-- inspect(globdirs("e:/tmp")) + -- t = dir.glob("c:/data/develop/context/sources/**/????-*.tex") -- t = dir.glob("c:/data/develop/tex/texmf/**/*.tex") -- t = dir.glob("c:/data/develop/context/texmf/**/*.tex") @@ -557,9 +587,13 @@ file.expandname = dir.expandname -- for convenience local stack = { } function dir.push(newdir) - insert(stack,currentdir()) + local curdir = currentdir() + insert(stack,curdir) if newdir and newdir ~= "" then chdir(newdir) + return newdir + else + return curdir 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 deleted file mode 100644 index db833a05eb0..00000000000 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-extended-merged.lua +++ /dev/null @@ -1,3233 +0,0 @@ --- merged file : lualibs-extended-merged.lua --- parent file : lualibs-extended.lua --- merge date : Wed Apr 6 23:53:30 2016 - -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=string.format,string.gsub,string.rep,string.sub -local load,dump=load,string.dump -local tonumber,type,tostring=tonumber,type,tostring -local unpack,concat=table.unpack,table.concat -local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc -local patterns,lpegmatch=lpeg.patterns,lpeg.match -local utfchar,utfbyte=utf.char,utf.byte -local loadstripped=nil -if _LUAVERSION<5.2 then - loadstripped=function(str,shortcuts) - return load(str) - end -else - loadstripped=function(str,shortcuts) - if shortcuts then - return load(dump(load(str),true),nil,nil,shortcuts) - else - return load(dump(load(str),true)) - end - end -end -if not number then number={} end -local stripper=patterns.stripzeros -local newline=patterns.newline -local endofstring=patterns.endofstring -local whitespace=patterns.whitespace -local spacer=patterns.spacer -local spaceortab=patterns.spaceortab -local function points(n) - n=tonumber(n) - return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) -end -local function basepoints(n) - n=tonumber(n) - return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536)) -end -number.points=points -number.basepoints=basepoints -local rubish=spaceortab^0*newline -local anyrubish=spaceortab+newline -local anything=patterns.anything -local stripped=(spaceortab^1/"")*newline -local leading=rubish^0/"" -local trailing=(anyrubish^1*endofstring)/"" -local redundant=rubish^3/"\n" -local pattern=Cs(leading*(trailing+redundant+stripped+anything)^0) -function strings.collapsecrlf(str) - return lpegmatch(pattern,str) -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+patterns.anything - )^1) -function strings.tabtospace(str,tab) - return lpegmatch(pattern,str,1,tab or 7) -end -local space=spacer^0 -local nospace=space/"" -local endofline=nospace*newline -local stripend=(whitespace^1*endofstring)/"" -local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) -local stripempty=endofline^1/"" -local normalempty=endofline^1 -local singleempty=endofline*(endofline^0/"") -local doubleempty=endofline*endofline^-1*(endofline^0/"") -local stripstart=stripempty^0 -local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 ) -local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 ) -local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 ) -local p_retain_normal=Cs ((normalline+normalempty )^0 ) -local p_retain_collapse=Cs ((normalline+doubleempty )^0 ) -local p_retain_noempty=Cs ((normalline+singleempty )^0 ) -local striplinepatterns={ - ["prune"]=p_prune_normal, - ["prune and collapse"]=p_prune_collapse, - ["prune and no empty"]=p_prune_noempty, - ["retain"]=p_retain_normal, - ["retain and collapse"]=p_retain_collapse, - ["retain and no empty"]=p_retain_noempty, - ["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 -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 zero=P("0")^1/"" -local plus=P("+")/"" -local minus=P("-") -local separator=S(".") -local digit=R("09") -local trailing=zero^1*#S("eE") -local exponent=(S("eE")*(plus+Cs((minus*zero^0*P(-1))/"")+minus)*zero^0*(P(-1)*Cc("0")+P(1)^1)) -local pattern_a=Cs(minus^0*digit^1*(separator/""*trailing+separator*(trailing+digit)^0)*exponent) -local pattern_b=Cs((exponent+P(1))^0) -function number.sparseexponent(f,n) - if not n then - n=f - f="%e" - end - local tn=type(n) - if tn=="string" then - local m=tonumber(n) - if m then - return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,m)) - end - elseif tn=="number" then - return lpegmatch((f=="%e" or f=="%E") and pattern_a or pattern_b,format(f,n)) - end - return tostring(n) -end -local template=[[ -%s -%s -return function(%s) return %s end -]] -local preamble,environment="",{} -if _LUAVERSION<5.2 then - preamble=[[ -local lpeg=lpeg -local type=type -local tostring=tostring -local tonumber=tonumber -local format=string.format -local concat=table.concat -local signed=number.signed -local points=number.points -local basepoints= number.basepoints -local utfchar=utf.char -local utfbyte=utf.byte -local lpegmatch=lpeg.match -local nspaces=string.nspaces -local tracedchar=string.tracedchar -local autosingle=string.autosingle -local autodouble=string.autodouble -local sequenced=table.sequenced -local formattednumber=number.formatted -local sparseexponent=number.sparseexponent - ]] -else - environment={ - global=global or _G, - lpeg=lpeg, - type=type, - tostring=tostring, - tonumber=tonumber, - format=string.format, - concat=table.concat, - signed=number.signed, - points=number.points, - basepoints=number.basepoints, - utfchar=utf.char, - utfbyte=utf.byte, - lpegmatch=lpeg.match, - nspaces=string.nspaces, - tracedchar=string.tracedchar, - autosingle=string.autosingle, - autodouble=string.autodouble, - sequenced=table.sequenced, - formattednumber=number.formatted, - sparseexponent=number.sparseexponent, - } -end -local arguments={ "a1" } -setmetatable(arguments,{ __index=function(t,k) - local v=t[k-1]..",a"..k - t[k]=v - return v - end -}) -local prefix_any=C((S("+- .")+R("09"))^0) -local prefix_tab=P("{")*C((1-P("}"))^0)*P("}")+C((1-R("az","AZ","09","%%"))^0) -local format_s=function(f) - n=n+1 - if f and f~="" then - 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_q=function() - n=n+1 - return format("(a%s and format('%%q',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_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("tostring(tonumber(a%s) or a%s)",n,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 digit=patterns.digit -local period=patterns.period -local three=digit*digit*digit -local splitter=Cs ( - (((1-(three^1*period))^1+C(three))*(Carg(1)*three)^1+C((1-period)^1))*(P(1)/""*Carg(2))*C(2) -) -patterns.formattednumber=splitter -function number.formatted(n,sep1,sep2) - local s=type(s)=="string" and n or format("%0.2f",n) - if sep1==true then - return lpegmatch(splitter,s,1,".",",") - elseif sep1=="." then - return lpegmatch(splitter,s,1,sep1,sep2 or ",") - elseif sep1=="," then - return lpegmatch(splitter,s,1,sep1,sep2 or ".") - else - return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") - end -end -local format_m=function(f) - n=n+1 - if not f or f=="" then - f="," - end - return format([[formattednumber(a%s,%q,".")]],n,f) -end -local format_M=function(f) - n=n+1 - if not f or f=="" then - f="." - end - return format([[formattednumber(a%s,%q,",")]],n,f) -end -local format_z=function(f) - n=n+(tonumber(f) or 1) - return "''" -end -local format_rest=function(s) - return format("%q",s) -end -local format_extension=function(extensions,f,name) - local extension=extensions[name] or "tostring(%s)" - local f=tonumber(f) or 1 - if f==0 then - return extension - elseif f==1 then - 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 - local t={} - for i=1,f do - n=n+1 - t[#t+1]="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("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("*") - )*(P(-1)+Carg(1)) - )^0, - ["s"]=(prefix_any*P("s"))/format_s, - ["q"]=(prefix_any*P("q"))/format_q, - ["i"]=(prefix_any*P("i"))/format_i, - ["d"]=(prefix_any*P("d"))/format_d, - ["f"]=(prefix_any*P("f"))/format_f, - ["F"]=(prefix_any*P("F"))/format_F, - ["g"]=(prefix_any*P("g"))/format_g, - ["G"]=(prefix_any*P("G"))/format_G, - ["e"]=(prefix_any*P("e"))/format_e, - ["E"]=(prefix_any*P("E"))/format_E, - ["x"]=(prefix_any*P("x"))/format_x, - ["X"]=(prefix_any*P("X"))/format_X, - ["o"]=(prefix_any*P("o"))/format_o, - ["S"]=(prefix_any*P("S"))/format_S, - ["Q"]=(prefix_any*P("Q"))/format_S, - ["N"]=(prefix_any*P("N"))/format_N, - ["c"]=(prefix_any*P("c"))/format_c, - ["C"]=(prefix_any*P("C"))/format_C, - ["r"]=(prefix_any*P("r"))/format_r, - ["h"]=(prefix_any*P("h"))/format_h, - ["H"]=(prefix_any*P("H"))/format_H, - ["u"]=(prefix_any*P("u"))/format_u, - ["U"]=(prefix_any*P("U"))/format_U, - ["p"]=(prefix_any*P("p"))/format_p, - ["b"]=(prefix_any*P("b"))/format_b, - ["t"]=(prefix_tab*P("t"))/format_t, - ["T"]=(prefix_tab*P("T"))/format_T, - ["l"]=(prefix_any*P("l"))/format_l, - ["L"]=(prefix_any*P("L"))/format_L, - ["I"]=(prefix_any*P("I"))/format_I, - ["w"]=(prefix_any*P("w"))/format_w, - ["W"]=(prefix_any*P("W"))/format_W, - ["j"]=(prefix_any*P("j"))/format_j, - ["J"]=(prefix_any*P("J"))/format_J, - ["m"]=(prefix_tab*P("m"))/format_m, - ["M"]=(prefix_tab*P("M"))/format_M, - ["z"]=(prefix_any*P("z"))/format_z, - ["a"]=(prefix_any*P("a"))/format_a, - ["A"]=(prefix_any*P("A"))/format_A, - ["*"]=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 direct=Cs ( - P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] -) -local function make(t,str) - local f - local p - 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 _LUAVERSION<5.2 then - function strings.formatters.new(noconcat) - local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_=preamble,_environment_={} } - setmetatable(t,{ __index=make,__call=use }) - return t - end -else - function strings.formatters.new(noconcat) - local e={} - for k,v in next,environment do - e[k]=v - end - local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_="",_environment_=e } - setmetatable(t,{ __index=make,__call=use }) - return t - end -end -local formatters=strings.formatters.new() -string.formatters=formatters -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("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"""+P(1))^0) -patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) -patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) -patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"')) -if _LUAVERSION<5.2 then - add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape") - add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape") - add(formatters,"lua",[[lpegmatch(luaescape,%s)]],"local luaescape = lpeg.patterns.luaescape") -else - add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape }) - add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) - add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) -end -local dquote=patterns.dquote -local equote=patterns.escaped+dquote/'\\"'+1 -local space=patterns.space -local cquote=Cc('"') -local pattern=Cs(dquote*(equote-P(-2))^0*dquote) -+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 - -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 extract=bit32.extract -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) - return f:seek("end") -end -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.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-0xFF-1 - else - return n - end -end -files.readcardinal1=files.readbyte -files.readcardinal=files.readcardinal1 -files.readinteger=files.readinteger1 -function files.readcardinal2(f) - local a,b=byte(f:read(2),1,2) - return 0x100*a+b -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 - else - return n - 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.readcardinal4(f) - local a,b,c,d=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) - local n=0x1000000*a+0x10000*b+0x100*c+d - if n>=0x8000000 then - return n-0xFFFFFFFF-1 - else - return n - 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 - else - return n+(0x100*c+d)/0xFFFF - end -end -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 - else - n=extract(n,30,2) - return n+m/0x4000 - 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 - -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=setmetatable,getmetatable,tonumber,tostring -local type,next,rawset,tonumber,tostring,load,select=type,next,rawset,tonumber,tostring,load,select -local lpegmatch,P,Cs,Cc=lpeg.match,lpeg.P,lpeg.Cs,lpeg.Cc -local 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 "," - if specification.preamble==true then - for f=1,#fields 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 - local field=ti[fields[f]] - if type(field)=="string" then - r[f]=lpegmatch(escape,field) - else - r[f]=tostring(field) - end - end - result[#result+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) - 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 - result[#result+1]=formatters["%s<entry n='%s'>"](s,k) - toxml(v,d+step,result,step) - result[#result+1]=formatters["%s</entry>"](s,k) - else - result[#result+1]=formatters["%s<%s>"](s,k) - toxml(v,d+step,result,step) - result[#result+1]=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) - else - result[#result+1]=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) - else - result[#result+1]=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 -function table.autokey(t,k) - local v={} - t[k]=v - return v -end -local selfmapper={ __index=function(t,k) t[k]=k return k end } -function table.twowaymapper(t) - if not t then - t={} - else - for i=0,#t do - local ti=t[i] - if ti then - local i=tostring(i) - t[i]=ti - t[ti]=i - end - end - t[""]=t[0] or "" - 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 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 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] - 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 - 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 - tt[i+1]=v - 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 - 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 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=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=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=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",{})) 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,type=setmetatable,getmetatable,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.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 - -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 comma=P(",") -local lbrace=P("{") -local rbrace=P("}") -local lparent=P("(") -local rparent=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 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 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=P(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 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 -patterns.settings_to_hash_a=pattern_a_s -patterns.settings_to_hash_b=pattern_b_s -patterns.settings_to_hash_c=pattern_c_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_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=P(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 -local cache_a={} -local cache_b={} -function parsers.groupedsplitat(symbol,withaction) - if not symbol then - symbol="," - end - local pattern=(withaction and cache_b or cache_a)[symbol] - if not pattern then - local symbols=S(symbol) - local separator=space^0*symbols*space^0 - local value=P(lbrace*C((nobrace+nestedbraces)^0)*rbrace)+C((nestedbraces+(1-(space^0*(symbols+P(-1)))))^0) - if withaction then - local withvalue=Carg(1)*value/function(f,s) return f(s) end - pattern=spaces*withvalue*(separator*withvalue)^0 - cache_b[symbol]=pattern - else - pattern=spaces*Ct(value*(separator*value)^0) - cache_a[symbol]=pattern - end - end - return pattern -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 wholeblob=Ct((newline^(specification.strict and -1 or 1)*record)^0) - return function(data,getheader) - if getheader then - local header,position=lpegmatch(headerline,data) - local data=lpegmatch(wholeblob,data,position) - return data,header - else - return lpegmatch(wholeblob,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*(C(cardinal)*(spacers*S(":-")*spacers*(C(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) )*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/2^16) -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=tonumber,tostring,rawset,type -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", - object=lbrace*Cf(Ct("")*V("pair")*(comma*V("pair"))^0,rawset)*rbrace, - pair=Cg(optionalws*key*optionalws*colon*V("value")), - array=Ct(lparent*V("value")*(comma*V("value"))^0*rparent), - value=optionalws*(jstring+V("object")+V("array")+jtrue+jfalse+jnull+jnumber+#rparent)*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 - -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 function starttiming(instance) - local timer=timers[instance or "notimer"] - local it=timer.timing or 0 - if it==0 then - timer.starttime=clock() - 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 then - local stoptime=clock() - local loadtime=stoptime-starttime - timer.stoptime=stoptime - timer.loadtime=timer.loadtime+loadtime - timer.timing=0 - return loadtime - end - end - return 0 -end -local function elapsed(instance) - if type(instance)=="number" then - return instance or 0 - else - local timer=timers[instance or "notimer"] - return timer and timer.loadtime or 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.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("luatex banner",function() - return 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)) - 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, used memory: %s, hash type: %s, hash chars: min(%s,40), symbol mask: %s (%s)", - jit and "luajit" or "lua", - 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=load,loadfile,type -utilities=utilities or {} -utilities.lua=utilities.lua or {} -local luautilities=utilities.lua -local report_lua=logs.reporter("system","lua") -local tracestripping=false -local forcestupidcompile=true -luautilities.stripcode=true -luautilities.alwaysstripcode=false -luautilities.nofstrippedchunks=0 -luautilities.nofstrippedbytes=0 -local strippedchunks={} -luautilities.strippedchunks=strippedchunks -luautilities.suffixes={ - tma="tma", - tmc=jit and "tmb" or "tmc", - lua="lua", - luc=jit and "lub" or "luc", - lui="lui", - luv="luv", - luj="luj", - tua="tua", - tuc="tuc", -} -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) - name=name or fullname - local code,message - if environment.loadpreprocessedfile then - code,message=environment.loadpreprocessedfile(fullname) - 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,forcestrip,name) - local code,message=load(code) - if not code then - report_lua("loading of file %a failed:\n\t%s",name,message or "no message") - end - 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.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 - -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=debug.getinfo -local type,next,tostring=type,next,tostring -local format,find=string.format,string.find -local is_boolean=string.is_boolean -utilities=utilities or {} -local debugger=utilities.debugger or {} -utilities.debugger=debugger -local counters={} -local names={} -local report=logs.reporter("debugger") -local function hook() - local f=getinfo(2) - 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) - end - else - n=f.name or f.namewhat or f.what - if not n or n=="" then - n="?" - end - if not names[n] then - names[n]=format("%42s : % 5i : %s",n,f.linedefined or 0,f.short_src or "unknown source") - end - end - counters[n]=(counters[n] or 0)+1 - end -end -function debugger.showstats(printer,threshold) - 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 } - 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 - printer(format("%8i %s\n",count,names[name])) - total=total+count - end - grandtotal=grandtotal+count - functions=functions+1 - 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)) -end -function debugger.savestats(filename,threshold) - local f=io.open(filename,'w') - if f then - debugger.showstats(function(str) f:write(str) end,threshold) - f:close() - end -end -function debugger.enable() - debug.sethook(hook,"c") -end -function debugger.disable() - debug.sethook() -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=tostring -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 - 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 fdd50b80ba3..9c55f8044ce 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--2016 by +-- Copyright (C) 2009--2017 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.4, - date = "2016-04-06", + version = 2.5, + date = "2017-02-01", description = "ConTeXt Lua libraries -- extended collection.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua index 7ed6370f260..f2a27ad1832 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-file.lua @@ -436,7 +436,7 @@ local deslasher = lpeg.replacer(S("\\/")^1,"/") function file.join(one, two, three, ...) if not two then - return one == "" and one or lpegmatch(stripper,one) + return one == "" and one or lpegmatch(reslasher,one) end if one == "" then return lpegmatch(stripper,three and concat({ two, three, ... },"/") or two) @@ -607,14 +607,17 @@ function file.robustname(str,strict) end end -file.readdata = io.loaddata -file.savedata = io.savedata +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 = io.loaddata(oldname) + local data = loaddata(oldname) if data and data ~= "" then - file.savedata(newname,data) + savedata(newname,data) end end end diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua index a91d44d8776..2039017b25d 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-io.lua @@ -7,6 +7,7 @@ if not modules then modules = { } end modules ['l-io'] = { } 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 @@ -30,15 +31,13 @@ local function readall(f) local size = f:seek("end") if size == 0 then return "" - elseif size < 1024*1024 then - f:seek("set",0) + end + f:seek("set",0) + if size < 1024*1024 then return f:read('*all') else - local done = f:seek("set",0) local step - if size < 1024*1024 then - step = 1024 * 1024 - elseif size > 16*1024*1024 then + if size > 16*1024*1024 then step = 16*1024*1024 else step = floor(size/(1024*1024)) * 1024 * 1024 / 8 @@ -58,9 +57,8 @@ end io.readall = readall function io.loaddata(filename,textmode) -- return nil if empty - local f = io.open(filename,(textmode and 'r') or 'rb') + local f = open(filename,(textmode and 'r') or 'rb') if f then - -- local data = f:read('*all') local data = readall(f) f:close() if #data > 0 then @@ -69,8 +67,55 @@ function io.loaddata(filename,textmode) -- return nil if empty 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 < 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 + end + end + g:close() + end + f:close() + flush() + end +end + function io.savedata(filename,data,joiner) - local f = io.open(filename,"wb") + local f = open(filename,"wb") if f then if type(data) == "table" then f:write(concat(data,joiner or "")) @@ -80,7 +125,7 @@ function io.savedata(filename,data,joiner) f:write(data or "") end f:close() - io.flush() + flush() return true else return false @@ -90,7 +135,7 @@ 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 = io.open(filename,'r') + local f = open(filename,'r') if not f then -- no file elseif n then @@ -118,7 +163,7 @@ function io.loadlines(filename,n) -- return nil if empty end function io.loadchunk(filename,n) - local f = io.open(filename,'rb') + local f = open(filename,'rb') if f then local data = f:read(n or 1024) f:close() @@ -129,7 +174,7 @@ function io.loadchunk(filename,n) end function io.exists(filename) - local f = io.open(filename) + local f = open(filename) if f == nil then return false else @@ -139,7 +184,7 @@ function io.exists(filename) end function io.size(filename) - local f = io.open(filename) + local f = open(filename) if f == nil then return 0 else @@ -149,11 +194,11 @@ function io.size(filename) end end -function io.noflines(f) +local function noflines(f) if type(f) == "string" then - local f = io.open(filename) + local f = open(filename) if f then - local n = f and io.noflines(f) or 0 + local n = f and noflines(f) or 0 f:close() return n else @@ -169,6 +214,10 @@ function io.noflines(f) end end +io.noflines = noflines + +-- inlined is faster + local nextchar = { [ 4] = function(f) return f:read(1,1,1,1) @@ -250,16 +299,16 @@ end function io.ask(question,default,options) while true do - io.write(question) + write(question) if options then - io.write(format(" [%s]",concat(options,"|"))) + write(format(" [%s]",concat(options,"|"))) end if default then - io.write(format(" [%s]",default)) + write(format(" [%s]",default)) end - io.write(format(" ")) - io.flush() - local answer = io.read() + write(format(" ")) + flush() + local answer = read() answer = gsub(answer,"^%s*(.*)%s*$","%1") if answer == "" and default then return default diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua index b90f37e3db3..35715383635 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-lua.lua @@ -198,3 +198,4 @@ if flush then local popen = io.popen if popen then function io.popen (...) flush() return popen (...) end 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 001ca31f773..c6f1e33597b 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-number.lua @@ -13,6 +13,7 @@ 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 @@ -205,3 +206,25 @@ end function number.bits(n) return { bits(n,1) } 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 diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua index e9dc2bbbcff..be8f397aee3 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-string.lua @@ -75,19 +75,19 @@ local collapser = patterns.collapser local longtostring = patterns.longtostring function string.strip(str) - return lpegmatch(stripper,str) or "" + return str and lpegmatch(stripper,str) or "" end function string.fullstrip(str) - return lpegmatch(fullstripper,str) or "" + return str and lpegmatch(fullstripper,str) or "" end function string.collapsespaces(str) - return lpegmatch(collapser,str) or "" + return str and lpegmatch(collapser,str) or "" end function string.longtostring(str) - return lpegmatch(longtostring,str) or "" + return str and lpegmatch(longtostring,str) or "" end -- function string.is_empty(str) @@ -99,7 +99,7 @@ local pattern = P(" ")^0 * P(-1) -- maybe also newlines -- patterns.onlyspaces = pattern function string.is_empty(str) - if str == "" then + if not str or str == "" then return true else return lpegmatch(pattern,str) and true or false @@ -163,7 +163,7 @@ function string.escapedpattern(str,simple) end function string.topattern(str,lowercase,strict) - if str=="" or type(str) ~= "string" then + if str == "" or type(str) ~= "string" then return ".*" elseif strict then str = lpegmatch(pattern_c,str) @@ -177,6 +177,7 @@ function string.topattern(str,lowercase,strict) end end +-- print(string.escapedpattern("abc*234",true)) -- print(string.escapedpattern("12+34*.tex",false)) -- print(string.escapedpattern("12+34*.tex",true)) -- print(string.topattern ("12+34*.tex",false,false)) diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua index 552097e1c10..39357bd25e6 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-table.lua @@ -478,7 +478,7 @@ function table.fromhash(t) return hsh end -local noquotes, hexify, handle, compact, inline, functions +local noquotes, hexify, handle, compact, inline, functions, metacheck local reserved = table.tohash { -- intercept a language inconvenience: no reserved words as key 'and', 'break', 'do', 'else', 'elseif', 'end', 'false', 'for', 'function', 'if', @@ -608,7 +608,8 @@ local function do_serialize(root,name,depth,level,indexed) if compact then last = #root for k=1,last do - if root[k] == nil then + -- if root[k] == nil then + if rawget(root,k) == nil then last = k - 1 break end @@ -673,6 +674,8 @@ local function do_serialize(root,name,depth,level,indexed) else handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) -- %.99g end + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then handle(format("%s %s=0x%X,",depth,k,v)) @@ -695,6 +698,8 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then handle(format("%s [%s]=%q,",depth,k and "true" or "false",v)) + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%q,",depth,k,v)) else @@ -710,6 +715,8 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then handle(format("%s [%s]={},",depth,k and "true" or "false")) + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s={},",depth,k)) else @@ -726,6 +733,8 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", "))) + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s={ %s },",depth,k,concat(st,", "))) else @@ -746,6 +755,8 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false")) + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%s,",depth,k,v and "true" or "false")) else @@ -763,6 +774,8 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f)) + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=load(%q),",depth,k,f)) else @@ -778,6 +791,8 @@ local function do_serialize(root,name,depth,level,indexed) end elseif tk == "boolean" then handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v))) + elseif tk ~= "string" then + -- ignore elseif noquotes and not reserved[k] and lpegmatch(propername,k) then handle(format("%s %s=%q,",depth,k,tostring(v))) else @@ -803,6 +818,7 @@ local function serialize(_handle,root,name,specification) -- handle wins functions = specification.functions compact = specification.compact inline = specification.inline and compact + metacheck = specification.metacheck if functions == nil then functions = true end @@ -812,6 +828,9 @@ local function serialize(_handle,root,name,specification) -- handle wins if inline == nil then inline = compact end + if metacheck == nil then + metacheck = true + end else noquotes = false hexify = false @@ -819,6 +838,7 @@ local function serialize(_handle,root,name,specification) -- handle wins compact = true inline = true functions = true + metacheck = true end if tname == "string" then if name == "return" then @@ -843,8 +863,9 @@ local function serialize(_handle,root,name,specification) -- handle wins end if root then -- The dummy access will initialize a table that has a delayed initialization - -- using a metatable. (maybe explicitly test for metatable) - if getmetatable(root) then -- todo: make this an option, maybe even per subtable + -- using a metatable. (maybe explicitly test for metatable). This can crash on + -- metatables that check the index against a number. + 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 @@ -950,6 +971,41 @@ 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 -- 20% faster than unique(collapsed(t)) +table.collapsedhash = collapsedhash + local function unnest(t,f) -- only used in mk, for old times sake if not f then -- and only relevant for token lists f = { } -- this one can become obsolete @@ -1056,7 +1112,7 @@ function table.count(t) return n end -function table.swapped(t,s) -- hash +function table.swapped(t,s) -- hash, we need to make sure we don't mess up next local n = { } if s then for k, v in next, s do @@ -1069,7 +1125,14 @@ function table.swapped(t,s) -- hash return n end -function table.mirrored(t) -- hash +function table.hashed(t) -- list, add hash to index (save because we are not yet mixed + for i=1,#t do + t[t[i]] = i + end + return t +end + +function table.mirrored(t) -- hash, we need to make sure we don't mess up next local n = { } for k, v in next, t do n[v] = k @@ -1165,7 +1228,7 @@ function table.has_one_entry(t) return t and next(t,next(t)) == nil end --- new +-- new (rather basic, not indexed and nested) function table.loweredkeys(t) -- maybe utf local l = { } 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 f4c4e555787..12a4f646ff4 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-trac-inf.lua @@ -14,7 +14,7 @@ if not modules then modules = { } end modules ['trac-inf'] = { 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 -- should go in environment +local clock = os.gettimeofday or os.clock -- should go in environment local setmetatableindex = table.setmetatableindex local serialize = table.serialize @@ -61,12 +61,13 @@ local function stoptiming(instance) timer.timing = it - 1 else local starttime = timer.starttime - if starttime then - local stoptime = clock() - local loadtime = stoptime - starttime - timer.stoptime = stoptime - timer.loadtime = timer.loadtime + loadtime - timer.timing = 0 + if starttime and starttime > 0 then + local stoptime = clock() + local loadtime = stoptime - starttime + timer.stoptime = stoptime + timer.loadtime = timer.loadtime + loadtime + timer.timing = 0 + timer.starttime = 0 return loadtime end end @@ -183,6 +184,7 @@ end function statistics.runtime() stoptiming(statistics) + -- 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-util-fil.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua index 28c92c7c3c3..0f9731a2656 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-fil.lua @@ -6,8 +6,10 @@ if not modules then modules = { } end modules ['util-fil'] = { license = "see context related readme files" } -local byte = string.byte -local extract = bit32.extract +local byte = string.byte +local char = string.char +local extract = bit32 and bit32.extract +local floor = math.floor -- 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 @@ -36,6 +38,8 @@ function files.size(f) return f:seek("end") end +files.getsize = files.size + function files.setposition(f,n) if zerobased[f] then f:seek("set",n) @@ -90,7 +94,8 @@ end function files.readinteger1(f) -- one byte local n = byte(f:read(1)) if n >= 0x80 then - return n - 0xFF - 1 + -- return n - 0xFF - 1 + return n - 0x100 else return n end @@ -104,12 +109,27 @@ 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) local n = 0x100 * a + b if n >= 0x8000 then - return n - 0xFFFF - 1 + -- return n - 0xFFFF - 1 + return n - 0x10000 + else + return n + 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 else return n end @@ -119,17 +139,57 @@ 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) + local n = 0x10000 * a + 0x100 * b + c + if n >= 0x80000 then + -- return n - 0xFFFFFF - 1 + return n - 0x1000000 + else + return n + 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 + else + return n + 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) local n = 0x1000000 * a + 0x10000 * b + 0x100 * c + d if n >= 0x8000000 then - return n - 0xFFFFFFFF - 1 + -- return n - 0xFFFFFFFF - 1 + return n - 0x100000000 + else + return n + 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 else return n end @@ -139,23 +199,28 @@ 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 - 0xFFFF - 1 + (0x100 * c + d)/0xFFFF + return n - 0x10000 + (0x100 * c + d)/0xFFFF else return n + (0x100 * c + d)/0xFFFF end end -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 - else - n = extract(n,30,2) - return n + m/0x4000 +if extract then + + 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 + else + n = extract(n,30,2) + return n + m/0x4000 + end end + end function files.skipshort(f,n) @@ -165,3 +230,32 @@ end function files.skiplong(f,n) f:read(4*(n or 1)) 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) +end + +function files.writecardinal4(f,n) + local a = char(n % 256) + n = floor(n/256) + local b = char(n % 256) + n = floor(n/256) + local c = char(n % 256) + n = floor(n/256) + 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 + 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 bbe25d89df8..e835c07d648 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-jsn.lua @@ -64,18 +64,19 @@ local jnumber = (1-whitespace-rparent-rbrace-comma)^1 / tonumber local key = jstring local jsonconverter = { "value", - object = lbrace * Cf(Ct("") * V("pair") * (comma * V("pair"))^0,rawset) * rbrace, - pair = Cg(optionalws * key * optionalws * colon * V("value")), - array = Ct(lparent * V("value") * (comma * V("value"))^0 * rparent), - value = optionalws * (jstring + V("object") + V("array") + jtrue + jfalse + jnull + jnumber + #rparent) * optionalws, + hash = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace, + pair = Cg(optionalws * key * optionalws * colon * V("value")), + array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent), +-- value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber + #rparent) * optionalws, + value = optionalws * (jstring + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws, } -- local jsonconverter = { "value", --- object = lbrace * Cf(Ct("") * V("pair") * (comma * V("pair"))^0,rawset) * rbrace, --- pair = Cg(optionalws * V("string") * optionalws * colon * V("value")), --- array = Ct(lparent * V("value") * (comma * V("value"))^0 * rparent), --- string = jstring, --- value = optionalws * (V("string") + V("object") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws, +-- hash = lbrace * Cf(Ct("") * (V("pair") * (comma * V("pair"))^0 + optionalws),rawset) * rbrace, +-- pair = Cg(optionalws * V("string") * optionalws * colon * V("value")), +-- array = Ct(lparent * (V("value") * (comma * V("value"))^0 + optionalws) * rparent), +-- string = jstring, +-- value = optionalws * (V("string") + V("hash") + V("array") + jtrue + jfalse + jnull + jnumber) * optionalws, -- } -- lpeg.print(jsonconverter) -- size 181 @@ -156,3 +157,5 @@ end -- inspect(tmp) -- inspect(json.tostring(true)) + +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 e1dcdc94d57..b3346006c94 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-lua.lua @@ -158,3 +158,21 @@ end -- luautilities.registerdatatype(lpeg.P("!"),"lpeg") -- -- print(luautilities.datatype(lpeg.P("oeps"))) + +-- These finalizers will only be invoked when we have a proper lua_close +-- call (which is not happening in luatex tex node yes) or finish with an +-- os.exit(n,true). + +local finalizers = { } + +setmetatable(finalizers, { + __gc = function(t) + for i=1,#t do + pcall(t[i]) -- let's not crash + end + end +} ) + +function luautilities.registerfinalizer(f) + finalizers[#finalizers+1] = f +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 01138f1bbb3..650a7ead6ae 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-prs.lua @@ -36,6 +36,8 @@ 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 @@ -44,8 +46,9 @@ local newline = lpegpatterns.newline local anything = lpegpatterns.anything local endofstring = lpegpatterns.endofstring -local nobrace = 1 - (lbrace + rbrace ) -local noparent = 1 - (lparent + rparent) +local nobrace = 1 - (lbrace + rbrace ) +local noparent = 1 - (lparent + rparent) +local nobracket = 1 - (lbracket + rbracket) -- we could use a Cf Cg construct @@ -56,11 +59,12 @@ lpegpatterns.balanced = P { [2] = left * V(1) * right } -local nestedbraces = P { lbrace * (nobrace + V(1))^0 * rbrace } -local nestedparents = P { lparent * (noparent + V(1))^0 * rparent } -local spaces = space^0 -local argument = Cs((lbrace/"") * ((nobrace + nestedbraces)^0) * (rbrace/"")) -local content = (1-endofstring)^0 +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 -- no capture lpegpatterns.nestedparents = nestedparents -- no capture @@ -79,10 +83,6 @@ local pattern_b = spaces * comma^0 * spaces * (key * ((spaces * equal * spaces * -- "a=1, b=2, c=3, d={a{b,c}d}, e=12345, f=xx{a{b,c}d}xx, g={}" : outer {} removes, leading spaces ignored --- todo: rewrite to fold etc --- --- parse = lpeg.Cf(lpeg.Carg(1) * lpeg.Cg(key * equal * value) * separator^0,rawset)^0 -- lpeg.match(parse,"...",1,hash) - local hash = { } local function set(key,value) @@ -193,6 +193,33 @@ function parsers.settings_to_array(str,strict) end end +function parsers.settings_to_numbers(str) + if not str or str == "" then + return { } + end + if type(str) == "table" then + -- fall through + elseif find(str,",",1,true) then + str = lpegmatch(pattern,str) + else + return { tonumber(str) } + end + for i=1,#str do + str[i] = tonumber(str[i]) + end + return str +end + +local value = P(lbrace * C((nobrace + nestedbraces)^0) * rbrace) + + C((nestedbraces + nestedbrackets + nestedparents + (1-comma))^0) +local pattern = spaces * Ct(value*(separator*value)^0) + +function parsers.settings_to_array_obey_fences(str) + return lpegmatch(pattern,str) +end + +-- inspect(parsers.settings_to_array_obey_fences("url(http://a,b.c)")) + -- this one also strips end spaces before separators -- -- "{123} , 456 " -> "123" "456" 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 95534c8d87f..fb510257a2f 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-str.lua @@ -10,7 +10,7 @@ utilities = utilities or { } utilities.strings = utilities.strings or { } local strings = utilities.strings -local format, gsub, rep, sub = string.format, string.gsub, string.rep, string.sub +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 unpack, concat = table.unpack, table.concat @@ -385,6 +385,43 @@ function number.signed(i) end end +-- maybe to util-num + +local digit = patterns.digit +local period = patterns.period +local three = digit * digit * digit + +local splitter = Cs ( + (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1)) + * (P(1)/"" * Carg(2)) * C(2) +) + +patterns.formattednumber = splitter + +function number.formatted(n,sep1,sep2) + local s = type(s) == "string" and n or format("%0.2f",n) + if sep1 == true then + return lpegmatch(splitter,s,1,".",",") + elseif sep1 == "." then + return lpegmatch(splitter,s,1,sep1,sep2 or ",") + elseif sep1 == "," then + return lpegmatch(splitter,s,1,sep1,sep2 or ".") + else + return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") + end +end + +-- print(number.formatted(1)) +-- print(number.formatted(12)) +-- print(number.formatted(123)) +-- print(number.formatted(1234)) +-- print(number.formatted(12345)) +-- print(number.formatted(123456)) +-- print(number.formatted(1234567)) +-- print(number.formatted(12345678)) +-- print(number.formatted(12345678,true)) +-- print(number.formatted(1234.56,"!","?")) + local zero = P("0")^1 / "" local plus = P("+") / "" local minus = P("-") @@ -732,43 +769,6 @@ local format_W = function(f) -- handy when doing depth related indent return format("nspaces[%s]",tonumber(f) or 0) end --- maybe to util-num - -local digit = patterns.digit -local period = patterns.period -local three = digit * digit * digit - -local splitter = Cs ( - (((1 - (three^1 * period))^1 + C(three)) * (Carg(1) * three)^1 + C((1-period)^1)) - * (P(1)/"" * Carg(2)) * C(2) -) - -patterns.formattednumber = splitter - -function number.formatted(n,sep1,sep2) - local s = type(s) == "string" and n or format("%0.2f",n) - if sep1 == true then - return lpegmatch(splitter,s,1,".",",") - elseif sep1 == "." then - return lpegmatch(splitter,s,1,sep1,sep2 or ",") - elseif sep1 == "," then - return lpegmatch(splitter,s,1,sep1,sep2 or ".") - else - return lpegmatch(splitter,s,1,sep1 or ",",sep2 or ".") - end -end - --- print(number.formatted(1)) --- print(number.formatted(12)) --- print(number.formatted(123)) --- print(number.formatted(1234)) --- print(number.formatted(12345)) --- print(number.formatted(123456)) --- print(number.formatted(1234567)) --- print(number.formatted(12345678)) --- print(number.formatted(12345678,true)) --- print(number.formatted(1234.56,"!","?")) - local format_m = function(f) n = n + 1 if not f or f == "" then @@ -801,9 +801,16 @@ end local format_extension = function(extensions,f,name) local extension = extensions[name] or "tostring(%s)" local f = tonumber(f) or 1 + local w = find(extension,"%.%.%.") if f == 0 then + if w then + extension = gsub(extension,"%.%.%.","") + end return extension elseif f == 1 then + if w then + extension = gsub(extension,"%.%.%.","%%s") + end n = n + 1 local a = "a" .. n return format(extension,a,a) -- maybe more times? @@ -811,10 +818,16 @@ local format_extension = function(extensions,f,name) local a = "a" .. (n + f + 1) return format(extension,a,a) else + if w then + extension = gsub(extension,"%.%.%.",rep("%%s,",f-1).."%%s") + end + -- we could fill an array and then n = n + 1 unpack(t,n,n+f) but as we + -- cache we don't save much and there are hardly any extensions anyway local t = { } for i=1,f do n = n + 1 - t[#t+1] = "a" .. n + -- t[#t+1] = "a" .. n + t[i] = "a" .. n end return format(extension,unpack(t)) end @@ -822,6 +835,10 @@ end -- aA b cC d eE f gG hH iI jJ lL mM N o p qQ r sS tT uU wW xX z +-- extensions : %!tag! + +-- can be made faster but not called that often + local builder = Cs { "start", start = ( ( @@ -850,10 +867,10 @@ local builder = Cs { "start", + V("a") -- new + V("A") -- new + V("j") + V("J") -- stripped e E - + V("m") + V("M") -- new + + V("m") + V("M") -- new (formatted number) + V("z") -- new -- - -- + V("?") -- ignores probably messed up % + -- + V("?") -- ignored, probably messed up % ) + V("*") ) 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 a6239adf409..0521a2a4f14 100644 --- a/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua +++ b/Master/texmf-dist/tex/luatex/lualibs/lualibs-util-tab.lua @@ -12,7 +12,7 @@ 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 = setmetatable, getmetatable, tonumber, tostring +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 @@ -169,7 +169,8 @@ function table.tocsv(t,specification) r[f] = tostring(field) end end - result[#result+1] = concat(r,separator) + -- result[#result+1] = concat(r,separator) + result[i+1] = concat(r,separator) end return concat(result,"\n") else @@ -485,11 +486,12 @@ end local selfmapper = { __index = function(t,k) t[k] = k return k end } -function table.twowaymapper(t) - if not t then - t = { } - else - for i=0,#t do +function table.twowaymapper(t) -- takes a 0/1 .. n indexed table and returns + if not t then -- it with string-numbers as indices + reverse + t = { } -- mapping (all strings) .. used in cvs etc but + else -- typically a helper that one forgets about + local zero = rawget(t,0) -- so it might move someplace else + for i=zero and 0 or 1,#t do local ti = t[i] -- t[1] = "one" if ti then local i = tostring(i) @@ -497,7 +499,6 @@ function table.twowaymapper(t) t[ti] = i -- t["one"] = "1" end end - t[""] = t[0] or "" end -- setmetatableindex(t,"key") setmetatable(t,selfmapper) @@ -616,7 +617,8 @@ local function serialize(root,name,specification) return nil end end - local haszero = t[0] + -- local haszero = t[0] + local haszero = rawget(t,0) -- don't trigger meta if n == nt then local tt = { } for i=1,nt do @@ -680,7 +682,8 @@ local function serialize(root,name,specification) local last = 0 last = #root for k=1,last do - if root[k] == nil then + if rawget(root,k) == nil then + -- if root[k] == nil then last = k - 1 break end @@ -810,9 +813,10 @@ local function serialize(root,name,specification) if root then -- The dummy access will initialize a table that has a delayed initialization - -- using a metatable. (maybe explicitly test for metatable) + -- using a metatable. (maybe explicitly test for metatable). This can crash on + -- metatables that check the index against a number. if getmetatable(root) then -- todo: make this an option, maybe even per subtable - local dummy = root._w_h_a_t_e_v_e_r_ + local dummy = root._w_h_a_t_e_v_e_r_ -- needed root._w_h_a_t_e_v_e_r_ = nil end -- Let's forget about empty tables. @@ -833,5 +837,10 @@ end table.serialize = serialize if setinspector then - setinspector("table",function(v) if type(v) == "table" then print(serialize(v,"table",{})) return true end end) + setinspector("table",function(v) + if type(v) == "table" then + print(serialize(v,"table",{ metacheck = false })) + return true + end + end) end diff --git a/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua b/Master/texmf-dist/tex/luatex/lualibs/lualibs.lua index 9810fd7b46a..1181bd1d840 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--2016 by +-- Copyright (C) 2009--2017 by -- PRAGMA ADE / ConTeXt Development Team -- The LuaLaTeX Dev Team -- @@ -25,8 +25,8 @@ lualibs = lualibs or { } lualibs.module_info = { name = "lualibs", - version = 2.4, - date = "2016-04-06", + version = 2.5, + date = "2017-02-01", description = "ConTeXt Lua standard libraries.", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", |