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
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62do
63
64package.loaded["l-bit32"] = package.loaded["l-bit32"] or true
65
66
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
192
193do
194
195package.loaded["l-lua"] = package.loaded["l-lua"] or true
196
197
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
319
320do
321
322package.loaded["l-macro"] = package.loaded["l-macro"] or true
323
324
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
574
575do
576
577package.loaded["l-sandbox"] = package.loaded["l-sandbox"] or true
578
579
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
847
848do
849
850package.loaded["l-package"] = package.loaded["l-package"] or true
851
852
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
1199
1200do
1201
1202package.loaded["l-lpeg"] = package.loaded["l-lpeg"] or true
1203
1204
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
1983
1984do
1985
1986package.loaded["l-function"] = package.loaded["l-function"] or true
1987
1988
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
2002
2003do
2004
2005package.loaded["l-string"] = package.loaded["l-string"] or true
2006
2007
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
2131
2132do
2133
2134package.loaded["l-table"] = package.loaded["l-table"] or true
2135
2136
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
3283
3284do
3285
3286package.loaded["l-io"] = package.loaded["l-io"] or true
3287
3288
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
3638
3639do
3640
3641package.loaded["l-number"] = package.loaded["l-number"] or true
3642
3643
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
3765
3766do
3767
3768package.loaded["l-set"] = package.loaded["l-set"] or true
3769
3770
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
3838
3839do
3840
3841package.loaded["l-os"] = package.loaded["l-os"] or true
3842
3843
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
4288
4289do
4290
4291package.loaded["l-file"] |