mtxrun.lua /size: 676 Kb    last modification: 2021-10-28 13:50
1#!/usr/bin/env texlua
2
3if not modules then modules = { } end modules ['mtxrun'] = {
4    version   = 1.001,
5    comment   = "runner, lua replacement for texmfstart.rb",
6    author    = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
7    copyright = "PRAGMA ADE / ConTeXt Development Team",
8    license   = "see context related readme files"
9}
10
11-- one can make a stub:
12
13-- mtxrun :
14--
15-- #!/bin/sh
16-- env LUATEXDIR=/....../texmf/scripts/context/lua luatex --luaonly mtxrun.lua "$@"
17
18-- mtxrun.cmd :
19--
20-- @luatex --luaonly %~d0%~p0mtxrun.lua %*
21
22-- filename : mtxrun.lua
23-- comment  : companion to context.tex
24-- author   : Hans Hagen, PRAGMA-ADE, Hasselt NL
25-- copyright: PRAGMA ADE / ConTeXt Development Team
26-- license  : see context related readme files
27
28-- This script is based on texmfstart.rb but does not use kpsewhich to locate files.
29-- Although kpse is a library it never came to opening up its interface to other
30-- programs (esp scripting languages) and so we do it ourselves. The lua variant
31-- evolved out of an experimental ruby one. Interesting is that using a scripting
32-- language instead of c does not have a speed penalty. Actually the lua variant is
33-- more efficient, especially when multiple calls to kpsewhich are involved. The lua
34-- library also gives way more control.
35
36-- When libraries used here are updates you can run
37--
38--   mtxrun --selfmerge
39--
40-- to update the embedded code. After that you might need to run
41--
42--   mtxrun --selfupdate
43--
44-- to copy the new script (from scripts/context/lua) to location where
45-- binaries are expected. If you want to remove the embedded code you can run
46--
47--   mtxxun --selfclean
48
49-- to be done / considered
50--
51-- support for --exec or make it default
52-- support for jar files (or maybe not, never used, too messy)
53-- support for $RUBYINPUTS cum suis (if still needed)
54-- remember for subruns: _CTX_K_V_#{original}_
55-- remember for subruns: _CTX_K_S_#{original}_
56-- remember for subruns: TEXMFSTART.#{original} [tex.rb texmfstart.rb]
57
58-- begin library merge
59
60
61
62do -- create closure to overcome 200 locals limit
63
64package.loaded["l-bit32"] = package.loaded["l-bit32"] or true
65
66-- original size: 3607, stripped down to: 3009
67
68if not modules then modules={} end modules ['l-bit32']={
69 version=1.001,
70 license="the same as regular Lua",
71 source="bitwise.lua, v 1.24 2014/12/26 17:20:53 roberto",
72 comment="drop-in for bit32, adapted a bit by Hans Hagen",
73}
74if bit32 then
75elseif utf8 then
76 load ([[
77local select = select -- instead of: arg = { ... }
78bit32 = {
79  bnot = function (a)
80    return ~a & 0xFFFFFFFF
81  end,
82  band = function (x, y, z, ...)
83    if not z then
84      return ((x or -1) & (y or -1)) & 0xFFFFFFFF
85    else
86      local res = x & y & z
87      for i=1,select("#",...) do
88        res = res & select(i,...)
89      end
90      return res & 0xFFFFFFFF
91    end
92  end,
93  bor = function (x, y, z, ...)
94    if not z then
95      return ((x or 0) | (y or 0)) & 0xFFFFFFFF
96    else
97      local res = x | y | z
98      for i=1,select("#",...) do
99        res = res | select(i,...)
100      end
101      return res & 0xFFFFFFFF
102    end
103  end,
104  bxor = function (x, y, z, ...)
105    if not z then
106      return ((x or 0) ~ (y or 0)) & 0xFFFFFFFF
107    else
108      local res = x ~ y ~ z
109      for i=1,select("#",...) do
110        res = res ~ select(i,...)
111      end
112      return res & 0xFFFFFFFF
113    end
114  end,
115  btest = function (x, y, z, ...)
116    if not z then
117      return (((x or -1) & (y or -1)) & 0xFFFFFFFF) ~= 0
118    else
119      local res = x & y & z
120      for i=1,select("#",...) do
121          res = res & select(i,...)
122      end
123      return (res & 0xFFFFFFFF) ~= 0
124    end
125  end,
126  lshift = function (a, b)
127    return ((a & 0xFFFFFFFF) << b) & 0xFFFFFFFF
128  end,
129  rshift = function (a, b)
130    return ((a & 0xFFFFFFFF) >> b) & 0xFFFFFFFF
131  end,
132  arshift = function (a, b)
133    a = a & 0xFFFFFFFF
134    if b <= 0 or (a & 0x80000000) == 0 then
135      return (a >> b) & 0xFFFFFFFF
136    else
137      return ((a >> b) | ~(0xFFFFFFFF >> b)) & 0xFFFFFFFF
138    end
139  end,
140  lrotate = function (a ,b)
141    b = b & 31
142    a = a & 0xFFFFFFFF
143    a = (a << b) | (a >> (32 - b))
144    return a & 0xFFFFFFFF
145  end,
146  rrotate = function (a, b)
147    b = -b & 31
148    a = a & 0xFFFFFFFF
149    a = (a << b) | (a >> (32 - b))
150    return a & 0xFFFFFFFF
151  end,
152  extract = function (a, f, w)
153    return (a >> f) & ~(-1 << (w or 1))
154  end,
155  replace = function (a, v, f, w)
156    local mask = ~(-1 << (w or 1))
157    return ((a & ~(mask << f)) | ((v & mask) << f)) & 0xFFFFFFFF
158  end,
159}
160        ]] ) ()
161elseif bit then
162 load ([[
163local band, bnot, rshift, lshift = bit.band, bit.bnot, bit.rshift, bit.lshift
164bit32 = {
165  arshift = bit.arshift,
166  band    = band,
167  bnot    = bnot,
168  bor     = bit.bor,
169  bxor    = bit.bxor,
170  btest   = function(...)
171    return band(...) ~= 0
172  end,
173  extract = function(a,f,w)
174    return band(rshift(a,f),2^(w or 1)-1)
175  end,
176  lrotate = bit.rol,
177  lshift  = lshift,
178  replace = function(a,v,f,w)
179    local mask = 2^(w or 1)-1
180    return band(a,bnot(lshift(mask,f)))+lshift(band(v,mask),f)
181  end,
182  rrotate = bit.ror,
183  rshift  = rshift,
184}
185        ]] ) ()
186else
187 xpcall(function() local _,t=require("bit32") if t then bit32=t end return end,function() end)
188end
189
190
191end -- of closure
192
193do -- create closure to overcome 200 locals limit
194
195package.loaded["l-lua"] = package.loaded["l-lua"] or true
196
197-- original size: 6405, stripped down to: 2865
198
199if not modules then modules={} end modules ['l-lua']={
200 version=1.001,
201 comment="companion to luat-lib.mkiv",
202 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
203 copyright="PRAGMA ADE / ConTeXt Development Team",
204 license="see context related readme files"
205}
206local next,type,tonumber=next,type,tonumber
207LUAMAJORVERSION,LUAMINORVERSION=string.match(_VERSION,"^[^%d]+(%d+)%.(%d+).*$")
208LUAMAJORVERSION=tonumber(LUAMAJORVERSION) or 5
209LUAMINORVERSION=tonumber(LUAMINORVERSION) or 1
210LUAVERSION=LUAMAJORVERSION+LUAMINORVERSION/10
211if LUAVERSION<5.2 and jit then
212 MINORVERSION=2
213 LUAVERSION=5.2
214end
215if not lpeg then
216 lpeg=require("lpeg")
217end
218if loadstring then
219 local loadnormal=load
220 function load(first,...)
221  if type(first)=="string" then
222   return loadstring(first,...)
223  else
224   return loadnormal(first,...)
225  end
226 end
227else
228 loadstring=load
229end
230if not ipairs then
231 local function iterate(a,i)
232  i=i+1
233  local v=a[i]
234  if v~=nil then
235   return i,v 
236  end
237 end
238 function ipairs(a)
239  return iterate,a,0
240 end
241end
242if not pairs then
243 function pairs(t)
244  return next,t 
245 end
246end
247if not table.unpack then
248 table.unpack=_G.unpack
249elseif not unpack then
250 _G.unpack=table.unpack
251end
252if not package.loaders then 
253 package.loaders=package.searchers
254end
255local print,select,tostring=print,select,tostring
256local inspectors={}
257function setinspector(kind,inspector) 
258 inspectors[kind]=inspector
259end
260function inspect(...) 
261 for s=1,select("#",...) do
262  local value=select(s,...)
263  if value==nil then
264   print("nil")
265  else
266   local done=false
267   local kind=type(value)
268   local inspector=inspectors[kind]
269   if inspector then
270    done=inspector(value)
271    if done then
272     break
273    end
274   end
275   for kind,inspector in next,inspectors do
276    done=inspector(value)
277    if done then
278     break
279    end
280   end
281   if not done then
282    print(tostring(value))
283   end
284  end
285 end
286end
287local dummy=function() end
288function optionalrequire(...)
289 local ok,result=xpcall(require,dummy,...)
290 if ok then
291  return result
292 end
293end
294local flush=io.flush
295if flush then
296 local execute=os.execute if execute then function os.execute(...) flush() return execute(...) end end
297 local exec=os.exec if exec then function os.exec   (...) flush() return exec   (...) end end
298 local spawn=os.spawn   if spawn   then function os.spawn  (...) flush() return spawn  (...) end end
299 local popen=io.popen   if popen   then function io.popen  (...) flush() return popen  (...) end end
300end
301FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
302if not FFISUPPORTED then
303 local okay;okay,ffi=pcall(require,"ffi")
304 FFISUPPORTED=type(ffi)=="table" and ffi.os~="" and ffi.arch~="" and ffi.load
305end
306if not FFISUPPORTED then
307 ffi=nil
308elseif not ffi.number then
309 ffi.number=tonumber
310end
311if LUAVERSION>5.3 then
312end
313if status and os.setenv then
314 os.setenv("engine",string.lower(status.luatex_engine or "unknown"))
315end
316
317
318end -- of closure
319
320do -- create closure to overcome 200 locals limit
321
322package.loaded["l-macro"] = package.loaded["l-macro"] or true
323
324-- original size: 10130, stripped down to: 5990
325
326if not modules then modules={} end modules ['l-macros']={
327 version=1.001,
328 comment="companion to luat-lib.mkiv",
329 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
330 copyright="PRAGMA ADE / ConTeXt Development Team",
331 license="see context related readme files"
332}
333local S,P,R,V,C,Cs,Cc,Ct,Carg=lpeg.S,lpeg.P,lpeg.R,lpeg.V,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Ct,lpeg.Carg
334local lpegmatch=lpeg.match
335local concat=table.concat
336local format,sub,match=string.format,string.sub,string.match
337local next,load,type=next,load,type
338local newline=S("\n\r")^1
339local continue=P("\\")*newline
340local whitespace=S(" \t\n\r")
341local spaces=S(" \t")+continue
342local nametoken=R("az","AZ","__","09")
343local name=nametoken^1
344local body=((continue/""+1)-newline)^1
345local lparent=P("(")
346local rparent=P(")")
347local noparent=1-(lparent+rparent)
348local nested=P { lparent*(noparent+V(1))^0*rparent }
349local escaped=P("\\")*P(1)
350local squote=P("'")
351local dquote=P('"')
352local quoted=dquote*(escaped+(1-dquote))^0*dquote+squote*(escaped+(1-squote))^0*squote
353local arguments=lparent*Ct((Cs((nested+(quoted+1-S("),")))^1)+S(", "))^0)*rparent
354local macros=lua.macros or {}
355lua.macros=macros
356local patterns={}
357local definitions={}
358local resolve
359local subparser
360local report_lua=function(...)
361 if logs and logs.reporter then
362  report_lua=logs.reporter("system","lua")
363  report_lua(...)
364 else
365  print(format(...))
366 end
367end
368local safeguard=P("local")*whitespace^1*name*(whitespace+P("="))
369resolve=safeguard+C(C(name)*(arguments^-1))/function(raw,s,a)
370 local d=definitions[s]
371 if d then
372  if a then
373   local n=#a
374   local p=patterns[s][n]
375   if p then
376    local d=d[n]
377    for i=1,n do
378     a[i]=lpegmatch(subparser,a[i]) or a[i]
379    end
380    return lpegmatch(p,d,1,a) or d
381   else
382    return raw
383   end
384  else
385   return d[0] or raw
386  end
387 elseif a then
388  for i=1,#a do
389   a[i]=lpegmatch(subparser,a[i]) or a[i]
390  end
391  return s.."("..concat(a,",")..")"
392 else
393  return raw
394 end
395end
396subparser=Cs((resolve+P(1))^1)
397local enddefine=P("#enddefine")/""
398local beginregister=(C(name)*(arguments+Cc(false))*C((1-enddefine)^1)*enddefine)/function(k,a,v)
399 local n=0
400 if a then
401  n=#a
402  local pattern=P(false)
403  for i=1,n do
404   pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end
405  end
406  pattern=Cs((pattern+P(1))^1)
407  local p=patterns[k]
408  if not p then
409   p={ [0]=false,false,false,false,false,false,false,false,false }
410   patterns[k]=p
411  end
412  p[n]=pattern
413 end
414 local d=definitions[k]
415 if not d then
416  d={ a=a,[0]=false,false,false,false,false,false,false,false,false }
417  definitions[k]=d
418 end
419 d[n]=lpegmatch(subparser,v) or v
420 return ""
421end
422local register=(Cs(name)*(arguments+Cc(false))*spaces^0*Cs(body))/function(k,a,v)
423 local n=0
424 if a then
425  n=#a
426  local pattern=P(false)
427  for i=1,n do
428   pattern=pattern+(P(a[i])*Carg(1))/function(t) return t[i] end
429  end
430  pattern=Cs((pattern+P(1))^1)
431  local p=patterns[k]
432  if not p then
433   p={ [0]=false,false,false,false,false,false,false,false,false }
434   patterns[k]=p
435  end
436  p[n]=pattern
437 end
438 local d=definitions[k]
439 if not d then
440  d={ a=a,[0]=false,false,false,false,false,false,false,false,false }
441  definitions[k]=d
442 end
443 d[n]=lpegmatch(subparser,v) or v
444 return ""
445end
446local unregister=(C(name)*spaces^0*(arguments+Cc(false)))/function(k,a)
447 local n=0
448 if a then
449  n=#a
450  local p=patterns[k]
451  if p then
452   p[n]=false
453  end
454 end
455 local d=definitions[k]
456 if d then
457  d[n]=false
458 end
459 return ""
460end
461local begindefine=(P("begindefine")*spaces^0/"")*beginregister
462local define=(P("define"  )*spaces^0/"")*register
463local undefine=(P("undefine"   )*spaces^0/"")*unregister
464local parser=Cs((((P("#")/"")*(define+begindefine+undefine)*(newline^0/"") )+resolve+P(1) )^0 )
465function macros.reset()
466 definitions={}
467 patterns={}
468end
469function macros.showdefinitions()
470 for name,list in table.sortedhash(definitions) do
471  local arguments=list.a
472  if arguments then
473   arguments="("..concat(arguments,",")..")"
474  else
475   arguments=""
476  end
477  print("macro: "..name..arguments)
478  for i=0,#list do
479   local l=list[i]
480   if l then
481    print("  "..l)
482   end
483  end
484 end
485end
486function macros.resolvestring(str)
487 return lpegmatch(parser,str) or str
488end
489function macros.resolving()
490 return next(patterns)
491end
492local function reload(path,name,data)
493 local only=match(name,".-([^/]+)%.lua")
494 if only and only~="" then
495  local name=path.."/"..only
496  local f=io.open(name,"wb")
497  f:write(data)
498  f:close()
499  local f=loadfile(name)
500  os.remove(name)
501  return f
502 end
503end
504local function reload(path,name,data)
505 if path and path~="" then
506  local only=string.match(name,".-([^/]+)%.lua")
507  if only and only~="" then
508   local name=path.."/"..only.."-macro.lua"
509   local f=io.open(name,"wb")
510   if f then
511    f:write(data)
512    f:close()
513    local l=loadfile(name)
514    os.remove(name)
515    return l
516   end
517  end
518 end
519 return load(data,name)
520end
521local function loaded(name,trace,detail)
522 local f=io.open(name,"rb")
523 if not f then
524  return false,format("file '%s' not found",name)
525 end
526 local c=f:read("*a")
527 if not c then
528  return false,format("file '%s' is invalid",name)
529 end
530 f:close()
531 local n=lpegmatch(parser,c)
532 if trace then
533  if #n~=#c then
534   report_lua("macros expanded in '%s' (%i => %i bytes)",name,#c,#n)
535   if detail then
536    report_lua()
537    report_lua(n)
538    report_lua()
539   end
540  elseif detail then
541   report_lua("no macros expanded in '%s'",name)
542  end
543 end
544 return reload(lfs and lfs.currentdir(),name,n)
545end
546macros.loaded=loaded
547function required(name,trace)
548 local filename=file.addsuffix(name,"lua")
549 local fullname=resolvers and resolvers.findfile(filename) or filename
550 if not fullname or fullname=="" then
551  return false
552 end
553 local codeblob=package.loaded[fullname]
554 if codeblob then
555  return codeblob
556 end
557 local code,message=loaded(fullname,macros,trace,trace)
558 if type(code)=="function" then
559  code=code()
560 else
561  report_lua("error when loading '%s'",fullname)
562  return false,message
563 end
564 if code==nil then
565  code=false
566 end
567 package.loaded[fullname]=code
568 return code
569end
570macros.required=required
571
572
573end -- of closure
574
575do -- create closure to overcome 200 locals limit
576
577package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true
578
579-- original size: 9604, stripped down to: 6394
580
581if not modules then modules={} end modules ['l-sandbox']={
582 version=1.001,
583 comment="companion to luat-lib.mkiv",
584 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
585 copyright="PRAGMA ADE / ConTeXt Development Team",
586 license="see context related readme files"
587}
588local global=_G
589local next=next
590local unpack=unpack or table.unpack
591local type=type
592local tprint=texio and texio.write_nl or print
593local tostring=tostring
594local format=string.format 
595local concat=table.concat
596local sort=table.sort
597local gmatch=string.gmatch
598local gsub=string.gsub
599local requiem=require
600sandbox={}
601local sandboxed=false
602local overloads={}
603local skiploads={}
604local initializers={}
605local finalizers={}
606local originals={}
607local comments={}
608local trace=false
609local logger=false
610local blocked={}
611local function report(...)
612 tprint("sandbox         ! "..format(...)) 
613end
614sandbox.report=report
615function sandbox.setreporter(r)
616 report=r
617 sandbox.report=r
618end
619function sandbox.settrace(v)
620 trace=v
621end
622function sandbox.setlogger(l)
623 logger=type(l)=="function" and l or false
624end
625local function register(func,overload,comment)
626 if type(func)=="function" then
627  if type(overload)=="string" then
628   comment=overload
629   overload=nil
630  end
631  local function f(...)
632   if sandboxed then
633    local overload=overloads[f]
634    if overload then
635     if logger then
636      local result={ overload(func,...) }
637      logger {
638       comment=comments[f] or tostring(f),
639       arguments={... },
640       result=result[1] and true or false,
641      }
642      return unpack(result)
643     else
644      return overload(func,...)
645     end
646    else
647    end
648   else
649    return func(...)
650   end
651  end
652  if comment then
653   comments[f]=comment
654   if trace then
655    report("registering function: %s",comment)
656   end
657  end
658  overloads[f]=overload or false
659  originals[f]=func
660  return f
661 end
662end
663local function redefine(func,comment)
664 if type(func)=="function" then
665  skiploads[func]=comment or comments[func] or "unknown"
666  if overloads[func]==false then
667   overloads[func]=nil 
668  end
669 end
670end
671sandbox.register=register
672sandbox.redefine=redefine
673function sandbox.original(func)
674 return originals and originals[func] or func
675end
676function sandbox.overload(func,overload,comment)
677 comment=comment or comments[func] or "?"
678 if type(func)~="function" then
679  if trace then
680   report("overloading unknown function: %s",comment)
681  end
682 elseif type(overload)~="function" then
683  if trace then
684   report("overloading function with bad overload: %s",comment)
685  end
686 elseif overloads[func]==nil then
687  if trace then
688   report("function is not registered: %s",comment)
689  end
690 elseif skiploads[func] then
691  if trace then
692   report("function is not skipped: %s",comment)
693  end
694 else
695  if trace then
696   report("overloading function: %s",comment)
697  end
698  overloads[func]=overload
699 end
700 return func
701end
702local function whatever(specification,what,target)
703 if type(specification)~="table" then
704  report("%s needs a specification",what)
705 elseif type(specification.category)~="string" or type(specification.action)~="function" then
706  report("%s needs a category and action",what)
707 elseif not sandboxed then
708  target[#target+1]=specification
709 elseif trace then
710  report("already enabled, discarding %s",what)
711 end
712end
713function sandbox.initializer(specification)
714 whatever(specification,"initializer",initializers)
715end
716function sandbox.finalizer(specification)
717 whatever(specification,"finalizer",finalizers)
718end
719function require(name)
720 local n=gsub(name,"^.*[\\/]","")
721 local n=gsub(n,"[%.].*$","")
722 local b=blocked[n]
723 if b==false then
724  return nil 
725 elseif b then
726  if trace then
727   report("using blocked: %s",n)
728  end
729  return b
730 else
731  if trace then
732   report("requiring: %s",name)
733  end
734  return requiem(name)
735 end
736end
737function blockrequire(name,lib)
738 if trace then
739  report("preventing reload of: %s",name)
740 end
741 blocked[name]=lib or _G[name] or false
742end
743function sandbox.enable()
744 if not sandboxed then
745  debug={
746   traceback=debug.traceback,
747  }
748  for i=1,#initializers do
749   initializers[i].action()
750  end
751  for i=1,#finalizers do
752   finalizers[i].action()
753  end
754  local nnot=0
755  local nyes=0
756  local cnot={}
757  local cyes={}
758  local skip={}
759  for k,v in next,overloads do
760   local c=comments[k]
761   if v then
762    if c then
763     cyes[#cyes+1]=c
764    else 
765     nyes=nyes+1
766    end
767   else
768    if c then
769     cnot[#cnot+1]=c
770    else 
771     nnot=nnot+1
772    end
773   end
774  end
775  for k,v in next,skiploads do
776   skip[#skip+1]=v
777  end
778  if #cyes>0 then
779   sort(cyes)
780   report("overloaded known: %s",concat(cyes," | "))
781  end
782  if nyes>0 then
783   report("overloaded unknown: %s",nyes)
784  end
785  if #cnot>0 then
786   sort(cnot)
787   report("not overloaded known: %s",concat(cnot," | "))
788  end
789  if nnot>0 then
790   report("not overloaded unknown: %s",nnot)
791  end
792  if #skip>0 then
793   sort(skip)
794   report("not overloaded redefined: %s",concat(skip," | "))
795  end
796  initializers=nil
797  finalizers=nil
798  originals=nil
799  sandboxed=true
800 end
801end
802blockrequire("lfs",lfs)
803blockrequire("io",io)
804blockrequire("os",os)
805blockrequire("ffi",ffi)
806local function supported(library)
807 local l=_G[library]
808 return l
809end
810loadfile=register(loadfile,"loadfile")
811if supported("lua") then
812 lua.openfile=register(lua.openfile,"lua.openfile")
813end
814if supported("io") then
815 io.open=register(io.open,"io.open")
816 io.popen=register(io.popen,"io.popen") 
817 io.lines=register(io.lines,"io.lines")
818 io.output=register(io.output,"io.output")
819 io.input=register(io.input,"io.input")
820end
821if supported("os") then
822 os.execute=register(os.execute,"os.execute")
823 os.spawn=register(os.spawn,"os.spawn")
824 os.exec=register(os.exec,"os.exec")
825 os.rename=register(os.rename,"os.rename")
826 os.remove=register(os.remove,"os.remove")
827end
828if supported("lfs") then
829 lfs.chdir=register(lfs.chdir,"lfs.chdir")
830 lfs.mkdir=register(lfs.mkdir,"lfs.mkdir")
831 lfs.rmdir=register(lfs.rmdir,"lfs.rmdir")
832 lfs.isfile=register(lfs.isfile,"lfs.isfile")
833 lfs.isdir=register(lfs.isdir,"lfs.isdir")
834 lfs.attributes=register(lfs.attributes,"lfs.attributes")
835 lfs.dir=register(lfs.dir,"lfs.dir")
836 lfs.lock_dir=register(lfs.lock_dir,"lfs.lock_dir")
837 lfs.touch=register(lfs.touch,"lfs.touch")
838 lfs.link=register(lfs.link,"lfs.link")
839 lfs.setmode=register(lfs.setmode,"lfs.setmode")
840 lfs.readlink=register(lfs.readlink,"lfs.readlink")
841 lfs.shortname=register(lfs.shortname,"lfs.shortname")
842 lfs.symlinkattributes=register(lfs.symlinkattributes,"lfs.symlinkattributes")
843end
844
845
846end -- of closure
847
848do -- create closure to overcome 200 locals limit
849
850package.loaded["l-package"] = package.loaded["l-package"] or true
851
852-- original size: 12566, stripped down to: 8937
853
854if not modules then modules={} end modules ['l-package']={
855 version=1.001,
856 comment="companion to luat-lib.mkiv",
857 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
858 copyright="PRAGMA ADE / ConTeXt Development Team",
859 license="see context related readme files"
860}
861local type,unpack=type,unpack
862local gsub,format,find=string.gsub,string.format,string.find
863local insert,remove=table.insert,table.remove
864local P,S,Cs,lpegmatch=lpeg.P,lpeg.S,lpeg.Cs,lpeg.match
865local package=package
866local searchers=package.searchers or package.loaders
867local filejoin=file and file.join  or function(path,name)   return path.."/"..name end
868local isreadable=file and file.is_readable or function(name)  local f=io.open(name) if f then f:close() return true end end
869local addsuffix=file and file.addsuffix   or function(name,suffix) return name.."."..suffix end
870local function cleanpath(path) 
871 return path
872end
873local pattern=Cs((((1-S("\\/"))^0*(S("\\/")^1/"/"))^0*(P(".")^1/"/"+P(1))^1)*-1)
874local function lualibfile(name)
875 return lpegmatch(pattern,name) or name
876end
877local offset=luarocks and 1 or 0 
878local helpers=package.helpers or {
879 cleanpath=cleanpath,
880 lualibfile=lualibfile,
881 trace=false,
882 report=function(...) print(format(...)) end,
883 builtin={
884  ["preload table"]=searchers[1+offset],
885  ["path specification"]=searchers[2+offset],
886  ["cpath specification"]=searchers[3+offset],
887  ["all in one fallback"]=searchers[4+offset],
888 },
889 methods={},
890 sequence={
891  "reset loaded",
892  "already loaded",
893  "preload table",
894  "qualified path",
895  "lua extra list",
896  "lib extra list",
897  "path specification",
898  "cpath specification",
899  "all in one fallback",
900  "not loaded",
901 }
902}
903package.helpers=helpers
904local methods=helpers.methods
905local builtin=helpers.builtin
906local extraluapaths={}
907local extralibpaths={}
908local checkedfiles={}
909local luapaths=nil 
910local libpaths=nil 
911local oldluapath=nil
912local oldlibpath=nil
913local nofextralua=-1
914local nofextralib=-1
915local nofpathlua=-1
916local nofpathlib=-1
917local function listpaths(what,paths)
918 local nofpaths=#paths
919 if nofpaths>0 then
920  for i=1,nofpaths do
921   helpers.report("using %s path %i: %s",what,i,paths[i])
922  end
923 else
924  helpers.report("no %s paths defined",what)
925 end
926 return nofpaths
927end
928local function getextraluapaths()
929 if helpers.trace and #extraluapaths~=nofextralua then
930  nofextralua=listpaths("extra lua",extraluapaths)
931 end
932 return extraluapaths
933end
934local function getextralibpaths()
935 if helpers.trace and #extralibpaths~=nofextralib then
936  nofextralib=listpaths("extra lib",extralibpaths)
937 end
938 return extralibpaths
939end
940local function getluapaths()
941 local luapath=package.path or ""
942 if oldluapath~=luapath then
943  luapaths=file.splitpath(luapath,";")
944  oldluapath=luapath
945  nofpathlua=-1
946 end
947 if helpers.trace and #luapaths~=nofpathlua then
948  nofpathlua=listpaths("builtin lua",luapaths)
949 end
950 return luapaths
951end
952local function getlibpaths()
953 local libpath=package.cpath or ""
954 if oldlibpath~=libpath then
955  libpaths=file.splitpath(libpath,";")
956  oldlibpath=libpath
957  nofpathlib=-1
958 end
959 if helpers.trace and #libpaths~=nofpathlib then
960  nofpathlib=listpaths("builtin lib",libpaths)
961 end
962 return libpaths
963end
964package.luapaths=getluapaths
965package.libpaths=getlibpaths
966package.extraluapaths=getextraluapaths
967package.extralibpaths=getextralibpaths
968local hashes={
969 lua={},
970 lib={},
971}
972local function registerpath(tag,what,target,...)
973 local pathlist={... }
974 local cleanpath=helpers.cleanpath
975 local trace=helpers.trace
976 local report=helpers.report
977 local hash=hashes[what]
978 local function add(path)
979  local path=cleanpath(path)
980  if not hash[path] then
981   target[#target+1]=path
982   hash[path]=true
983   if trace then
984    report("registered %s path %s: %s",tag,#target,path)
985   end
986  else
987   if trace then
988    report("duplicate %s path: %s",tag,path)
989   end
990  end
991 end
992 for p=1,#pathlist do
993  local path=pathlist[p]
994  if type(path)=="table" then
995   for i=1,#path do
996    add(path[i])
997   end
998  else
999   add(path)
1000  end
1001 end
1002end
1003local function pushpath(tag,what,target,path)
1004 local path=helpers.cleanpath(path)
1005 insert(target,1,path)
1006 if helpers.trace then
1007  helpers.report("pushing %s path in front: %s",tag,path)
1008 end
1009end
1010local function poppath(tag,what,target)
1011 local path=remove(target,1)
1012 if helpers.trace then
1013  if path then
1014   helpers.report("popping %s path from front: %s",tag,path)
1015  else
1016   helpers.report("no %s path to pop",tag)
1017  end
1018 end
1019end
1020helpers.registerpath=registerpath
1021function package.extraluapath(...)
1022 registerpath("extra lua","lua",extraluapaths,...)
1023end
1024function package.pushluapath(path)
1025 pushpath("extra lua","lua",extraluapaths,path)
1026end
1027function package.popluapath()
1028 poppath("extra lua","lua",extraluapaths)
1029end
1030function package.extralibpath(...)
1031 registerpath("extra lib","lib",extralibpaths,...)
1032end
1033function package.pushlibpath(path)
1034 pushpath("extra lib","lib",extralibpaths,path)
1035end
1036function package.poplibpath()
1037 poppath("extra lib","lua",extralibpaths)
1038end
1039local function loadedaslib(resolved,rawname) 
1040 local base=gsub(rawname,"%.","_")
1041 local init="luaopen_"..gsub(base,"%.","_")
1042 local data={ resolved,init,"" }
1043 checkedfiles[#checkedfiles+1]=data
1044 if helpers.trace then
1045  helpers.report("calling loadlib with '%s' with init '%s'",resolved,init)
1046 end
1047 local a,b,c=package.loadlib(resolved,init)
1048 if not a and type(b)=="string" then
1049  data[3]=string.fullstrip(b or "unknown error")
1050 end
1051 return a,b,c 
1052end
1053helpers.loadedaslib=loadedaslib
1054local function loadedbypath(name,rawname,paths,islib,what)
1055 local trace=helpers.trace
1056 for p=1,#paths do
1057  local path=paths[p]
1058  local resolved=filejoin(path,name)
1059  if trace then
1060   helpers.report("%s path, identifying '%s' on '%s'",what,name,path)
1061  end
1062  if isreadable(resolved) then
1063   if trace then
1064    helpers.report("%s path, '%s' found on '%s'",what,name,resolved)
1065   end
1066   if islib then
1067    return loadedaslib(resolved,rawname)
1068   else
1069    return loadfile(resolved)
1070   end
1071  end
1072 end
1073end
1074helpers.loadedbypath=loadedbypath
1075local function loadedbyname(name,rawname)
1076 if find(name,"^/") or find(name,"^[a-zA-Z]:/") then
1077  local trace=helpers.trace
1078  if trace then
1079   helpers.report("qualified name, identifying '%s'",what,name)
1080  end
1081  if isreadable(name) then
1082   if trace then
1083    helpers.report("qualified name, '%s' found",what,name)
1084   end
1085   return loadfile(name)
1086  end
1087 end
1088end
1089helpers.loadedbyname=loadedbyname
1090methods["reset loaded"]=function(name)
1091 checkedfiles={}
1092 return false
1093end
1094methods["already loaded"]=function(name)
1095 return package.loaded[name]
1096end
1097methods["preload table"]=function(name)
1098 local f=builtin["preload table"]
1099 if f then
1100  return f(name)
1101 end
1102end
1103methods["qualified path"]=function(name)
1104  return loadedbyname(addsuffix(lualibfile(name),"lua"),name)
1105end
1106methods["lua extra list"]=function(name)
1107 return loadedbypath(addsuffix(lualibfile(name),"lua"),name,getextraluapaths(),false,"lua")
1108end
1109methods["lib extra list"]=function(name)
1110 return loadedbypath(addsuffix(lualibfile(name),os.libsuffix),name,getextralibpaths(),true,"lib")
1111end
1112methods["path specification"]=function(name)
1113 local f=builtin["path specification"]
1114 if f then
1115  getluapaths() 
1116  return f(name)
1117 end
1118end
1119methods["cpath specification"]=function(name)
1120 local f=builtin["cpath specification"]
1121 if f then
1122  getlibpaths() 
1123  return f(name)
1124 end
1125end
1126methods["all in one fallback"]=function(name)
1127 local f=builtin["all in one fallback"]
1128 if f then
1129  return f(name)
1130 end
1131end
1132methods["not loaded"]=function(name)
1133 if helpers.trace then
1134  helpers.report("unable to locate '%s'",name or "?")
1135  for i=1,#checkedfiles do
1136   helpers.report("checked file '%s', initializer '%s', message '%s'",unpack(checkedfiles[i]))
1137  end
1138 end
1139 return nil
1140end
1141local level=0
1142local used={}
1143helpers.traceused=false
1144function helpers.loaded(name)
1145 local sequence=helpers.sequence
1146 level=level+1
1147 for i=1,#sequence do
1148  local method=sequence[i]
1149  local lookup=method and methods[method]
1150  if type(lookup)=="function" then
1151   if helpers.trace then
1152    helpers.report("%s, level '%s', method '%s', name '%s'","locating",level,method,name)
1153   end
1154   local result,rest=lookup(name)
1155   if type(result)=="function" then
1156    if helpers.trace then
1157     helpers.report("%s, level '%s', method '%s', name '%s'","found",level,method,name)
1158    end
1159    if helpers.traceused then
1160     used[#used+1]={ level=level,name=name }
1161    end
1162    level=level-1
1163    return result,rest
1164   end
1165  end
1166 end
1167 level=level-1
1168 return nil
1169end
1170function helpers.showused()
1171 local n=#used
1172 if n>0 then
1173  helpers.report("%s libraries loaded:",n)
1174  helpers.report()
1175  for i=1,n do
1176   local u=used[i]
1177   helpers.report("%i %a",u.level,u.name)
1178  end
1179  helpers.report()
1180  end
1181end
1182function helpers.unload(name)
1183 if helpers.trace then
1184  if package.loaded[name] then
1185   helpers.report("unloading, name '%s', %s",name,"done")
1186  else
1187   helpers.report("unloading, name '%s', %s",name,"not loaded")
1188  end
1189 end
1190 package.loaded[name]=nil
1191end
1192table.insert(searchers,1,helpers.loaded)
1193if context then
1194 package.path=""
1195end
1196
1197
1198end -- of closure
1199
1200do -- create closure to overcome 200 locals limit
1201
1202package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true
1203
1204-- original size: 38742, stripped down to: 19489
1205
1206if not modules then modules={} end modules ['l-lpeg']={
1207 version=1.001,
1208 comment="companion to luat-lib.mkiv",
1209 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
1210 copyright="PRAGMA ADE / ConTeXt Development Team",
1211 license="see context related readme files"
1212}
1213lpeg=require("lpeg") 
1214local lpeg=lpeg
1215if not lpeg.print then function lpeg.print(...) print(lpeg.pcode(...)) end end
1216local type,next,tostring=type,next,tostring
1217local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.format
1218local floor=math.floor
1219local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt
1220local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print
1221if setinspector then
1222 setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end)
1223end
1224lpeg.patterns=lpeg.patterns or {} 
1225local patterns=lpeg.patterns
1226local anything=P(1)
1227local endofstring=P(-1)
1228local alwaysmatched=P(true)
1229patterns.anything=anything
1230patterns.endofstring=endofstring
1231patterns.beginofstring=alwaysmatched
1232patterns.alwaysmatched=alwaysmatched
1233local sign=S('+-')
1234local zero=P('0')
1235local digit=R('09')
1236local digits=digit^1
1237local octdigit=R("07")
1238local octdigits=octdigit^1
1239local lowercase=R("az")
1240local uppercase=R("AZ")
1241local underscore=P("_")
1242local hexdigit=digit+lowercase+uppercase
1243local hexdigits=hexdigit^1
1244local cr,lf,crlf=P("\r"),P("\n"),P("\r\n")
1245local newline=P("\r")*(P("\n")+P(true))+P("\n")  
1246local escaped=P("\\")*anything
1247local squote=P("'")
1248local dquote=P('"')
1249local space=P(" ")
1250local period=P(".")
1251local comma=P(",")
1252local utfbom_32_be=P('\000\000\254\255') 
1253local utfbom_32_le=P('\255\254\000\000') 
1254local utfbom_16_be=P('\254\255')   
1255local utfbom_16_le=P('\255\254')   
1256local utfbom_8=P('\239\187\191')  
1257local utfbom=utfbom_32_be+utfbom_32_le+utfbom_16_be+utfbom_16_le+utfbom_8
1258local utftype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")+alwaysmatched*Cc("utf-8") 
1259local utfstricttype=utfbom_32_be*Cc("utf-32-be")+utfbom_32_le*Cc("utf-32-le")+utfbom_16_be*Cc("utf-16-be")+utfbom_16_le*Cc("utf-16-le")+utfbom_8*Cc("utf-8")
1260local utfoffset=utfbom_32_be*Cc(4)+utfbom_32_le*Cc(4)+utfbom_16_be*Cc(2)+utfbom_16_le*Cc(2)+utfbom_8*Cc(3)+Cc(0)
1261local utf8next=R("\128\191")
1262patterns.utfbom_32_be=utfbom_32_be
1263patterns.utfbom_32_le=utfbom_32_le
1264patterns.utfbom_16_be=utfbom_16_be
1265patterns.utfbom_16_le=utfbom_16_le
1266patterns.utfbom_8=utfbom_8
1267patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") 
1268patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") 
1269patterns.utf_32_be_nl=P("\000\000\000\r\000\000\000\n")+P("\000\000\000\r")+P("\000\000\000\n")
1270patterns.utf_32_le_nl=P("\r\000\000\000\n\000\000\000")+P("\r\000\000\000")+P("\n\000\000\000")
1271patterns.utf8one=R("\000\127")
1272patterns.utf8two=R("\194\223")*utf8next
1273patterns.utf8three=R("\224\239")*utf8next*utf8next
1274patterns.utf8four=R("\240\244")*utf8next*utf8next*utf8next
1275patterns.utfbom=utfbom
1276patterns.utftype=utftype
1277patterns.utfstricttype=utfstricttype
1278patterns.utfoffset=utfoffset
1279local utf8char=patterns.utf8one+patterns.utf8two+patterns.utf8three+patterns.utf8four
1280local validutf8char=utf8char^0*endofstring*Cc(true)+Cc(false)
1281local utf8character=P(1)*R("\128\191")^0 
1282patterns.utf8=utf8char
1283patterns.utf8char=utf8char
1284patterns.utf8character=utf8character 
1285patterns.validutf8=validutf8char
1286patterns.validutf8char=validutf8char
1287local eol=S("\n\r")
1288local spacer=S(" \t\f\v")  
1289local whitespace=eol+spacer
1290local nonspacer=1-spacer
1291local nonwhitespace=1-whitespace
1292patterns.eol=eol
1293patterns.spacer=spacer
1294patterns.whitespace=whitespace
1295patterns.nonspacer=nonspacer
1296patterns.nonwhitespace=nonwhitespace
1297local stripper=spacer^0*C((spacer^0*nonspacer^1)^0)  
1298local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0)
1299local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0))
1300local nospacer=Cs((whitespace^1/""+nonwhitespace^1)^0)
1301local b_collapser=Cs(whitespace^0/""*(nonwhitespace^1+whitespace^1/" ")^0)
1302local m_collapser=Cs((nonwhitespace^1+whitespace^1/" ")^0)
1303local e_collapser=Cs((whitespace^1*endofstring/""+nonwhitespace^1+whitespace^1/" ")^0)
1304local x_collapser=Cs((nonwhitespace^1+whitespace^1/"" )^0)
1305local b_stripper=Cs(spacer^0/""*(nonspacer^1+spacer^1/" ")^0)
1306local m_stripper=Cs((nonspacer^1+spacer^1/" ")^0)
1307local e_stripper=Cs((spacer^1*endofstring/""+nonspacer^1+spacer^1/" ")^0)
1308local x_stripper=Cs((nonspacer^1+spacer^1/"" )^0)
1309patterns.stripper=stripper
1310patterns.fullstripper=fullstripper
1311patterns.collapser=collapser
1312patterns.nospacer=nospacer
1313patterns.b_collapser=b_collapser
1314patterns.m_collapser=m_collapser
1315patterns.e_collapser=e_collapser
1316patterns.x_collapser=x_collapser
1317patterns.b_stripper=b_stripper
1318patterns.m_stripper=m_stripper
1319patterns.e_stripper=e_stripper
1320patterns.x_stripper=x_stripper
1321patterns.lowercase=lowercase
1322patterns.uppercase=uppercase
1323patterns.letter=patterns.lowercase+patterns.uppercase
1324patterns.space=space
1325patterns.tab=P("\t")
1326patterns.spaceortab=patterns.space+patterns.tab
1327patterns.newline=newline
1328patterns.emptyline=newline^1
1329patterns.equal=P("=")
1330patterns.comma=comma
1331patterns.commaspacer=comma*spacer^0
1332patterns.period=period
1333patterns.colon=P(":")
1334patterns.semicolon=P(";")
1335patterns.underscore=underscore
1336patterns.escaped=escaped
1337patterns.squote=squote
1338patterns.dquote=dquote
1339patterns.nosquote=(escaped+(1-squote))^0
1340patterns.nodquote=(escaped+(1-dquote))^0
1341patterns.unsingle=(squote/"")*patterns.nosquote*(squote/"") 
1342patterns.undouble=(dquote/"")*patterns.nodquote*(dquote/"") 
1343patterns.unquoted=patterns.undouble+patterns.unsingle 
1344patterns.unspacer=((patterns.spacer^1)/"")^0
1345patterns.singlequoted=squote*patterns.nosquote*squote
1346patterns.doublequoted=dquote*patterns.nodquote*dquote
1347patterns.quoted=patterns.doublequoted+patterns.singlequoted
1348patterns.digit=digit
1349patterns.digits=digits
1350patterns.octdigit=octdigit
1351patterns.octdigits=octdigits
1352patterns.hexdigit=hexdigit
1353patterns.hexdigits=hexdigits
1354patterns.sign=sign
1355patterns.cardinal=digits
1356patterns.integer=sign^-1*digits
1357patterns.unsigned=digit^0*period*digits
1358patterns.float=sign^-1*patterns.unsigned
1359patterns.cunsigned=digit^0*comma*digits
1360patterns.cpunsigned=digit^0*(period+comma)*digits
1361patterns.cfloat=sign^-1*patterns.cunsigned
1362patterns.cpfloat=sign^-1*patterns.cpunsigned
1363patterns.number=patterns.float+patterns.integer
1364patterns.cnumber=patterns.cfloat+patterns.integer
1365patterns.cpnumber=patterns.cpfloat+patterns.integer
1366patterns.oct=zero*octdigits 
1367patterns.octal=patterns.oct
1368patterns.HEX=zero*P("X")*(digit+uppercase)^1
1369patterns.hex=zero*P("x")*(digit+lowercase)^1
1370patterns.hexadecimal=zero*S("xX")*hexdigits
1371patterns.hexafloat=sign^-1*zero*S("xX")*(hexdigit^0*period*hexdigits+hexdigits*period*hexdigit^0+hexdigits)*(S("pP")*sign^-1*hexdigits)^-1
1372patterns.decafloat=sign^-1*(digit^0*period*digits+digits*period*digit^0+digits)*S("eE")*sign^-1*digits
1373patterns.propername=(uppercase+lowercase+underscore)*(uppercase+lowercase+underscore+digit)^0*endofstring
1374patterns.somecontent=(anything-newline-space)^1 
1375patterns.beginline=#(1-newline)
1376patterns.longtostring=Cs(whitespace^0/""*((patterns.quoted+nonwhitespace^1+whitespace^1/""*(endofstring+Cc(" ")))^0))
1377local function anywhere(pattern) 
1378 return (1-P(pattern))^0*P(pattern)
1379end
1380lpeg.anywhere=anywhere
1381function lpeg.instringchecker(p)
1382 p=anywhere(p)
1383 return function(str)
1384  return lpegmatch(p,str) and true or false
1385 end
1386end
1387function lpeg.splitter(pattern,action)
1388 if action then
1389  return (((1-P(pattern))^1)/action+1)^0
1390 else
1391  return (Cs((1-P(pattern))^1)+1)^0
1392 end
1393end
1394function lpeg.tsplitter(pattern,action)
1395 if action then
1396  return Ct((((1-P(pattern))^1)/action+1)^0)
1397 else
1398  return Ct((Cs((1-P(pattern))^1)+1)^0)
1399 end
1400end
1401local splitters_s,splitters_m,splitters_t={},{},{}
1402local function splitat(separator,single)
1403 local splitter=(single and splitters_s[separator]) or splitters_m[separator]
1404 if not splitter then
1405  separator=P(separator)
1406  local other=C((1-separator)^0)
1407  if single then
1408   local any=anything
1409   splitter=other*(separator*C(any^0)+"") 
1410   splitters_s[separator]=splitter
1411  else
1412   splitter=other*(separator*other)^0
1413   splitters_m[separator]=splitter
1414  end
1415 end
1416 return splitter
1417end
1418local function tsplitat(separator)
1419 local splitter=splitters_t[separator]
1420 if not splitter then
1421  splitter=Ct(splitat(separator))
1422  splitters_t[separator]=splitter
1423 end
1424 return splitter
1425end
1426lpeg.splitat=splitat
1427lpeg.tsplitat=tsplitat
1428function string.splitup(str,separator)
1429 if not separator then
1430  separator=","
1431 end
1432 return lpegmatch(splitters_m[separator] or splitat(separator),str)
1433end
1434local cache={}
1435function lpeg.split(separator,str)
1436 local c=cache[separator]
1437 if not c then
1438  c=tsplitat(separator)
1439  cache[separator]=c
1440 end
1441 return lpegmatch(c,str)
1442end
1443function string.split(str,separator)
1444 if separator then
1445  local c=cache[separator]
1446  if not c then
1447   c=tsplitat(separator)
1448   cache[separator]=c
1449  end
1450  return lpegmatch(c,str)
1451 else
1452  return { str }
1453 end
1454end
1455local spacing=patterns.spacer^0*newline 
1456local empty=spacing*Cc("")
1457local nonempty=Cs((1-spacing)^1)*spacing^-1
1458local content=(empty+nonempty)^1
1459patterns.textline=content
1460local linesplitter=tsplitat(newline)
1461patterns.linesplitter=linesplitter
1462function string.splitlines(str)
1463 return lpegmatch(linesplitter,str)
1464end
1465local cache={}
1466function lpeg.checkedsplit(separator,str)
1467 local c=cache[separator]
1468 if not c then
1469  separator=P(separator)
1470  local other=C((1-separator)^1)
1471  c=Ct(separator^0*other*(separator^1*other)^0)
1472  cache[separator]=c
1473 end
1474 return lpegmatch(c,str)
1475end
1476function string.checkedsplit(str,separator)
1477 local c=cache[separator]
1478 if not c then
1479  separator=P(separator)
1480  local other=C((1-separator)^1)
1481  c=Ct(separator^0*other*(separator^1*other)^0)
1482  cache[separator]=c
1483 end
1484 return lpegmatch(c,str)
1485end
1486local function f2(s) local c1,c2=byte(s,1,2) return   c1*64+c2-12416 end
1487local function f3(s) local c1,c2,c3=byte(s,1,3) return  (c1*64+c2)*64+c3-925824 end
1488local function f4(s) local c1,c2,c3,c4=byte(s,1,4) return ((c1*64+c2)*64+c3)*64+c4-63447168 end
1489local utf8byte=patterns.utf8one/byte+patterns.utf8two/f2+patterns.utf8three/f3+patterns.utf8four/f4
1490patterns.utf8byte=utf8byte
1491local cache={}
1492function lpeg.stripper(str)
1493 if type(str)=="string" then
1494  local s=cache[str]
1495  if not s then
1496   s=Cs(((S(str)^1)/""+1)^0)
1497   cache[str]=s
1498  end
1499  return s
1500 else
1501  return Cs(((str^1)/""+1)^0)
1502 end
1503end
1504local cache={}
1505function lpeg.keeper(str)
1506 if type(str)=="string" then
1507  local s=cache[str]
1508  if not s then
1509   s=Cs((((1-S(str))^1)/""+1)^0)
1510   cache[str]=s
1511  end
1512  return s
1513 else
1514  return Cs((((1-str)^1)/""+1)^0)
1515 end
1516end
1517function lpeg.frontstripper(str) 
1518 return (P(str)+P(true))*Cs(anything^0)
1519end
1520function lpeg.endstripper(str) 
1521 return Cs((1-P(str)*endofstring)^0)
1522end
1523function lpeg.replacer(one,two,makefunction,isutf) 
1524 local pattern
1525 local u=isutf and utf8char or 1
1526 if type(one)=="table" then
1527  local no=#one
1528  local p=P(false)
1529  if no==0 then
1530   for k,v in next,one do
1531    p=p+P(k)/v
1532   end
1533   pattern=Cs((p+u)^0)
1534  elseif no==1 then
1535   local o=one[1]
1536   one,two=P(o[1]),o[2]
1537   pattern=Cs((one/two+u)^0)
1538  else
1539   for i=1,no do
1540    local o=one[i]
1541    p=p+P(o[1])/o[2]
1542   end
1543   pattern=Cs((p+u)^0)
1544  end
1545 else
1546  pattern=Cs((P(one)/(two or "")+u)^0)
1547 end
1548 if makefunction then
1549  return function(str)
1550   return lpegmatch(pattern,str)
1551  end
1552 else
1553  return pattern
1554 end
1555end
1556function lpeg.finder(lst,makefunction,isutf) 
1557 local pattern
1558 if type(lst)=="table" then
1559  pattern=P(false)
1560  if #lst==0 then
1561   for k,v in next,lst do
1562    pattern=pattern+P(k) 
1563   end
1564  else
1565   for i=1,#lst do
1566    pattern=pattern+P(lst[i])
1567   end
1568  end
1569 else
1570  pattern=P(lst)
1571 end
1572 if isutf then
1573  pattern=((utf8char or 1)-pattern)^0*pattern
1574 else
1575  pattern=(1-pattern)^0*pattern
1576 end
1577 if makefunction then
1578  return function(str)
1579   return lpegmatch(pattern,str)
1580  end
1581 else
1582  return pattern
1583 end
1584end
1585local splitters_f,splitters_s={},{}
1586function lpeg.firstofsplit(separator) 
1587 local splitter=splitters_f[separator]
1588 if not splitter then
1589  local pattern=P(separator)
1590  splitter=C((1-pattern)^0)
1591  splitters_f[separator]=splitter
1592 end
1593 return splitter
1594end
1595function lpeg.secondofsplit(separator) 
1596 local splitter=splitters_s[separator]
1597 if not splitter then
1598  local pattern=P(separator)
1599  splitter=(1-pattern)^0*pattern*C(anything^0)
1600  splitters_s[separator]=splitter
1601 end
1602 return splitter
1603end
1604local splitters_s,splitters_p={},{}
1605function lpeg.beforesuffix(separator) 
1606 local splitter=splitters_s[separator]
1607 if not splitter then
1608  local pattern=P(separator)
1609  splitter=C((1-pattern)^0)*pattern*endofstring
1610  splitters_s[separator]=splitter
1611 end
1612 return splitter
1613end
1614function lpeg.afterprefix(separator) 
1615 local splitter=splitters_p[separator]
1616 if not splitter then
1617  local pattern=P(separator)
1618  splitter=pattern*C(anything^0)
1619  splitters_p[separator]=splitter
1620 end
1621 return splitter
1622end
1623function lpeg.balancer(left,right)
1624 left,right=P(left),P(right)
1625 return P { left*((1-left-right)+V(1))^0*right }
1626end
1627function lpeg.counter(pattern,action)
1628 local n=0
1629 local pattern=(P(pattern)/function() n=n+1 end+anything)^0
1630 if action then
1631  return function(str) n=0;lpegmatch(pattern,str);action(n) end
1632 else
1633  return function(str) n=0;lpegmatch(pattern,str);return n end
1634 end
1635end
1636function lpeg.is_lpeg(p)
1637 return p and lpegtype(p)=="pattern"
1638end
1639function lpeg.oneof(list,...) 
1640 if type(list)~="table" then
1641  list={ list,... }
1642 end
1643 local p=P(list[1])
1644 for l=2,#list do
1645  p=p+P(list[l])
1646 end
1647 return p
1648end
1649local sort=table.sort
1650local function copyindexed(old)
1651 local new={}
1652 for i=1,#old do
1653  new[i]=old
1654 end
1655 return new
1656end
1657local function sortedkeys(tab)
1658 local keys,s={},0
1659 for key,_ in next,tab do
1660  s=s+1
1661  keys[s]=key
1662 end
1663 sort(keys)
1664 return keys
1665end
1666function lpeg.append(list,pp,delayed,checked)
1667 local p=pp
1668 if #list>0 then
1669  local keys=copyindexed(list)
1670  sort(keys)
1671  for i=#keys,1,-1 do
1672   local k=keys[i]
1673   if p then
1674    p=P(k)+p
1675   else
1676    p=P(k)
1677   end
1678  end
1679 elseif delayed then 
1680  local keys=sortedkeys(list)
1681  if p then
1682   for i=1,#keys,1 do
1683    local k=keys[i]
1684    local v=list[k]
1685    p=P(k)/list+p
1686   end
1687  else
1688   for i=1,#keys do
1689    local k=keys[i]
1690    local v=list[k]
1691    if p then
1692     p=P(k)+p
1693    else
1694     p=P(k)
1695    end
1696   end
1697   if p then
1698    p=p/list
1699   end
1700  end
1701 elseif checked then
1702  local keys=sortedkeys(list)
1703  for i=1,#keys do
1704   local k=keys[i]
1705   local v=list[k]
1706   if p then
1707    if k==v then
1708     p=P(k)+p
1709    else
1710     p=P(k)/v+p
1711    end
1712   else
1713    if k==v then
1714     p=P(k)
1715    else
1716     p=P(k)/v
1717    end
1718   end
1719  end
1720 else
1721  local keys=sortedkeys(list)
1722  for i=1,#keys do
1723   local k=keys[i]
1724   local v=list[k]
1725   if p then
1726    p=P(k)/v+p
1727   else
1728    p=P(k)/v
1729   end
1730  end
1731 end
1732 return p
1733end
1734local p_false=P(false)
1735local p_true=P(true)
1736local lower=utf and utf.lower or string.lower
1737local upper=utf and utf.upper or string.upper
1738function lpeg.setutfcasers(l,u)
1739 lower=l or lower
1740 upper=u or upper
1741end
1742local function make1(t,rest)
1743 local p=p_false
1744 local keys=sortedkeys(t)
1745 for i=1,#keys do
1746  local k=keys[i]
1747  if k~="" then
1748   local v=t[k]
1749   if v==true then
1750    p=p+P(k)*p_true
1751   elseif v==false then
1752   else
1753    p=p+P(k)*make1(v,v[""])
1754   end
1755  end
1756 end
1757 if rest then
1758  p=p+p_true
1759 end
1760 return p
1761end
1762local function make2(t,rest) 
1763 local p=p_false
1764 local keys=sortedkeys(t)
1765 for i=1,#keys do
1766  local k=keys[i]
1767  if k~="" then
1768   local v=t[k]
1769   if v==true then
1770    p=p+(P(lower(k))+P(upper(k)))*p_true
1771   elseif v==false then
1772   else
1773    p=p+(P(lower(k))+P(upper(k)))*make2(v,v[""])
1774   end
1775  end
1776 end
1777 if rest then
1778  p=p+p_true
1779 end
1780 return p
1781end
1782local function utfchartabletopattern(list,insensitive) 
1783 local tree={}
1784 local n=#list
1785 if n==0 then
1786  for s in next,list do
1787   local t=tree
1788   local p,pk
1789   for c in gmatch(s,".") do
1790    if t==true then
1791     t={ [c]=true,[""]=true }
1792     p[pk]=t
1793     p=t
1794     t=false
1795    elseif t==false then
1796     t={ [c]=false }
1797     p[pk]=t
1798     p=t
1799     t=false
1800    else
1801     local tc=t[c]
1802     if not tc then
1803      tc=false
1804      t[c]=false
1805     end
1806     p=t
1807     t=tc
1808    end
1809    pk=c
1810   end
1811   if t==false then
1812    p[pk]=true
1813   elseif t==true then
1814   else
1815    t[""]=true
1816   end
1817  end
1818 else
1819  for i=1,n do
1820   local s=list[i]
1821   local t=tree
1822   local p,pk
1823   for c in gmatch(s,".") do
1824    if t==true then
1825     t={ [c]=true,[""]=true }
1826     p[pk]=t
1827     p=t
1828     t=false
1829    elseif t==false then
1830     t={ [c]=false }
1831     p[pk]=t
1832     p=t
1833     t=false
1834    else
1835     local tc=t[c]
1836     if not tc then
1837      tc=false
1838      t[c]=false
1839     end
1840     p=t
1841     t=tc
1842    end
1843    pk=c
1844   end
1845   if t==false then
1846    p[pk]=true
1847   elseif t==true then
1848   else
1849    t[""]=true
1850   end
1851  end
1852 end
1853 return (insensitive and make2 or make1)(tree)
1854end
1855lpeg.utfchartabletopattern=utfchartabletopattern
1856function lpeg.utfreplacer(list,insensitive)
1857 local pattern=Cs((utfchartabletopattern(list,insensitive)/list+utf8character)^0)
1858 return function(str)
1859  return lpegmatch(pattern,str) or str
1860 end
1861end
1862patterns.containseol=lpeg.finder(eol)
1863local function nextstep(n,step,result)
1864 local m=n%step   
1865 local d=floor(n/step) 
1866 if d>0 then
1867  local v=V(tostring(step))
1868  local s=result.start
1869  for i=1,d do
1870   if s then
1871    s=v*s
1872   else
1873    s=v
1874   end
1875  end
1876  result.start=s
1877 end
1878 if step>1 and result.start then
1879  local v=V(tostring(step/2))
1880  result[tostring(step)]=v*v
1881 end
1882 if step>0 then
1883  return nextstep(m,step/2,result)
1884 else
1885  return result
1886 end
1887end
1888function lpeg.times(pattern,n)
1889 return P(nextstep(n,2^16,{ "start",["1"]=pattern }))
1890end
1891do
1892 local trailingzeros=zero^0*-digit 
1893 local stripper=Cs((
1894  digits*(
1895   period*trailingzeros/""+period*(digit-trailingzeros)^1*(trailingzeros/"")
1896  )+1
1897 )^0)
1898 lpeg.patterns.stripzeros=stripper 
1899 local nonzero=digit-zero
1900 local trailingzeros=zero^1*endofstring
1901 local stripper=Cs((1-period)^0*(
1902  period*trailingzeros/""+period*(nonzero^1+(trailingzeros/"")+zero^1)^0+endofstring
1903 ))
1904 lpeg.patterns.stripzero=stripper
1905end
1906local byte_to_HEX={}
1907local byte_to_hex={}
1908local byte_to_dec={} 
1909local hex_to_byte={}
1910for i=0,255 do
1911 local H=format("%02X",i)
1912 local h=format("%02x",i)
1913 local d=format("%03i",i)
1914 local c=char(i)
1915 byte_to_HEX[c]=H
1916 byte_to_hex[c]=h
1917 byte_to_dec[c]=d
1918 hex_to_byte[h]=c
1919 hex_to_byte[H]=c
1920end
1921local hextobyte=P(2)/hex_to_byte
1922local bytetoHEX=P(1)/byte_to_HEX
1923local bytetohex=P(1)/byte_to_hex
1924local bytetodec=P(1)/byte_to_dec
1925local hextobytes=Cs(hextobyte^0)
1926local bytestoHEX=Cs(bytetoHEX^0)
1927local bytestohex=Cs(bytetohex^0)
1928local bytestodec=Cs(bytetodec^0)
1929patterns.hextobyte=hextobyte
1930patterns.bytetoHEX=bytetoHEX
1931patterns.bytetohex=bytetohex
1932patterns.bytetodec=bytetodec
1933patterns.hextobytes=hextobytes
1934patterns.bytestoHEX=bytestoHEX
1935patterns.bytestohex=bytestohex
1936patterns.bytestodec=bytestodec
1937function string.toHEX(s)
1938 if not s or s=="" then
1939  return s
1940 else
1941  return lpegmatch(bytestoHEX,s)
1942 end
1943end
1944function string.tohex(s)
1945 if not s or s=="" then
1946  return s
1947 else
1948  return lpegmatch(bytestohex,s)
1949 end
1950end
1951function string.todec(s)
1952 if not s or s=="" then
1953  return s
1954 else
1955  return lpegmatch(bytestodec,s)
1956 end
1957end
1958function string.tobytes(s)
1959 if not s or s=="" then
1960  return s
1961 else
1962  return lpegmatch(hextobytes,s)
1963 end
1964end
1965local patterns={} 
1966local function containsws(what)
1967 local p=patterns[what]
1968 if not p then
1969  local p1=P(what)*(whitespace+endofstring)*Cc(true)
1970  local p2=whitespace*P(p1)
1971  p=P(p1)+P(1-p2)^0*p2+Cc(false)
1972  patterns[what]=p
1973 end
1974 return p
1975end
1976lpeg.containsws=containsws
1977function string.containsws(str,what)
1978 return lpegmatch(patterns[what] or containsws(what),str)
1979end
1980
1981
1982end -- of closure
1983
1984do -- create closure to overcome 200 locals limit
1985
1986package.loaded["l-function"] = package.loaded["l-function"] or true
1987
1988-- original size: 361, stripped down to: 317
1989
1990if not modules then modules={} end modules ['l-functions']={
1991 version=1.001,
1992 comment="companion to luat-lib.mkiv",
1993 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
1994 copyright="PRAGMA ADE / ConTeXt Development Team",
1995 license="see context related readme files"
1996}
1997functions=functions or {}
1998function functions.dummy() end
1999
2000
2001end -- of closure
2002
2003do -- create closure to overcome 200 locals limit
2004
2005package.loaded["l-string"] = package.loaded["l-string"] or true
2006
2007-- original size: 6644, stripped down to: 3410
2008
2009if not modules then modules={} end modules ['l-string']={
2010 version=1.001,
2011 comment="companion to luat-lib.mkiv",
2012 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
2013 copyright="PRAGMA ADE / ConTeXt Development Team",
2014 license="see context related readme files"
2015}
2016local string=string
2017local sub,gmatch,format,char,byte,rep,lower=string.sub,string.gmatch,string.format,string.char,string.byte,string.rep,string.lower
2018local lpegmatch,patterns=lpeg.match,lpeg.patterns
2019local P,S,C,Ct,Cc,Cs=lpeg.P,lpeg.S,lpeg.C,lpeg.Ct,lpeg.Cc,lpeg.Cs
2020local unquoted=patterns.squote*C(patterns.nosquote)*patterns.squote+patterns.dquote*C(patterns.nodquote)*patterns.dquote
2021function string.unquoted(str)
2022 return lpegmatch(unquoted,str) or str
2023end
2024function string.quoted(str)
2025 return format("%q",str) 
2026end
2027function string.count(str,pattern) 
2028 local n=0
2029 for _ in gmatch(str,pattern) do 
2030  n=n+1
2031 end
2032 return n
2033end
2034function string.limit(str,n,sentinel) 
2035 if #str>n then
2036  sentinel=sentinel or "..."
2037  return sub(str,1,(n-#sentinel))..sentinel
2038 else
2039  return str
2040 end
2041end
2042local stripper=patterns.stripper
2043local fullstripper=patterns.fullstripper
2044local collapser=patterns.collapser
2045local nospacer=patterns.nospacer
2046local longtostring=patterns.longtostring
2047function string.strip(str)
2048 return str and lpegmatch(stripper,str) or ""
2049end
2050function string.fullstrip(str)
2051 return str and lpegmatch(fullstripper,str) or ""
2052end
2053function string.collapsespaces(str)
2054 return str and lpegmatch(collapser,str) or ""
2055end
2056function string.nospaces(str)
2057 return str and lpegmatch(nospacer,str) or ""
2058end
2059function string.longtostring(str)
2060 return str and lpegmatch(longtostring,str) or ""
2061end
2062local pattern=P(" ")^0*P(-1)
2063function string.is_empty(str)
2064 if not str or str=="" then
2065  return true
2066 else
2067  return lpegmatch(pattern,str) and true or false
2068 end
2069end
2070local anything=patterns.anything
2071local moreescapes=Cc("%")*S(".-+%?()[]*$^{}")
2072local allescapes=Cc("%")*S(".-+%?()[]*")   
2073local someescapes=Cc("%")*S(".-+%()[]")  
2074local matchescapes=Cc(".")*S("*?")     
2075local pattern_m=Cs ((moreescapes+anything )^0 )
2076local pattern_a=Cs ((allescapes+anything )^0 )
2077local pattern_b=Cs ((someescapes+matchescapes+anything )^0 )
2078local pattern_c=Cs (Cc("^")*(someescapes+matchescapes+anything )^0*Cc("$") )
2079function string.escapedpattern(str,simple)
2080 return lpegmatch(simple and pattern_b or pattern_a,str)
2081end
2082function string.topattern(str,lowercase,strict)
2083 if str=="" or type(str)~="string" then
2084  return ".*"
2085 elseif strict=="all" then
2086  str=lpegmatch(pattern_m,str)
2087 elseif strict then
2088  str=lpegmatch(pattern_c,str)
2089 else
2090  str=lpegmatch(pattern_b,str)
2091 end
2092 if lowercase then
2093  return lower(str)
2094 else
2095  return str
2096 end
2097end
2098function string.valid(str,default)
2099 return (type(str)=="string" and str~="" and str) or default or nil
2100end
2101string.itself=function(s) return s end
2102local pattern_c=Ct(C(1)^0) 
2103local pattern_b=Ct((C(1)/byte)^0)
2104function string.totable(str,bytes)
2105 return lpegmatch(bytes and pattern_b or pattern_c,str)
2106end
2107local replacer=lpeg.replacer("@","%%") 
2108function string.tformat(fmt,...)
2109 return format(lpegmatch(replacer,fmt),...)
2110end
2111string.quote=string.quoted
2112string.unquote=string.unquoted
2113if not string.bytetable then 
2114 local limit=5000 
2115 function string.bytetable(str) 
2116  local n=#str
2117  if n>limit then
2118   local t={ byte(str,1,limit) }
2119   for i=limit+1,n do
2120    t[i]=byte(str,i)
2121   end
2122   return t
2123  else
2124   return { byte(str,1,n) }
2125  end
2126 end
2127end
2128
2129
2130end -- of closure
2131
2132do -- create closure to overcome 200 locals limit
2133
2134package.loaded["l-table"] = package.loaded["l-table"] or true
2135
2136-- original size: 41758, stripped down to: 22643
2137
2138if not modules then modules={} end modules ['l-table']={
2139 version=1.001,
2140 comment="companion to luat-lib.mkiv",
2141 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
2142 copyright="PRAGMA ADE / ConTeXt Development Team",
2143 license="see context related readme files"
2144}
2145local type,next,tostring,tonumber,select,rawget=type,next,tostring,tonumber,select,rawget
2146local table,string=table,string
2147local concat,sort=table.concat,table.sort
2148local format,lower,dump=string.format,string.lower,string.dump
2149local getmetatable,setmetatable=getmetatable,setmetatable
2150local lpegmatch,patterns=lpeg.match,lpeg.patterns
2151local floor=math.floor
2152local stripper=patterns.stripper
2153function table.getn(t)
2154 return t and #t 
2155end
2156function table.strip(tab)
2157 local lst={}
2158 local l=0
2159 for i=1,#tab do
2160  local s=lpegmatch(stripper,tab[i]) or ""
2161  if s=="" then
2162  else
2163   l=l+1
2164   lst[l]=s
2165  end
2166 end
2167 return lst
2168end
2169function table.keys(t)
2170 if t then
2171  local keys={}
2172  local k=0
2173  for key in next,t do
2174   k=k+1
2175   keys[k]=key
2176  end
2177  return keys
2178 else
2179  return {}
2180 end
2181end
2182local function compare(a,b)
2183 local ta=type(a) 
2184 if ta=="number" then
2185  local tb=type(b) 
2186  if ta==tb then
2187   return a<b
2188  elseif tb=="string" then
2189   return tostring(a)<b
2190  end
2191 elseif ta=="string" then
2192  local tb=type(b) 
2193  if ta==tb then
2194   return a<b
2195  else
2196   return a<tostring(b)
2197  end
2198 end
2199 return tostring(a)<tostring(b) 
2200end
2201local function sortedkeys(tab)
2202 if tab then
2203  local srt={}
2204  local category=0 
2205  local s=0
2206  for key in next,tab do
2207   s=s+1
2208   srt[s]=key
2209   if category~=3 then
2210    local tkey=type(key)
2211    if category==1 then
2212     if tkey~="string" then
2213      category=3
2214     end
2215    elseif category==2 then
2216     if tkey~="number" then
2217      category=3
2218     end
2219    else
2220     if tkey=="string" then
2221      category=1
2222     elseif tkey=="number" then
2223      category=2
2224     else
2225      category=3
2226     end
2227    end
2228   end
2229  end
2230  if s<2 then
2231  elseif category==3 then
2232   sort(srt,compare)
2233  else
2234   sort(srt)
2235  end
2236  return srt
2237 else
2238  return {}
2239 end
2240end
2241local function sortedhashonly(tab)
2242 if tab then
2243  local srt={}
2244  local s=0
2245  for key in next,tab do
2246   if type(key)=="string" then
2247    s=s+1
2248    srt[s]=key
2249   end
2250  end
2251  if s>1 then
2252   sort(srt)
2253  end
2254  return srt
2255 else
2256  return {}
2257 end
2258end
2259local function sortedindexonly(tab)
2260 if tab then
2261  local srt={}
2262  local s=0
2263  for key in next,tab do
2264   if type(key)=="number" then
2265    s=s+1
2266    srt[s]=key
2267   end
2268  end
2269  if s>1 then
2270   sort(srt)
2271  end
2272  return srt
2273 else
2274  return {}
2275 end
2276end
2277local function sortedhashkeys(tab,cmp) 
2278 if tab then
2279  local srt={}
2280  local s=0
2281  for key in next,tab do
2282   if key then
2283    s=s+1
2284    srt[s]=key
2285   end
2286  end
2287  if s>1 then
2288   sort(srt,cmp)
2289  end
2290  return srt
2291 else
2292  return {}
2293 end
2294end
2295function table.allkeys(t)
2296 local keys={}
2297 for k,v in next,t do
2298  for k in next,v do
2299   keys[k]=true
2300  end
2301 end
2302 return sortedkeys(keys)
2303end
2304table.sortedkeys=sortedkeys
2305table.sortedhashonly=sortedhashonly
2306table.sortedindexonly=sortedindexonly
2307table.sortedhashkeys=sortedhashkeys
2308local function nothing() end
2309local function sortedhash(t,cmp)
2310 if t then
2311  local s
2312  if cmp then
2313   s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
2314  else
2315   s=sortedkeys(t) 
2316  end
2317  local m=#s
2318  if m==1 then
2319   return next,t
2320  elseif m>0 then
2321   local n=0
2322   return function()
2323    if n<m then
2324     n=n+1
2325     local k=s[n]
2326     return k,t[k]
2327    end
2328   end
2329  end
2330 end
2331 return nothing
2332end
2333table.sortedhash=sortedhash
2334table.sortedpairs=sortedhash 
2335function table.append(t,list)
2336 local n=#t
2337 for i=1,#list do
2338  n=n+1
2339  t[n]=list[i]
2340 end
2341 return t
2342end
2343function table.prepend(t,list)
2344 local nl=#list
2345 local nt=nl+#t
2346 for i=#t,1,-1 do
2347  t[nt]=t[i]
2348  nt=nt-1
2349 end
2350 for i=1,#list do
2351  t[i]=list[i]
2352 end
2353 return t
2354end
2355function table.merge(t,...) 
2356 if not t then
2357  t={}
2358 end
2359 for i=1,select("#",...) do
2360  for k,v in next,(select(i,...)) do
2361   t[k]=v
2362  end
2363 end
2364 return t
2365end
2366function table.merged(...)
2367 local t={}
2368 for i=1,select("#",...) do
2369  for k,v in next,(select(i,...)) do
2370   t[k]=v
2371  end
2372 end
2373 return t
2374end
2375function table.imerge(t,...)
2376 local nt=#t
2377 for i=1,select("#",...) do
2378  local nst=select(i,...)
2379  for j=1,#nst do
2380   nt=nt+1
2381   t[nt]=nst[j]
2382  end
2383 end
2384 return t
2385end
2386function table.imerged(...)
2387 local tmp={}
2388 local ntmp=0
2389 for i=1,select("#",...) do
2390  local nst=select(i,...)
2391  for j=1,#nst do
2392   ntmp=ntmp+1
2393   tmp[ntmp]=nst[j]
2394  end
2395 end
2396 return tmp
2397end
2398local function fastcopy(old,metatabletoo) 
2399 if old then
2400  local new={}
2401  for k,v in next,old do
2402   if type(v)=="table" then
2403    new[k]=fastcopy(v,metatabletoo) 
2404   else
2405    new[k]=v
2406   end
2407  end
2408  if metatabletoo then
2409   local mt=getmetatable(old)
2410   if mt then
2411    setmetatable(new,mt)
2412   end
2413  end
2414  return new
2415 else
2416  return {}
2417 end
2418end
2419local function copy(t,tables) 
2420 if not tables then
2421  tables={}
2422 end
2423 local tcopy={}
2424 if not tables[t] then
2425  tables[t]=tcopy
2426 end
2427 for i,v in next,t do 
2428  if type(i)=="table" then
2429   if tables[i] then
2430    i=tables[i]
2431   else
2432    i=copy(i,tables)
2433   end
2434  end
2435  if type(v)~="table" then
2436   tcopy[i]=v
2437  elseif tables[v] then
2438   tcopy[i]=tables[v]
2439  else
2440   tcopy[i]=copy(v,tables)
2441  end
2442 end
2443 local mt=getmetatable(t)
2444 if mt then
2445  setmetatable(tcopy,mt)
2446 end
2447 return tcopy
2448end
2449table.fastcopy=fastcopy
2450table.copy=copy
2451function table.derive(parent) 
2452 local child={}
2453 if parent then
2454  setmetatable(child,{ __index=parent })
2455 end
2456 return child
2457end
2458function table.tohash(t,value)
2459 local h={}
2460 if t then
2461  if value==nil then value=true end
2462  for _,v in next,t do
2463   h[v]=value
2464  end
2465 end
2466 return h
2467end
2468function table.fromhash(t)
2469 local hsh={}
2470 local h=0
2471 for k,v in next,t do
2472  if v then
2473   h=h+1
2474   hsh[h]=k
2475  end
2476 end
2477 return hsh
2478end
2479local noquotes,hexify,handle,compact,inline,functions,metacheck,accurate
2480local reserved=table.tohash { 
2481 'and','break','do','else','elseif','end','false','for','function','if',
2482 'in','local','nil','not','or','repeat','return','then','true','until','while',
2483 'NaN','goto','const',
2484}
2485local function is_simple_table(t,hexify,accurate) 
2486 local nt=#t
2487 if nt>0 then
2488  local n=0
2489  for _,v in next,t do
2490   n=n+1
2491   if type(v)=="table" then
2492    return nil
2493   end
2494  end
2495  local haszero=rawget(t,0) 
2496  if n==nt then
2497   local tt={}
2498   for i=1,nt do
2499    local v=t[i]
2500    local tv=type(v)
2501    if tv=="number" then
2502     if hexify then
2503      tt[i]=format("0x%X",v)
2504     elseif accurate then
2505      tt[i]=format("%q",v)
2506     else
2507      tt[i]=v 
2508     end
2509    elseif tv=="string" then
2510     tt[i]=format("%q",v) 
2511    elseif tv=="boolean" then
2512     tt[i]=v and "true" or "false"
2513    else
2514     return nil
2515    end
2516   end
2517   return tt
2518  elseif haszero and (n==nt+1) then
2519   local tt={}
2520   for i=0,nt do
2521    local v=t[i]
2522    local tv=type(v)
2523    if tv=="number" then
2524     if hexify then
2525      tt[i+1]=format("0x%X",v)
2526     elseif accurate then
2527      tt[i+1]=format("%q",v)
2528     else
2529      tt[i+1]=v 
2530     end
2531    elseif tv=="string" then
2532     tt[i+1]=format("%q",v) 
2533    elseif tv=="boolean" then
2534     tt[i+1]=v and "true" or "false"
2535    else
2536     return nil
2537    end
2538   end
2539   tt[1]="[0] = "..tt[1]
2540   return tt
2541  end
2542 end
2543 return nil
2544end
2545table.is_simple_table=is_simple_table
2546local propername=patterns.propername 
2547local function dummy() end
2548local function do_serialize(root,name,depth,level,indexed)
2549 if level>0 then
2550  depth=depth.." "
2551  if indexed then
2552   handle(format("%s{",depth))
2553  else
2554   local tn=type(name)
2555   if tn=="number" then
2556    if hexify then
2557     handle(format("%s[0x%X]={",depth,name))
2558    else
2559     handle(format("%s[%s]={",depth,name))
2560    end
2561   elseif tn=="string" then
2562    if noquotes and not reserved[name] and lpegmatch(propername,name) then
2563     handle(format("%s%s={",depth,name))
2564    else
2565     handle(format("%s[%q]={",depth,name))
2566    end
2567   elseif tn=="boolean" then
2568    handle(format("%s[%s]={",depth,name and "true" or "false"))
2569   else
2570    handle(format("%s{",depth))
2571   end
2572  end
2573 end
2574 if root and next(root)~=nil then
2575  local first=nil
2576  local last=0
2577  if compact then
2578   last=#root
2579   for k=1,last do
2580    if rawget(root,k)==nil then
2581     last=k-1
2582     break
2583    end
2584   end
2585   if last>0 then
2586    first=1
2587   end
2588  end
2589  local sk=sortedkeys(root)
2590  for i=1,#sk do
2591   local k=sk[i]
2592   local v=root[k]
2593   local tv=type(v)
2594   local tk=type(k)
2595   if compact and first and tk=="number" and k>=first and k<=last then
2596    if tv=="number" then
2597     if hexify then
2598      handle(format("%s 0x%X,",depth,v))
2599     elseif accurate then
2600      handle(format("%s %q,",depth,v))
2601     else
2602      handle(format("%s %s,",depth,v)) 
2603     end
2604    elseif tv=="string" then
2605     handle(format("%s %q,",depth,v))
2606    elseif tv=="table" then
2607     if next(v)==nil then
2608      handle(format("%s {},",depth))
2609     elseif inline then 
2610      local st=is_simple_table(v,hexify,accurate)
2611      if st then
2612       handle(format("%s { %s },",depth,concat(st,", ")))
2613      else
2614       do_serialize(v,k,depth,level+1,true)
2615      end
2616     else
2617      do_serialize(v,k,depth,level+1,true)
2618     end
2619    elseif tv=="boolean" then
2620     handle(format("%s %s,",depth,v and "true" or "false"))
2621    elseif tv=="function" then
2622     if functions then
2623      handle(format('%s load(%q),',depth,dump(v))) 
2624     else
2625      handle(format('%s "function",',depth))
2626     end
2627    else
2628     handle(format("%s %q,",depth,tostring(v)))
2629    end
2630   elseif k=="__p__" then 
2631    if false then
2632     handle(format("%s __p__=nil,",depth))
2633    end
2634   elseif tv=="number" then
2635    if tk=="number" then
2636     if hexify then
2637      handle(format("%s [0x%X]=0x%X,",depth,k,v))
2638     elseif accurate then
2639      handle(format("%s [%s]=%q,",depth,k,v))
2640     else
2641      handle(format("%s [%s]=%s,",depth,k,v)) 
2642     end
2643    elseif tk=="boolean" then
2644     if hexify then
2645      handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v))
2646     elseif accurate then
2647      handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
2648     else
2649      handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) 
2650     end
2651    elseif tk~="string" then
2652    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2653     if hexify then
2654      handle(format("%s %s=0x%X,",depth,k,v))
2655     elseif accurate then
2656      handle(format("%s %s=%q,",depth,k,v))
2657     else
2658      handle(format("%s %s=%s,",depth,k,v)) 
2659     end
2660    else
2661     if hexify then
2662      handle(format("%s [%q]=0x%X,",depth,k,v))
2663     elseif accurate then
2664      handle(format("%s [%q]=%q,",depth,k,v))
2665     else
2666      handle(format("%s [%q]=%s,",depth,k,v)) 
2667     end
2668    end
2669   elseif tv=="string" then
2670    if tk=="number" then
2671     if hexify then
2672      handle(format("%s [0x%X]=%q,",depth,k,v))
2673     elseif accurate then
2674      handle(format("%s [%q]=%q,",depth,k,v))
2675     else
2676      handle(format("%s [%s]=%q,",depth,k,v))
2677     end
2678    elseif tk=="boolean" then
2679     handle(format("%s [%s]=%q,",depth,k and "true" or "false",v))
2680    elseif tk~="string" then
2681    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2682     handle(format("%s %s=%q,",depth,k,v))
2683    else
2684     handle(format("%s [%q]=%q,",depth,k,v))
2685    end
2686   elseif tv=="table" then
2687    if next(v)==nil then
2688     if tk=="number" then
2689      if hexify then
2690       handle(format("%s [0x%X]={},",depth,k))
2691      elseif accurate then
2692       handle(format("%s [%q]={},",depth,k))
2693      else
2694       handle(format("%s [%s]={},",depth,k))
2695      end
2696     elseif tk=="boolean" then
2697      handle(format("%s [%s]={},",depth,k and "true" or "false"))
2698     elseif tk~="string" then
2699     elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2700      handle(format("%s %s={},",depth,k))
2701     else
2702      handle(format("%s [%q]={},",depth,k))
2703     end
2704    elseif inline then
2705     local st=is_simple_table(v,hexify,accurate)
2706     if st then
2707      if tk=="number" then
2708       if hexify then
2709        handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", ")))
2710       elseif accurate then
2711        handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
2712       else
2713        handle(format("%s [%s]={ %s },",depth,k,concat(st,", ")))
2714       end
2715      elseif tk=="boolean" then
2716       handle(format("%s [%s]={ %s },",depth,k and "true" or "false",concat(st,", ")))
2717      elseif tk~="string" then
2718      elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2719       handle(format("%s %s={ %s },",depth,k,concat(st,", ")))
2720      else
2721       handle(format("%s [%q]={ %s },",depth,k,concat(st,", ")))
2722      end
2723     else
2724      do_serialize(v,k,depth,level+1)
2725     end
2726    else
2727     do_serialize(v,k,depth,level+1)
2728    end
2729   elseif tv=="boolean" then
2730    if tk=="number" then
2731     if hexify then
2732      handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false"))
2733     elseif accurate then
2734      handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
2735     else
2736      handle(format("%s [%s]=%s,",depth,k,v and "true" or "false"))
2737     end
2738    elseif tk=="boolean" then
2739     handle(format("%s [%s]=%s,",depth,tostring(k),v and "true" or "false"))
2740    elseif tk~="string" then
2741    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2742     handle(format("%s %s=%s,",depth,k,v and "true" or "false"))
2743    else
2744     handle(format("%s [%q]=%s,",depth,k,v and "true" or "false"))
2745    end
2746   elseif tv=="function" then
2747    if functions then
2748     local getinfo=debug and debug.getinfo
2749     if getinfo then
2750      local f=getinfo(v).what=="C" and dump(dummy) or dump(v)
2751      if tk=="number" then
2752       if hexify then
2753        handle(format("%s [0x%X]=load(%q),",depth,k,f))
2754       elseif accurate then
2755        handle(format("%s [%q]=load(%q),",depth,k,f))
2756       else
2757        handle(format("%s [%s]=load(%q),",depth,k,f))
2758       end
2759      elseif tk=="boolean" then
2760       handle(format("%s [%s]=load(%q),",depth,k and "true" or "false",f))
2761      elseif tk~="string" then
2762      elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2763       handle(format("%s %s=load(%q),",depth,k,f))
2764      else
2765       handle(format("%s [%q]=load(%q),",depth,k,f))
2766      end
2767     end
2768    end
2769   else
2770    if tk=="number" then
2771     if hexify then
2772      handle(format("%s [0x%X]=%q,",depth,k,tostring(v)))
2773     elseif accurate then
2774      handle(format("%s [%q]=%q,",depth,k,tostring(v)))
2775     else
2776      handle(format("%s [%s]=%q,",depth,k,tostring(v)))
2777     end
2778    elseif tk=="boolean" then
2779     handle(format("%s [%s]=%q,",depth,k and "true" or "false",tostring(v)))
2780    elseif tk~="string" then
2781    elseif noquotes and not reserved[k] and lpegmatch(propername,k) then
2782     handle(format("%s %s=%q,",depth,k,tostring(v)))
2783    else
2784     handle(format("%s [%q]=%q,",depth,k,tostring(v)))
2785    end
2786   end
2787  end
2788 end
2789 if level>0 then
2790  handle(format("%s},",depth))
2791 end
2792end
2793local function serialize(_handle,root,name,specification) 
2794 local tname=type(name)
2795 if type(specification)=="table" then
2796  noquotes=specification.noquotes
2797  hexify=specification.hexify
2798  accurate=specification.accurate
2799  handle=_handle or specification.handle or print
2800  functions=specification.functions
2801  compact=specification.compact
2802  inline=specification.inline and compact
2803  metacheck=specification.metacheck
2804  if functions==nil then
2805   functions=true
2806  end
2807  if compact==nil then
2808   compact=true
2809  end
2810  if inline==nil then
2811   inline=compact
2812  end
2813  if metacheck==nil then
2814   metacheck=true
2815  end
2816 else
2817  noquotes=false
2818  hexify=false
2819  handle=_handle or print
2820  compact=true
2821  inline=true
2822  functions=true
2823  metacheck=true
2824 end
2825 if tname=="string" then
2826  if name=="return" then
2827   handle("return {")
2828  else
2829   handle(name.."={")
2830  end
2831 elseif tname=="number" then
2832  if hexify then
2833   handle(format("[0x%X]={",name))
2834  else
2835   handle("["..name.."]={")
2836  end
2837 elseif tname=="boolean" then
2838  if name then
2839   handle("return {")
2840  else
2841   handle("{")
2842  end
2843 else
2844  handle("t={")
2845 end
2846 if root then
2847  if metacheck and getmetatable(root) then
2848   local dummy=root._w_h_a_t_e_v_e_r_
2849   root._w_h_a_t_e_v_e_r_=nil
2850  end
2851  if next(root)~=nil then
2852   do_serialize(root,name,"",0)
2853  end
2854 end
2855 handle("}")
2856end
2857function table.serialize(root,name,specification)
2858 local t={}
2859 local n=0
2860 local function flush(s)
2861  n=n+1
2862  t[n]=s
2863 end
2864 serialize(flush,root,name,specification)
2865 return concat(t,"\n")
2866end
2867table.tohandle=serialize
2868local maxtab=2*1024
2869function table.tofile(filename,root,name,specification)
2870 local f=io.open(filename,'w')
2871 if f then
2872  if maxtab>1 then
2873   local t={}
2874   local n=0
2875   local function flush(s)
2876    n=n+1
2877    t[n]=s
2878    if n>maxtab then
2879     f:write(concat(t,"\n"),"\n") 
2880     t={} 
2881     n=0
2882    end
2883   end
2884   serialize(flush,root,name,specification)
2885   f:write(concat(t,"\n"),"\n")
2886  else
2887   local function flush(s)
2888    f:write(s,"\n")
2889   end
2890   serialize(flush,root,name,specification)
2891  end
2892  f:close()
2893  io.flush()
2894 end
2895end
2896local function flattened(t,f,depth) 
2897 if f==nil then
2898  f={}
2899  depth=0xFFFF
2900 elseif tonumber(f) then
2901  depth=f
2902  f={}
2903 elseif not depth then
2904  depth=0xFFFF
2905 end
2906 for k,v in next,t do
2907  if type(k)~="number" then
2908   if depth>0 and type(v)=="table" then
2909    flattened(v,f,depth-1)
2910   else
2911    f[#f+1]=v
2912   end
2913  end
2914 end
2915 for k=1,#t do
2916  local v=t[k]
2917  if depth>0 and type(v)=="table" then
2918   flattened(v,f,depth-1)
2919  else
2920   f[#f+1]=v
2921  end
2922 end
2923 return f
2924end
2925table.flattened=flattened
2926local function collapsed(t,f,h)
2927 if f==nil then
2928  f={}
2929  h={}
2930 end
2931 for k=1,#t do
2932  local v=t[k]
2933  if type(v)=="table" then
2934   collapsed(v,f,h)
2935  elseif not h[v] then
2936   f[#f+1]=v
2937   h[v]=true
2938  end
2939 end
2940 return f
2941end
2942local function collapsedhash(t,h)
2943 if h==nil then
2944  h={}
2945 end
2946 for k=1,#t do
2947  local v=t[k]
2948  if type(v)=="table" then
2949   collapsedhash(v,h)
2950  else
2951   h[v]=true
2952  end
2953 end
2954 return h
2955end
2956table.collapsed=collapsed  
2957table.collapsedhash=collapsedhash
2958local function unnest(t,f) 
2959 if not f then    
2960  f={}   
2961 end
2962 for i=1,#t do
2963  local v=t[i]
2964  if type(v)=="table" then
2965   if type(v[1])=="table" then
2966    unnest(v,f)
2967   else
2968    f[#f+1]=v
2969   end
2970  else
2971   f[#f+1]=v
2972  end
2973 end
2974 return f
2975end
2976function table.unnest(t) 
2977 return unnest(t)
2978end
2979local function are_equal(a,b,n,m) 
2980 if a==b then
2981  return true
2982 elseif a and b and #a==#b then
2983  if not n then
2984   n=1
2985  end
2986  if not m then
2987   m=#a
2988  end
2989  for i=n,m do
2990   local ai,bi=a[i],b[i]
2991   if ai==bi then
2992   elseif type(ai)=="table" and type(bi)=="table" then
2993    if not are_equal(ai,bi) then
2994     return false
2995    end
2996   else
2997    return false
2998   end
2999  end
3000  return true
3001 else
3002  return false
3003 end
3004end
3005local function identical(a,b) 
3006 if a~=b then
3007  for ka,va in next,a do
3008   local vb=b[ka]
3009   if va==vb then
3010   elseif type(va)=="table" and  type(vb)=="table" then
3011    if not identical(va,vb) then
3012     return false
3013    end
3014   else
3015    return false
3016   end
3017  end
3018 end
3019 return true
3020end
3021table.identical=identical
3022table.are_equal=are_equal
3023local function sparse(old,nest,keeptables)
3024 local new={}
3025 for k,v in next,old do
3026  if not (v=="" or v==false) then
3027   if nest and type(v)=="table" then
3028    v=sparse(v,nest)
3029    if keeptables or next(v)~=nil then
3030     new[k]=v
3031    end
3032   else
3033    new[k]=v
3034   end
3035  end
3036 end
3037 return new
3038end
3039table.sparse=sparse
3040function table.compact(t)
3041 return sparse(t,true,true)
3042end
3043function table.contains(t,v)
3044 if t then
3045  for i=1,#t do
3046   if t[i]==v then
3047    return i
3048   end
3049  end
3050 end
3051 return false
3052end
3053function table.count(t)
3054 local n=0
3055 for k,v in next,t do
3056  n=n+1
3057 end
3058 return n
3059end
3060function table.swapped(t,s) 
3061 local n={}
3062 if s then
3063  for k,v in next,s do
3064   n[k]=v
3065  end
3066 end
3067 for k,v in next,t do
3068  n[v]=k
3069 end
3070 return n
3071end
3072function table.hashed(t) 
3073 for i=1,#t do
3074  t[t[i]]=i
3075 end
3076 return t
3077end
3078function table.mirrored(t) 
3079 local n={}
3080 for k,v in next,t do
3081  n[v]=k
3082  n[k]=v
3083 end
3084 return n
3085end
3086function table.reversed(t)
3087 if t then
3088  local tt={}
3089  local tn=#t
3090  if tn>0 then
3091   local ttn=0
3092   for i=tn,1,-1 do
3093    ttn=ttn+1
3094    tt[ttn]=t[i]
3095   end
3096  end
3097  return tt
3098 end
3099end
3100function table.reverse(t) 
3101 if t then
3102  local n=#t
3103  local m=n+1
3104  for i=1,floor(n/2) do 
3105   local j=m-i
3106   t[i],t[j]=t[j],t[i]
3107  end
3108  return t
3109 end
3110end
3111local function sequenced(t,sep,simple)
3112 if not t then
3113  return ""
3114 elseif type(t)~="table" then
3115  return t 
3116 end
3117 local n=#t
3118 local s={}
3119 if n>0 then
3120  for i=1,n do
3121   local v=t[i]
3122   if type(v)=="table" then
3123    s[i]="{"..sequenced(v,sep,simple).."}"
3124   else
3125    s[i]=tostring(t[i])
3126   end
3127  end
3128 else
3129  n=0
3130  for k,v in sortedhash(t) do
3131   if simple then
3132    if v==true then
3133     n=n+1
3134     s[n]=k
3135    elseif v and v~="" then
3136     n=n+1
3137     if type(v)=="table" then
3138      s[n]=k.."={"..sequenced(v,sep,simple).."}"
3139     else
3140      s[n]=k.."="..tostring(v)
3141     end
3142    end
3143   else
3144    n=n+1
3145    if type(v)=="table" then
3146     s[n]=k.."={"..sequenced(v,sep,simple).."}"
3147    else
3148     s[n]=k.."="..tostring(v)
3149    end
3150   end
3151  end
3152 end
3153 if sep==true then
3154  return "{ "..concat(s,", ").." }"
3155 else
3156  return concat(s,sep or " | ")
3157 end
3158end
3159table.sequenced=sequenced
3160function table.print(t,...)
3161 if type(t)~="table" then
3162  print(tostring(t))
3163 else
3164  serialize(print,t,...)
3165 end
3166end
3167if setinspector then
3168 setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end)
3169end
3170function table.sub(t,i,j)
3171 return { unpack(t,i,j) }
3172end
3173function table.is_empty(t)
3174 return not t or next(t)==nil
3175end
3176function table.has_one_entry(t)
3177 return t and next(t,next(t))==nil
3178end
3179function table.loweredkeys(t) 
3180 local l={}
3181 for k,v in next,t do
3182  l[lower(k)]=v
3183 end
3184 return l
3185end
3186function table.unique(old)
3187 local hash={}
3188 local new={}
3189 local n=0
3190 for i=1,#old do
3191  local oi=old[i]
3192  if not hash[oi] then
3193   n=n+1
3194   new[n]=oi
3195   hash[oi]=true
3196  end
3197 end
3198 return new
3199end
3200function table.sorted(t,...)
3201 sort(t,...)
3202 return t 
3203end
3204function table.values(t,s) 
3205 if t then
3206  local values={}
3207  local keys={}
3208  local v=0
3209  for key,value in next,t do
3210   if not keys[value] then
3211    v=v+1
3212    values[v]=value
3213    keys[k]=key
3214   end
3215  end
3216  if s then
3217   sort(values)
3218  end
3219  return values
3220 else
3221  return {}
3222 end
3223end
3224function table.filtered(t,pattern,sort,cmp)
3225 if t and type(pattern)=="string" then
3226  if sort then
3227   local s
3228   if cmp then
3229    s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end)
3230   else
3231    s=sortedkeys(t) 
3232   end
3233   local n=0
3234   local m=#s
3235   local function kv(s)
3236    while n<m do
3237     n=n+1
3238     local k=s[n]
3239     if find(k,pattern) then
3240      return k,t[k]
3241     end
3242    end
3243   end
3244   return kv,s
3245  else
3246   local n=next(t)
3247   local function iterator()
3248    while n~=nil do
3249     local k=n
3250     n=next(t,k)
3251     if find(k,pattern) then
3252      return k,t[k]
3253     end
3254    end
3255   end
3256   return iterator,t
3257  end
3258 else
3259  return nothing
3260 end
3261end
3262if not table.move then
3263 function table.move(a1,f,e,t,a2)
3264  if a2 and a1~=a2 then
3265   for i=f,e do
3266    a2[t]=a1[i]
3267    t=t+1
3268   end
3269   return a2
3270  else
3271   t=t+e-f
3272   for i=e,f,-1 do
3273    a1[t]=a1[i]
3274    t=t-1
3275   end
3276   return a1
3277  end
3278 end
3279end
3280
3281
3282end -- of closure
3283
3284do -- create closure to overcome 200 locals limit
3285
3286package.loaded["l-io"] = package.loaded["l-io"] or true
3287
3288-- original size: 11988, stripped down to: 6430
3289
3290if not modules then modules={} end modules ['l-io']={
3291 version=1.001,
3292 comment="companion to luat-lib.mkiv",
3293 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
3294 copyright="PRAGMA ADE / ConTeXt Development Team",
3295 license="see context related readme files"
3296}
3297local io=io
3298local open,flush,write,read=io.open,io.flush,io.write,io.read
3299local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format
3300local concat=table.concat
3301local type=type
3302if string.find(os.getenv("PATH") or "",";",1,true) then
3303 io.fileseparator,io.pathseparator="\\",";"
3304else
3305 io.fileseparator,io.pathseparator="/",":"
3306end
3307local large=0x01000000 
3308local medium=0x00100000 
3309local small=0x00020000
3310local function readall(f)
3311 local size=f:seek("end")
3312 if size>0 then
3313  f:seek("set",0)
3314  return f:read(size)
3315 else
3316  return ""
3317 end
3318end
3319io.readall=readall
3320function io.loaddata(filename,textmode) 
3321 local f=open(filename,(textmode and 'r') or 'rb')
3322 if f then
3323  local size=f:seek("end")
3324  local data=nil
3325  if size>0 then
3326   f:seek("set",0)
3327   data=f:read(size)
3328  end
3329  f:close()
3330  return data
3331 end
3332end
3333function io.copydata(source,target,action)
3334 local f=open(source,"rb")
3335 if f then
3336  local g=open(target,"wb")
3337  if g then
3338   local size=f:seek("end")
3339   if size>0 then
3340    f:seek("set",0)
3341    local data=f:read(size)
3342    if action then
3343     data=action(data)
3344    end
3345    if data then
3346     g:write(data)
3347    end
3348   end
3349   g:close()
3350  end
3351  f:close()
3352  flush()
3353 end
3354end
3355function io.savedata(filename,data,joiner,append)
3356 local f=open(filename,append and "ab" or "wb")
3357 if f then
3358  if append and joiner and f:seek("end")>0 then
3359   f:write(joiner)
3360  end
3361  if type(data)=="table" then
3362   f:write(concat(data,joiner or ""))
3363  elseif type(data)=="function" then
3364   data(f)
3365  else
3366   f:write(data or "")
3367  end
3368  f:close()
3369  flush()
3370  return true
3371 else
3372  return false
3373 end
3374end
3375if fio and fio.readline then
3376 local readline=fio.readline
3377 function io.loadlines(filename,n) 
3378  local f=open(filename,'r')
3379  if not f then
3380  elseif n then
3381   local lines={}
3382   for i=1,n do
3383    local line=readline(f)
3384    if line then
3385     lines[i]=line
3386    else
3387     break
3388    end
3389   end
3390   f:close()
3391   lines=concat(lines,"\n")
3392   if #lines>0 then
3393    return lines
3394   end
3395  else
3396   local line=readline(f)
3397   f:close()
3398   if line and #line>0 then
3399    return line
3400   end
3401  end
3402 end
3403else
3404 function io.loadlines(filename,n) 
3405  local f=open(filename,'r')
3406  if not f then
3407  elseif n then
3408   local lines={}
3409   for i=1,n do
3410    local line=f:read("*lines")
3411    if line then
3412     lines[i]=line
3413    else
3414     break
3415    end
3416   end
3417   f:close()
3418   lines=concat(lines,"\n")
3419   if #lines>0 then
3420    return lines
3421   end
3422  else
3423   local line=f:read("*line") or ""
3424   f:close()
3425   if #line>0 then
3426    return line
3427   end
3428  end
3429 end
3430end
3431function io.loadchunk(filename,n)
3432 local f=open(filename,'rb')
3433 if f then
3434  local data=f:read(n or 1024)
3435  f:close()
3436  if #data>0 then
3437   return data
3438  end
3439 end
3440end
3441function io.exists(filename)
3442 local f=open(filename)
3443 if f==nil then
3444  return false
3445 else
3446  f:close()
3447  return true
3448 end
3449end
3450function io.size(filename)
3451 local f=open(filename)
3452 if f==nil then
3453  return 0
3454 else
3455  local s=f:seek("end")
3456  f:close()
3457  return s
3458 end
3459end
3460local function noflines(f)
3461 if type(f)=="string" then
3462  local f=open(filename)
3463  if f then
3464   local n=f and noflines(f) or 0
3465   f:close()
3466   return n
3467  else
3468   return 0
3469  end
3470 else
3471  local n=0
3472  for _ in f:lines() do
3473   n=n+1
3474  end
3475  f:seek('set',0)
3476  return n
3477 end
3478end
3479io.noflines=noflines
3480local nextchar={
3481 [ 4]=function(f)
3482  return f:read(1,1,1,1)
3483 end,
3484 [ 2]=function(f)
3485  return f:read(1,1)
3486 end,
3487 [ 1]=function(f)
3488  return f:read(1)
3489 end,
3490 [-2]=function(f)
3491  local a,b=f:read(1,1)
3492  return b,a
3493 end,
3494 [-4]=function(f)
3495  local a,b,c,d=f:read(1,1,1,1)
3496  return d,c,b,a
3497 end
3498}
3499function io.characters(f,n)
3500 if f then
3501  return nextchar[n or 1],f
3502 end
3503end
3504local nextbyte={
3505 [4]=function(f)
3506  local a,b,c,d=f:read(1,1,1,1)
3507  if d then
3508   return byte(a),byte(b),byte(c),byte(d)
3509  end
3510 end,
3511 [3]=function(f)
3512  local a,b,c=f:read(1,1,1)
3513  if b then
3514   return byte(a),byte(b),byte(c)
3515  end
3516 end,
3517 [2]=function(f)
3518  local a,b=f:read(1,1)
3519  if b then
3520   return byte(a),byte(b)
3521  end
3522 end,
3523 [1]=function (f)
3524  local a=f:read(1)
3525  if a then
3526   return byte(a)
3527  end
3528 end,
3529 [-2]=function (f)
3530  local a,b=f:read(1,1)
3531  if b then
3532   return byte(b),byte(a)
3533  end
3534 end,
3535 [-3]=function(f)
3536  local a,b,c=f:read(1,1,1)
3537  if b then
3538   return byte(c),byte(b),byte(a)
3539  end
3540 end,
3541 [-4]=function(f)
3542  local a,b,c,d=f:read(1,1,1,1)
3543  if d then
3544   return byte(d),byte(c),byte(b),byte(a)
3545  end
3546 end
3547}
3548function io.bytes(f,n)
3549 if f then
3550  return nextbyte[n or 1],f
3551 else
3552  return nil,nil
3553 end
3554end
3555function io.ask(question,default,options)
3556 while true do
3557  write(question)
3558  if options then
3559   write(format(" [%s]",concat(options,"|")))
3560  end
3561  if default then
3562   write(format(" [%s]",default))
3563  end
3564  write(format(" "))
3565  flush()
3566  local answer=read()
3567  answer=gsub(answer,"^%s*(.*)%s*$","%1")
3568  if answer=="" and default then
3569   return default
3570  elseif not options then
3571   return answer
3572  else
3573   for k=1,#options do
3574    if options[k]==answer then
3575     return answer
3576    end
3577   end
3578   local pattern="^"..answer
3579   for k=1,#options do
3580    local v=options[k]
3581    if find(v,pattern) then
3582     return v
3583    end
3584   end
3585  end
3586 end
3587end
3588local function readnumber(f,n,m) 
3589 if m then
3590  f:seek("set",n)
3591  n=m
3592 end
3593 if n==1 then
3594  return byte(f:read(1))
3595 elseif n==2 then
3596  local a,b=byte(f:read(2),1,2)
3597  return 0x100*a+b
3598 elseif n==3 then
3599  local a,b,c=byte(f:read(3),1,3)
3600  return 0x10000*a+0x100*b+c
3601 elseif n==4 then
3602  local a,b,c,d=byte(f:read(4),1,4)
3603  return 0x1000000*a+0x10000*b+0x100*c+d
3604 elseif n==8 then
3605  local a,b=readnumber(f,4),readnumber(f,4)
3606  return 0x100*a+b
3607 elseif n==12 then
3608  local a,b,c=readnumber(f,4),readnumber(f,4),readnumber(f,4)
3609  return 0x10000*a+0x100*b+c
3610 elseif n==-2 then
3611  local b,a=byte(f:read(2),1,2)
3612  return 0x100*a+b
3613 elseif n==-3 then
3614  local c,b,a=byte(f:read(3),1,3)
3615  return 0x10000*a+0x100*b+c
3616 elseif n==-4 then
3617  local d,c,b,a=byte(f:read(4),1,4)
3618  return 0x1000000*a+0x10000*b+0x100*c+d
3619 elseif n==-8 then
3620  local h,g,f,e,d,c,b,a=byte(f:read(8),1,8)
3621  return 0x100000000000000*a+0x1000000000000*b+0x10000000000*c+0x100000000*d+0x1000000*e+0x10000*f+0x100*g+h
3622 else
3623  return 0
3624 end
3625end
3626io.readnumber=readnumber
3627function io.readstring(f,n,m)
3628 if m then
3629  f:seek("set",n)
3630  n=m
3631 end
3632 local str=gsub(f:read(n),"\000","")
3633 return str
3634end
3635
3636
3637end -- of closure
3638
3639do -- create closure to overcome 200 locals limit
3640
3641package.loaded["l-number"] = package.loaded["l-number"] or true
3642
3643-- original size: 4588, stripped down to: 2159
3644
3645if not modules then modules={} end modules ['l-number']={
3646 version=1.001,
3647 comment="companion to luat-lib.mkxl",
3648 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
3649 copyright="PRAGMA ADE / ConTeXt Development Team",
3650 license="see context related readme files"
3651}
3652local tostring,tonumber=tostring,tonumber
3653local format,match,rep=string.format,string.match,string.rep
3654local concat,insert=table.concat,table.insert
3655local lpegmatch=lpeg.match
3656local floor=math.floor
3657number=number or {}
3658local number=number
3659if bit32 then
3660 local bextract=bit32.extract
3661 local t={
3662  "0","0","0","0","0","0","0","0",
3663  "0","0","0","0","0","0","0","0",
3664  "0","0","0","0","0","0","0","0",
3665  "0","0","0","0","0","0","0","0",
3666 }
3667 function number.tobitstring(b,m,w)
3668  if not w then
3669   w=32
3670  end
3671  local n=w
3672  for i=0,w-1 do
3673   local v=bextract(b,i)
3674   local k=w-i
3675   if v==1 then
3676    n=k
3677    t[k]="1"
3678   else
3679    t[k]="0"
3680   end
3681  end
3682  if w then
3683   return concat(t,"",1,w)
3684  elseif m then
3685   m=33-m*8
3686   if m<1 then
3687    m=1
3688   end
3689   return concat(t,"",1,m)
3690  elseif n<8 then
3691   return concat(t)
3692  elseif n<16 then
3693   return concat(t,"",9)
3694  elseif n<24 then
3695   return concat(t,"",17)
3696  else
3697   return concat(t,"",25)
3698  end
3699 end
3700else
3701 function number.tobitstring(n,m)
3702  if n>0 then
3703   local t={}
3704   while n>0 do
3705    insert(t,1,n%2>0 and 1 or 0)
3706    n=floor(n/2)
3707   end
3708   local nn=8-#t%8
3709   if nn>0 and nn<8 then
3710    for i=1,nn do
3711     insert(t,1,0)
3712    end
3713   end
3714   if m then
3715    m=m*8-#t
3716    if m>0 then
3717     insert(t,1,rep("0",m))
3718    end
3719   end
3720   return concat(t)
3721  elseif m then
3722   rep("00000000",m)
3723  else
3724   return "00000000"
3725  end
3726 end
3727end
3728function number.valid(str,default)
3729 return tonumber(str) or default or nil
3730end
3731function number.toevenhex(n)
3732 local s=format("%X",n)
3733 if #s%2==0 then
3734  return s
3735 else
3736  return "0"..s
3737 end
3738end
3739function number.bytetodecimal(b)
3740 local d=floor(b*100/255+0.5)
3741 if d>100 then
3742  return 100
3743 elseif d<-100 then
3744  return -100
3745 else
3746  return d
3747 end
3748end
3749function number.decimaltobyte(d)
3750 local b=floor(d*255/100+0.5)
3751 if b>255 then
3752  return 255
3753 elseif b<-255 then
3754  return -255
3755 else
3756  return b
3757 end
3758end
3759function number.idiv(i,d)
3760 return floor(i/d) 
3761end
3762
3763
3764end -- of closure
3765
3766do -- create closure to overcome 200 locals limit
3767
3768package.loaded["l-set"] = package.loaded["l-set"] or true
3769
3770-- original size: 1923, stripped down to: 1044
3771
3772if not modules then modules={} end modules ['l-set']={
3773 version=1.001,
3774 comment="companion to luat-lib.mkiv",
3775 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
3776 copyright="PRAGMA ADE / ConTeXt Development Team",
3777 license="see context related readme files"
3778}
3779set=set or {}
3780local nums={}
3781local tabs={}
3782local concat=table.concat
3783local next,type=next,type
3784set.create=table.tohash
3785function set.tonumber(t)
3786 if next(t) then
3787  local s=""
3788  for k,v in next,t do
3789   if v then
3790    s=s.." "..k
3791   end
3792  end
3793  local n=nums[s]
3794  if not n then
3795   n=#tabs+1
3796   tabs[n]=t
3797   nums[s]=n
3798  end
3799  return n
3800 else
3801  return 0
3802 end
3803end
3804function set.totable(n)
3805 if n==0 then
3806  return {}
3807 else
3808  return tabs[n] or {}
3809 end
3810end
3811function set.tolist(n)
3812 if n==0 or not tabs[n] then
3813  return ""
3814 else
3815  local t,n={},0
3816  for k,v in next,tabs[n] do
3817   if v then
3818    n=n+1
3819    t[n]=k
3820   end
3821  end
3822  return concat(t," ")
3823 end
3824end
3825function set.contains(n,s)
3826 if type(n)=="table" then
3827  return n[s]
3828 elseif n==0 then
3829  return false
3830 else
3831  local t=tabs[n]
3832  return t and t[s]
3833 end
3834end
3835
3836
3837end -- of closure
3838
3839do -- create closure to overcome 200 locals limit
3840
3841package.loaded["l-os"] = package.loaded["l-os"] or true
3842
3843-- original size: 20575, stripped down to: 10700
3844
3845if not modules then modules={} end modules ['l-os']={
3846 version=1.001,
3847 comment="companion to luat-lib.mkiv",
3848 author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
3849 copyright="PRAGMA ADE / ConTeXt Development Team",
3850 license="see context related readme files"
3851}
3852local os=os
3853local date,time,difftime=os.date,os.time,os.difftime
3854local find,format,gsub,upper,gmatch=string.find,string.format,string.gsub,string.upper,string.gmatch
3855local concat=table.concat
3856local random,ceil,randomseed,modf=math.random,math.ceil,math.randomseed,math.modf
3857local type,setmetatable,tonumber,tostring=type,setmetatable,tonumber,tostring
3858do
3859 local selfdir=os.selfdir
3860 if selfdir=="" then
3861  selfdir=nil
3862 end
3863 if not selfdir then
3864  if arg then
3865   for i=1,#arg do
3866    local a=arg[i]
3867    if find(a,"^%-%-[c:]*texmfbinpath=") then
3868     selfdir=gsub(a,"^.-=","")
3869     break
3870    end
3871   end
3872  end
3873  if not selfdir then
3874   selfdir=os.selfbin or "luatex"
3875   if find(selfdir,"[/\\]") then
3876    selfdir=gsub(selfdir,"[/\\][^/\\]*$","")
3877   elseif os.getenv then
3878    local path=os.getenv("PATH")
3879    local name=gsub(selfdir,"^.*[/\\][^/\\]","")
3880    local patt="[^:]+"
3881    if os.type=="windows" then
3882     patt="[^;]+"
3883     name=name..".exe"
3884    end
3885    local isfile
3886    if lfs then
3887     local attributes=lfs.attributes
3888     isfile=function(name)
3889      local a=attributes(name,"mode")
3890      return a=="file" or a=="link" or nil
3891     end
3892    else
3893     local open=io.open
3894     isfile=function(name)
3895      local f=open(name)
3896      if f then
3897       f:close()
3898       return true
3899      end
3900     end
3901    end
3902    for p in gmatch(path,patt) do
3903     if isfile(p.."/"..name) then
3904      selfdir=p
3905      break
3906     end
3907    end
3908   end
3909  end
3910  os.selfdir=selfdir or "."
3911 end
3912end
3913math.initialseed=tonumber(string.sub(string.reverse(tostring(ceil(socket and socket.gettime()*10000 or time()))),1,6))
3914randomseed(math.initialseed)
3915if not os.__getenv__ then
3916 os.__getenv__=os.getenv
3917 os.__setenv__=os.setenv
3918 if os.env then
3919  local osgetenv=os.getenv
3920  local ossetenv=os.setenv
3921  local osenv=os.env   local _=osenv.PATH 
3922  function os.setenv(k,v)
3923   if v==nil then
3924    v=""
3925   end
3926   local K=upper(k)
3927   osenv[K]=v
3928   if type(v)=="table" then
3929    v=concat(v,";") 
3930   end
3931   ossetenv(K,v)
3932  end
3933  function os.getenv(k)
3934   local K=upper(k)
3935   local v=osenv[K] or osenv[k] or osgetenv(K) or osgetenv(k)
3936   if v=="" then
3937    return nil
3938   else
3939    return v
3940   end
3941  end
3942 else
3943  local ossetenv=os.setenv
3944  local osgetenv=os.getenv
3945  local osenv={}
3946  function os.setenv(k,v)
3947   if v==nil then
3948    v=""
3949   end
3950   local K=upper(k)
3951   osenv[K]=v
3952  end
3953  function os.getenv(k)
3954   local K=upper(k)
3955   local v=osenv[K] or osgetenv(K) or osgetenv(k)
3956   if v=="" then
3957    return nil
3958   else
3959    return v
3960   end
3961  end
3962  local function __index(t,k)
3963   return os.getenv(k)
3964  end
3965  local function __newindex(t,k,v)
3966   os.setenv(k,v)
3967  end
3968  os.env={}
3969  setmetatable(os.env,{ __index=__index,__newindex=__newindex } )
3970 end
3971end
3972if not io.fileseparator then
3973 if find(os.getenv("PATH"),";",1,true) then
3974  io.fileseparator,io.pathseparator,os.type="\\",";",os.type or "windows"
3975 else
3976  io.fileseparator,io.pathseparator,os.type="/",":",os.type or "unix"
3977 end
3978end
3979os.type=os.type or (io.pathseparator==";"    and "windows") or "unix"
3980os.name=os.name or (os.type=="windows" and "mswin"  ) or "linux"
3981if os.type=="windows" then
3982 os.libsuffix,os.binsuffix,os.binsuffixes='dll','exe',{ 'exe','cmd','bat' }
3983else
3984 os.libsuffix,os.binsuffix,os.binsuffixes='so','',{ '' }
3985end
3986do
3987 local execute=os.execute
3988 local iopopen=io.popen
3989 local ostype=os.type
3990 local function resultof(command)
3991  local handle=iopopen(command,ostype=="windows" and "rb" or "r")
3992  if handle then
3993   local result=handle:read("*all") or ""
3994   handle:close()
3995   return result
3996  else
3997   return ""
3998  end
3999 end
4000 os.resultof=resultof
4001 function os.pipeto(command)
4002  return iopopen(command,"w") 
4003 end
4004 local launchers={
4005  windows="start %s",
4006  macosx="open %s",
4007  unix="xdg-open %s &> /dev/null &",
4008 }
4009 function os.launch(str)
4010  local command=format(launchers[os.name] or launchers.unix,str)
4011  execute(command)
4012 end
4013end
4014do
4015 local gettimeofday=os.gettimeofday or os.clock
4016 os.gettimeofday=gettimeofday
4017 local startuptime=gettimeofday()
4018 function os.runtime()
4019  return gettimeofday()-startuptime
4020 end
4021end
4022do
4023 local name=os.name or "linux"
4024 local platform=os.getenv("MTX_PLATFORM") or ""
4025 local architecture=os.uname and os.uname().machine 
4026 local bits=os.getenv("MTX_BITS") or find(platform,"64") and 64 or 32
4027 if platform~="" then
4028 elseif os.type=="windows" then
4029  architecture=string.lower(architecture or os.getenv("PROCESSOR_ARCHITECTURE") or "")
4030  if architecture=="x86_64" then
4031   bits,platform=64,"win64"
4032  elseif find(architecture,"amd64") then
4033   bits,platform=64,"win64"
4034  elseif find(architecture,"arm64") then
4035   bits,platform=64,"windows-arm64"
4036  elseif find(architecture,"arm32") then
4037   bits,platform=32,"windows-arm32"
4038  else
4039   bits,platform=32,"mswin"
4040  end
4041 elseif name=="linux" then
4042  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
4043  local musl=find(os.selfdir or "","linuxmusl")
4044  if find(architecture,"x86_64") then
4045   bits,platform=64,musl and "linuxmusl" or "linux-64"
4046  elseif find(architecture,"ppc") then
4047   bits,platform=32,"linux-ppc" 
4048  else
4049   bits,platform=32,musl and "linuxmusl" or "linux"
4050  end
4051 elseif name=="macosx" then
4052  architecture=architecture or resultof("echo $HOSTTYPE") or ""
4053  if architecture=="" then
4054   bits,platform=64,"osx-intel"
4055  elseif find(architecture,"i386") then
4056   bits,platform=64,"osx-intel"
4057  elseif find(architecture,"x86_64") then
4058   bits,platform=64,"osx-64"
4059  elseif find(architecture,"arm64") then
4060   bits,platform=64,"osx-arm"
4061  else
4062   bits,platform=32,"osx-ppc"
4063  end
4064 elseif name=="sunos" then
4065  architecture=architecture or resultof("uname -m") or ""
4066  if find(architecture,"sparc") then
4067   bits,platform=32,"solaris-sparc"
4068  else 
4069   bits,platform=32,"solaris-intel"
4070  end
4071 elseif name=="freebsd" then
4072  architecture=architecture or os.getenv("MACHTYPE") or resultof("uname -m") or ""
4073  if find(architecture,"amd64") or find(architecture,"AMD64") then
4074   bits,platform=64,"freebsd-amd64"
4075  else
4076   bits,platform=32,"freebsd"
4077  end
4078 elseif name=="kfreebsd" then
4079  architecture=architecture or os.getenv("HOSTTYPE") or resultof("uname -m") or ""
4080  if architecture=="x86_64" then
4081   bits,platform=64,"kfreebsd-amd64"
4082  else
4083   bits,platform=32,"kfreebsd-i386"
4084  end
4085 else
4086  architecture=architecture or resultof("uname -m") or ""
4087  if find(architecture,"aarch64") then
4088   bits,platform="linux-aarch64"
4089  elseif find(architecture,"armv7l") then
4090   bits,platform=32,"linux-armhf"
4091  elseif find(architecture,"mips64") or find(architecture,"mips64el") then
4092   bits,platform=64,"linux-mipsel"
4093  elseif find(architecture,"mipsel") or find(architecture,"mips") then
4094   bits,platform=32,"linux-mipsel"
4095  else
4096   bits,platform=64,"linux-64" 
4097  end
4098 end
4099 os.setenv("MTX_PLATFORM",platform)
4100 os.setenv("MTX_BITS",bits)
4101 os.platform=platform
4102 os.bits=bits
4103 os.newline=name=="windows" and "\013\010" or "\010" 
4104end
4105do
4106 local t={ 8,9,"a","b" }
4107 function os.uuid()
4108  return format("%04x%04x-4%03x-%s%03x-%04x-%04x%04x%04x",
4109   random(0xFFFF),random(0xFFFF),
4110   random(0x0FFF),
4111   t[ceil(random(4))] or 8,random(0x0FFF),
4112   random(0xFFFF),
4113   random(0xFFFF),random(0xFFFF),random(0xFFFF)
4114  )
4115 end
4116end
4117do
4118 local hour,min
4119 function os.timezone(difference)
4120  if not hour then
4121   local current=time()
4122   local utcdate=date("!*t",current)
4123   local localdate=date("*t",current)
4124   localdate.isdst=false
4125   local timediff=difftime(time(localdate),time(utcdate))
4126   hour,min=modf(timediff/3600)
4127   min=min*60
4128  end
4129  if difference then
4130   return hour,min
4131  else
4132   return format("%+03d:%02d",hour,min) 
4133  end
4134 end
4135 local timeformat=format("%%s%s",os.timezone())
4136 local dateformat="%Y-%m-%d %H:%M:%S"
4137 local lasttime=nil
4138 local lastdate=nil
4139 function os.fulltime(t,default)
4140  t=t and tonumber(t) or 0
4141  if t>0 then
4142  elseif default then
4143   return default
4144  else
4145   t=time()
4146  end
4147  if t~=lasttime then
4148   lasttime=t
4149   lastdate=format(timeformat,date(dateformat))
4150  end
4151  return lastdate
4152 end
4153 local dateformat="%Y-%m-%d %H:%M:%S"
4154 local lasttime=nil
4155 local lastdate=nil
4156 function os.localtime(t,default)
4157  t=t and tonumber(t) or 0
4158  if t>0 then
4159  elseif default then
4160   return default
4161  else
4162   t=time()
4163  end
4164  if t~=lasttime then
4165   lasttime=t
4166   lastdate=date(dateformat,t)
4167  end
4168  return lastdate
4169 end
4170 function os.converttime(t,default)
4171  local t=tonumber(t)
4172  if t and t>0 then
4173   return date(dateformat,t)
4174  else
4175   return default or "-"
4176  end
4177 end
4178 function os.today()
4179  return date("!*t")
4180 end
4181 function os.now()
4182  return date("!%Y-%m-%d %H:%M:%S")
4183 end
4184end
4185do
4186 local cache={}
4187 local function which(filename)
4188  local fullname=cache[filename]
4189  if fullname==nil then
4190   local suffix=file.suffix(filename)
4191   local suffixes=suffix=="" and os.binsuffixes or { suffix }
4192   for directory in gmatch(os.getenv("PATH"),"[^"..io.pathseparator.."]+") do
4193    local df=file.join(directory,filename)
4194    for i=1,#suffixes do
4195     local dfs=file.addsuffix(df,suffixes[i])
4196     if io.exists(dfs) then
4197      fullname=dfs
4198      break
4199     end
4200    end
4201   end
4202   if not fullname then
4203    fullname=false
4204   end
4205   cache[filename]=fullname
4206  end
4207  return fullname
4208 end
4209 os.which=which
4210 os.where=which
4211end
4212if not os.sleep then
4213 local socket=socket
4214 function os.sleep(n)
4215  if not socket then
4216   socket=require("socket")
4217  end
4218  socket.sleep(n)
4219 end
4220end
4221do
4222 local function isleapyear(year)
4223  return (year%4==0) and (year%100~=0 or year%400==0)
4224 end
4225 os.isleapyear=isleapyear
4226 local days={ 31,28,31,30,31,30,31,31,30,31,30,31 }
4227 local function nofdays(year,month,day)
4228  if not month then
4229   return isleapyear(year) and 365 or 364
4230  elseif not day then
4231   return month==2 and isleapyear(year) and 29 or days[month]
4232  else
4233   for i=1,month-1 do
4234    day=day+days[i]
4235   end
4236   if month>2 and isleapyear(year) then
4237    day=day+1
4238   end
4239   return day
4240  end
4241 end
4242 os.nofdays=nofdays
4243 function os.weekday(day,month,year)
4244  return date("%w",time { year=year,month=month,day=day })+1
4245 end
4246 function os.validdate(year,month,day)
4247  if month<1 then
4248   month=1
4249  elseif month>12 then
4250   month=12
4251  end
4252  if day<1 then
4253   day=1
4254  else
4255   local max=nofdays(year,month)
4256   if day>max then
4257    day=max
4258   end
4259  end
4260  return year,month,day
4261 end
4262 function os.date(fmt,...)
4263  if not fmt then
4264   fmt="%Y-%m-%d %H:%M"
4265  end
4266  return date(fmt,...)
4267 end
4268end
4269do
4270 local osexit=os.exit
4271 local exitcode=nil
4272 function os.setexitcode(code)
4273  exitcode=code
4274 end
4275 function os.exit(c)
4276  if exitcode~=nil then
4277   return osexit(exitcode)
4278  end
4279  if c~=nil then
4280   return osexit(c)
4281  end
4282  return osexit()
4283 end
4284end
4285
4286
4287end -- of closure
4288
4289do -- create closure to overcome 200 locals limit
4290
4291package.loaded["l-file"]