summaryrefslogtreecommitdiff
path: root/macros/luatex/generic
diff options
context:
space:
mode:
Diffstat (limited to 'macros/luatex/generic')
-rw-r--r--macros/luatex/generic/lualibs/NEWS6
-rw-r--r--macros/luatex/generic/lualibs/README.md9
-rw-r--r--macros/luatex/generic/lualibs/lualibs-basic-merged.lua641
-rw-r--r--macros/luatex/generic/lualibs/lualibs-dir.lua12
-rw-r--r--macros/luatex/generic/lualibs/lualibs-extended-merged.lua1173
-rw-r--r--macros/luatex/generic/lualibs/lualibs-file.lua2
-rw-r--r--macros/luatex/generic/lualibs/lualibs-gzip.lua180
-rw-r--r--macros/luatex/generic/lualibs/lualibs-io.lua10
-rw-r--r--macros/luatex/generic/lualibs/lualibs-lpeg.lua12
-rw-r--r--macros/luatex/generic/lualibs/lualibs-math.lua16
-rw-r--r--macros/luatex/generic/lualibs/lualibs-os.lua748
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-deb.lua22
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-jsn.lua19
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-prs.lua67
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-sac.lua582
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-str.lua59
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-tab.lua54
-rw-r--r--macros/luatex/generic/lualibs/lualibs-util-zip.lua684
-rw-r--r--macros/luatex/generic/lualibs/lualibs.dtx31
-rw-r--r--macros/luatex/generic/lualibs/lualibs.pdfbin81627 -> 81128 bytes
20 files changed, 3336 insertions, 991 deletions
diff --git a/macros/luatex/generic/lualibs/NEWS b/macros/luatex/generic/lualibs/NEWS
index cf8a853b6c..889232dc47 100644
--- a/macros/luatex/generic/lualibs/NEWS
+++ b/macros/luatex/generic/lualibs/NEWS
@@ -1,6 +1,12 @@
History of the lualibs package
+2022/10/04 v2.75/
+ * sync with Context current as of 2022/10/04.
+ * add util-sac
+ * Replace l-gzip with util-zip
+
2021/05/20 v2.74/
* sync with Context current as of 2021/05/20.
+
2020/12/30 v2.73/
* sync with Context current as of 2020/12/30.
diff --git a/macros/luatex/generic/lualibs/README.md b/macros/luatex/generic/lualibs/README.md
index e2cd6be9bd..09194115ce 100644
--- a/macros/luatex/generic/lualibs/README.md
+++ b/macros/luatex/generic/lualibs/README.md
@@ -1,10 +1,10 @@
# The Lualibs Package
-VERSION: 2.74
+VERSION: 2.75
-DATE: 2021-05-20
+DATE: 2022-10-04
-FONTLOADERDATE: 2021-05-20
+FONTLOADERDATE: 2022-10-04
Lualibs is a collection of Lua modules useful for general programming.
@@ -47,7 +47,6 @@ See the 'NEWS' file for version history.
| lualibs-compat.lua |tex/luatex/lualibs/lualibs-compat.lua
| lualibs-dir.lua |tex/luatex/lualibs/lualibs-dir.lua
| lualibs-file.lua | tex/luatex/lualibs/lualibs-file.lua
-| lualibs-gzip.lua | tex/luatex/lualibs/lualibs-gzip.lua
| lualibs-function.lua | tex/luatex/lualibs/lualibs-function.lua
| lualibs-io.lua | tex/luatex/lualibs/lualibs-io.lua
| lualibs-lpeg.lua | tex/luatex/lualibs/lualibs-lpeg.lua
@@ -68,11 +67,13 @@ See the 'NEWS' file for version history.
| lualibs-util-jsn.lua | tex/luatex/lualibs/lualibs-util-jsn.lua
| lualibs-util-lua.lua | tex/luatex/lualibs/lualibs-util-lua.lua
| lualibs-util-prs.lua | tex/luatex/lualibs/lualibs-util-prs.lua
+| lualibs-util-sac.lua | tex/luatex/lualibs/lualibs-util-sac.lua
| lualibs-util-sta.lua | tex/luatex/lualibs/lualibs-util-sta.lua
| lualibs-util-sto.lua | tex/luatex/lualibs/lualibs-util-sto.lua
| lualibs-util-str.lua | tex/luatex/lualibs/lualibs-util-str.lua
| lualibs-util-tab.lua | tex/luatex/lualibs/lualibs-util-tab.lua
| lualibs-util-tpl.lua | tex/luatex/lualibs/lualibs-util-tpl.lua
+| lualibs-util-zip.lua | tex/luatex/lualibs/lualibs-util-zip.lua
| LICENSE | doc/luatex/lualibs/LICENSE
| NEWS | doc/luatex/lualibs/NEWS
| README | doc/luatex/lualibs/README
diff --git a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua
index ac98df379a..690a3160ac 100644
--- a/macros/luatex/generic/lualibs/lualibs-basic-merged.lua
+++ b/macros/luatex/generic/lualibs/lualibs-basic-merged.lua
@@ -1,6 +1,6 @@
-- merged file : lualibs-basic-merged.lua
-- parent file : lualibs-basic.lua
--- merge date : 2021-05-20 23:14
+-- merge date : 2022-10-04 17:16
do -- begin closure to overcome local limits and interference
@@ -2737,8 +2737,14 @@ if not math.ceiling then
math.ceiling=math.ceil
end
if not math.round then
- local floor=math.floor
- function math.round(x) return floor(x+0.5) end
+ if xmath then
+ math.round=xmath.round
+ else
+ local floor=math.floor
+ function math.round(x)
+ return x<0 and -floor(-x+0.5) or floor(x+0.5)
+ end
+ end
end
if not math.div then
local floor=math.floor
@@ -2808,7 +2814,7 @@ if not math.tointeger then
end
if not math.ult then
local floor=math.floor
- function math.tointeger(m,n)
+ function math.ult(m,n)
return floor(m)<floor(n)
end
end
@@ -2882,9 +2888,12 @@ function io.copydata(source,target,action)
flush()
end
end
-function io.savedata(filename,data,joiner)
- local f=open(filename,"wb")
+function io.savedata(filename,data,joiner,append)
+ local f=open(filename,append and "ab" or "wb")
if f then
+ if append and joiner and f:seek("end")>0 then
+ f:write(joiner)
+ end
if type(data)=="table" then
f:write(concat(data,joiner or ""))
elseif type(data)=="function" then
@@ -3172,10 +3181,10 @@ if not modules then modules={} end modules ['l-os']={
license="see context related readme files"
}
local os=os
-local date,time=os.date,os.time
+local date,time,difftime=os.date,os.time,os.difftime
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 random,ceil,randomseed,modf=math.random,math.ceil,math.randomseed,math.modf
local type,setmetatable,tonumber,tostring=type,setmetatable,tonumber,tostring
do
local selfdir=os.selfdir
@@ -3273,7 +3282,7 @@ if not os.__getenv__ then
osenv[K]=v
end
function os.getenv(k)
- local K=upper(k)
+ local K=upper(k)
local v=osenv[K] or osgetenv(K) or osgetenv(k)
if v=="" then
return nil
@@ -3291,22 +3300,6 @@ if not os.__getenv__ then
setmetatable(os.env,{ __index=__index,__newindex=__newindex } )
end
end
-local execute=os.execute
-local iopopen=io.popen
-local function resultof(command)
- local handle=iopopen(command,"r")
- if handle then
- local result=handle:read("*all") or ""
- handle:close()
- return result
- else
- return ""
- end
-end
-os.resultof=resultof
-function os.pipeto(command)
- return iopopen(command,"w")
-end
if not io.fileseparator then
if find(os.getenv("PATH"),";",1,true) then
io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows"
@@ -3321,228 +3314,231 @@ if os.type=="windows" then
else
os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' }
end
-local launchers={
- windows="start %s",
- macosx="open %s",
- unix="xdg-open %s &> /dev/null &",
-}
-function os.launch(str)
- local command=format(launchers[os.name] or launchers.unix,str)
- execute(command)
-end
-local gettimeofday=os.gettimeofday or os.clock
-os.gettimeofday=gettimeofday
-local startuptime=gettimeofday()
-function os.runtime()
- return gettimeofday()-startuptime
-end
-local resolvers=os.resolvers or {}
-os.resolvers=resolvers
-setmetatable(os,{ __index=function(t,k)
- local r=resolvers[k]
- return r and r(t,k) or nil
-end })
-local name,platform=os.name or "linux",os.getenv("MTX_PLATFORM") or ""
-if platform~="" then
- os.platform=platform
-elseif os.type=="windows" then
- function resolvers.platform(t,k)
- local architecture=os.getenv("PROCESSOR_ARCHITECTURE") or ""
- local platform=""
- if find(architecture,"AMD64",1,true) then
- platform="win64"
+do
+ local execute=os.execute
+ local iopopen=io.popen
+ local ostype=os.type
+ local function resultof(command)
+ local handle=iopopen(command,ostype=="windows" and "rb" or "r")
+ if handle then
+ local result=handle:read("*all") or ""
+ handle:close()
+ return result
else
- platform="mswin"
+ return ""
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform=platform
- return platform
end
-elseif name=="linux" then
- function resolvers.platform(t,k)
- local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or ""
- local platform=os.getenv("MTX_PLATFORM") or ""
+ os.resultof=resultof
+ function os.pipeto(command)
+ return iopopen(command,"w")
+ end
+ local launchers={
+ windows="start %s",
+ macosx="open %s",
+ unix="xdg-open %s &> /dev/null &",
+ }
+ function os.launch(str)
+ local command=format(launchers[os.name] or launchers.unix,str)
+ execute(command)
+ end
+end
+do
+ local gettimeofday=os.gettimeofday or os.clock
+ os.gettimeofday=gettimeofday
+ local startuptime=gettimeofday()
+ function os.runtime()
+ return gettimeofday()-startuptime
+ end
+end
+do
+ local name=os.name or "linux"
+ local platform=os.getenv("MTX_PLATFORM") or ""
+ local architecture=os.uname and os.uname().machine
+ local bits=os.getenv("MTX_BITS") or find(platform,"64") and 64 or 32
+ if platform~="" then
+ elseif os.type=="windows" then
+ architecture=string.lower(architecture or os.getenv("PROCESSOR_ARCHITECTURE") or "")
+ if architecture=="x86_64" then
+ bits,platform=64,"win64"
+ elseif find(architecture,"amd64") then
+ bits,platform=64,"win64"
+ elseif find(architecture,"arm64") then
+ bits,platform=64,"windows-arm64"
+ elseif find(architecture,"arm32") then
+ bits,platform=32,"windows-arm32"
+ else
+ bits,platform=32,"mswin"
+ end
+ elseif name=="linux" then
+ architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
local musl=find(os.selfdir or "","linuxmusl")
- if platform~="" then
- elseif find(architecture,"x86_64",1,true) then
- platform=musl and "linuxmusl" or "linux-64"
- elseif find(architecture,"ppc",1,true) then
- platform="linux-ppc"
+ if find(architecture,"x86_64") then
+ bits,platform=64,musl and "linuxmusl" or "linux-64"
+ elseif find(architecture,"ppc") then
+ bits,platform=32,"linux-ppc"
else
- platform=musl and "linuxmusl" or "linux"
+ bits,platform=32,musl and "linuxmusl" or "linux"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform=platform
- return platform
- end
-elseif name=="macosx" then
- function resolvers.platform(t,k)
- local architecture=resultof("echo $HOSTTYPE") or ""
- local platform=""
+ elseif name=="macosx" then
+ architecture=architecture or 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"
- elseif find(architecture,"arm64",1,true) then
- platform="osx-arm"
+ bits,platform=64,"osx-intel"
+ elseif find(architecture,"i386") then
+ bits,platform=64,"osx-intel"
+ elseif find(architecture,"x86_64") then
+ bits,platform=64,"osx-64"
+ elseif find(architecture,"arm64") then
+ bits,platform=64,"osx-arm"
else
- platform="osx-ppc"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform=platform
- return platform
- end
-elseif name=="sunos" then
- function resolvers.platform(t,k)
- local architecture=resultof("uname -m") or ""
- local platform=""
- if find(architecture,"sparc",1,true) then
- platform="solaris-sparc"
+ bits,platform=32,"osx-ppc"
+ end
+ elseif name=="sunos" then
+ architecture=architecture or resultof("uname -m") or ""
+ if find(architecture,"sparc") then
+ bits,platform=32,"solaris-sparc"
else
- platform="solaris-intel"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform=platform
- return platform
- end
-elseif name=="freebsd" then
- function resolvers.platform(t,k)
- local architecture=resultof("uname -m") or ""
- local platform=""
- if find(architecture,"amd64",1,true) then
- platform="freebsd-amd64"
+ bits,platform=32,"solaris-intel"
+ end
+ elseif name=="freebsd" then
+ architecture=architecture or os.getenv("MACHTYPE") or resultof("uname -m") or ""
+ if find(architecture,"amd64") or find(architecture,"AMD64") then
+ bits,platform=64,"freebsd-amd64"
else
- platform="freebsd"
- end
- os.setenv("MTX_PLATFORM",platform)
- os.platform=platform
- return platform
- end
-elseif name=="kfreebsd" then
- function resolvers.platform(t,k)
- local architecture=os.getenv("HOSTTYPE") or resultof("uname -m") or ""
- local platform=""
- if find(architecture,"x86_64",1,true) then
- platform="kfreebsd-amd64"
+ bits,platform=32,"freebsd"
+ end
+ elseif name=="kfreebsd" then
+ architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+ if architecture=="x86_64" then
+ bits,platform=64,"kfreebsd-amd64"
+ else
+ bits,platform=32,"kfreebsd-i386"
+ end
+ else
+ architecture=architecture or resultof("uname -m") or ""
+ if find(architecture,"aarch64") then
+ bits,platform="linux-aarch64"
+ elseif find(architecture,"armv7l") then
+ bits,platform=32,"linux-armhf"
+ elseif find(architecture,"mips64") or find(architecture,"mips64el") then
+ bits,platform=64,"linux-mipsel"
+ elseif find(architecture,"mipsel") or find(architecture,"mips") then
+ bits,platform=32,"linux-mipsel"
else
- platform="kfreebsd-i386"
+ bits,platform=64,"linux-64"
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
+ os.setenv("MTX_PLATFORM",platform)
+ os.setenv("MTX_BITS",bits)
+ os.platform=platform
+ os.bits=bits
+ os.newline=name=="windows" and "\013\010" or "\010"
+end
+do
+ 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
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(date("%H")) or 0)-(tonumber(date("!%H")) or 0))
- if delta then
- if d>0 then
- return format("+%02i:00",d)
+do
+ local hour,min
+ function os.timezone(difference)
+ if not hour then
+ local current=time()
+ local utcdate=date("!*t",current)
+ local localdate=date("*t",current)
+ localdate.isdst=false
+ local timediff=difftime(time(localdate),time(utcdate))
+ hour,min=modf(timediff/3600)
+ min=min*60
+ end
+ if difference then
+ return hour,min
else
- return format("-%02i:00",-d)
+ return format("%+03d:%02d",hour,min)
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)
+ local timeformat=format("%%s%s",os.timezone())
+ 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
+ function os.today()
+ return date("!*t")
+ end
+ function os.now()
+ return date("!%Y-%m-%d %H:%M:%S")
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
+do
+ local cache={}
+ local function which(filename)
+ local fullname=cache[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
+ cache[filename]=fullname
end
- if not fullname then
- fullname=false
- end
- memory[filename]=fullname
+ return 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")
+ os.which=which
+ os.where=which
end
if not os.sleep then
local socket=socket
@@ -3553,65 +3549,69 @@ if not os.sleep then
socket.sleep(n)
end
end
-local function isleapyear(year)
- return (year%4==0) and (year%100~=0 or year%400==0)
-end
-os.isleapyear=isleapyear
-local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
-local function nofdays(year,month,day)
- if not month then
- return isleapyear(year) and 365 or 364
- elseif not day then
- return month==2 and isleapyear(year) and 29 or days[month]
- else
- for i=1,month-1 do
- day=day+days[i]
- end
- if month>2 and isleapyear(year) then
- day=day+1
+do
+ local function isleapyear(year)
+ return (year%4==0) and (year%100~=0 or year%400==0)
+ end
+ os.isleapyear=isleapyear
+ local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
+ local function nofdays(year,month,day)
+ if not month then
+ return isleapyear(year) and 365 or 364
+ elseif not day then
+ return month==2 and isleapyear(year) and 29 or days[month]
+ else
+ for i=1,month-1 do
+ day=day+days[i]
+ end
+ if month>2 and isleapyear(year) then
+ day=day+1
+ end
+ return day
end
- return day
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
+ os.nofdays=nofdays
+ function os.weekday(day,month,year)
+ return date("%w",time { year=year,month=month,day=day })+1
end
- if day<1 then
- day=1
- else
- local max=nofdays(year,month)
- if day>max then
- day=max
+ 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
- return year,month,day
-end
-function os.date(fmt,...)
- if not fmt then
- fmt="%Y-%m-%d %H:%M"
+ function os.date(fmt,...)
+ if not fmt then
+ fmt="%Y-%m-%d %H:%M"
+ end
+ return date(fmt,...)
end
- return date(fmt,...)
end
-local osexit=os.exit
-local exitcode=nil
-function os.setexitcode(code)
- exitcode=code
-end
-function os.exit(c)
- if exitcode~=nil then
- return osexit(exitcode)
+do
+ local osexit=os.exit
+ local exitcode=nil
+ function os.setexitcode(code)
+ exitcode=code
end
- if c~=nil then
- return osexit(c)
+ function os.exit(c)
+ if exitcode~=nil then
+ return osexit(exitcode)
+ end
+ if c~=nil then
+ return osexit(c)
+ end
+ return osexit()
end
- return osexit()
end
end -- closure
@@ -3872,7 +3872,7 @@ function file.join(one,two,three,...)
if not two then
return one=="" and one or lpegmatch(reslasher,one)
end
- if one=="" then
+ if not one or one=="" then
return lpegmatch(stripper,three and concat({ two,three,... },"/") or two)
end
if lpegmatch(isnetwork,one) then
@@ -4031,87 +4031,6 @@ 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"
-}
-gzip=gzip or {}
-if not zlib then
- zlib=xzip
-elseif not xzip then
- xzip=zlib
-end
-if zlib then
- local suffix=file.suffix
- local suffixes=file.suffixes
- local find=string.find
- local openfile=io.open
- local gzipwindow=15+16
- local gziplevel=3
- local identifier="^\x1F\x8B\x08"
- local compress=zlib.compress
- local decompress=zlib.decompress
- function gzip.load(filename)
- local f=openfile(filename,"rb")
- if not f then
- else
- local data=f:read("*all")
- f:close()
- if data and data~="" then
- if suffix(filename)=="gz" then
- data=decompress(data,gzipwindow)
- end
- return data
- end
- end
- end
- function gzip.save(filename,data,level)
- if suffix(filename)~="gz" then
- filename=filename..".gz"
- end
- local f=openfile(filename,"wb")
- if f then
- data=compress(data or "",level or gziplevel,nil,gzipwindow)
- f:write(data)
- f:close()
- return #data
- end
- end
- function gzip.suffix(filename)
- local suffix,extra=suffixes(filename)
- local gzipped=extra=="gz"
- return suffix,gzipped
- end
- function gzip.compressed(s)
- return s and find(s,identifier)
- end
- function gzip.compress(s,level)
- if s and not find(s,identifier) then
- if not level then
- level=gziplevel
- elseif level<=0 then
- return s
- elseif level>9 then
- level=9
- end
- return compress(s,level or gziplevel,nil,gzipwindow) or s
- end
- end
- function gzip.decompress(s)
- if s and find(s,identifier) then
- return decompress(s,gzipwindow)
- else
- return s
- end
- end
-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",
@@ -4389,15 +4308,15 @@ 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)
+ (Cs(P(".")+slash^1)+Cs(R("az","AZ")*P(":")*slash^0)+Cc("./"))*V(2)*V(3),
+ Cs(((1-S("*?/\\"))^0*slash)^0),
+ 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)
+ (C(P(".")+P("/")^1)+Cc("./"))*V(2)*V(3),
+ C(((1-S("*?/"))^0*P("/"))^0),
+ C(P(1)^0)
}
end
local filter=Cs ((
diff --git a/macros/luatex/generic/lualibs/lualibs-dir.lua b/macros/luatex/generic/lualibs/lualibs-dir.lua
index 325039cb1e..ac8e2f4e8e 100644
--- a/macros/luatex/generic/lualibs/lualibs-dir.lua
+++ b/macros/luatex/generic/lualibs/lualibs-dir.lua
@@ -230,18 +230,18 @@ if onwindows then -- we could sanitize here
-- pattern = Ct {
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)
+ (Cs(P(".") + slash^1) + Cs(R("az","AZ") * P(":") * slash^0) + Cc("./")) * V(2) * V(3),
+ Cs(((1-S("*?/\\"))^0 * slash)^0),
+ Cs(P(1)^0)
}
else -- assume unix
-- pattern = Ct {
pattern = {
- [1] = (C(P(".") + P("/")^1) + Cc("./")) * V(2) * V(3),
- [2] = C(((1-S("*?/"))^0 * P("/"))^0),
- [3] = C(P(1)^0)
+ (C(P(".") + P("/")^1) + Cc("./")) * V(2) * V(3),
+ C(((1-S("*?/"))^0 * P("/"))^0),
+ C(P(1)^0)
}
end
diff --git a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua
index 9cd4487bf2..08428c51ac 100644
--- a/macros/luatex/generic/lualibs/lualibs-extended-merged.lua
+++ b/macros/luatex/generic/lualibs/lualibs-extended-merged.lua
@@ -1,6 +1,511 @@
-- merged file : lualibs-extended-merged.lua
-- parent file : lualibs-extended.lua
--- merge date : 2021-05-20 23:14
+-- merge date : 2022-10-04 17:16
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['util-sac']={
+ version=1.001,
+ optimize=true,
+ comment="companion to luat-lib.mkiv",
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local byte,sub=string.byte,string.sub
+local tonumber=tonumber
+utilities=utilities or {}
+local streams={}
+utilities.streams=streams
+function streams.open(filename,zerobased)
+ local f=filename and io.loaddata(filename)
+ if f then
+ return { f,1,#f,zerobased or false }
+ end
+end
+function streams.openstring(f,zerobased)
+ if f then
+ return { f,1,#f,zerobased or false }
+ end
+end
+function streams.getstring(f)
+ if f then
+ return f[1]
+ end
+end
+function streams.close()
+end
+function streams.size(f)
+ return f and f[3] or 0
+end
+streams.getsize=streams.size
+function streams.setposition(f,i)
+ if f[4] then
+ if i<=0 then
+ f[2]=1
+ else
+ f[2]=i+1
+ end
+ else
+ if i<=1 then
+ f[2]=1
+ else
+ f[2]=i
+ end
+ end
+end
+function streams.getposition(f)
+ if f[4] then
+ return f[2]-1
+ else
+ return f[2]
+ end
+end
+function streams.look(f,n,chars)
+ local b=f[2]
+ local e=b+n-1
+ if chars then
+ return sub(f[1],b,e)
+ else
+ return byte(f[1],b,e)
+ end
+end
+function streams.skip(f,n)
+ f[2]=f[2]+n
+end
+function streams.readbyte(f)
+ local i=f[2]
+ f[2]=i+1
+ return byte(f[1],i)
+end
+function streams.readbytes(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return byte(f[1],i,j-1)
+end
+function streams.readbytetable(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return { byte(f[1],i,j-1) }
+end
+function streams.skipbytes(f,n)
+ f[2]=f[2]+n
+end
+function streams.readchar(f)
+ local i=f[2]
+ f[2]=i+1
+ return sub(f[1],i,i)
+end
+function streams.readstring(f,n)
+ local i=f[2]
+ local j=i+n
+ f[2]=j
+ return sub(f[1],i,j-1)
+end
+function streams.readinteger1(f)
+ local i=f[2]
+ f[2]=i+1
+ local n=byte(f[1],i)
+ if n>=0x80 then
+ return n-0x100
+ else
+ return n
+ end
+end
+streams.readcardinal1=streams.readbyte
+streams.readcardinal=streams.readcardinal1
+streams.readinteger=streams.readinteger1
+function streams.readcardinal2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ return 0x100*a+b
+end
+function streams.readcardinal2le(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local b,a=byte(f[1],i,j)
+ return 0x100*a+b
+end
+function streams.readinteger2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ if a>=0x80 then
+ return 0x100*a+b-0x10000
+ else
+ return 0x100*a+b
+ end
+end
+function streams.readinteger2le(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local b,a=byte(f[1],i,j)
+ if a>=0x80 then
+ return 0x100*a+b-0x10000
+ else
+ return 0x100*a+b
+ end
+end
+function streams.readcardinal3(f)
+ local i=f[2]
+ local j=i+2
+ f[2]=j+1
+ local a,b,c=byte(f[1],i,j)
+ return 0x10000*a+0x100*b+c
+end
+function streams.readcardinal3le(f)
+ local i=f[2]
+ local j=i+2
+ f[2]=j+1
+ local c,b,a=byte(f[1],i,j)
+ return 0x10000*a+0x100*b+c
+end
+function streams.readinteger3(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c=byte(f[1],i,j)
+ if a>=0x80 then
+ return 0x10000*a+0x100*b+c-0x1000000
+ else
+ return 0x10000*a+0x100*b+c
+ end
+end
+function streams.readinteger3le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local c,b,a=byte(f[1],i,j)
+ if a>=0x80 then
+ return 0x10000*a+0x100*b+c-0x1000000
+ else
+ return 0x10000*a+0x100*b+c
+ end
+end
+function streams.readcardinal4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ return 0x1000000*a+0x10000*b+0x100*c+d
+end
+function streams.readcardinal4le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local d,c,b,a=byte(f[1],i,j)
+ return 0x1000000*a+0x10000*b+0x100*c+d
+end
+function streams.readinteger4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ if a>=0x80 then
+ return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+ return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function streams.readinteger4le(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local d,c,b,a=byte(f[1],i,j)
+ if a>=0x80 then
+ return 0x1000000*a+0x10000*b+0x100*c+d-0x100000000
+ else
+ return 0x1000000*a+0x10000*b+0x100*c+d
+ end
+end
+function streams.readfixed2(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local n1,n2=byte(f[1],i,j)
+ if n1>=0x80 then
+ n1=n1-0x100
+ end
+ return n1+n2/0xFF
+end
+function streams.readfixed4(f)
+ local i=f[2]
+ local j=i+3
+ f[2]=j+1
+ local a,b,c,d=byte(f[1],i,j)
+ local n1=0x100*a+b
+ local n2=0x100*c+d
+ if n1>=0x8000 then
+ n1=n1-0x10000
+ end
+ return n1+n2/0xFFFF
+end
+if bit32 then
+ local extract=bit32.extract
+ local band=bit32.band
+ function streams.read2dot14(f)
+ local i=f[2]
+ local j=i+1
+ f[2]=j+1
+ local a,b=byte(f[1],i,j)
+ if a>=0x80 then
+ local n=-(0x100*a+b)
+ return-(extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+ else
+ local n=0x100*a+b
+ return (extract(n,14,2)+(band(n,0x3FFF)/16384.0))
+ end
+ end
+end
+function streams.skipshort(f,n)
+ f[2]=f[2]+2*(n or 1)
+end
+function streams.skiplong(f,n)
+ f[2]=f[2]+4*(n or 1)
+end
+if sio and sio.readcardinal2 then
+ local readcardinal1=sio.readcardinal1
+ local readcardinal2=sio.readcardinal2
+ local readcardinal3=sio.readcardinal3
+ local readcardinal4=sio.readcardinal4
+ local readinteger1=sio.readinteger1
+ local readinteger2=sio.readinteger2
+ local readinteger3=sio.readinteger3
+ local readinteger4=sio.readinteger4
+ local readfixed2=sio.readfixed2
+ local readfixed4=sio.readfixed4
+ local read2dot14=sio.read2dot14
+ local readbytes=sio.readbytes
+ local readbytetable=sio.readbytetable
+ function streams.readcardinal1(f)
+ local i=f[2]
+ f[2]=i+1
+ return readcardinal1(f[1],i)
+ end
+ function streams.readcardinal2(f)
+ local i=f[2]
+ f[2]=i+2
+ return readcardinal2(f[1],i)
+ end
+ function streams.readcardinal3(f)
+ local i=f[2]
+ f[2]=i+3
+ return readcardinal3(f[1],i)
+ end
+ function streams.readcardinal4(f)
+ local i=f[2]
+ f[2]=i+4
+ return readcardinal4(f[1],i)
+ end
+ function streams.readinteger1(f)
+ local i=f[2]
+ f[2]=i+1
+ return readinteger1(f[1],i)
+ end
+ function streams.readinteger2(f)
+ local i=f[2]
+ f[2]=i+2
+ return readinteger2(f[1],i)
+ end
+ function streams.readinteger3(f)
+ local i=f[2]
+ f[2]=i+3
+ return readinteger3(f[1],i)
+ end
+ function streams.readinteger4(f)
+ local i=f[2]
+ f[2]=i+4
+ return readinteger4(f[1],i)
+ end
+ function streams.readfixed2(f)
+ local i=f[2]
+ f[2]=i+2
+ return readfixed2(f[1],i)
+ end
+ function streams.readfixed4(f)
+ local i=f[2]
+ f[2]=i+4
+ return readfixed4(f[1],i)
+ end
+ function streams.read2dot14(f)
+ local i=f[2]
+ f[2]=i+2
+ return read2dot14(f[1],i)
+ end
+ function streams.readbytes(f,n)
+ local i=f[2]
+ local s=f[3]
+ local p=i+n
+ if p>s then
+ f[2]=s+1
+ else
+ f[2]=p
+ end
+ return readbytes(f[1],i,n)
+ end
+ function streams.readbytetable(f,n)
+ local i=f[2]
+ local s=f[3]
+ local p=i+n
+ if p>s then
+ f[2]=s+1
+ else
+ f[2]=p
+ end
+ return readbytetable(f[1],i,n)
+ end
+ streams.readbyte=streams.readcardinal1
+ streams.readsignedbyte=streams.readinteger1
+ streams.readcardinal=streams.readcardinal1
+ streams.readinteger=streams.readinteger1
+end
+if sio and sio.readcardinaltable then
+ local readcardinaltable=sio.readcardinaltable
+ local readintegertable=sio.readintegertable
+ function utilities.streams.readcardinaltable(f,n,b)
+ local i=f[2]
+ local s=f[3]
+ local p=i+n*b
+ if p>s then
+ f[2]=s+1
+ else
+ f[2]=p
+ end
+ return readcardinaltable(f[1],i,n,b)
+ end
+ function utilities.streams.readintegertable(f,n,b)
+ local i=f[2]
+ local s=f[3]
+ local p=i+n*b
+ if p>s then
+ f[2]=s+1
+ else
+ f[2]=p
+ end
+ return readintegertable(f[1],i,n,b)
+ end
+else
+ local readcardinal1=streams.readcardinal1
+ local readcardinal2=streams.readcardinal2
+ local readcardinal3=streams.readcardinal3
+ local readcardinal4=streams.readcardinal4
+ function streams.readcardinaltable(f,n,b)
+ local i=f[2]
+ local s=f[3]
+ local p=i+n*b
+ if p>s then
+ f[2]=s+1
+ else
+ f[2]=p
+ end
+ local t={}
+ if b==1 then for i=1,n do t[i]=readcardinal1(f[1],i) end
+ elseif b==2 then for i=1,n do t[i]=readcardinal2(f[1],i) end
+ elseif b==3 then for i=1,n do t[i]=readcardinal3(f[1],i) end
+ elseif b==4 then for i=1,n do t[i]=readcardinal4(f[1],i) end end
+ return t
+ end
+ local readinteger1=streams.readinteger1
+ local readinteger2=streams.readinteger2
+ local readinteger3=streams.readinteger3
+ local readinteger4=streams.readinteger4
+ function streams.readintegertable(f,n,b)
+ local i=f[2]
+ local s=f[3]
+ local p=i+n*b
+ if p>s then
+ f[2]=s+1
+ else
+ f[2]=p
+ end
+ local t={}
+ if b==1 then for i=1,n do t[i]=readinteger1(f[1],i) end
+ elseif b==2 then for i=1,n do t[i]=readinteger2(f[1],i) end
+ elseif b==3 then for i=1,n do t[i]=readinteger3(f[1],i) end
+ elseif b==4 then for i=1,n do t[i]=readinteger4(f[1],i) end end
+ return t
+ end
+end
+do
+ local files=utilities.files
+ if files then
+ local openfile=files.open
+ local openstream=streams.open
+ local openstring=streams.openstring
+ local setmetatable=setmetatable
+ function io.newreader(str,method)
+ local f,m
+ if method=="string" then
+ f=openstring(str,true)
+ m=streams
+ elseif method=="stream" then
+ f=openstream(str,true)
+ m=streams
+ else
+ f=openfile(str,"rb")
+ m=files
+ end
+ if f then
+ local t={}
+ setmetatable(t,{
+ __index=function(t,k)
+ local r=m[k]
+ if k=="close" then
+ if f then
+ m.close(f)
+ f=nil
+ end
+ return function() end
+ elseif r then
+ local v=function(_,a,b) return r(f,a,b) end
+ t[k]=v
+ return v
+ else
+ print("unknown key",k)
+ end
+ end
+ } )
+ return t
+ end
+ end
+ end
+end
+if bit32 and not streams.tocardinal1 then
+ local extract=bit32.extract
+ local char=string.char
+ streams.tocardinal1=char
+ function streams.tocardinal2(n) return char(extract(8,8),extract(0,8)) end
+ function streams.tocardinal3(n) return char(extract(16,8),extract(8,8),extract(0,8)) end
+ function streams.tocardinal4(n) return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end
+ streams.tocardinal1le=char
+ function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end
+ function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end
+ function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end
+end
+if not streams.readcstring then
+ local readchar=streams.readchar
+ local concat=table.concat
+ function streams.readcstring(f)
+ local t={}
+ while true do
+ local c=readchar(f)
+ if c and c~="\0" then
+ t[#t+1]=c
+ else
+ return concat(t)
+ end
+ end
+ end
+end
+
+end -- closure
do -- begin closure to overcome local limits and interference
@@ -14,12 +519,13 @@ if not modules then modules={} end modules ['util-str']={
utilities=utilities or {}
utilities.strings=utilities.strings or {}
local strings=utilities.strings
-local format,gsub,rep,sub,find=string.format,string.gsub,string.rep,string.sub,string.find
+local format,gsub,rep,sub,find,char=string.format,string.gsub,string.rep,string.sub,string.find,string.char
local load,dump=load,string.dump
local tonumber,type,tostring,next,setmetatable=tonumber,type,tostring,next,setmetatable
local unpack,concat=table.unpack,table.concat
local 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 tsplitat=lpeg.tsplitat
local utfchar,utfbyte,utflen=utf.char,utf.byte,utf.len
local loadstripped=function(str,shortcuts)
if shortcuts then
@@ -373,6 +879,14 @@ patterns.escapedquotes=pattern
function string.escapedquotes(s)
return lpegmatch(pattern,s)
end
+local pattern=(1-P("\\"))^1;pattern=Cs (
+ pattern*((P("\\")/""*(digit^-3/function(s) return char(tonumber(s)) end))+pattern )^1
+)
+patterns.unescapedquotes=pattern
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+string.texnewlines=lpeg.replacer(patterns.newline,"\r",true)
local preamble=""
local environment={
global=global or _G,
@@ -908,7 +1422,6 @@ function number.to16dot16(n)
return f_16_16(n/65536.0)
end
if not string.explode then
- local tsplitat=lpeg.tsplitat
local p_utf=patterns.utf8character
local p_check=C(p_utf)*(P("+")*Cc(true))^0
local p_split=Ct(C(p_utf)^0)
@@ -928,6 +1441,20 @@ if not string.explode then
end
end
end
+do
+ local p_whitespace=patterns.whitespace^1
+ local cache=setmetatable({},{ __index=function(t,k)
+ local p=tsplitat(p_whitespace*P(k)*p_whitespace)
+ local v=function(s)
+ return lpegmatch(p,s)
+ end
+ t[k]=v
+ return v
+ end })
+ function string.wordsplitter(s)
+ return cache[s]
+ end
+end
end -- closure
@@ -1552,9 +2079,6 @@ if JITSUPPORTED then
return concat(fastserialize(t,true))
end
else
- local f_v=formatters["[%q]=%q,"]
- local f_t=formatters["[%q]="]
- local f_q=formatters["%q,"]
function table.fastserialize(t,prefix)
local r={ type(prefix)=="string" and prefix or "return" }
local m=1
@@ -1963,6 +2487,21 @@ function table.ordered(t)
return function() end
end
end
+function combine(target,source)
+ if target then
+ for k,v in next,source do
+ if type(v)=="table" then
+ target[k]=combine(target[k],source[k])
+ else
+ target[k]=v
+ end
+ end
+ return target
+ else
+ return source
+ end
+end
+table.combine=combine
end -- closure
@@ -2181,8 +2720,8 @@ local noparent=1-(lparent+rparent)
local nobracket=1-(lbracket+rbracket)
local escape,left,right=P("\\"),P('{'),P('}')
lpegpatterns.balanced=P {
- [1]=((escape*(left+right))+(1-(left+right))+V(2))^0,
- [2]=left*V(1)*right
+ ((escape*(left+right))+(1-(left+right))+V(2))^0,
+ left*V(1)*right
}
local nestedbraces=P { lbrace*(nobrace+V(1))^0*rbrace }
local nestedparents=P { lparent*(noparent+V(1))^0*rparent }
@@ -2190,11 +2729,12 @@ local nestedbrackets=P { lbracket*(nobracket+V(1))^0*rbracket }
local spaces=space^0
local argument=Cs((lbrace/"")*((nobrace+nestedbraces)^0)*(rbrace/""))
local content=(1-endofstring)^0
-lpegpatterns.nestedbraces=nestedbraces
-lpegpatterns.nestedparents=nestedparents
-lpegpatterns.nested=nestedbraces
-lpegpatterns.argument=argument
-lpegpatterns.content=content
+lpegpatterns.nestedbraces=nestedbraces
+lpegpatterns.nestedparents=nestedparents
+lpegpatterns.nestedbrackets=nestedbrackets
+lpegpatterns.nested=nestedbraces
+lpegpatterns.argument=argument
+lpegpatterns.content=content
local value=lbrace*C((nobrace+nestedbraces)^0)*rbrace+C((nestedbraces+(1-comma))^0)
local key=C((1-equal-comma)^1)
local pattern_a=(space+comma)^0*(key*equal*value+key*C(""))
@@ -2600,15 +3140,24 @@ local function ranger(first,last,n,action)
action(first)
end
end
-local cardinal=lpegpatterns.cardinal/tonumber
+local cardinal=(lpegpatterns.hexadecimal+lpegpatterns.cardinal)/tonumber
local spacers=lpegpatterns.spacer^0
local endofstring=lpegpatterns.endofstring
local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1
local stepper=spacers*(cardinal*(spacers*S(":-")*spacers*(cardinal+(P("*")+endofstring)*Cc(true) )+Cc(false) )*Carg(1)*Carg(2)/ranger*S(", ")^0 )^1*endofstring
function parsers.stepper(str,n,action)
+ local ts=type(str)
if type(n)=="function" then
- lpegmatch(stepper,str,1,false,n or print)
- else
+ if ts=="number" then
+ n(str)
+ elseif ts=="table" then
+ for i=1,#str do
+ n(str[i])
+ end
+ else
+ lpegmatch(stepper,str,1,false,n or print)
+ end
+ elseif ts=="string" then
lpegmatch(stepper,str,1,n,action or print)
end
end
@@ -2626,7 +3175,7 @@ local cache={}
local spaces=lpegpatterns.space^0
local dummy=function() end
setmetatableindex(cache,function(t,k)
- local separator=P(k)
+ local separator=S(k)
local value=(1-separator)^0
local pattern=spaces*C(value)*separator^0*Cp()
t[k]=pattern
@@ -2706,8 +3255,11 @@ local p_year=lpegpatterns.digit^4/tonumber
local pattern=Cf(Ct("")*(
(Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("day")*cardinal)
)+(Cg(Cc("day")*cardinal)*S("-/")*Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
+ )+(Cg(Cc("year")*p_year)*S("-/")*Cg(Cc("month")*cardinal)
+ )+(Cg(Cc("month")*cardinal)*S("-/")*Cg(Cc("year")*p_year)
)
- )*P(" ")*Cg(Cc("hour")*cardinal)*P(":")*Cg(Cc("min")*cardinal)*(P(":")*Cg(Cc("sec")*cardinal))^-1
+ )*(
+ P(" ")*Cg(Cc("hour")*cardinal)*P(":")*Cg(Cc("min")*cardinal)*(P(":")*Cg(Cc("sec")*cardinal))^-1+P(-1) )
,rawset)
lpegpatterns.splittime=pattern
function parsers.totime(str)
@@ -2914,6 +3466,9 @@ if not modules then modules={} end modules ['util-jsn']={
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files"
}
+if utilities and utilities.json then
+ return json
+end
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,gsub=string.format,string.gsub
@@ -3118,6 +3673,8 @@ do
k=lpegmatch(escaper,k) or k
v=lpegmatch(escaper,v) or v
n=n+1 t[n]=f_key_val_str(depth,k,v)
+ elseif i>1 then
+ n=n-1
end
elseif tv=="table" then
local l=#v
@@ -3133,6 +3690,8 @@ do
end
elseif next(v) then
tojsonpp(v,k,depth,level+1,0)
+ elseif i>1 then
+ n=n-1
end
elseif tv=="boolean" then
if tk=="number" then
@@ -3150,6 +3709,8 @@ do
else
t[n]=f_key_val_nop(depth,k)
end
+ elseif i>1 then
+ n=n-1
end
else
if tk=="number" then
@@ -3159,6 +3720,8 @@ do
k=lpegmatch(escaper,k) or k
n=n+1
t[n]=f_key_val_null(depth,k)
+ elseif i>1 then
+ n=n-1
end
end
end
@@ -3260,7 +3823,6 @@ do
return jsontostring(value,true)
end
end
-return json
end -- closure
@@ -3990,6 +4552,22 @@ local function showtraceback(rep)
end
end
debugger.showtraceback=showtraceback
+if luac then
+ local show,dump=luac.print,string.dump
+ function luac.inspect(v)
+ if type(v)=="function" then
+ local ok,str=xpcall(dump,function() end,v)
+ if ok then
+ v=str
+ end
+ end
+ if type(v)=="string" then
+ show(v,true)
+ else
+ print(v)
+ end
+ end
+end
end -- closure
@@ -4379,3 +4957,560 @@ function stacker.new(name)
end
end -- closure
+
+do -- begin closure to overcome local limits and interference
+
+if not modules then modules={} end modules ['util-zip']={
+ version=1.001,
+ author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright="PRAGMA ADE / ConTeXt Development Team",
+ license="see context related readme files"
+}
+local type,tostring,tonumber=type,tostring,tonumber
+local sort,concat=table.sort,table.concat
+local find,format,sub,gsub=string.find,string.format,string.sub,string.gsub
+local osdate,ostime,osclock=os.date,os.time,os.clock
+local ioopen=io.open
+local loaddata,savedata=io.loaddata,io.savedata
+local filejoin,isdir,dirname,mkdirs=file.join,lfs.isdir,file.dirname,dir.mkdirs
+local suffix,suffixes=file.suffix,file.suffixes
+local openfile=io.open
+gzip=gzip or {}
+if not zlib then
+ zlib=xzip
+elseif not xzip then
+ xzip=zlib
+end
+local files=utilities.files
+local openfile=files.open
+local closefile=files.close
+local readstring=files.readstring
+local readcardinal2=files.readcardinal2le
+local readcardinal4=files.readcardinal4le
+local setposition=files.setposition
+local getposition=files.getposition
+local band=bit32.band
+local rshift=bit32.rshift
+local lshift=bit32.lshift
+local zlibdecompress=zlib.decompress
+local zlibdecompresssize=zlib.decompresssize
+local zlibchecksum=zlib.crc32
+if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+ local cs=zlibchecksum
+ zlibchecksum=function(str,n) return cs(n or 0,str) end
+end
+local decompress=function(source) return zlibdecompress (source,-15) end
+local decompresssize=function(source,targetsize) return zlibdecompresssize(source,targetsize,-15) end
+local calculatecrc=function(buffer,initial) return zlibchecksum (initial or 0,buffer) end
+local zipfiles={}
+utilities.zipfiles=zipfiles
+local openzipfile,closezipfile,unzipfile,foundzipfile,getziphash,getziplist do
+ function openzipfile(name)
+ return {
+ name=name,
+ handle=openfile(name,0),
+ }
+ end
+ local function collect(z)
+ if not z.list then
+ local list={}
+ local hash={}
+ local position=0
+ local index=0
+ local handle=z.handle
+ while true do
+ setposition(handle,position)
+ local signature=readstring(handle,4)
+ if signature=="PK\3\4" then
+ local version=readcardinal2(handle)
+ local flag=readcardinal2(handle)
+ local method=readcardinal2(handle)
+ local filetime=readcardinal2(handle)
+ local filedate=readcardinal2(handle)
+ local crc32=readcardinal4(handle)
+ local compressed=readcardinal4(handle)
+ local uncompressed=readcardinal4(handle)
+ local namelength=readcardinal2(handle)
+ local extralength=readcardinal2(handle)
+ local filename=readstring(handle,namelength)
+ local descriptor=band(flag,8)~=0
+ local encrypted=band(flag,1)~=0
+ local acceptable=method==0 or method==8
+ local skipped=0
+ local size=0
+ if encrypted then
+ size=readcardinal2(handle)
+ skipbytes(size)
+ skipped=skipped+size+2
+ skipbytes(8)
+ skipped=skipped+8
+ size=readcardinal2(handle)
+ skipbytes(size)
+ skipped=skipped+size+2
+ size=readcardinal4(handle)
+ skipbytes(size)
+ skipped=skipped+size+4
+ size=readcardinal2(handle)
+ skipbytes(size)
+ skipped=skipped+size+2
+ end
+ position=position+30+namelength+extralength+skipped
+ if descriptor then
+ setposition(handle,position+compressed)
+ crc32=readcardinal4(handle)
+ compressed=readcardinal4(handle)
+ uncompressed=readcardinal4(handle)
+ end
+ if acceptable then
+ index=index+1
+ local data={
+ filename=filename,
+ index=index,
+ position=position,
+ method=method,
+ compressed=compressed,
+ uncompressed=uncompressed,
+ crc32=crc32,
+ encrypted=encrypted,
+ }
+ hash[filename]=data
+ list[index]=data
+ else
+ end
+ position=position+compressed
+ else
+ break
+ end
+ z.list=list
+ z.hash=hash
+ end
+ end
+ end
+ function getziplist(z)
+ local list=z.list
+ if not list then
+ collect(z)
+ end
+ return z.list
+ end
+ function getziphash(z)
+ local hash=z.hash
+ if not hash then
+ collect(z)
+ end
+ return z.hash
+ end
+ function foundzipfile(z,name)
+ return getziphash(z)[name]
+ end
+ function closezipfile(z)
+ local f=z.handle
+ if f then
+ closefile(f)
+ z.handle=nil
+ end
+ end
+ function unzipfile(z,filename,check)
+ local hash=z.hash
+ if not hash then
+ hash=zipfiles.hash(z)
+ end
+ local data=hash[filename]
+ if not data then
+ end
+ if data then
+ local handle=z.handle
+ local position=data.position
+ local compressed=data.compressed
+ if compressed>0 then
+ setposition(handle,position)
+ local result=readstring(handle,compressed)
+ if data.method==8 then
+ if decompresssize then
+ result=decompresssize(result,data.uncompressed)
+ else
+ result=decompress(result)
+ end
+ end
+ if check and data.crc32~=calculatecrc(result) then
+ print("checksum mismatch")
+ return ""
+ end
+ return result
+ else
+ return ""
+ end
+ end
+ end
+ zipfiles.open=openzipfile
+ zipfiles.close=closezipfile
+ zipfiles.unzip=unzipfile
+ zipfiles.hash=getziphash
+ zipfiles.list=getziplist
+ zipfiles.found=foundzipfile
+end
+if xzip then
+ local writecardinal1=files.writebyte
+ local writecardinal2=files.writecardinal2le
+ local writecardinal4=files.writecardinal4le
+ local logwriter=logs.writer
+ local globpattern=dir.globpattern
+ local compress=xzip.compress
+ local checksum=xzip.crc32
+ local function fromdostime(dostime,dosdate)
+ return ostime {
+ year=rshift(dosdate,9)+1980,
+ month=band(rshift(dosdate,5),0x0F),
+ day=band((dosdate ),0x1F),
+ hour=band(rshift(dostime,11) ),
+ min=band(rshift(dostime,5),0x3F),
+ sec=band((dostime ),0x1F),
+ }
+ end
+ local function todostime(time)
+ local t=osdate("*t",time)
+ return
+ lshift(t.year-1980,9)+lshift(t.month,5)+t.day,
+ lshift(t.hour,11)+lshift(t.min,5)+rshift(t.sec,1)
+ end
+ local function openzip(filename,level,comment,verbose)
+ local f=ioopen(filename,"wb")
+ if f then
+ return {
+ filename=filename,
+ handle=f,
+ list={},
+ level=tonumber(level) or 3,
+ comment=tostring(comment),
+ verbose=verbose,
+ uncompressed=0,
+ compressed=0,
+ }
+ end
+ end
+ local function writezip(z,name,data,level,time)
+ local f=z.handle
+ local list=z.list
+ local level=tonumber(level) or z.level or 3
+ local method=8
+ local zipped=compress(data,level)
+ local checksum=checksum(data)
+ local verbose=z.verbose
+ if not zipped then
+ method=0
+ zipped=data
+ end
+ local start=f:seek()
+ local compressed=#zipped
+ local uncompressed=#data
+ z.compressed=z.compressed+compressed
+ z.uncompressed=z.uncompressed+uncompressed
+ if verbose then
+ local pct=100*compressed/uncompressed
+ if pct>=100 then
+ logwriter(format("%10i %s",uncompressed,name))
+ else
+ logwriter(format("%10i %02.1f %s",uncompressed,pct,name))
+ end
+ end
+ f:write("\x50\x4b\x03\x04")
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal2(f,method)
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal4(f,checksum)
+ writecardinal4(f,compressed)
+ writecardinal4(f,uncompressed)
+ writecardinal2(f,#name)
+ writecardinal2(f,0)
+ f:write(name)
+ f:write(zipped)
+ list[#list+1]={ #zipped,#data,name,checksum,start,time or 0 }
+ end
+ local function closezip(z)
+ local f=z.handle
+ local list=z.list
+ local comment=z.comment
+ local verbose=z.verbose
+ local count=#list
+ local start=f:seek()
+ for i=1,count do
+ local l=list[i]
+ local compressed=l[1]
+ local uncompressed=l[2]
+ local name=l[3]
+ local checksum=l[4]
+ local start=l[5]
+ local time=l[6]
+ local date,time=todostime(time)
+ f:write('\x50\x4b\x01\x02')
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal2(f,8)
+ writecardinal2(f,time)
+ writecardinal2(f,date)
+ writecardinal4(f,checksum)
+ writecardinal4(f,compressed)
+ writecardinal4(f,uncompressed)
+ writecardinal2(f,#name)
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal4(f,0)
+ writecardinal4(f,start)
+ f:write(name)
+ end
+ local stop=f:seek()
+ local size=stop-start
+ f:write('\x50\x4b\x05\x06')
+ writecardinal2(f,0)
+ writecardinal2(f,0)
+ writecardinal2(f,count)
+ writecardinal2(f,count)
+ writecardinal4(f,size)
+ writecardinal4(f,start)
+ if type(comment)=="string" and comment~="" then
+ writecardinal2(f,#comment)
+ f:write(comment)
+ else
+ writecardinal2(f,0)
+ end
+ if verbose then
+ local compressed=z.compressed
+ local uncompressed=z.uncompressed
+ local filename=z.filename
+ local pct=100*compressed/uncompressed
+ logwriter("")
+ if pct>=100 then
+ logwriter(format("%10i %s",uncompressed,filename))
+ else
+ logwriter(format("%10i %02.1f %s",uncompressed,pct,filename))
+ end
+ end
+ f:close()
+ end
+ local function zipdir(zipname,path,level,verbose)
+ if type(zipname)=="table" then
+ verbose=zipname.verbose
+ level=zipname.level
+ path=zipname.path
+ zipname=zipname.zipname
+ end
+ if not zipname or zipname=="" then
+ return
+ end
+ if not path or path=="" then
+ path="."
+ end
+ if not isdir(path) then
+ return
+ end
+ path=gsub(path,"\\+","/")
+ path=gsub(path,"/+","/")
+ local list={}
+ local count=0
+ globpattern(path,"",true,function(name,size,time)
+ count=count+1
+ list[count]={ name,time }
+ end)
+ sort(list,function(a,b)
+ return a[1]<b[1]
+ end)
+ local zipf=openzip(zipname,level,comment,verbose)
+ if zipf then
+ local p=#path+2
+ for i=1,count do
+ local li=list[i]
+ local name=li[1]
+ local time=li[2]
+ local data=loaddata(name)
+ local name=sub(name,p,#name)
+ writezip(zipf,name,data,level,time,verbose)
+ end
+ closezip(zipf)
+ end
+ end
+ local function unzipdir(zipname,path,verbose)
+ if type(zipname)=="table" then
+ verbose=zipname.verbose
+ path=zipname.path
+ zipname=zipname.zipname
+ end
+ if not zipname or zipname=="" then
+ return
+ end
+ if not path or path=="" then
+ path="."
+ end
+ local z=openzipfile(zipname)
+ if z then
+ local list=getziplist(z)
+ if list then
+ local total=0
+ local count=#list
+ local step=number.idiv(count,10)
+ local done=0
+ local steps=verbose=="steps"
+ local time=steps and osclock()
+ for i=1,count do
+ local l=list[i]
+ local n=l.filename
+ local d=unzipfile(z,n)
+ if d then
+ local p=filejoin(path,n)
+ if mkdirs(dirname(p)) then
+ if steps then
+ total=total+#d
+ done=done+1
+ if done>=step then
+ done=0
+ logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time))
+ end
+ elseif verbose then
+ logwriter(n)
+ end
+ savedata(p,d)
+ end
+ else
+ logwriter(format("problem with file %s",n))
+ end
+ end
+ if steps then
+ logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time))
+ end
+ closezipfile(z)
+ return true
+ else
+ closezipfile(z)
+ end
+ end
+ end
+ zipfiles.zipdir=zipdir
+ zipfiles.unzipdir=unzipdir
+end
+local pattern="^\x1F\x8B\x08"
+local gziplevel=3
+function gzip.suffix(filename)
+ local suffix,extra=suffixes(filename)
+ local gzipped=extra=="gz"
+ return suffix,gzipped
+end
+function gzip.compressed(s)
+ return s and find(s,pattern)
+end
+local getdecompressed
+local putcompressed
+if gzip.compress then
+ local gzipwindow=15+16
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ getdecompressed=function(str)
+ return decompress(str,gzipwindow)
+ end
+ putcompressed=function(str,level)
+ return compress(str,level or gziplevel,nil,gzipwindow)
+ end
+else
+ local gzipwindow=-15
+ local identifier="\x1F\x8B"
+ local compress=zlib.compress
+ local decompress=zlib.decompress
+ local zlibchecksum=zlib.crc32
+ if not CONTEXTLMTXMODE or CONTEXTLMTXMODE==0 then
+ local cs=zlibchecksum
+ zlibchecksum=function(str,n) return cs(n or 0,str) end
+ end
+ local streams=utilities.streams
+ local openstream=streams.openstring
+ local closestream=streams.close
+ local getposition=streams.getposition
+ local readbyte=streams.readbyte
+ local readcardinal4=streams.readcardinal4le
+ local readcardinal2=streams.readcardinal2le
+ local readstring=streams.readstring
+ local readcstring=streams.readcstring
+ local skipbytes=streams.skip
+ local tocardinal1=streams.tocardinal1
+ local tocardinal4=streams.tocardinal4le
+ getdecompressed=function(str)
+ local s=openstream(str)
+ local identifier=readstring(s,2)
+ local method=readbyte(s,1)
+ local flags=readbyte(s,1)
+ local timestamp=readcardinal4(s)
+ local compression=readbyte(s,1)
+ local operating=readbyte(s,1)
+ local isjusttext=band(flags,0x01)~=0 and true or false
+ local extrasize=band(flags,0x04)~=0 and readcardinal2(s) or 0
+ local filename=band(flags,0x08)~=0 and readcstring(s) or ""
+ local comment=band(flags,0x10)~=0 and readcstring(s) or ""
+ local checksum=band(flags,0x02)~=0 and readcardinal2(s) or 0
+ local compressed=readstring(s,#str)
+ local data=decompress(compressed,gzipwindow)
+ return data
+ end
+ putcompressed=function(str,level,originalname)
+ return concat {
+ identifier,
+ tocardinal1(0x08),
+ tocardinal1(0x08),
+ tocardinal4(os.time()),
+ tocardinal1(0x02),
+ tocardinal1(0xFF),
+ (originalname or "unknownname").."\0",
+ compress(str,level,nil,gzipwindow),
+ tocardinal4(zlibchecksum(str)),
+ tocardinal4(#str),
+ }
+ end
+end
+function gzip.load(filename)
+ local f=openfile(filename,"rb")
+ if not f then
+ else
+ local data=f:read("*all")
+ f:close()
+ if data and data~="" then
+ if suffix(filename)=="gz" then
+ data=getdecompressed(data)
+ end
+ return data
+ end
+ end
+end
+function gzip.save(filename,data,level,originalname)
+ if suffix(filename)~="gz" then
+ filename=filename..".gz"
+ end
+ local f=openfile(filename,"wb")
+ if f then
+ data=putcompressed(data or "",level or gziplevel,originalname)
+ f:write(data)
+ f:close()
+ return #data
+ end
+end
+function gzip.compress(s,level)
+ if s and not find(s,pattern) then
+ if not level then
+ level=gziplevel
+ elseif level<=0 then
+ return s
+ elseif level>9 then
+ level=9
+ end
+ return putcompressed(s,level or gziplevel) or s
+ end
+end
+function gzip.decompress(s)
+ if s and find(s,pattern) then
+ return getdecompressed(s)
+ else
+ return s
+ end
+end
+
+end -- closure
diff --git a/macros/luatex/generic/lualibs/lualibs-file.lua b/macros/luatex/generic/lualibs/lualibs-file.lua
index d0af94f09d..9f8fd65483 100644
--- a/macros/luatex/generic/lualibs/lualibs-file.lua
+++ b/macros/luatex/generic/lualibs/lualibs-file.lua
@@ -456,7 +456,7 @@ function file.join(one, two, three, ...)
if not two then
return one == "" and one or lpegmatch(reslasher,one)
end
- if one == "" then
+ if not one or one == "" then
return lpegmatch(stripper,three and concat({ two, three, ... },"/") or two)
end
if lpegmatch(isnetwork,one) then
diff --git a/macros/luatex/generic/lualibs/lualibs-gzip.lua b/macros/luatex/generic/lualibs/lualibs-gzip.lua
deleted file mode 100644
index f141b5ebbb..0000000000
--- a/macros/luatex/generic/lualibs/lualibs-gzip.lua
+++ /dev/null
@@ -1,180 +0,0 @@
-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"
-}
-
--- We only have a few official methods here:
---
--- local decompressed = gzip.load (filename)
--- local resultsize = gzip.save (filename,compresslevel)
--- local compressed = gzip.compress (str,compresslevel)
--- local decompressed = gzip.decompress (str)
--- local iscompressed = gzip.compressed (str)
--- local suffix, okay = gzip.suffix (filename)
---
--- In LuaMetaTeX we have only xzip which implements a very few methods:
---
--- compress (str,level,method,window,memory,strategy)
--- decompress (str,window)
--- adler32 (str,checksum)
--- crc32 (str,checksum)
---
--- Special window values are:
---
--- flate : - 15
--- zlib : 15
--- gzip : 15 | 16
--- auto : 15 | 32
-
-gzip = gzip or { } -- so in luatex we keep the old ones too
-
-if not zlib then
- zlib = xzip -- in luametatex we shadow the old one
-elseif not xzip then
- xzip = zlib
-end
-
-if zlib then
-
- local suffix = file.suffix
- local suffixes = file.suffixes
- local find = string.find
- local openfile = io.open
-
- local gzipwindow = 15 + 16 -- +16: gzip, +32: gzip|zlib
- local gziplevel = 3
- local identifier = "^\x1F\x8B\x08"
-
- local compress = zlib.compress
- local decompress = zlib.decompress
-
- function gzip.load(filename)
- local f = openfile(filename,"rb")
- if not f then
- -- invalid file
- else
- local data = f:read("*all")
- f:close()
- if data and data ~= "" then
- if suffix(filename) == "gz" then
- data = decompress(data,gzipwindow)
- end
- return data
- end
- end
- end
-
- function gzip.save(filename,data,level)
- if suffix(filename) ~= "gz" then
- filename = filename .. ".gz"
- end
- local f = openfile(filename,"wb")
- if f then
- data = compress(data or "",level or gziplevel,nil,gzipwindow)
- f:write(data)
- f:close()
- return #data
- end
- end
-
- function gzip.suffix(filename)
- local suffix, extra = suffixes(filename)
- local gzipped = extra == "gz"
- return suffix, gzipped
- end
-
- function gzip.compressed(s)
- return s and find(s,identifier)
- end
-
- function gzip.compress(s,level)
- if s and not find(s,identifier) then -- the find check might go away
- if not level then
- level = gziplevel
- elseif level <= 0 then
- return s
- elseif level > 9 then
- level = 9
- end
- return compress(s,level or gziplevel,nil,gzipwindow) or s
- end
- end
-
- function gzip.decompress(s)
- if s and find(s,identifier) then
- return decompress(s,gzipwindow)
- else
- return s
- end
- end
-
-end
-
--- In luametatex we can use this one but it doesn't look like there wil be stream
--- support so for now we still use zlib (the performance difference is not that
--- spectacular in our usage.
-
--- if flate then
---
--- local type = type
--- local find = string.find
---
--- local compress = flate.gz_compress
--- local decompress = flate.gz_decompress
---
--- local absmax = 128*1024*1024
--- local initial = 64*1024
--- local identifier = "^\x1F\x8B\x08"
---
--- function gzip.compressed(s)
--- return s and find(s,identifier)
--- end
---
--- function gzip.compress(s,level)
--- if s and not find(s,identifier) then -- the find check might go away
--- if not level then
--- level = 3
--- elseif level <= 0 then
--- return s
--- elseif level > 9 then
--- level = 9
--- end
--- return compress(s,level) or s
--- end
--- end
---
--- function gzip.decompress(s,size,iterate)
--- if s and find(s,identifier) then
--- if type(size) ~= "number" then
--- size = initial
--- end
--- if size > absmax then
--- size = absmax
--- end
--- if type(iterate) == "number" then
--- max = size * iterate
--- elseif iterate == nil or iterate == true then
--- iterate = true
--- max = absmax
--- end
--- if max > absmax then
--- max = absmax
--- end
--- while true do
--- local d = decompress(s,size)
--- if d then
--- return d
--- end
--- size = 2 * size
--- if not iterate or size > max then
--- return false
--- end
--- end
--- else
--- return s
--- end
--- end
---
--- end
diff --git a/macros/luatex/generic/lualibs/lualibs-io.lua b/macros/luatex/generic/lualibs/lualibs-io.lua
index a955262a31..6bf7a97bda 100644
--- a/macros/luatex/generic/lualibs/lualibs-io.lua
+++ b/macros/luatex/generic/lualibs/lualibs-io.lua
@@ -147,9 +147,12 @@ function io.copydata(source,target,action)
end
end
-function io.savedata(filename,data,joiner)
- local f = open(filename,"wb")
+function io.savedata(filename,data,joiner,append)
+ local f = open(filename,append and "ab" or "wb")
if f then
+ if append and joiner and f:seek("end") > 0 then
+ f:write(joiner)
+ end
if type(data) == "table" then
f:write(concat(data,joiner or ""))
elseif type(data) == "function" then
@@ -288,7 +291,8 @@ end
io.noflines = noflines
--- inlined is faster ... beware, better use util-fil
+-- inlined is faster ... beware, better use util-fil so these are obsolete
+-- and will go
local nextchar = {
[ 4] = function(f)
diff --git a/macros/luatex/generic/lualibs/lualibs-lpeg.lua b/macros/luatex/generic/lualibs/lualibs-lpeg.lua
index 50306e4ab6..5f3bea08ca 100644
--- a/macros/luatex/generic/lualibs/lualibs-lpeg.lua
+++ b/macros/luatex/generic/lualibs/lualibs-lpeg.lua
@@ -665,12 +665,12 @@ end
-- lpeg.print(lpeg.P("a","b","c"))
-- lpeg.print(lpeg.S("a","b","c"))
--- print(lpeg.count("äáàa",lpeg.P("á") + lpeg.P("à")))
--- print(lpeg.count("äáàa",lpeg.UP("áà")))
--- print(lpeg.count("äáàa",lpeg.US("àá")))
--- print(lpeg.count("äáàa",lpeg.UR("aá")))
--- print(lpeg.count("äáàa",lpeg.UR("àá")))
--- print(lpeg.count("äáàa",lpeg.UR(0x0000,0xFFFF)))
+-- print(lpeg.counter(lpeg.P("á") + lpeg.P("à"))("äáàa"))
+-- print(lpeg.counter(lpeg.UP("áà"))("äáàa"))
+-- print(lpeg.counter(lpeg.US("àá"))("äáàa"))
+-- print(lpeg.counter(lpeg.UR("aá"))("äáàa"))
+-- print(lpeg.counter(lpeg.UR("àá"))("äáàa"))
+-- print(lpeg.counter(lpeg.UR(0x0000,0xFFFF)))
function lpeg.is_lpeg(p)
return p and lpegtype(p) == "pattern"
diff --git a/macros/luatex/generic/lualibs/lualibs-math.lua b/macros/luatex/generic/lualibs/lualibs-math.lua
index e5668a5db0..6105bc3c2d 100644
--- a/macros/luatex/generic/lualibs/lualibs-math.lua
+++ b/macros/luatex/generic/lualibs/lualibs-math.lua
@@ -14,9 +14,19 @@ end
if not math.round then
- local floor = math.floor
+ if xmath then
+
+ math.round = xmath.round
+
+ else
- function math.round(x) return floor(x + 0.5) end
+ local floor = math.floor
+
+ function math.round(x)
+ return x < 0 and -floor(-x + 0.5) or floor(x + 0.5)
+ end
+
+ end
end
@@ -141,7 +151,7 @@ if not math.ult then
local floor = math.floor
- function math.tointeger(m,n)
+ function math.ult(m,n)
-- not ok but i'm not motivated to look into it now
return floor(m) < floor(n) -- unsigned comparison needed
end
diff --git a/macros/luatex/generic/lualibs/lualibs-os.lua b/macros/luatex/generic/lualibs/lualibs-os.lua
index c7584ccce9..faae76881a 100644
--- a/macros/luatex/generic/lualibs/lualibs-os.lua
+++ b/macros/luatex/generic/lualibs/lualibs-os.lua
@@ -26,22 +26,27 @@ if not modules then modules = { } end modules ['l-os'] = {
-- math.randomseed(tonumber(string.sub(string.reverse(tostring(math.floor(socket.gettime()*10000))),1,6)))
local os = os
-local date, time = os.date, os.time
+local date, time, difftime = os.date, os.time, os.difftime
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 random, ceil, randomseed, modf = math.random, math.ceil, math.randomseed, math.modf
local type, setmetatable, tonumber, tostring = type, setmetatable, tonumber, tostring
-- This check needs to happen real early on. Todo: we can pick it up from the commandline
-- if we pass --binpath= (which is useful anyway)
do
+
local selfdir = os.selfdir
+
if selfdir == "" then
selfdir = nil
end
+
if not selfdir then
+
-- We need a fallback plan so let's see what we get.
+
if arg then
-- passed by mtx-context ... saves network access
for i=1,#arg do
@@ -52,6 +57,7 @@ do
end
end
end
+
if not selfdir then
selfdir = os.selfbin or "luatex"
if find(selfdir,"[/\\]") then
@@ -92,11 +98,16 @@ do
end
end
end
+
-- let's hope we're okay now
+
os.selfdir = selfdir or "."
+
end
+
+ -- print(os.selfdir) os.exit()
+
end
--- print(os.selfdir) os.exit()
-- The following code permits traversing the environment table, at least in luatex. Internally all
-- environment names are uppercase.
@@ -157,7 +168,7 @@ if not os.__getenv__ then
end
function os.getenv(k)
- local K = upper(k)
+ local K = upper(k) -- hm utf
local v = osenv[K] or osgetenv(K) or osgetenv(k)
if v == "" then
return nil
@@ -183,32 +194,14 @@ end
-- end of environment hack
-local execute = os.execute
-local iopopen = io.popen
-
-local function resultof(command)
- local handle = iopopen(command,"r") -- already has flush
- if handle then
- local result = handle:read("*all") or ""
- handle:close()
- return result
- else
- return ""
- end
-end
-
-os.resultof = resultof
-
-function os.pipeto(command)
- return iopopen(command,"w") -- already has flush
-end
-
if not io.fileseparator then
+
if find(os.getenv("PATH"),";",1,true) then
io.fileseparator, io.pathseparator, os.type = "\\", ";", os.type or "windows"
else
io.fileseparator, io.pathseparator, os.type = "/" , ":", os.type or "unix"
end
+
end
os.type = os.type or (io.pathseparator == ";" and "windows") or "unix"
@@ -220,351 +213,370 @@ else
os.libsuffix, os.binsuffix, os.binsuffixes = 'so', '', { '' }
end
-local launchers = {
- windows = "start %s",
- macosx = "open %s",
- unix = "xdg-open %s &> /dev/null &",
-}
+do
-function os.launch(str)
- local command = format(launchers[os.name] or launchers.unix,str)
- -- todo: pcall
--- print(command)
- execute(command)
-end
+ local execute = os.execute
+ local iopopen = io.popen
+ local ostype = os.type
+
+ local function resultof(command)
+ -- already has flush, b is new and we need it to pipe xz output
+ local handle = iopopen(command,ostype == "windows" and "rb" or "r")
+ if handle then
+ local result = handle:read("*all") or ""
+ handle:close()
+ return result
+ else
+ return ""
+ end
+ end
-local gettimeofday = os.gettimeofday or os.clock
-os.gettimeofday = gettimeofday
+ os.resultof = resultof
-local startuptime = gettimeofday()
+ function os.pipeto(command)
+ return iopopen(command,"w") -- already has flush
+ end
-function os.runtime()
- return gettimeofday() - startuptime
-end
+ local launchers = {
+ windows = "start %s",
+ macosx = "open %s",
+ unix = "xdg-open %s &> /dev/null &",
+ }
+
+ function os.launch(str)
+ local command = format(launchers[os.name] or launchers.unix,str)
+ -- todo: pcall
+ -- print(command)
+ execute(command)
+ end
--- print(os.gettimeofday()-os.time())
--- os.sleep(1.234)
--- print (">>",os.runtime())
--- print(os.date("%H:%M:%S",os.gettimeofday()))
--- print(os.date("%H:%M:%S",os.time()))
+end
--- no need for function anymore as we have more clever code and helpers now
--- this metatable trickery might as well disappear
+do
-local resolvers = os.resolvers or { }
-os.resolvers = resolvers
+ local gettimeofday = os.gettimeofday or os.clock
+ os.gettimeofday = gettimeofday
-setmetatable(os, { __index = function(t,k)
- local r = resolvers[k]
- return r and r(t,k) or nil -- no memoize
-end })
+ local startuptime = gettimeofday()
--- we can use HOSTTYPE on some platforms
+ function os.runtime()
+ return gettimeofday() - startuptime
+ end
-local name, platform = os.name or "linux", os.getenv("MTX_PLATFORM") or ""
+ -- print(os.gettimeofday()-os.time())
+ -- os.sleep(1.234)
+ -- print (">>",os.runtime())
+ -- print(os.date("%H:%M:%S",os.gettimeofday()))
+ -- print(os.date("%H:%M:%S",os.time()))
--- local function guess()
--- local architecture = resultof("uname -m") or ""
--- if architecture ~= "" then
--- return architecture
--- end
--- architecture = os.getenv("HOSTTYPE") or ""
--- if architecture ~= "" then
--- return architecture
--- end
--- return resultof("echo $HOSTTYPE") or ""
--- end
+end
+-- We can use HOSTTYPE on some platforms (but not consistently on e.g. Linux).
+--
-- os.bits = 32 | 64
+--
+-- os.uname() : return {
+-- machine = "x86_64",
+-- nodename = "MYLAPTOP",
+-- release = "build 9200",
+-- sysname = "Windows",
+-- version = "6.02",
+-- }
--- os.uname()
--- sysname
--- machine
--- release
--- version
--- nodename
-
-if platform ~= "" then
+do
- os.platform = platform
+ local name = os.name or "linux"
+ local platform = os.getenv("MTX_PLATFORM") or ""
+ local architecture = os.uname and os.uname().machine -- lmtx
+ local bits = os.getenv("MTX_BITS") or find(platform,"64") and 64 or 32
-elseif os.type == "windows" then
+ if platform ~= "" then
- -- we could set the variable directly, no function needed here
+ -- we're okay already
- -- PROCESSOR_ARCHITECTURE : binary platform
- -- PROCESSOR_ARCHITEW6432 : OS platform
+ elseif os.type == "windows" then
- -- mswin-64 is now win64
+ -- PROCESSOR_ARCHITECTURE : binary platform
+ -- PROCESSOR_ARCHITEW6432 : OS platform
- function resolvers.platform(t,k)
- local architecture = os.getenv("PROCESSOR_ARCHITECTURE") or ""
- local platform = ""
- if find(architecture,"AMD64",1,true) then
- platform = "win64"
+ architecture = string.lower(architecture or os.getenv("PROCESSOR_ARCHITECTURE") or "")
+ if architecture == "x86_64" then
+ bits, platform = 64, "win64"
+ elseif find(architecture,"amd64") then
+ bits, platform = 64, "win64"
+ elseif find(architecture,"arm64") then
+ bits, platform = 64, "windows-arm64"
+ elseif find(architecture,"arm32") then
+ bits, platform = 32, "windows-arm32"
else
- platform = "mswin"
+ bits, platform = 32, "mswin"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-elseif name == "linux" then
-
- function resolvers.platform(t,k)
- -- we sometimes have HOSTTYPE set so let's check that first
- local architecture = os.getenv("HOSTTYPE") or resultof("uname -m") or ""
- local platform = os.getenv("MTX_PLATFORM") or ""
- local musl = find(os.selfdir or "","linuxmusl")
- if platform ~= "" then
- -- we're done
- elseif find(architecture,"x86_64",1,true) then
- platform = musl and "linuxmusl" or "linux-64"
- elseif find(architecture,"ppc",1,true) then
- platform = "linux-ppc"
+ elseif name == "linux" then
+
+ -- There is no way to detect if musl is used because there is no __MUSL__
+ -- and it looks like there never will be. Folks don't care about cases where
+ -- one ships multipe binaries (as with TeX distibutions) and want to select
+ -- the right one. So probably it expects users to compile locally in which
+ -- case we don't care to much as they can then sort it out.
+
+ architecture = architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+ local musl = find(os.selfdir or "","linuxmusl")
+ if find(architecture,"x86_64") then
+ bits, platform = 64, musl and "linuxmusl" or "linux-64"
+ elseif find(architecture,"ppc") then
+ bits, platform = 32, "linux-ppc" -- this will be dropped
else
- platform = musl and "linuxmusl" or "linux"
+ bits, platform = 32, musl and "linuxmusl" or "linux"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-elseif name == "macosx" then
-
- --[[
- Identifying the architecture of OSX is quite a mess and this
- is the best we can come up with. For some reason $HOSTTYPE is
- a kind of pseudo environment variable, not known to the current
- environment. And yes, uname cannot be trusted either, so there
- is a change that you end up with a 32 bit run on a 64 bit system.
- Also, some proper 64 bit intel macs are too cheap (low-end) and
- therefore not permitted to run the 64 bit kernel.
- ]]--
-
- function resolvers.platform(t,k)
- -- local platform = ""
- -- local architecture = os.getenv("HOSTTYPE") or ""
- -- if architecture == "" then
- -- architecture = resultof("echo $HOSTTYPE") or ""
- -- end
- local architecture = resultof("echo $HOSTTYPE") or ""
- local platform = ""
+ elseif name == "macosx" then
+
+ -- Identifying the architecture of OSX is quite a mess and this is the best
+ -- we can come up with. For some reason $HOSTTYPE is a kind of pseudo
+ -- environment variable, not known to the current environment. And yes,
+ -- uname cannot be trusted either, so there is a change that you end up with
+ -- a 32 bit run on a 64 bit system. Also, some proper 64 bit intel macs are
+ -- too cheap (low-end) and therefore not permitted to run the 64 bit kernel.
+
+ architecture = architecture or resultof("echo $HOSTTYPE") or ""
if architecture == "" then
- -- print("\nI have no clue what kind of OSX you're running so let's assume an 32 bit intel.\n")
- platform = "osx-intel"
- elseif find(architecture,"i386",1,true) then
- platform = "osx-intel"
- elseif find(architecture,"x86_64",1,true) then
- platform = "osx-64"
- elseif find(architecture,"arm64",1,true) then
- platform = "osx-arm"
+ bits, platform = 64, "osx-intel"
+ elseif find(architecture,"i386") then
+ bits, platform = 64, "osx-intel"
+ elseif find(architecture,"x86_64") then
+ bits, platform = 64, "osx-64"
+ elseif find(architecture,"arm64") then
+ bits, platform = 64, "osx-arm"
else
- platform = "osx-ppc"
+ bits, platform = 32, "osx-ppc"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-elseif name == "sunos" then
+ elseif name == "sunos" then
- function resolvers.platform(t,k)
- local architecture = resultof("uname -m") or ""
- local platform = ""
- if find(architecture,"sparc",1,true) then
- platform = "solaris-sparc"
+ architecture = architecture or resultof("uname -m") or ""
+ if find(architecture,"sparc") then
+ bits, platform = 32, "solaris-sparc"
else -- if architecture == 'i86pc'
- platform = "solaris-intel"
+ bits, platform = 32, "solaris-intel"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-elseif name == "freebsd" then
+ elseif name == "freebsd" then
- function resolvers.platform(t,k)
- local architecture = resultof("uname -m") or ""
- local platform = ""
- if find(architecture,"amd64",1,true) then
- platform = "freebsd-amd64"
+ architecture = architecture or os.getenv("MACHTYPE") or resultof("uname -m") or ""
+ if find(architecture,"amd64") or find(architecture,"AMD64") then
+ bits, platform = 64, "freebsd-amd64"
else
- platform = "freebsd"
+ bits, platform = 32, "freebsd"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-elseif name == "kfreebsd" then
+ elseif name == "kfreebsd" then
- function resolvers.platform(t,k)
- -- we sometimes have HOSTTYPE set so let's check that first
- local architecture = os.getenv("HOSTTYPE") or resultof("uname -m") or ""
- local platform = ""
- if find(architecture,"x86_64",1,true) then
- platform = "kfreebsd-amd64"
+ architecture = architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
+ if architecture == "x86_64" then
+ bits, platform = 64, "kfreebsd-amd64"
else
- platform = "kfreebsd-i386"
+ bits, platform = 32, "kfreebsd-i386"
end
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
- end
-else
+ else
- -- platform = "linux"
- -- os.setenv("MTX_PLATFORM",platform)
- -- os.platform = platform
+ architecture = architecture or resultof("uname -m") or ""
+
+ if find(architecture,"aarch64") then
+ bits, platform = "linux-aarch64"
+ elseif find(architecture,"armv7l") then
+ -- linux-armel
+ bits, platform = 32, "linux-armhf"
+ elseif find(architecture,"mips64") or find(architecture,"mips64el") then
+ bits, platform = 64, "linux-mipsel"
+ elseif find(architecture,"mipsel") or find(architecture,"mips") then
+ bits, platform = 32, "linux-mipsel"
+ else
+ bits, platform = 64, "linux-64" -- was 32, "linux"
+ end
- function resolvers.platform(t,k)
- local platform = "linux"
- os.setenv("MTX_PLATFORM",platform)
- os.platform = platform
- return platform
end
-end
+ os.setenv("MTX_PLATFORM",platform)
+ os.setenv("MTX_BITS", bits)
-os.newline = name == "windows" and "\013\010" or "\010" -- crlf or lf
+ os.platform = platform
+ os.bits = bits
+ os.newline = name == "windows" and "\013\010" or "\010" -- crlf or lf
-function resolvers.bits(t,k)
- local bits = find(os.platform,"64",1,true) and 64 or 32
- os.bits = bits
- return bits
end
-- beware, we set the randomseed
--- from wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This algorithm sets the
--- version number as well as two reserved bits. All other bits are set using a random or pseudorandom
--- data source. Version 4 UUIDs have the form xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal
--- digits x and hexadecimal digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479.
---
--- as we don't call this function too often there is not so much risk on repetition
-
-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)
- )
+-- From wikipedia: Version 4 UUIDs use a scheme relying only on random numbers. This
+-- algorithm sets the version number as well as two reserved bits. All other bits
+-- are set using a random or pseudorandom data source. Version 4 UUIDs have the form
+-- xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx with hexadecimal digits x and hexadecimal
+-- digits 8, 9, A, or B for y. e.g. f47ac10b-58cc-4372-a567-0e02b2c3d479. As we don't
+-- call this function too often there is not so much risk on repetition.
+
+do
+
+ 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
+
end
-local d
+do
-function os.timezone(delta)
- d = d or ((tonumber(date("%H")) or 0) - (tonumber(date("!%H")) or 0))
- if delta then
- if d > 0 then
- return format("+%02i:00",d)
+ -- this is fragile because it depends on time and so we only check once during
+ -- a run (the computer doesn't move zones) .. Michal Vlasák made a better one
+
+ -- local d
+ --
+ -- function os.timezone()
+ -- d = d or ((tonumber(date("%H")) or 0) - (tonumber(date("!%H")) or 0))
+ -- if d > 0 then
+ -- return format("+%02i:00",d)
+ -- else
+ -- return format("-%02i:00",-d)
+ -- end
+ -- end
+
+ local hour, min
+
+ function os.timezone(difference)
+ if not hour then
+ -- somehow looks too complex:
+ local current = time()
+ local utcdate = date("!*t", current)
+ local localdate = date("*t", current)
+ localdate.isdst = false
+ local timediff = difftime(time(localdate), time(utcdate))
+ hour, min = modf(timediff / 3600)
+ min = min * 60
+ end
+ if difference then
+ return hour, min
else
- return format("-%02i:00",-d)
+ return format("%+03d:%02d",hour,min) -- %+ means: always show sign
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
- -- valid time
- elseif default then
- return default
- else
- t = time()
- end
- if t ~= lasttime then
- lasttime = t
- lastdate = format(timeformat,date(dateformat))
+ -- localtime with timezone: 2021-10-22 10:22:54+02:00
+
+ local timeformat = format("%%s%s",os.timezone())
+ 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
+ -- valid time
+ elseif default then
+ return default
+ else
+ t = time()
+ end
+ if t ~= lasttime then
+ lasttime = t
+ lastdate = format(timeformat,date(dateformat))
+ end
+ return lastdate
end
- return lastdate
-end
-local dateformat = "%Y-%m-%d %H:%M:%S"
-local lasttime = nil
-local lastdate = nil
+ -- localtime without timezone: 2021-10-22 10:22:54
-function os.localtime(t,default)
- t = t and tonumber(t) or 0
- if t > 0 then
- -- valid time
- elseif default then
- return default
- else
- t = time()
+ 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
+ -- valid time
+ elseif default then
+ return default
+ else
+ t = time()
+ end
+ if t ~= lasttime then
+ lasttime = t
+ lastdate = date(dateformat,t)
+ end
+ return lastdate
end
- if t ~= lasttime then
- lasttime = t
- lastdate = date(dateformat,t)
+
+ 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
- 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 "-"
+ -- table with values
+
+ function os.today()
+ return date("!*t")
+ end
+
+ -- utc time without timezone: 2021-10-22 08:22:54
+
+ function os.now()
+ return date("!%Y-%m-%d %H:%M:%S")
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
+do
+
+ local cache = { }
+
+ local function which(filename)
+ local fullname = cache[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
+ cache[filename] = fullname
end
- if not fullname then
- fullname = false
- end
- memory[filename] = fullname
+ return fullname
end
- return fullname
-end
-os.which = which
-os.where = which
+ os.which = which
+ os.where = which
-function os.today()
- return date("!*t") -- table with values
-end
+ -- print(os.which("inkscape.exe"))
+ -- print(os.which("inkscape"))
+ -- print(os.which("gs.exe"))
+ -- print(os.which("ps2pdf"))
-function os.now()
- return date("!%Y-%m-%d %H:%M:%S") -- 2011-12-04 14:59:12
end
--- if not os.sleep and socket then
--- os.sleep = socket.sleep
--- end
-
if not os.sleep then
+
local socket = socket
+
function os.sleep(n)
if not socket then
-- so we delay ... if os.sleep is really needed then one should also
@@ -573,101 +585,105 @@ if not os.sleep then
end
socket.sleep(n)
end
-end
-
--- print(os.which("inkscape.exe"))
--- print(os.which("inkscape"))
--- print(os.which("gs.exe"))
--- print(os.which("ps2pdf"))
-
--- These are moved from core-con.lua (as I needed them elsewhere).
-local function isleapyear(year) -- timed for bram's cs practicum
- -- return (year % 400 == 0) or (year % 100 ~= 0 and year % 4 == 0) -- 3:4:1600:1900 = 9.9 : 8.2 : 5.0 : 6.8 (29.9)
- return (year % 4 == 0) and (year % 100 ~= 0 or year % 400 == 0) -- 3:4:1600:1900 = 5.1 : 6.5 : 8.1 : 10.2 (29.9)
- -- return (year % 4 == 0) and (year % 400 == 0 or year % 100 ~= 0) -- 3:4:1600:1900 = 5.2 : 8.5 : 6.8 : 10.1 (30.6)
end
-os.isleapyear = isleapyear
+-- These are moved from core-con.lua (as I needed them elsewhere).
--- nicer:
---
--- local days = {
--- [false] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
--- [true] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
--- }
---
--- local function nofdays(year,month)
--- return days[isleapyear(year)][month]
--- return month == 2 and isleapyear(year) and 29 or days[month]
--- end
---
--- more efficient:
+do
-local days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ local function isleapyear(year) -- timed for bram's cs practicum
+ -- return (year % 400 == 0) or (year % 100 ~= 0 and year % 4 == 0) -- 3:4:1600:1900 = 9.9 : 8.2 : 5.0 : 6.8 (29.9)
+ return (year % 4 == 0) and (year % 100 ~= 0 or year % 400 == 0) -- 3:4:1600:1900 = 5.1 : 6.5 : 8.1 : 10.2 (29.9)
+ -- return (year % 4 == 0) and (year % 400 == 0 or year % 100 ~= 0) -- 3:4:1600:1900 = 5.2 : 8.5 : 6.8 : 10.1 (30.6)
+ end
-local function nofdays(year,month,day)
- if not month then
- return isleapyear(year) and 365 or 364
- elseif not day then
- return month == 2 and isleapyear(year) and 29 or days[month]
- else
- for i=1,month-1 do
- day = day + days[i]
- end
- if month > 2 and isleapyear(year) then
- day = day + 1
+ os.isleapyear = isleapyear
+
+ -- nicer:
+ --
+ -- local days = {
+ -- [false] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },
+ -- [true] = { 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+ -- }
+ --
+ -- local function nofdays(year,month)
+ -- return days[isleapyear(year)][month]
+ -- return month == 2 and isleapyear(year) and 29 or days[month]
+ -- end
+ --
+ -- more efficient:
+
+ local days = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }
+
+ local function nofdays(year,month,day)
+ if not month then
+ return isleapyear(year) and 365 or 364
+ elseif not day then
+ return month == 2 and isleapyear(year) and 29 or days[month]
+ else
+ for i=1,month-1 do
+ day = day + days[i]
+ end
+ if month > 2 and isleapyear(year) then
+ day = day + 1
+ end
+ return day
end
- return day
end
-end
-
-os.nofdays = nofdays
-function os.weekday(day,month,year)
- return date("%w",time { year = year, month = month, day = day }) + 1
-end
+ os.nofdays = nofdays
-function os.validdate(year,month,day)
- -- we assume that all three values are set
- -- year is always ok, even if lua has a 1970 time limit
- if month < 1 then
- month = 1
- elseif month > 12 then
- month = 12
+ function os.weekday(day,month,year)
+ return date("%w",time { year = year, month = month, day = day }) + 1
end
- if day < 1 then
- day = 1
- else
- local max = nofdays(year,month)
- if day > max then
- day = max
+
+ function os.validdate(year,month,day)
+ -- we assume that all three values are set
+ -- year is always ok, even if lua has a 1970 time limit
+ 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
- return year, month, day
-end
-function os.date(fmt,...)
- if not fmt then
- -- otherwise differences between unix, mingw and msvc
- fmt = "%Y-%m-%d %H:%M"
+ function os.date(fmt,...)
+ if not fmt then
+ -- otherwise differences between unix, mingw and msvc
+ fmt = "%Y-%m-%d %H:%M"
+ end
+ return date(fmt,...)
end
- return date(fmt,...)
+
end
-local osexit = os.exit
-local exitcode = nil
+do
-function os.setexitcode(code)
- exitcode = code
-end
+ local osexit = os.exit
+ local exitcode = nil
-function os.exit(c)
- if exitcode ~= nil then
- return osexit(exitcode)
+ function os.setexitcode(code)
+ exitcode = code
end
- if c ~= nil then
- return osexit(c)
+
+ function os.exit(c)
+ if exitcode ~= nil then
+ return osexit(exitcode)
+ end
+ if c ~= nil then
+ return osexit(c)
+ end
+ return osexit()
end
- return osexit()
+
end
diff --git a/macros/luatex/generic/lualibs/lualibs-util-deb.lua b/macros/luatex/generic/lualibs/lualibs-util-deb.lua
index bd94b6d01e..10e5731b03 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-deb.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-deb.lua
@@ -346,3 +346,25 @@ debugger.showtraceback = showtraceback
-- debug.showtraceback = showtraceback
-- showtraceback()
+
+-- For now also here because we want it in mtxrun (taken from lmt file):
+
+if luac then
+
+ local show, dump = luac.print, string.dump
+
+ function luac.inspect(v)
+ if type(v) == "function" then
+ local ok, str = xpcall(dump,function() end,v)
+ if ok then
+ v = str
+ end
+ end
+ if type(v) == "string" then
+ show(v,true)
+ else
+ print(v)
+ end
+ end
+
+end
diff --git a/macros/luatex/generic/lualibs/lualibs-util-jsn.lua b/macros/luatex/generic/lualibs/lualibs-util-jsn.lua
index 8da3518979..2d78561971 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-jsn.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-jsn.lua
@@ -17,6 +17,10 @@ if not modules then modules = { } end modules ['util-jsn'] = {
--
-- Upgraded for handling the somewhat more fax server templates.
+if utilities and utilities.json then
+ return json
+end
+
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, gsub = string.format, string.gsub
@@ -265,6 +269,8 @@ do
k = lpegmatch(escaper,k) or k
v = lpegmatch(escaper,v) or v
n = n + 1 t[n] = f_key_val_str(depth,k,v)
+ elseif i > 1 then
+ n = n - 1
end
elseif tv == "table" then
local l = #v
@@ -280,6 +286,9 @@ do
end
elseif next(v) then
tojsonpp(v,k,depth,level+1,0)
+ elseif i > 1 then
+ n = n - 1
+ -- we don't know if we have a hash or string
end
elseif tv == "boolean" then
if tk == "number" then
@@ -297,6 +306,8 @@ do
else
t[n] = f_key_val_nop(depth,k)
end
+ elseif i > 1 then
+ n = n - 1
end
else
if tk == "number" then
@@ -306,6 +317,8 @@ do
k = lpegmatch(escaper,k) or k
n = n + 1
t[n] = f_key_val_null(depth,k)
+ elseif i > 1 then
+ n = n - 1
end
end
end
@@ -440,4 +453,8 @@ end
-- inspect(l)
-- print(s==l.s)
-return json
+-- if not package.loaded.json then
+-- package.loaded.json = json
+-- end
+
+-- return json
diff --git a/macros/luatex/generic/lualibs/lualibs-util-prs.lua b/macros/luatex/generic/lualibs/lualibs-util-prs.lua
index 6d2f8c19e0..635b610e07 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-prs.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-prs.lua
@@ -55,9 +55,13 @@ local nobracket = 1 - (lbracket + rbracket)
local escape, left, right = P("\\"), P('{'), P('}')
+-- lpegpatterns.balanced = P {
+-- [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+-- [2] = left * V(1) * right
+-- }
lpegpatterns.balanced = P {
- [1] = ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
- [2] = left * V(1) * right
+ ((escape * (left+right)) + (1 - (left+right)) + V(2))^0,
+ left * V(1) * right
}
local nestedbraces = P { lbrace * (nobrace + V(1))^0 * rbrace }
@@ -67,11 +71,12 @@ 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
-lpegpatterns.nested = nestedbraces -- no capture
-lpegpatterns.argument = argument -- argument after e.g. =
-lpegpatterns.content = content -- rest after e.g =
+lpegpatterns.nestedbraces = nestedbraces -- no capture
+lpegpatterns.nestedparents = nestedparents -- no capture
+lpegpatterns.nestedbrackets = nestedbrackets -- no capture
+lpegpatterns.nested = nestedbraces -- no capture
+lpegpatterns.argument = argument -- argument after e.g. =
+lpegpatterns.content = content -- rest after e.g =
local value = lbrace * C((nobrace + nestedbraces)^0) * rbrace
+ C((nestedbraces + (1-comma))^0)
@@ -568,9 +573,9 @@ end
-- "1","2","3","4"
-- "5","6","7","8"
-- ]]
---
+
-- local mycsvsplitter = parsers.csvsplitter { numbers = true }
---
+
-- local list = mycsvsplitter(crap) inspect(list)
-- and this is a slightly patched version of a version posted by Philipp Gesang
@@ -617,12 +622,6 @@ end
-- local list, names = mycsvsplitter(crap,true) inspect(list) inspect(names)
-- local list, names = mycsvsplitter(crap) inspect(list) inspect(names)
--- parsers.stepper("1,7-",9,function(i) print(">>>",i) end)
--- parsers.stepper("1-3,7,8,9")
--- parsers.stepper("1-3,6,7",function(i) print(">>>",i) end)
--- parsers.stepper(" 1 : 3, ,7 ")
--- parsers.stepper("1:4,9:13,24:*",30)
-
local function ranger(first,last,n,action)
if not first then
-- forget about it
@@ -639,7 +638,7 @@ local function ranger(first,last,n,action)
end
end
-local cardinal = lpegpatterns.cardinal / tonumber
+local cardinal = (lpegpatterns.hexadecimal + lpegpatterns.cardinal) / tonumber
local spacers = lpegpatterns.spacer^0
local endofstring = lpegpatterns.endofstring
@@ -650,14 +649,29 @@ local stepper = spacers * ( cardinal * ( spacers * S(":-") * spacers * ( cardin
* Carg(1) * Carg(2) / ranger * S(", ")^0 )^1 * endofstring -- we're sort of strict (could do without endofstring)
function parsers.stepper(str,n,action)
+ local ts = type(str)
if type(n) == "function" then
- lpegmatch(stepper,str,1,false,n or print)
- else
+ if ts == "number" then
+ n(str)
+ elseif ts == "table" then
+ for i=1,#str do
+ n(str[i])
+ end
+ else
+ lpegmatch(stepper,str,1,false,n or print)
+ end
+ elseif ts == "string" then
lpegmatch(stepper,str,1,n,action or print)
end
end
---
+-- parsers.stepper("1,7-",9,function(i) print(">>>",i) end)
+-- parsers.stepper("1-3,7,8,9")
+-- parsers.stepper("1-3,6,7",function(i) print(">>>",i) end)
+-- parsers.stepper(" 1 : 3, ,7 ")
+-- parsers.stepper("1:4,9:13,24:*",30)
+-- parsers.stepper(1,print)
+-- parsers.stepper({1,3,4},print)
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)
@@ -681,7 +695,7 @@ local spaces = lpegpatterns.space^0
local dummy = function() end
setmetatableindex(cache,function(t,k)
- local separator = P(k)
+ local separator = S(k) -- was P
local value = (1-separator)^0
local pattern = spaces * C(value) * separator^0 * Cp()
t[k] = pattern
@@ -801,11 +815,20 @@ local pattern = Cf( Ct("") *
( Cg(Cc("day") * cardinal)
* S("-/") * Cg(Cc("month") * cardinal)
* S("-/") * Cg(Cc("year") * p_year)
+ ) +
+ ( Cg(Cc("year") * p_year)
+ * S("-/") * Cg(Cc("month") * cardinal)
+ ) +
+ ( Cg(Cc("month") * cardinal)
+ * S("-/") * Cg(Cc("year") * p_year)
)
)
- * P(" ") * Cg(Cc("hour") * cardinal)
+ * (
+ P(" ") * Cg(Cc("hour") * cardinal)
* P(":") * Cg(Cc("min") * cardinal)
* (P(":") * Cg(Cc("sec") * cardinal))^-1
+ + P(-1) )
+
, rawset)
lpegpatterns.splittime = pattern
@@ -814,6 +837,8 @@ function parsers.totime(str)
return lpegmatch(pattern,str)
end
+-- inspect(parsers.totime("2019-03-05"))
+-- inspect(parsers.totime("2019-03-05 12:12:12"))
-- print(os.time(parsers.totime("2019-03-05 12:12:12")))
-- print(os.time(parsers.totime("2019/03/05 12:12:12")))
-- print(os.time(parsers.totime("05-03-2019 12:12:12")))
diff --git a/macros/luatex/generic/lualibs/lualibs-util-sac.lua b/macros/luatex/generic/lualibs/lualibs-util-sac.lua
new file mode 100644
index 0000000000..36daef8167
--- /dev/null
+++ b/macros/luatex/generic/lualibs/lualibs-util-sac.lua
@@ -0,0 +1,582 @@
+if not modules then modules = { } end modules ['util-sac'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to luat-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- experimental string access (some 3 times faster than file access when messing
+-- with bytes)
+
+local byte, sub = string.byte, string.sub
+local tonumber = tonumber
+
+utilities = utilities or { }
+local streams = { }
+utilities.streams = streams
+
+function streams.open(filename,zerobased)
+ local f = filename and io.loaddata(filename)
+ if f then
+ return { f, 1, #f, zerobased or false }
+ end
+end
+
+function streams.openstring(f,zerobased)
+ if f then
+ return { f, 1, #f, zerobased or false }
+ end
+end
+
+function streams.getstring(f)
+ if f then
+ return f[1]
+ end
+end
+
+function streams.close()
+ -- dummy
+end
+
+function streams.size(f)
+ return f and f[3] or 0
+end
+
+streams.getsize = streams.size
+
+function streams.setposition(f,i)
+ if f[4] then
+ -- zerobased
+ if i <= 0 then
+ f[2] = 1
+ else
+ f[2] = i + 1
+ end
+ else
+ if i <= 1 then
+ f[2] = 1
+ else
+ f[2] = i
+ end
+ end
+end
+
+function streams.getposition(f)
+ if f[4] then
+ -- zerobased
+ return f[2] - 1
+ else
+ return f[2]
+ end
+end
+
+function streams.look(f,n,chars)
+ local b = f[2]
+ local e = b + n - 1
+ if chars then
+ return sub(f[1],b,e)
+ else
+ return byte(f[1],b,e)
+ end
+end
+
+function streams.skip(f,n)
+ f[2] = f[2] + n
+end
+
+function streams.readbyte(f)
+ local i = f[2]
+ f[2] = i + 1
+ return byte(f[1],i)
+end
+
+function streams.readbytes(f,n)
+ local i = f[2]
+ local j = i + n
+ f[2] = j
+ return byte(f[1],i,j-1)
+end
+
+function streams.readbytetable(f,n)
+ local i = f[2]
+ local j = i + n
+ f[2] = j
+ return { byte(f[1],i,j-1) }
+end
+
+function streams.skipbytes(f,n)
+ f[2] = f[2] + n
+end
+
+function streams.readchar(f)
+ local i = f[2]
+ f[2] = i + 1
+ return sub(f[1],i,i)
+end
+
+function streams.readstring(f,n)
+ local i = f[2]
+ local j = i + n
+ f[2] = j
+ return sub(f[1],i,j-1)
+end
+
+function streams.readinteger1(f) -- one byte
+ local i = f[2]
+ f[2] = i + 1
+ local n = byte(f[1],i)
+ if n >= 0x80 then
+ return n - 0x100
+ else
+ return n
+ end
+end
+
+streams.readcardinal1 = streams.readbyte -- one byte
+streams.readcardinal = streams.readcardinal1
+streams.readinteger = streams.readinteger1
+
+function streams.readcardinal2(f)
+ local i = f[2]
+ local j = i + 1
+ f[2] = j + 1
+ local a, b = byte(f[1],i,j)
+ return 0x100 * a + b
+end
+
+function streams.readcardinal2le(f)
+ local i = f[2]
+ local j = i + 1
+ f[2] = j + 1
+ local b, a = byte(f[1],i,j)
+ return 0x100 * a + b
+end
+
+function streams.readinteger2(f)
+ local i = f[2]
+ local j = i + 1
+ f[2] = j + 1
+ local a, b = byte(f[1],i,j)
+ if a >= 0x80 then
+ return 0x100 * a + b - 0x10000
+ else
+ return 0x100 * a + b
+ end
+end
+
+function streams.readinteger2le(f)
+ local i = f[2]
+ local j = i + 1
+ f[2] = j + 1
+ local b, a = byte(f[1],i,j)
+ if a >= 0x80 then
+ return 0x100 * a + b - 0x10000
+ else
+ return 0x100 * a + b
+ end
+end
+
+function streams.readcardinal3(f)
+ local i = f[2]
+ local j = i + 2
+ f[2] = j + 1
+ local a, b, c = byte(f[1],i,j)
+ return 0x10000 * a + 0x100 * b + c
+end
+
+function streams.readcardinal3le(f)
+ local i = f[2]
+ local j = i + 2
+ f[2] = j + 1
+ local c, b, a = byte(f[1],i,j)
+ return 0x10000 * a + 0x100 * b + c
+end
+
+function streams.readinteger3(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local a, b, c = byte(f[1],i,j)
+ if a >= 0x80 then
+ return 0x10000 * a + 0x100 * b + c - 0x1000000
+ else
+ return 0x10000 * a + 0x100 * b + c
+ end
+end
+
+function streams.readinteger3le(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local c, b, a = byte(f[1],i,j)
+ if a >= 0x80 then
+ return 0x10000 * a + 0x100 * b + c - 0x1000000
+ else
+ return 0x10000 * a + 0x100 * b + c
+ end
+end
+
+function streams.readcardinal4(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local a, b, c, d = byte(f[1],i,j)
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
+end
+
+function streams.readcardinal4le(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local d, c, b, a = byte(f[1],i,j)
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
+end
+
+function streams.readinteger4(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local a, b, c, d = byte(f[1],i,j)
+ if a >= 0x80 then
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
+ else
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
+ end
+end
+
+function streams.readinteger4le(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local d, c, b, a = byte(f[1],i,j)
+ if a >= 0x80 then
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d - 0x100000000
+ else
+ return 0x1000000 * a + 0x10000 * b + 0x100 * c + d
+ end
+end
+
+function streams.readfixed2(f)
+ local i = f[2]
+ local j = i + 1
+ f[2] = j + 1
+ local n1, n2 = byte(f[1],i,j)
+ if n1 >= 0x80 then
+ n1 = n1 - 0x100
+ end
+ return n1 + n2/0xFF
+end
+
+function streams.readfixed4(f)
+ local i = f[2]
+ local j = i + 3
+ f[2] = j + 1
+ local a, b, c, d = byte(f[1],i,j)
+ local n1 = 0x100 * a + b
+ local n2 = 0x100 * c + d
+ if n1 >= 0x8000 then
+ n1 = n1 - 0x10000
+ end
+ return n1 + n2/0xFFFF
+end
+
+if bit32 then
+
+ local extract = bit32.extract
+ local band = bit32.band
+
+ function streams.read2dot14(f)
+ local i = f[2]
+ local j = i + 1
+ f[2] = j + 1
+ local a, b = byte(f[1],i,j)
+ if a >= 0x80 then
+ local n = -(0x100 * a + b)
+ return - (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
+ else
+ local n = 0x100 * a + b
+ return (extract(n,14,2) + (band(n,0x3FFF) / 16384.0))
+ end
+ end
+
+end
+
+function streams.skipshort(f,n)
+ f[2] = f[2] + 2*(n or 1)
+end
+
+function streams.skiplong(f,n)
+ f[2] = f[2] + 4*(n or 1)
+end
+
+if sio and sio.readcardinal2 then
+
+ local readcardinal1 = sio.readcardinal1
+ local readcardinal2 = sio.readcardinal2
+ local readcardinal3 = sio.readcardinal3
+ local readcardinal4 = sio.readcardinal4
+ local readinteger1 = sio.readinteger1
+ local readinteger2 = sio.readinteger2
+ local readinteger3 = sio.readinteger3
+ local readinteger4 = sio.readinteger4
+ local readfixed2 = sio.readfixed2
+ local readfixed4 = sio.readfixed4
+ local read2dot14 = sio.read2dot14
+ local readbytes = sio.readbytes
+ local readbytetable = sio.readbytetable
+
+ function streams.readcardinal1(f)
+ local i = f[2]
+ f[2] = i + 1
+ return readcardinal1(f[1],i)
+ end
+ function streams.readcardinal2(f)
+ local i = f[2]
+ f[2] = i + 2
+ return readcardinal2(f[1],i)
+ end
+ function streams.readcardinal3(f)
+ local i = f[2]
+ f[2] = i + 3
+ return readcardinal3(f[1],i)
+ end
+ function streams.readcardinal4(f)
+ local i = f[2]
+ f[2] = i + 4
+ return readcardinal4(f[1],i)
+ end
+ function streams.readinteger1(f)
+ local i = f[2]
+ f[2] = i + 1
+ return readinteger1(f[1],i)
+ end
+ function streams.readinteger2(f)
+ local i = f[2]
+ f[2] = i + 2
+ return readinteger2(f[1],i)
+ end
+ function streams.readinteger3(f)
+ local i = f[2]
+ f[2] = i + 3
+ return readinteger3(f[1],i)
+ end
+ function streams.readinteger4(f)
+ local i = f[2]
+ f[2] = i + 4
+ return readinteger4(f[1],i)
+ end
+ function streams.readfixed2(f) -- needs recent luatex
+ local i = f[2]
+ f[2] = i + 2
+ return readfixed2(f[1],i)
+ end
+ function streams.readfixed4(f) -- needs recent luatex
+ local i = f[2]
+ f[2] = i + 4
+ return readfixed4(f[1],i)
+ end
+ function streams.read2dot14(f)
+ local i = f[2]
+ f[2] = i + 2
+ return read2dot14(f[1],i)
+ end
+ function streams.readbytes(f,n)
+ local i = f[2]
+ local s = f[3]
+ local p = i + n
+ if p > s then
+ f[2] = s + 1
+ else
+ f[2] = p
+ end
+ return readbytes(f[1],i,n)
+ end
+ function streams.readbytetable(f,n)
+ local i = f[2]
+ local s = f[3]
+ local p = i + n
+ if p > s then
+ f[2] = s + 1
+ else
+ f[2] = p
+ end
+ return readbytetable(f[1],i,n)
+ end
+
+ streams.readbyte = streams.readcardinal1
+ streams.readsignedbyte = streams.readinteger1
+ streams.readcardinal = streams.readcardinal1
+ streams.readinteger = streams.readinteger1
+
+end
+
+if sio and sio.readcardinaltable then
+
+ local readcardinaltable = sio.readcardinaltable
+ local readintegertable = sio.readintegertable
+
+ function utilities.streams.readcardinaltable(f,n,b)
+ local i = f[2]
+ local s = f[3]
+ local p = i + n * b
+ if p > s then
+ f[2] = s + 1
+ else
+ f[2] = p
+ end
+ return readcardinaltable(f[1],i,n,b)
+ end
+
+ function utilities.streams.readintegertable(f,n,b)
+ local i = f[2]
+ local s = f[3]
+ local p = i + n * b
+ if p > s then
+ f[2] = s + 1
+ else
+ f[2] = p
+ end
+ return readintegertable(f[1],i,n,b)
+ end
+
+else
+
+ local readcardinal1 = streams.readcardinal1
+ local readcardinal2 = streams.readcardinal2
+ local readcardinal3 = streams.readcardinal3
+ local readcardinal4 = streams.readcardinal4
+
+ function streams.readcardinaltable(f,n,b)
+ local i = f[2]
+ local s = f[3]
+ local p = i + n * b
+ if p > s then
+ f[2] = s + 1
+ else
+ f[2] = p
+ end
+ local t = { }
+ if b == 1 then for i=1,n do t[i] = readcardinal1(f[1],i) end
+ elseif b == 2 then for i=1,n do t[i] = readcardinal2(f[1],i) end
+ elseif b == 3 then for i=1,n do t[i] = readcardinal3(f[1],i) end
+ elseif b == 4 then for i=1,n do t[i] = readcardinal4(f[1],i) end end
+ return t
+ end
+
+ local readinteger1 = streams.readinteger1
+ local readinteger2 = streams.readinteger2
+ local readinteger3 = streams.readinteger3
+ local readinteger4 = streams.readinteger4
+
+ function streams.readintegertable(f,n,b)
+ local i = f[2]
+ local s = f[3]
+ local p = i + n * b
+ if p > s then
+ f[2] = s + 1
+ else
+ f[2] = p
+ end
+ local t = { }
+ if b == 1 then for i=1,n do t[i] = readinteger1(f[1],i) end
+ elseif b == 2 then for i=1,n do t[i] = readinteger2(f[1],i) end
+ elseif b == 3 then for i=1,n do t[i] = readinteger3(f[1],i) end
+ elseif b == 4 then for i=1,n do t[i] = readinteger4(f[1],i) end end
+ return t
+ end
+
+end
+
+-- For practical reasons we put this here. It's less efficient but ok when we don't
+-- have much access.
+
+do
+
+ local files = utilities.files
+
+ if files then
+
+ local openfile = files.open
+ local openstream = streams.open
+ local openstring = streams.openstring
+
+ local setmetatable = setmetatable
+
+ function io.newreader(str,method)
+ local f, m
+ if method == "string" then
+ f = openstring(str,true)
+ m = streams
+ elseif method == "stream" then
+ f = openstream(str,true)
+ m = streams
+ else
+ f = openfile(str,"rb")
+ m = files
+ end
+ if f then
+ local t = { }
+ setmetatable(t, {
+ __index = function(t,k)
+ local r = m[k]
+ if k == "close" then
+ -- maybe use __toclose
+ if f then
+ m.close(f)
+ f = nil
+ end
+ return function() end
+ elseif r then
+ local v = function(_,a,b) return r(f,a,b) end
+ t[k] = v
+ return v
+ else
+ print("unknown key",k)
+ end
+ end
+ } )
+ return t
+ end
+ end
+
+ end
+
+end
+
+if bit32 and not streams.tocardinal1 then
+
+ local extract = bit32.extract
+ local char = string.char
+
+ streams.tocardinal1 = char
+ function streams.tocardinal2(n) return char(extract( 8,8),extract( 0,8)) end
+ function streams.tocardinal3(n) return char(extract(16,8),extract( 8,8),extract(0,8)) end
+ function streams.tocardinal4(n) return char(extract(24,8),extract(16,8),extract(8,8),extract(0,8)) end
+
+ streams.tocardinal1le = char
+ function streams.tocardinal2le(n) return char(extract(0,8),extract(8,8)) end
+ function streams.tocardinal3le(n) return char(extract(0,8),extract(8,8),extract(16,8)) end
+ function streams.tocardinal4le(n) return char(extract(0,8),extract(8,8),extract(16,8),extract(24,8)) end
+
+end
+
+if not streams.readcstring then
+
+ local readchar = streams.readchar
+ local concat = table.concat
+
+ function streams.readcstring(f)
+ local t = { }
+ while true do
+ local c = readchar(f)
+ if c and c ~= "\0" then
+ t[#t+1] = c
+ else
+ return concat(t)
+ end
+ end
+ end
+
+end
diff --git a/macros/luatex/generic/lualibs/lualibs-util-str.lua b/macros/luatex/generic/lualibs/lualibs-util-str.lua
index 0d1f39de9d..b5c721a41d 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-str.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-str.lua
@@ -10,12 +10,13 @@ utilities = utilities or { }
utilities.strings = utilities.strings or { }
local strings = utilities.strings
-local format, gsub, rep, sub, find = string.format, string.gsub, string.rep, string.sub, string.find
+local format, gsub, rep, sub, find, char = string.format, string.gsub, string.rep, string.sub, string.find, string.char
local load, dump = load, string.dump
local tonumber, type, tostring, next, setmetatable = tonumber, type, tostring, next, setmetatable
local unpack, concat = table.unpack, table.concat
local 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 tsplitat = lpeg.tsplitat
local utfchar, utfbyte, utflen = utf.char, utf.byte, utf.len
----- loadstripped = utilities.lua.loadstripped
@@ -622,7 +623,7 @@ local template = [[
return function(%s) return %s end
]]
--- this might move
+-- We only use fast serialize in controlled cases.
local pattern = Cs(Cc('"') * (
(1-S('"\\\n\r'))^1
@@ -632,12 +633,43 @@ local pattern = Cs(Cc('"') * (
+ P('\r') / '\\r'
)^0 * Cc('"'))
+-- -- I need to do more experiments with this:
+--
+-- local pattern = Cs(Cc('"') * (
+-- (1-S('"\\\n\r'))^1
+-- + P('"') / '\\034'
+-- + P('\\') / '\\092'
+-- + P('\n') / '\\013'
+-- + P('\r') / '\\010'
+-- )^0 * Cc('"'))
+
patterns.escapedquotes = pattern
function string.escapedquotes(s)
return lpegmatch(pattern,s)
end
+local pattern = (1 - P("\\"))^1 ; pattern = Cs (
+ pattern
+ * ( (P("\\") / "" * (digit^-3 / function(s) return char(tonumber(s)) end)) + pattern )^1
+)
+
+patterns.unescapedquotes = pattern
+
+function string.unescapedquotes(s)
+ return lpegmatch(pattern,s) or s
+end
+
+-- function string.longifneeded(s)
+-- if find(s,'["\\\n\r]') then
+-- return "[===[" .. s .. "]===]"
+-- else
+-- return '"' .. s ..'"'
+-- end
+-- end
+
+string.texnewlines = lpeg.replacer(patterns.newline,"\r",true)
+
-- print(string.escapedquotes('1\\23\n"'))
-- but for now here
@@ -1476,7 +1508,7 @@ end
if not string.explode then
- local tsplitat = lpeg.tsplitat
+ -- local tsplitat = lpeg.tsplitat
local p_utf = patterns.utf8character
local p_check = C(p_utf) * (P("+") * Cc(true))^0
@@ -1499,3 +1531,24 @@ if not string.explode then
end
end
+
+
+do
+
+ local p_whitespace = patterns.whitespace^1
+
+ local cache = setmetatable({ }, { __index = function(t,k)
+ local p = tsplitat(p_whitespace * P(k) * p_whitespace)
+ local v = function(s)
+ return lpegmatch(p,s)
+ end
+ t[k] = v
+ return v
+ end })
+
+ function string.wordsplitter(s)
+ return cache[s]
+ end
+
+end
+
diff --git a/macros/luatex/generic/lualibs/lualibs-util-tab.lua b/macros/luatex/generic/lualibs/lualibs-util-tab.lua
index 9f7112eb91..64fa1af4fb 100644
--- a/macros/luatex/generic/lualibs/lualibs-util-tab.lua
+++ b/macros/luatex/generic/lualibs/lualibs-util-tab.lua
@@ -417,9 +417,9 @@ if JITSUPPORTED then
else
- local f_v = formatters["[%q]=%q,"]
- local f_t = formatters["[%q]="]
- local f_q = formatters["%q,"]
+ -- local f_v = formatters["[%q]=%q,"]
+ -- local f_t = formatters["[%q]="]
+ -- local f_q = formatters["%q,"]
function table.fastserialize(t,prefix) -- todo, move local function out
local r = { type(prefix) == "string" and prefix or "return" }
@@ -720,6 +720,7 @@ local function serialize(root,name,specification)
local t -- = { }
local n = 1
+ -- local m = 0 -- no gain
local unknown = false
local function do_serialize(root,name,depth,level,indexed)
@@ -850,6 +851,12 @@ local function serialize(root,name,specification)
n = n + 1 t[n] = f_key_str_value_str(depth,tostring(k),tostring(v))
end
end
+ -- if n > 100000 then -- no gain
+ -- local k = m + 1
+ -- t[k] = concat(t,"\n",k,n)
+ -- n = k
+ -- m = k
+ -- end
end
end
if level > 0 then
@@ -898,6 +905,7 @@ local function serialize(root,name,specification)
n = n + 1
t[n] = f_table_finish()
return concat(t,"\n")
+ -- return concat(t,"\n",1,n) -- no gain
end
table.serialize = serialize
@@ -970,3 +978,43 @@ end
-- return remove(t,random(1,n))
-- end
-- end
+
+function combine(target,source)
+ -- no copy so if that is needed one needs to deepcopy source first
+ if target then
+ for k, v in next, source do
+ if type(v) == "table" then
+ target[k] = combine(target[k],source[k])
+ else
+ target[k] = v
+ end
+ end
+ return target
+ else
+ return source
+ end
+end
+
+table.combine = combine
+
+-- If needed we can add something (some discussion on the list but I'm not sure if
+-- it makes sense because merging such mixed tables is quite unusual.
+--
+-- function table.himerged(...)
+-- local result = { }
+-- local r = 0
+-- for i=1,select("#",...) do
+-- local s = select(i,...)
+-- if s then
+-- for k, v in next, s do
+-- if type(k) == "number" then
+-- r = r + 1
+-- result[r] = v
+-- else
+-- result[k] = v
+-- end
+-- end
+-- end
+-- end
+-- return result
+-- end
diff --git a/macros/luatex/generic/lualibs/lualibs-util-zip.lua b/macros/luatex/generic/lualibs/lualibs-util-zip.lua
new file mode 100644
index 0000000000..bd8fdf287f
--- /dev/null
+++ b/macros/luatex/generic/lualibs/lualibs-util-zip.lua
@@ -0,0 +1,684 @@
+if not modules then modules = { } end modules ['util-zip'] = {
+ version = 1.001,
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- This module is mostly meant for relative simple zip and unzip tasks. We can read
+-- and write zip files but with limitations. Performance is quite good and it makes
+-- us independent of zip tools, which (for some reason) are not always installed.
+--
+-- This is an lmtx module and at some point will be lmtx only but for a while we
+-- keep some hybrid functionality.
+
+local type, tostring, tonumber = type, tostring, tonumber
+local sort, concat = table.sort, table.concat
+
+local find, format, sub, gsub = string.find, string.format, string.sub, string.gsub
+local osdate, ostime, osclock = os.date, os.time, os.clock
+local ioopen = io.open
+local loaddata, savedata = io.loaddata, io.savedata
+local filejoin, isdir, dirname, mkdirs = file.join, lfs.isdir, file.dirname, dir.mkdirs
+local suffix, suffixes = file.suffix, file.suffixes
+local openfile = io.open
+
+gzip = gzip or { } -- so in luatex we keep the old ones too
+
+if not zlib then
+ zlib = xzip -- in luametatex we shadow the old one
+elseif not xzip then
+ xzip = zlib
+end
+
+local files = utilities.files
+local openfile = files.open
+local closefile = files.close
+local readstring = files.readstring
+local readcardinal2 = files.readcardinal2le
+local readcardinal4 = files.readcardinal4le
+local setposition = files.setposition
+local getposition = files.getposition
+
+local band = bit32.band
+local rshift = bit32.rshift
+local lshift = bit32.lshift
+
+local zlibdecompress = zlib.decompress
+local zlibdecompresssize = zlib.decompresssize
+local zlibchecksum = zlib.crc32
+
+if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then
+ local cs = zlibchecksum
+ zlibchecksum = function(str,n) return cs(n or 0, str) end
+end
+
+local decompress = function(source) return zlibdecompress (source,-15) end -- auto
+local decompresssize = function(source,targetsize) return zlibdecompresssize(source,targetsize,-15) end -- auto
+local calculatecrc = function(buffer,initial) return zlibchecksum (initial or 0,buffer) end
+
+local zipfiles = { }
+utilities.zipfiles = zipfiles
+
+local openzipfile, closezipfile, unzipfile, foundzipfile, getziphash, getziplist do
+
+ function openzipfile(name)
+ return {
+ name = name,
+ handle = openfile(name,0),
+ }
+ end
+
+ local function collect(z)
+ if not z.list then
+ local list = { }
+ local hash = { }
+ local position = 0
+ local index = 0
+ local handle = z.handle
+ while true do
+ setposition(handle,position)
+ local signature = readstring(handle,4)
+ if signature == "PK\3\4" then
+ -- [local file header 1]
+ -- [encryption header 1]
+ -- [file data 1]
+ -- [data descriptor 1]
+ local version = readcardinal2(handle)
+ local flag = readcardinal2(handle)
+ local method = readcardinal2(handle)
+ local filetime = readcardinal2(handle)
+ local filedate = readcardinal2(handle)
+ local crc32 = readcardinal4(handle)
+ local compressed = readcardinal4(handle)
+ local uncompressed = readcardinal4(handle)
+ local namelength = readcardinal2(handle)
+ local extralength = readcardinal2(handle)
+ local filename = readstring(handle,namelength)
+ local descriptor = band(flag,8) ~= 0
+ local encrypted = band(flag,1) ~= 0
+ local acceptable = method == 0 or method == 8
+ -- 30 bytes of header including the signature
+ local skipped = 0
+ local size = 0
+ if encrypted then
+ size = readcardinal2(handle)
+ skipbytes(size)
+ skipped = skipped + size + 2
+ skipbytes(8)
+ skipped = skipped + 8
+ size = readcardinal2(handle)
+ skipbytes(size)
+ skipped = skipped + size + 2
+ size = readcardinal4(handle)
+ skipbytes(size)
+ skipped = skipped + size + 4
+ size = readcardinal2(handle)
+ skipbytes(size)
+ skipped = skipped + size + 2
+ end
+ position = position + 30 + namelength + extralength + skipped
+ if descriptor then
+ setposition(handle,position + compressed)
+ crc32 = readcardinal4(handle)
+ compressed = readcardinal4(handle)
+ uncompressed = readcardinal4(handle)
+ end
+ if acceptable then
+ index = index + 1
+ local data = {
+ filename = filename,
+ index = index,
+ position = position,
+ method = method,
+ compressed = compressed,
+ uncompressed = uncompressed,
+ crc32 = crc32,
+ encrypted = encrypted,
+ }
+ hash[filename] = data
+ list[index] = data
+ else
+ -- maybe a warning when encrypted
+ end
+ position = position + compressed
+ else
+ break
+ end
+ z.list = list
+ z.hash = hash
+ end
+ end
+ end
+
+ function getziplist(z)
+ local list = z.list
+ if not list then
+ collect(z)
+ end
+ return z.list
+ end
+
+ function getziphash(z)
+ local hash = z.hash
+ if not hash then
+ collect(z)
+ end
+ return z.hash
+ end
+
+ function foundzipfile(z,name)
+ return getziphash(z)[name]
+ end
+
+ function closezipfile(z)
+ local f = z.handle
+ if f then
+ closefile(f)
+ z.handle = nil
+ end
+ end
+
+ function unzipfile(z,filename,check)
+ local hash = z.hash
+ if not hash then
+ hash = zipfiles.hash(z)
+ end
+ local data = hash[filename] -- normalize
+ if not data then
+ -- lower and cleanup
+ -- only name
+ end
+ if data then
+ local handle = z.handle
+ local position = data.position
+ local compressed = data.compressed
+ if compressed > 0 then
+ setposition(handle,position)
+ local result = readstring(handle,compressed)
+ if data.method == 8 then
+ if decompresssize then
+ result = decompresssize(result,data.uncompressed)
+ else
+ result = decompress(result)
+ end
+ end
+ if check and data.crc32 ~= calculatecrc(result) then
+ print("checksum mismatch")
+ return ""
+ end
+ return result
+ else
+ return ""
+ end
+ end
+ end
+
+ zipfiles.open = openzipfile
+ zipfiles.close = closezipfile
+ zipfiles.unzip = unzipfile
+ zipfiles.hash = getziphash
+ zipfiles.list = getziplist
+ zipfiles.found = foundzipfile
+
+end
+
+if xzip then -- flate then do
+
+ local writecardinal1 = files.writebyte
+ local writecardinal2 = files.writecardinal2le
+ local writecardinal4 = files.writecardinal4le
+
+ local logwriter = logs.writer
+
+ local globpattern = dir.globpattern
+-- local compress = flate.flate_compress
+-- local checksum = flate.update_crc32
+ local compress = xzip.compress
+ local checksum = xzip.crc32
+
+ -- local function fromdostime(dostime,dosdate)
+ -- return ostime {
+ -- year = (dosdate >> 9) + 1980, -- 25 .. 31
+ -- month = (dosdate >> 5) & 0x0F, -- 21 .. 24
+ -- day = (dosdate ) & 0x1F, -- 16 .. 20
+ -- hour = (dostime >> 11) , -- 11 .. 15
+ -- min = (dostime >> 5) & 0x3F, -- 5 .. 10
+ -- sec = (dostime ) & 0x1F, -- 0 .. 4
+ -- }
+ -- end
+ --
+ -- local function todostime(time)
+ -- local t = osdate("*t",time)
+ -- return
+ -- ((t.year - 1980) << 9) + (t.month << 5) + t.day,
+ -- (t.hour << 11) + (t.min << 5) + (t.sec >> 1)
+ -- end
+
+ local function fromdostime(dostime,dosdate)
+ return ostime {
+ year = rshift(dosdate, 9) + 1980, -- 25 .. 31
+ month = band(rshift(dosdate, 5), 0x0F), -- 21 .. 24
+ day = band( (dosdate ), 0x1F), -- 16 .. 20
+ hour = band(rshift(dostime,11) ), -- 11 .. 15
+ min = band(rshift(dostime, 5), 0x3F), -- 5 .. 10
+ sec = band( (dostime ), 0x1F), -- 0 .. 4
+ }
+ end
+
+ local function todostime(time)
+ local t = osdate("*t",time)
+ return
+ lshift(t.year - 1980, 9) + lshift(t.month,5) + t.day,
+ lshift(t.hour ,11) + lshift(t.min ,5) + rshift(t.sec,1)
+ end
+
+ local function openzip(filename,level,comment,verbose)
+ local f = ioopen(filename,"wb")
+ if f then
+ return {
+ filename = filename,
+ handle = f,
+ list = { },
+ level = tonumber(level) or 3,
+ comment = tostring(comment),
+ verbose = verbose,
+ uncompressed = 0,
+ compressed = 0,
+ }
+ end
+ end
+
+ local function writezip(z,name,data,level,time)
+ local f = z.handle
+ local list = z.list
+ local level = tonumber(level) or z.level or 3
+ local method = 8
+ local zipped = compress(data,level)
+ local checksum = checksum(data)
+ local verbose = z.verbose
+ --
+ if not zipped then
+ method = 0
+ zipped = data
+ end
+ --
+ local start = f:seek()
+ local compressed = #zipped
+ local uncompressed = #data
+ --
+ z.compressed = z.compressed + compressed
+ z.uncompressed = z.uncompressed + uncompressed
+ --
+ if verbose then
+ local pct = 100 * compressed/uncompressed
+ if pct >= 100 then
+ logwriter(format("%10i %s",uncompressed,name))
+ else
+ logwriter(format("%10i %02.1f %s",uncompressed,pct,name))
+ end
+ end
+ --
+ f:write("\x50\x4b\x03\x04") -- PK.. 0x04034b50
+ --
+ writecardinal2(f,0) -- minimum version
+ writecardinal2(f,0) -- flag
+ writecardinal2(f,method) -- method
+ writecardinal2(f,0) -- time
+ writecardinal2(f,0) -- date
+ writecardinal4(f,checksum) -- crc32
+ writecardinal4(f,compressed) -- compressed
+ writecardinal4(f,uncompressed) -- uncompressed
+ writecardinal2(f,#name) -- namelength
+ writecardinal2(f,0) -- extralength
+ --
+ f:write(name) -- name
+ f:write(zipped)
+ --
+ list[#list+1] = { #zipped, #data, name, checksum, start, time or 0 }
+ end
+
+ local function closezip(z)
+ local f = z.handle
+ local list = z.list
+ local comment = z.comment
+ local verbose = z.verbose
+ local count = #list
+ local start = f:seek()
+ --
+ for i=1,count do
+ local l = list[i]
+ local compressed = l[1]
+ local uncompressed = l[2]
+ local name = l[3]
+ local checksum = l[4]
+ local start = l[5]
+ local time = l[6]
+ local date, time = todostime(time)
+ f:write('\x50\x4b\x01\x02')
+ writecardinal2(f,0) -- version made by
+ writecardinal2(f,0) -- version needed to extract
+ writecardinal2(f,0) -- flags
+ writecardinal2(f,8) -- method
+ writecardinal2(f,time) -- time
+ writecardinal2(f,date) -- date
+ writecardinal4(f,checksum) -- crc32
+ writecardinal4(f,compressed) -- compressed
+ writecardinal4(f,uncompressed) -- uncompressed
+ writecardinal2(f,#name) -- namelength
+ writecardinal2(f,0) -- extralength
+ writecardinal2(f,0) -- commentlength
+ writecardinal2(f,0) -- nofdisks -- ?
+ writecardinal2(f,0) -- internal attr (type)
+ writecardinal4(f,0) -- external attr (mode)
+ writecardinal4(f,start) -- local offset
+ f:write(name) -- name
+ end
+ --
+ local stop = f:seek()
+ local size = stop - start
+ --
+ f:write('\x50\x4b\x05\x06')
+ writecardinal2(f,0) -- disk
+ writecardinal2(f,0) -- disks
+ writecardinal2(f,count) -- entries
+ writecardinal2(f,count) -- entries
+ writecardinal4(f,size) -- dir size
+ writecardinal4(f,start) -- dir offset
+ if type(comment) == "string" and comment ~= "" then
+ writecardinal2(f,#comment) -- comment length
+ f:write(comment) -- comemnt
+ else
+ writecardinal2(f,0)
+ end
+ --
+ if verbose then
+ local compressed = z.compressed
+ local uncompressed = z.uncompressed
+ local filename = z.filename
+ --
+ local pct = 100 * compressed/uncompressed
+ logwriter("")
+ if pct >= 100 then
+ logwriter(format("%10i %s",uncompressed,filename))
+ else
+ logwriter(format("%10i %02.1f %s",uncompressed,pct,filename))
+ end
+ end
+ --
+ f:close()
+ end
+
+ local function zipdir(zipname,path,level,verbose)
+ if type(zipname) == "table" then
+ verbose = zipname.verbose
+ level = zipname.level
+ path = zipname.path
+ zipname = zipname.zipname
+ end
+ if not zipname or zipname == "" then
+ return
+ end
+ if not path or path == "" then
+ path = "."
+ end
+ if not isdir(path) then
+ return
+ end
+ path = gsub(path,"\\+","/")
+ path = gsub(path,"/+","/")
+ local list = { }
+ local count = 0
+ globpattern(path,"",true,function(name,size,time)
+ count = count + 1
+ list[count] = { name, time }
+ end)
+ sort(list,function(a,b)
+ return a[1] < b[1]
+ end)
+ local zipf = openzip(zipname,level,comment,verbose)
+ if zipf then
+ local p = #path + 2
+ for i=1,count do
+ local li = list[i]
+ local name = li[1]
+ local time = li[2]
+ local data = loaddata(name)
+ local name = sub(name,p,#name)
+ writezip(zipf,name,data,level,time,verbose)
+ end
+ closezip(zipf)
+ end
+ end
+
+ local function unzipdir(zipname,path,verbose)
+ if type(zipname) == "table" then
+ verbose = zipname.verbose
+ path = zipname.path
+ zipname = zipname.zipname
+ end
+ if not zipname or zipname == "" then
+ return
+ end
+ if not path or path == "" then
+ path = "."
+ end
+ local z = openzipfile(zipname)
+ if z then
+ local list = getziplist(z)
+ if list then
+ local total = 0
+ local count = #list
+ local step = number.idiv(count,10)
+ local done = 0
+ local steps = verbose == "steps"
+ local time = steps and osclock()
+ for i=1,count do
+ local l = list[i]
+ local n = l.filename
+ local d = unzipfile(z,n) -- true for check
+ if d then
+ local p = filejoin(path,n)
+ if mkdirs(dirname(p)) then
+ if steps then
+ total = total + #d
+ done = done + 1
+ if done >= step then
+ done = 0
+ logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",i,count,total,osclock()-time))
+ end
+ elseif verbose then
+ logwriter(n)
+ end
+ savedata(p,d)
+ end
+ else
+ logwriter(format("problem with file %s",n))
+ end
+ end
+ if steps then
+ logwriter(format("%4i files of %4i done, %10i bytes, %0.3f seconds",count,count,total,osclock()-time))
+ end
+ closezipfile(z)
+ return true
+ else
+ closezipfile(z)
+ end
+ end
+ end
+
+ zipfiles.zipdir = zipdir
+ zipfiles.unzipdir = unzipdir
+
+end
+
+-- todo: compress/decompress that work with offset in string
+
+-- We only have a few official methods here:
+--
+-- local decompressed = gzip.load (filename)
+-- local resultsize = gzip.save (filename,compresslevel)
+-- local compressed = gzip.compress (str,compresslevel)
+-- local decompressed = gzip.decompress (str)
+-- local iscompressed = gzip.compressed (str)
+-- local suffix, okay = gzip.suffix (filename)
+--
+-- In LuaMetaTeX we have only xzip which implements a very few methods:
+--
+-- compress (str,level,method,window,memory,strategy)
+-- decompress (str,window)
+-- adler32 (str,checksum)
+-- crc32 (str,checksum)
+
+local pattern = "^\x1F\x8B\x08"
+local gziplevel = 3
+
+function gzip.suffix(filename)
+ local suffix, extra = suffixes(filename)
+ local gzipped = extra == "gz"
+ return suffix, gzipped
+end
+
+function gzip.compressed(s)
+ return s and find(s,pattern)
+end
+
+local getdecompressed
+local putcompressed
+
+if gzip.compress then
+
+ local gzipwindow = 15 + 16 -- +16: gzip, +32: gzip|zlib
+
+ local compress = zlib.compress
+ local decompress = zlib.decompress
+
+ getdecompressed = function(str)
+ return decompress(str,gzipwindow) -- pass offset
+ end
+
+ putcompressed = function(str,level)
+ return compress(str,level or gziplevel,nil,gzipwindow)
+ end
+
+else
+
+ -- Special window values are: flate: -15, zlib: 15, gzip : -15
+
+ local gzipwindow = -15 -- miniz needs this
+ local identifier = "\x1F\x8B"
+
+ local compress = zlib.compress
+ local decompress = zlib.decompress
+ local zlibchecksum = zlib.crc32
+
+ if not CONTEXTLMTXMODE or CONTEXTLMTXMODE == 0 then
+ local cs = zlibchecksum
+ zlibchecksum = function(str,n) return cs(n or 0, str) end
+ end
+
+ local streams = utilities.streams
+ local openstream = streams.openstring
+ local closestream = streams.close
+ local getposition = streams.getposition
+ local readbyte = streams.readbyte
+ local readcardinal4 = streams.readcardinal4le
+ local readcardinal2 = streams.readcardinal2le
+ local readstring = streams.readstring
+ local readcstring = streams.readcstring
+ local skipbytes = streams.skip
+
+ local tocardinal1 = streams.tocardinal1
+ local tocardinal4 = streams.tocardinal4le
+
+ getdecompressed = function(str)
+ local s = openstream(str)
+ local identifier = readstring(s,2)
+ local method = readbyte(s,1)
+ local flags = readbyte(s,1)
+ local timestamp = readcardinal4(s)
+ local compression = readbyte(s,1)
+ local operating = readbyte(s,1)
+ -- local isjusttext = (flags & 0x01 ~= 0) and true or false
+ -- local extrasize = (flags & 0x04 ~= 0) and readcardinal2(s) or 0
+ -- local filename = (flags & 0x08 ~= 0) and readcstring(s) or ""
+ -- local comment = (flags & 0x10 ~= 0) and readcstring(s) or ""
+ -- local checksum = (flags & 0x02 ~= 0) and readcardinal2(s) or 0
+ local isjusttext = band(flags,0x01) ~= 0 and true or false
+ local extrasize = band(flags,0x04) ~= 0 and readcardinal2(s) or 0
+ local filename = band(flags,0x08) ~= 0 and readcstring(s) or ""
+ local comment = band(flags,0x10) ~= 0 and readcstring(s) or ""
+ local checksum = band(flags,0x02) ~= 0 and readcardinal2(s) or 0
+ local compressed = readstring(s,#str)
+ local data = decompress(compressed,gzipwindow) -- pass offset
+ return data
+ end
+
+ putcompressed = function(str,level,originalname)
+ return concat {
+ identifier, -- 2 identifier
+ tocardinal1(0x08), -- 1 method
+ tocardinal1(0x08), -- 1 flags
+ tocardinal4(os.time()), -- 4 mtime
+ tocardinal1(0x02), -- 1 compression (2 or 4)
+ tocardinal1(0xFF), -- 1 operating
+ (originalname or "unknownname") .. "\0",
+ compress(str,level,nil,gzipwindow),
+ tocardinal4(zlibchecksum(str)), -- 4
+ tocardinal4(#str), -- 4
+ }
+ end
+
+end
+
+function gzip.load(filename)
+ local f = openfile(filename,"rb")
+ if not f then
+ -- invalid file
+ else
+ local data = f:read("*all")
+ f:close()
+ if data and data ~= "" then
+ if suffix(filename) == "gz" then
+ data = getdecompressed(data)
+ end
+ return data
+ end
+ end
+end
+
+function gzip.save(filename,data,level,originalname)
+ if suffix(filename) ~= "gz" then
+ filename = filename .. ".gz"
+ end
+ local f = openfile(filename,"wb")
+ if f then
+ data = putcompressed(data or "",level or gziplevel,originalname)
+ f:write(data)
+ f:close()
+ return #data
+ end
+end
+
+function gzip.compress(s,level)
+ if s and not find(s,pattern) then
+ if not level then
+ level = gziplevel
+ elseif level <= 0 then
+ return s
+ elseif level > 9 then
+ level = 9
+ end
+ return putcompressed(s,level or gziplevel) or s
+ end
+end
+
+function gzip.decompress(s)
+ if s and find(s,pattern) then
+ return getdecompressed(s)
+ else
+ return s
+ end
+end
+
+-- return zipfiles
diff --git a/macros/luatex/generic/lualibs/lualibs.dtx b/macros/luatex/generic/lualibs/lualibs.dtx
index 73c5aafcc1..ebdba58424 100644
--- a/macros/luatex/generic/lualibs/lualibs.dtx
+++ b/macros/luatex/generic/lualibs/lualibs.dtx
@@ -37,7 +37,7 @@
\input docstrip.tex
\Msg{************************************************************************}
\Msg{* Installation}
-\Msg{* Package: lualibs 2021-05-20 v2.74 Lua additional functions.}
+\Msg{* Package: lualibs 2022-10-04 v2.75 Lua additional functions.}
\Msg{************************************************************************}
\keepsilent
@@ -107,7 +107,7 @@ and lualibs-extended.lua.
%<*driver>
\NeedsTeXFormat{LaTeX2e}
\ProvidesFile{lualibs.drv}
- [2021/05/20 v2.74 Lua Libraries.]
+ [2022/10/04 v2.75 Lua Libraries.]
\documentclass{ltxdoc}
\usepackage{fancyvrb,xspace}
\usepackage[x11names]{xcolor}
@@ -115,6 +115,7 @@ and lualibs-extended.lua.
\def\primarycolor{DodgerBlue4} %%-> rgb 16 78 139 | #104e8b
\def\secondarycolor{Goldenrod4} %%-> rgb 139 105 200 | #8b6914
%
+\AddToHook{package/hyperref/after}{%
\hypersetup{
colorlinks=true,
linkcolor=\primarycolor,
@@ -123,7 +124,7 @@ and lualibs-extended.lua.
pdftitle={The lualibs package},
pdfsubject={Port of the ConTeXt Lua libraries},
pdfauthor={Elie Roux & Philipp Gesang},
- pdfkeywords={luatex, lualatex, unicode, opentype}}
+ pdfkeywords={luatex, lualatex, unicode, opentype}}}
\newcommand*\email[1]{\href{mailto:#1}{#1}}
\usepackage{fontspec}
@@ -207,7 +208,7 @@ and lualibs-extended.lua.
% \GetFileInfo{lualibs.drv}
%
% \title{The \identifier{lualibs} package}
-% \date{2021/05/20 v2.74}
+% \date{2022/10/04 v2.75}
% \author{Élie Roux · \email{elie.roux@telecom-bretagne.eu}\\
% Philipp Gesang · \email{phg@phi-gamma.net}\\
% The \LaTeX{} Project · \email{https://github.com/latex3/lualibs/}\\
@@ -322,12 +323,11 @@ and lualibs-extended.lua.
% lualibs-io.lua & l-io.lua & reading and writing files \\
% lualibs-os.lua & l-os.lua & platform specific code \\
% lualibs-file.lua & l-file.lua & filesystem operations \\
-% lualibs-gzip.lua & l-gzip.lua & wrapper for \identifier{lgzip} \\
% lualibs-md5.lua & l-md5.lua & checksum functions \\
% lualibs-dir.lua & l-dir.lua & directory handling \\
% lualibs-unicode.lua & l-unicode.lua & utf and unicode \\
% lualibs-url.lua & l-url.lua & url handling \\
-% lualibs-set.lua & l-set.lua & sets \\[1ex]
+% lualibs-set.lua & l-set.lua & sets \\
% \end{tabular}
% \label{tab:basic}
% \hrule
@@ -346,6 +346,7 @@ and lualibs-extended.lua.
% \vskip1em
% \begin{tabular}{l l l}
% \identifier{lualibs} name & \CONTEXT name & primary purpose \\[1ex]
+% lualibs-util-sac.lua & util-sac.lua & string based file readers \\
% lualibs-util-str.lua & util-str.lua & extra |string| functions \\
% lualibs-util-fil.lua & util-fil.lua & extra |file| functions \\
% lualibs-util-tab.lua & util-tab.lua & extra |table| functions \\
@@ -357,7 +358,8 @@ and lualibs-extended.lua.
% lualibs-util-deb.lua & util-deb.lua & extra |debug| functionality \\
% lualibs-util-tpl.lua & util-tpl.lua & templating \\
% lualibs-util-sta.lua & util-sta.lua & stacker (e.~g. for \abbrev{pdf}) \\
-% lualibs-util-jsn.lua & util-jsn.lua & conversion to and from json \\[1ex]
+% lualibs-util-jsn.lua & util-jsn.lua & conversion to and from json \\
+% lualibs-util-zip.lua & util-zip.lua & compression and zip files \\[1ex]
% \end{tabular}
% \label{tab:extended}
% \hrule
@@ -428,8 +430,8 @@ lualibs = lualibs or { }
lualibs.module_info = {
name = "lualibs",
- version = "2.74", --TAGVERSION
- date = "2021-05-20", --TAGDATE
+ version = "2.75", --TAGVERSION
+ date = "2022-10-04", --TAGDATE
description = "ConTeXt Lua standard libraries.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -582,8 +584,8 @@ local loadmodule = lualibs.loadmodule
local lualibs_basic_module = {
name = "lualibs-basic",
- version = "2.74", --TAGVERSION
- date = "2021-05-20", --TAGDATE
+ version = "2.75", --TAGVERSION
+ date = "2022-10-04", --TAGDATE
description = "ConTeXt Lua libraries -- basic collection.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -621,7 +623,6 @@ if loaded == false then
loadmodule("lualibs-io.lua")
loadmodule("lualibs-os.lua")
loadmodule("lualibs-file.lua")
- loadmodule("lualibs-gzip.lua")
loadmodule("lualibs-md5.lua")
loadmodule("lualibs-dir.lua")
loadmodule("lualibs-unicode.lua")
@@ -664,8 +665,8 @@ lualibs = lualibs or { }
local lualibs_extended_module = {
name = "lualibs-extended",
- version = "2.74", --TAGVERSION
- date = "2021-05-20", --TAGDATE
+ version = "2.75", --TAGVERSION
+ date = "2022-10-04", --TAGDATE
description = "ConTeXt Lua libraries -- extended collection.",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL & Elie Roux & Philipp Gesang",
copyright = "PRAGMA ADE / ConTeXt Development Team",
@@ -776,6 +777,7 @@ else
end
if loaded == false then
+ loadmodule("lualibs-util-sac.lua")--- streams: string based file parsers
loadmodule("lualibs-util-str.lua")--- string formatters (fast)
loadmodule("lualibs-util-fil.lua")--- extra file helpers
loadmodule("lualibs-util-tab.lua")--- extended table operations
@@ -795,6 +797,7 @@ if loaded == false then
loadmodule("lualibs-util-deb.lua")--- extra debugging
loadmodule("lualibs-util-tpl.lua")--- templating
loadmodule("lualibs-util-sta.lua")--- stacker (for writing pdf)
+ loadmodule("lualibs-util-zip.lua")--- compression and zip files
end
unfake_context() --- TODO check if this works at runtime
diff --git a/macros/luatex/generic/lualibs/lualibs.pdf b/macros/luatex/generic/lualibs/lualibs.pdf
index 23df3045e6..175e7e9f01 100644
--- a/macros/luatex/generic/lualibs/lualibs.pdf
+++ b/macros/luatex/generic/lualibs/lualibs.pdf
Binary files differ