diff options
Diffstat (limited to 'scripts')
-rw-r--r-- | scripts/context/lua/mtx-context.lua | 101 | ||||
-rw-r--r-- | scripts/context/lua/mtx-server.lua | 36 | ||||
-rw-r--r-- | scripts/context/lua/mtx-update.lua | 4 | ||||
-rw-r--r-- | scripts/context/lua/mtxrun.lua | 218 | ||||
-rw-r--r-- | scripts/context/stubs/mswin/mtxrun.lua | 218 | ||||
-rw-r--r-- | scripts/context/stubs/unix/mtxrun | 218 |
6 files changed, 639 insertions, 156 deletions
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua index 677b580ea..f164aadd4 100644 --- a/scripts/context/lua/mtx-context.lua +++ b/scripts/context/lua/mtx-context.lua @@ -597,7 +597,8 @@ function scripts.context.run(ctxdata,filename) experiments = validstring(environment.experiments), -- gets passed via mtxrun -- result = validstring(resultname), - input = validstring(filename), + input = validstring(getargument("input") or filename), -- alternative input + fulljobname = validstring(filename), files = concat(files,","), ctx = validstring(ctxname), } @@ -609,14 +610,14 @@ function scripts.context.run(ctxdata,filename) end -- local l_flags = { - ["interaction"] = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or nil, - ["synctex"] = a_synctex and 1 or nil, - ["no-parse-first-line"] = true, - -- ["no-mktex"] = true, - -- ["file-line-error-style"] = true, - ["fmt"] = formatfile, - ["lua"] = scriptfile, - ["jobname"] = jobname, + ["interaction"] = (a_batchmode and "batchmode") or (a_nonstopmode and "nonstopmode") or nil, + ["synctex"] = a_synctex and 1 or nil, + ["no-parse-first-line"] = true, + -- ["no-mktex"] = true, + -- ["file-line-error-style"] = true, + ["fmt"] = formatfile, + ["lua"] = scriptfile, + ["jobname"] = jobname, } -- if a_synctex then @@ -853,44 +854,48 @@ function scripts.context.autoctx() scripts.context.run(ctxdata) end -local template = [[ -\starttext - \directMPgraphic{%s}{input "%s"} -\stoptext -]] - -local loaded = false +-- no longer ok as mlib-run misses something: -function scripts.context.metapost() - local filename = environment.files[1] or "" - if not loaded then - dofile(resolvers.findfile("mlib-run.lua")) - loaded = true - commands = commands or { } - commands.writestatus = report -- no longer needed - end - local formatname = getargument("format") or "metafun" - if formatname == "" or type(formatname) == "boolean" then - formatname = "metafun" - end - if getargument("pdf") then - local basename = file.removesuffix(filename) - local resultname = getargument("result") or basename - local jobname = "mtx-context-metapost" - local tempname = file.addsuffix(jobname,"tex") - io.savedata(tempname,format(template,"metafun",filename)) - environment.files[1] = tempname - setargument("result",resultname) - setargument("once",true) - scripts.context.run() - scripts.context.purge_job(jobname,true) - scripts.context.purge_job(resultname,true) - elseif getargument("svg") then - metapost.directrun(formatname,filename,"svg") - else - metapost.directrun(formatname,filename,"mps") - end -end +-- local template = [[ +-- \starttext +-- \directMPgraphic{%s}{input "%s"} +-- \stoptext +-- ]] +-- +-- local loaded = false +-- +-- function scripts.context.metapost() +-- local filename = environment.files[1] or "" +-- if not loaded then +-- dofile(resolvers.findfile("mlib-run.lua")) +-- loaded = true +-- commands = commands or { } +-- commands.writestatus = report -- no longer needed +-- end +-- local formatname = getargument("format") or "metafun" +-- if formatname == "" or type(formatname) == "boolean" then +-- formatname = "metafun" +-- end +-- if getargument("pdf") then +-- local basename = file.removesuffix(filename) +-- local resultname = getargument("result") or basename +-- local jobname = "mtx-context-metapost" +-- local tempname = file.addsuffix(jobname,"tex") +-- io.savedata(tempname,format(template,"metafun",filename)) +-- environment.files[1] = tempname +-- setargument("result",resultname) +-- setargument("once",true) +-- scripts.context.run() +-- scripts.context.purge_job(jobname,true) +-- scripts.context.purge_job(resultname,true) +-- elseif getargument("svg") then +-- metapost.directrun(formatname,filename,"svg") +-- else +-- metapost.directrun(formatname,filename,"mps") +-- end +-- end + +-- -- function scripts.context.version() local name = resolvers.findfile("context.mkiv") @@ -1374,8 +1379,8 @@ elseif getargument("generate") then scripts.context.timed(function() scripts.context.generate() end) elseif getargument("ctx") then scripts.context.timed(scripts.context.ctx) -elseif getargument("mp") or getargument("metapost") then - scripts.context.timed(scripts.context.metapost) +-- elseif getargument("mp") or getargument("metapost") then +-- scripts.context.timed(scripts.context.metapost) elseif getargument("version") then application.identify() scripts.context.version() diff --git a/scripts/context/lua/mtx-server.lua b/scripts/context/lua/mtx-server.lua index a3771ed5a..bb60af091 100644 --- a/scripts/context/lua/mtx-server.lua +++ b/scripts/context/lua/mtx-server.lua @@ -231,6 +231,7 @@ function handlers.lua(client,configuration,filename,suffix,iscontent,hashed) -- end if result then if type(result) == "function" then + report("running script: %s",filename) result = result(configuration,filename,hashed) -- second argument will become query end if result and type(result) == "string" then @@ -301,33 +302,46 @@ function scripts.webserver.run(configuration) report("scripts subpath: %s",configuration.scripts) report("context services: http://localhost:%s/mtx-server-ctx-startup.lua",configuration.port) local server = assert(socket.bind("*", configuration.port)) --- local reading = { server } - while true do -- no multiple clients + local script = configuration.script + while true do -- blocking local start = os.clock() --- local input = socket.select(reading) --- local client = input:accept() local client = server:accept() client:settimeout(configuration.timeout or 60) local request, e = client:receive() --- local request, e = client:receive("*a") -- doesn't work well (so no post) if e then errormessage(client,configuration,404) else local from = client:getpeername() report("request from: %s",tostring(from)) - local fullurl = request:match("GET (.+) HTTP/.*$") or "" -- todo: more clever / post + report("request data: %s",tostring(request)) + +print(">>>>>>>>>>>>>",request) + + local fullurl = string.match(request,"GET (.+) HTTP/.*$") or "" -- todo: more clever / post if fullurl == "" then + report("no url") errormessage(client,configuration,404) else - fullurl = socket.url.unescape(fullurl) + report("requested url: %s",fullurl) + fullurl = socket.url.unescape(fullurl) -- still needed? local hashed = url.hashed(fullurl) local query = url.query(hashed.query) local filename = hashed.path -- hm, not query? --- table.print(hashed) - if filename then + if script then + filename = script + report("forced script: %s",filename) + local suffix = file.suffix(filename) + local action = handlers[suffix] or handlers.generic + if action then + report("performing action: %s",filename) + action(client,configuration,filename,suffix,false,hashed) -- filename and no content + else + errormessage(client,configuration,404) + end + elseif filename then filename = socket.url.unescape(filename) report("requested action: %s",filename) - if filename:find("%.%.") then + if string.find(filename,"%.%.") then filename = nil -- invalid path end if filename == nil or filename == "" or filename == "/" then @@ -358,6 +372,7 @@ if environment.argument("auto") then port = environment.argument("port"), root = environment.argument("root") or file.dirname(path) or ".", scripts = environment.argument("scripts") or file.dirname(path) or ".", + script = environment.argument("script"), } elseif environment.argument("start") then scripts.webserver.run { @@ -365,6 +380,7 @@ elseif environment.argument("start") then root = environment.argument("root") or ".", -- "e:/websites/www.pragma-ade.com", index = environment.argument("index"), scripts = environment.argument("scripts"), + script = environment.argument("script"), } else application.help() diff --git a/scripts/context/lua/mtx-update.lua b/scripts/context/lua/mtx-update.lua index 037de8650..b5f34d615 100644 --- a/scripts/context/lua/mtx-update.lua +++ b/scripts/context/lua/mtx-update.lua @@ -421,9 +421,9 @@ function scripts.update.synchronize() if platform == 'mswin' then bin = gsub(bin,"([a-zA-Z]):/", "/cygdrive/%1/") texroot = gsub(texroot,"([a-zA-Z]):/", "/cygdrive/%1/") - command = format("%s -t %s/texmf-context/scripts/context/lua/%s.lua %s/texmf-mswin/bin/", bin, texroot, script, texroot) + command = format([[%s -t "%s/texmf-context/scripts/context/lua/%s.lua" "%s/texmf-mswin/bin/"]], bin, texroot, script, texroot) else - command = format("%s -tgo --chmod=a+x %s/texmf-context/scripts/context/lua/%s.lua %s/texmf-%s/bin/%s", bin, texroot, script, texroot, platform, script) + command = format([[%s -tgo --chmod=a+x '%s/texmf-context/scripts/context/lua/%s.lua' '%s/texmf-%s/bin/%s']], bin, texroot, script, texroot, platform, script) end report("updating %s for %s: %s", script, platform, command) scripts.update.run(command) diff --git a/scripts/context/lua/mtxrun.lua b/scripts/context/lua/mtxrun.lua index 1eb0f5816..ec6c9c520 100644 --- a/scripts/context/lua/mtxrun.lua +++ b/scripts/context/lua/mtxrun.lua @@ -1145,6 +1145,8 @@ local lpeg = require("lpeg") -- tracing (only used when we encounter a problem in integration of lpeg in luatex) +-- some code will move to unicode and string + local report = texio and texio.write_nl or print -- Watch this: Lua does some juggling with replacement values and although lpeg itself is agnostic of @@ -1207,7 +1209,7 @@ local byte, char, gmatch, format = string.byte, string.char, string.gmatch, stri lpeg.patterns = lpeg.patterns or { } -- so that we can share local patterns = lpeg.patterns -local P, R, S, V, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, V, Ct, C, Cs, Cc, Cp = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Cp local lpegtype, lpegmatch = lpeg.type, lpeg.match local utfcharacters = string.utfcharacters @@ -1427,6 +1429,57 @@ function string.utfsplitlines(str) return lpegmatch(utflinesplitter,str or "") end +local utfcharsplitter_ows = utfbom^-1 * Ct(C(utf8char)^0) +local utfcharsplitter_iws = utfbom^-1 * Ct((whitespace^1 + C(utf8char))^0) + +function string.utfsplit(str,ignorewhitespace) -- new + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end +end + +-- inspect(string.utfsplit("a b c d")) +-- inspect(string.utfsplit("a b c d",true)) + +-- -- alternative 1: 0.77 +-- +-- local utfcharcounter = utfbom^-1 * Cs((utf8char/'!')^0) +-- +-- function string.utflength(str) +-- return #lpegmatch(utfcharcounter,str or "") +-- end +-- +-- -- alternative 2: 1.70 +-- +-- local n = 0 +-- +-- local utfcharcounter = utfbom^-1 * (utf8char/function() n = n + 1 end)^0 -- slow +-- +-- function string.utflength(str) +-- n = 0 +-- lpegmatch(utfcharcounter,str or "") +-- return n +-- end +-- +-- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047) + +local n = 0 + +local utfcharcounter = utfbom^-1 * Cs ( ( + Cp() * (lpeg.patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end + + Cp() * (lpeg.patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end + + Cp() * (lpeg.patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end + + Cp() * (lpeg.patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end +)^0 ) + +function string.utflength(str) + n = 0 + lpegmatch(utfcharcounter,str or "") + return n +end + local cache = { } @@ -1508,33 +1561,43 @@ function lpeg.replacer(one,two) if type(one) == "table" then local no = #one local p - if no > 0 then - for i=1,no do - local o = one[i] - local pp = P(o[1]) / o[2] + if no == 0 then + for k, v in next, one do + local pp = P(k) / v if p then p = p + pp else p = pp end end + return Cs((p + 1)^0) + elseif no == 1 then + local o = one[1] + one, two = P(o[1]), o[2] + return Cs(((1-one)^1 + one/two)^0) else - for k, v in next, one do - local pp = P(k) / v + for i=1,no do + local o = one[i] + local pp = P(o[1]) / o[2] if p then p = p + pp else p = pp end end + return Cs((p + 1)^0) end - return Cs((p + 1)^0) else + one = P(one) two = two or "" - return Cs((P(one)/two + 1)^0) + return Cs(((1-one)^1 + one/two)^0) end end +-- print(lpeg.match(lpeg.replacer("e","a"),"test test")) +-- print(lpeg.match(lpeg.replacer{{"e","a"}},"test test")) +-- print(lpeg.match(lpeg.replacer({ e = "a", t = "x" }),"test test")) + local splitters_f, splitters_s = { }, { } function lpeg.firstofsplit(separator) -- always return value @@ -2446,6 +2509,7 @@ if not modules then modules = { } end modules ['l-os'] = { -- maybe build io.flush in os.execute local os = os +local date = os.date local find, format, gsub, upper, gmatch = string.find, string.format, string.gsub, string.upper, string.gmatch local concat = table.concat local random, ceil = math.random, math.ceil @@ -2775,7 +2839,7 @@ end local d function os.timezone(delta) - d = d or tonumber(tonumber(os.date("%H")-os.date("!%H"))) + d = d or tonumber(tonumber(date("%H")-date("!%H"))) if delta then if d > 0 then return format("+%02i:00",d) @@ -2787,6 +2851,13 @@ function os.timezone(delta) end end +local timeformat = format("%%s%s",os.timezone(true)) +local dateformat = "!%Y-%m-%d %H:%M:%S" + +function os.fulltime(t) + return format(timeformat,date(dateformat,t)) +end + local memory = { } local function which(filename) @@ -3363,9 +3434,10 @@ setmetatable(escapes, { __index = function(t,k) return v end }) -local escaper = Cs((R("09","AZ","az") + P(" ")/"%%20" + S("-./_") + P(1) / escapes)^0) -- space happens most +local escaper = Cs((R("09","AZ","az")^1 + P(" ")/"%%20" + S("-./_")^1 + P(1) / escapes)^0) -- space happens most local unescaper = Cs((escapedchar + 1)^0) +lpegpatterns.urlunescaped = escapedchar lpegpatterns.urlescaper = escaper lpegpatterns.urlunescaper = unescaper @@ -4030,11 +4102,27 @@ if not modules then modules = { } end modules ['l-unicode'] = { if not unicode then - unicode = { utf8 = { } } + unicode = { } + +end + +local unicode = unicode + +utf = utf or unicode.utf8 + +if not utf then + + utf8 = { } + unicode.utf8 = utf8 + utf = utf8 + +end + +if not utf.char then local floor, char = math.floor, string.char - function unicode.utf8.utfchar(n) + function utf.char(n) if n < 0x80 then return char(n) elseif n < 0x800 then @@ -4069,10 +4157,6 @@ if not unicode then end -local unicode = unicode - -utf = utf or unicode.utf8 - local concat = table.concat local utfchar, utfbyte, utfgsub = utf.char, utf.byte, utf.gsub local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -4377,6 +4461,16 @@ function string.validutf(str) end +utf.length = string.utflength +utf.split = string.utfsplit +utf.splitines = string.utfsplitlines +utf.valid = string.validutf + +if not utf.len then + utf.len = utf.length +end + + end -- of closure do -- create closure to overcome 200 locals limit @@ -4433,10 +4527,11 @@ utilities = utilities or {} utilities.tables = utilities.tables or { } local tables = utilities.tables -local format, gmatch, rep = string.format, string.gmatch, string.rep +local format, gmatch, rep, gsub = string.format, string.gmatch, string.rep, string.gsub local concat, insert, remove = table.concat, table.insert, table.remove local setmetatable, getmetatable, tonumber, tostring = setmetatable, getmetatable, tonumber, tostring local type, next, rawset, tonumber = type, next, rawset, tonumber +local lpegmatch = lpeg.match function tables.definetable(target) -- defines undefined tables local composed, t, n = nil, { }, 0 @@ -4590,6 +4685,48 @@ function tables.encapsulate(core,capsule,protect) end end +local function serialize(t,r) -- no mixes + r[#r+1] = "{" + local n = #t + if n > 0 then + for i=1,n do + local v = t[i] + local tv = type(v) + if tv == "table" then + serialize(v,r) + elseif tv == "string" then + r[#r+1] = format("%q,",v) + elseif tv == "number" then + r[#r+1] = format("%s,",v) + elseif tv == "boolean" then + r[#r+1] = format("%s,",tostring(v)) + end + end + else + for k, v in next, t do + local tv = type(v) + if tv == "table" then + r[#r+1] = format("[%q]=",k) + serialize(v,r) + elseif tv == "string" then + r[#r+1] = format("[%q]=%q,",k,v) + elseif tv == "number" then + r[#r+1] = format("[%q]=%s,",k,v) + elseif tv == "boolean" then + r[#r+1] = format("[%q]=%s,",k,tostring(v)) + end + end + end + r[#r+1] = "}" + return r +end + +function table.fastserialize(t,prefix) + return concat(serialize(t,{ prefix })) +end + +-- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7 } }) + end -- of closure @@ -5649,7 +5786,7 @@ if not modules then modules = { } end modules ['trac-inf'] = { local format, lower = string.format, string.lower local clock = os.gettimeofday or os.clock -- should go in environment -local write_nl = texio.write_nl +local write_nl = texio and texio.write_nl or print statistics = statistics or { } local statistics = statistics @@ -7267,9 +7404,6 @@ end local function checkstrip(filename) local modu = modules[file.nameonly(filename)] --- if not modu then --- print(">>>>>>>>>>>>>>>>>>>>>>>>",filename) --- end return modu and modu.dataonly end @@ -7385,7 +7519,7 @@ local utf = unicode.utf8 local concat, remove, insert = table.concat, table.remove, table.insert local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatable, getmetatable, tonumber local format, lower, find, match, gsub = string.format, string.lower, string.find, string.match, string.gsub -local utfchar, utffind, utfgsub = utf.char, utf.find, utf.gsub +local utfchar, utfgsub = utf.char, utf.gsub local lpegmatch = lpeg.match local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs @@ -7638,10 +7772,8 @@ local privates_n = { local function escaped(s) if s == "" then return "" - else -- if utffind(s,privates_u) then + else return (utfgsub(s,".",privates_u)) - -- else - -- return s end end @@ -16141,7 +16273,6 @@ function environment.make_format(name) end function environment.run_format(name,data,more) - -- hm, rather old code here; we can now use the file.whatever functions if name and name ~= "" then local barename = file.removesuffix(name) local fmtname = caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats") @@ -16195,6 +16326,8 @@ local report_template = logs.reporter("template") local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +local replacer + local function replacekey(k,t) local v = t[k] if not v then @@ -16206,7 +16339,8 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - return v + -- return v + return lpegmatch(replacer,v,1,t) -- recursive end end @@ -16219,21 +16353,41 @@ local rightmarker = P("%") / "" local key = leftmarker * (C((1-rightmarker)^1 * Carg(1))/replacekey) * rightmarker local any = P(1) -local replacer = Cs((escape + key + any)^0) + replacer = Cs((escape + key + any)^0) -function templates.replace(str,mapping) - return mapping and lpegmatch(replacer,str,1,mapping) or str +local function replace(str,mapping) + if mapping then + return lpegmatch(replacer,str,1,mapping) or str + else + return str + end end +templates.replace = replace + function templates.load(filename,mapping) local data = io.loaddata(filename) or "" if mapping and next(mapping) then - return templates.replace(data,mapping) + return replace(data,mapping) else return data end end +function templates.resolve(t,mapping) + if not mapping then + mapping = t + end + for k, v in next, t do + t[k] = replace(v,mapping) + end + return t +end + +-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" })) +-- inspect(utilities.templates.resolve({ one = "%two%", two = "two" })) + + end -- of closure -- end library merge diff --git a/scripts/context/stubs/mswin/mtxrun.lua b/scripts/context/stubs/mswin/mtxrun.lua index 1eb0f5816..ec6c9c520 100644 --- a/scripts/context/stubs/mswin/mtxrun.lua +++ b/scripts/context/stubs/mswin/mtxrun.lua @@ -1145,6 +1145,8 @@ local lpeg = require("lpeg") -- tracing (only used when we encounter a problem in integration of lpeg in luatex) +-- some code will move to unicode and string + local report = texio and texio.write_nl or print -- Watch this: Lua does some juggling with replacement values and although lpeg itself is agnostic of @@ -1207,7 +1209,7 @@ local byte, char, gmatch, format = string.byte, string.char, string.gmatch, stri lpeg.patterns = lpeg.patterns or { } -- so that we can share local patterns = lpeg.patterns -local P, R, S, V, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, V, Ct, C, Cs, Cc, Cp = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Cp local lpegtype, lpegmatch = lpeg.type, lpeg.match local utfcharacters = string.utfcharacters @@ -1427,6 +1429,57 @@ function string.utfsplitlines(str) return lpegmatch(utflinesplitter,str or "") end +local utfcharsplitter_ows = utfbom^-1 * Ct(C(utf8char)^0) +local utfcharsplitter_iws = utfbom^-1 * Ct((whitespace^1 + C(utf8char))^0) + +function string.utfsplit(str,ignorewhitespace) -- new + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end +end + +-- inspect(string.utfsplit("a b c d")) +-- inspect(string.utfsplit("a b c d",true)) + +-- -- alternative 1: 0.77 +-- +-- local utfcharcounter = utfbom^-1 * Cs((utf8char/'!')^0) +-- +-- function string.utflength(str) +-- return #lpegmatch(utfcharcounter,str or "") +-- end +-- +-- -- alternative 2: 1.70 +-- +-- local n = 0 +-- +-- local utfcharcounter = utfbom^-1 * (utf8char/function() n = n + 1 end)^0 -- slow +-- +-- function string.utflength(str) +-- n = 0 +-- lpegmatch(utfcharcounter,str or "") +-- return n +-- end +-- +-- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047) + +local n = 0 + +local utfcharcounter = utfbom^-1 * Cs ( ( + Cp() * (lpeg.patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end + + Cp() * (lpeg.patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end + + Cp() * (lpeg.patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end + + Cp() * (lpeg.patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end +)^0 ) + +function string.utflength(str) + n = 0 + lpegmatch(utfcharcounter,str or "") + return n +end + local cache = { } @@ -1508,33 +1561,43 @@ function lpeg.replacer(one,two) if type(one) == "table" then local no = #one local p - if no > 0 then - for i=1,no do - local o = one[i] - local pp = P(o[1]) / o[2] + if no == 0 then + for k, v in next, one do + local pp = P(k) / v if p then p = p + pp else p = pp end end + return Cs((p + 1)^0) + elseif no == 1 then + local o = one[1] + one, two = P(o[1]), o[2] + return Cs(((1-one)^1 + one/two)^0) else - for k, v in next, one do - local pp = P(k) / v + for i=1,no do + local o = one[i] + local pp = P(o[1]) / o[2] if p then p = p + pp else p = pp end end + return Cs((p + 1)^0) end - return Cs((p + 1)^0) else + one = P(one) two = two or "" - return Cs((P(one)/two + 1)^0) + return Cs(((1-one)^1 + one/two)^0) end end +-- print(lpeg.match(lpeg.replacer("e","a"),"test test")) +-- print(lpeg.match(lpeg.replacer{{"e","a"}},"test test")) +-- print(lpeg.match(lpeg.replacer({ e = "a", t = "x" }),"test test")) + local splitters_f, splitters_s = { }, { } function lpeg.firstofsplit(separator) -- always return value @@ -2446,6 +2509,7 @@ if not modules then modules = { } end modules ['l-os'] = { -- maybe build io.flush in os.execute local os = os +local date = os.date local find, format, gsub, upper, gmatch = string.find, string.format, string.gsub, string.upper, string.gmatch local concat = table.concat local random, ceil = math.random, math.ceil @@ -2775,7 +2839,7 @@ end local d function os.timezone(delta) - d = d or tonumber(tonumber(os.date("%H")-os.date("!%H"))) + d = d or tonumber(tonumber(date("%H")-date("!%H"))) if delta then if d > 0 then return format("+%02i:00",d) @@ -2787,6 +2851,13 @@ function os.timezone(delta) end end +local timeformat = format("%%s%s",os.timezone(true)) +local dateformat = "!%Y-%m-%d %H:%M:%S" + +function os.fulltime(t) + return format(timeformat,date(dateformat,t)) +end + local memory = { } local function which(filename) @@ -3363,9 +3434,10 @@ setmetatable(escapes, { __index = function(t,k) return v end }) -local escaper = Cs((R("09","AZ","az") + P(" ")/"%%20" + S("-./_") + P(1) / escapes)^0) -- space happens most +local escaper = Cs((R("09","AZ","az")^1 + P(" ")/"%%20" + S("-./_")^1 + P(1) / escapes)^0) -- space happens most local unescaper = Cs((escapedchar + 1)^0) +lpegpatterns.urlunescaped = escapedchar lpegpatterns.urlescaper = escaper lpegpatterns.urlunescaper = unescaper @@ -4030,11 +4102,27 @@ if not modules then modules = { } end modules ['l-unicode'] = { if not unicode then - unicode = { utf8 = { } } + unicode = { } + +end + +local unicode = unicode + +utf = utf or unicode.utf8 + +if not utf then + + utf8 = { } + unicode.utf8 = utf8 + utf = utf8 + +end + +if not utf.char then local floor, char = math.floor, string.char - function unicode.utf8.utfchar(n) + function utf.char(n) if n < 0x80 then return char(n) elseif n < 0x800 then @@ -4069,10 +4157,6 @@ if not unicode then end -local unicode = unicode - -utf = utf or unicode.utf8 - local concat = table.concat local utfchar, utfbyte, utfgsub = utf.char, utf.byte, utf.gsub local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -4377,6 +4461,16 @@ function string.validutf(str) end +utf.length = string.utflength +utf.split = string.utfsplit +utf.splitines = string.utfsplitlines +utf.valid = string.validutf + +if not utf.len then + utf.len = utf.length +end + + end -- of closure do -- create closure to overcome 200 locals limit @@ -4433,10 +4527,11 @@ utilities = utilities or {} utilities.tables = utilities.tables or { } local tables = utilities.tables -local format, gmatch, rep = string.format, string.gmatch, string.rep +local format, gmatch, rep, gsub = string.format, string.gmatch, string.rep, string.gsub local concat, insert, remove = table.concat, table.insert, table.remove local setmetatable, getmetatable, tonumber, tostring = setmetatable, getmetatable, tonumber, tostring local type, next, rawset, tonumber = type, next, rawset, tonumber +local lpegmatch = lpeg.match function tables.definetable(target) -- defines undefined tables local composed, t, n = nil, { }, 0 @@ -4590,6 +4685,48 @@ function tables.encapsulate(core,capsule,protect) end end +local function serialize(t,r) -- no mixes + r[#r+1] = "{" + local n = #t + if n > 0 then + for i=1,n do + local v = t[i] + local tv = type(v) + if tv == "table" then + serialize(v,r) + elseif tv == "string" then + r[#r+1] = format("%q,",v) + elseif tv == "number" then + r[#r+1] = format("%s,",v) + elseif tv == "boolean" then + r[#r+1] = format("%s,",tostring(v)) + end + end + else + for k, v in next, t do + local tv = type(v) + if tv == "table" then + r[#r+1] = format("[%q]=",k) + serialize(v,r) + elseif tv == "string" then + r[#r+1] = format("[%q]=%q,",k,v) + elseif tv == "number" then + r[#r+1] = format("[%q]=%s,",k,v) + elseif tv == "boolean" then + r[#r+1] = format("[%q]=%s,",k,tostring(v)) + end + end + end + r[#r+1] = "}" + return r +end + +function table.fastserialize(t,prefix) + return concat(serialize(t,{ prefix })) +end + +-- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7 } }) + end -- of closure @@ -5649,7 +5786,7 @@ if not modules then modules = { } end modules ['trac-inf'] = { local format, lower = string.format, string.lower local clock = os.gettimeofday or os.clock -- should go in environment -local write_nl = texio.write_nl +local write_nl = texio and texio.write_nl or print statistics = statistics or { } local statistics = statistics @@ -7267,9 +7404,6 @@ end local function checkstrip(filename) local modu = modules[file.nameonly(filename)] --- if not modu then --- print(">>>>>>>>>>>>>>>>>>>>>>>>",filename) --- end return modu and modu.dataonly end @@ -7385,7 +7519,7 @@ local utf = unicode.utf8 local concat, remove, insert = table.concat, table.remove, table.insert local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatable, getmetatable, tonumber local format, lower, find, match, gsub = string.format, string.lower, string.find, string.match, string.gsub -local utfchar, utffind, utfgsub = utf.char, utf.find, utf.gsub +local utfchar, utfgsub = utf.char, utf.gsub local lpegmatch = lpeg.match local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs @@ -7638,10 +7772,8 @@ local privates_n = { local function escaped(s) if s == "" then return "" - else -- if utffind(s,privates_u) then + else return (utfgsub(s,".",privates_u)) - -- else - -- return s end end @@ -16141,7 +16273,6 @@ function environment.make_format(name) end function environment.run_format(name,data,more) - -- hm, rather old code here; we can now use the file.whatever functions if name and name ~= "" then local barename = file.removesuffix(name) local fmtname = caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats") @@ -16195,6 +16326,8 @@ local report_template = logs.reporter("template") local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +local replacer + local function replacekey(k,t) local v = t[k] if not v then @@ -16206,7 +16339,8 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - return v + -- return v + return lpegmatch(replacer,v,1,t) -- recursive end end @@ -16219,21 +16353,41 @@ local rightmarker = P("%") / "" local key = leftmarker * (C((1-rightmarker)^1 * Carg(1))/replacekey) * rightmarker local any = P(1) -local replacer = Cs((escape + key + any)^0) + replacer = Cs((escape + key + any)^0) -function templates.replace(str,mapping) - return mapping and lpegmatch(replacer,str,1,mapping) or str +local function replace(str,mapping) + if mapping then + return lpegmatch(replacer,str,1,mapping) or str + else + return str + end end +templates.replace = replace + function templates.load(filename,mapping) local data = io.loaddata(filename) or "" if mapping and next(mapping) then - return templates.replace(data,mapping) + return replace(data,mapping) else return data end end +function templates.resolve(t,mapping) + if not mapping then + mapping = t + end + for k, v in next, t do + t[k] = replace(v,mapping) + end + return t +end + +-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" })) +-- inspect(utilities.templates.resolve({ one = "%two%", two = "two" })) + + end -- of closure -- end library merge diff --git a/scripts/context/stubs/unix/mtxrun b/scripts/context/stubs/unix/mtxrun index 1eb0f5816..ec6c9c520 100644 --- a/scripts/context/stubs/unix/mtxrun +++ b/scripts/context/stubs/unix/mtxrun @@ -1145,6 +1145,8 @@ local lpeg = require("lpeg") -- tracing (only used when we encounter a problem in integration of lpeg in luatex) +-- some code will move to unicode and string + local report = texio and texio.write_nl or print -- Watch this: Lua does some juggling with replacement values and although lpeg itself is agnostic of @@ -1207,7 +1209,7 @@ local byte, char, gmatch, format = string.byte, string.char, string.gmatch, stri lpeg.patterns = lpeg.patterns or { } -- so that we can share local patterns = lpeg.patterns -local P, R, S, V, Ct, C, Cs, Cc = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc +local P, R, S, V, Ct, C, Cs, Cc, Cp = lpeg.P, lpeg.R, lpeg.S, lpeg.V, lpeg.Ct, lpeg.C, lpeg.Cs, lpeg.Cc, lpeg.Cp local lpegtype, lpegmatch = lpeg.type, lpeg.match local utfcharacters = string.utfcharacters @@ -1427,6 +1429,57 @@ function string.utfsplitlines(str) return lpegmatch(utflinesplitter,str or "") end +local utfcharsplitter_ows = utfbom^-1 * Ct(C(utf8char)^0) +local utfcharsplitter_iws = utfbom^-1 * Ct((whitespace^1 + C(utf8char))^0) + +function string.utfsplit(str,ignorewhitespace) -- new + if ignorewhitespace then + return lpegmatch(utfcharsplitter_iws,str or "") + else + return lpegmatch(utfcharsplitter_ows,str or "") + end +end + +-- inspect(string.utfsplit("a b c d")) +-- inspect(string.utfsplit("a b c d",true)) + +-- -- alternative 1: 0.77 +-- +-- local utfcharcounter = utfbom^-1 * Cs((utf8char/'!')^0) +-- +-- function string.utflength(str) +-- return #lpegmatch(utfcharcounter,str or "") +-- end +-- +-- -- alternative 2: 1.70 +-- +-- local n = 0 +-- +-- local utfcharcounter = utfbom^-1 * (utf8char/function() n = n + 1 end)^0 -- slow +-- +-- function string.utflength(str) +-- n = 0 +-- lpegmatch(utfcharcounter,str or "") +-- return n +-- end +-- +-- -- alternative 3: 0.24 (native unicode.utf8.len: 0.047) + +local n = 0 + +local utfcharcounter = utfbom^-1 * Cs ( ( + Cp() * (lpeg.patterns.utf8one )^1 * Cp() / function(f,t) n = n + t - f end + + Cp() * (lpeg.patterns.utf8two )^1 * Cp() / function(f,t) n = n + (t - f)/2 end + + Cp() * (lpeg.patterns.utf8three)^1 * Cp() / function(f,t) n = n + (t - f)/3 end + + Cp() * (lpeg.patterns.utf8four )^1 * Cp() / function(f,t) n = n + (t - f)/4 end +)^0 ) + +function string.utflength(str) + n = 0 + lpegmatch(utfcharcounter,str or "") + return n +end + local cache = { } @@ -1508,33 +1561,43 @@ function lpeg.replacer(one,two) if type(one) == "table" then local no = #one local p - if no > 0 then - for i=1,no do - local o = one[i] - local pp = P(o[1]) / o[2] + if no == 0 then + for k, v in next, one do + local pp = P(k) / v if p then p = p + pp else p = pp end end + return Cs((p + 1)^0) + elseif no == 1 then + local o = one[1] + one, two = P(o[1]), o[2] + return Cs(((1-one)^1 + one/two)^0) else - for k, v in next, one do - local pp = P(k) / v + for i=1,no do + local o = one[i] + local pp = P(o[1]) / o[2] if p then p = p + pp else p = pp end end + return Cs((p + 1)^0) end - return Cs((p + 1)^0) else + one = P(one) two = two or "" - return Cs((P(one)/two + 1)^0) + return Cs(((1-one)^1 + one/two)^0) end end +-- print(lpeg.match(lpeg.replacer("e","a"),"test test")) +-- print(lpeg.match(lpeg.replacer{{"e","a"}},"test test")) +-- print(lpeg.match(lpeg.replacer({ e = "a", t = "x" }),"test test")) + local splitters_f, splitters_s = { }, { } function lpeg.firstofsplit(separator) -- always return value @@ -2446,6 +2509,7 @@ if not modules then modules = { } end modules ['l-os'] = { -- maybe build io.flush in os.execute local os = os +local date = os.date local find, format, gsub, upper, gmatch = string.find, string.format, string.gsub, string.upper, string.gmatch local concat = table.concat local random, ceil = math.random, math.ceil @@ -2775,7 +2839,7 @@ end local d function os.timezone(delta) - d = d or tonumber(tonumber(os.date("%H")-os.date("!%H"))) + d = d or tonumber(tonumber(date("%H")-date("!%H"))) if delta then if d > 0 then return format("+%02i:00",d) @@ -2787,6 +2851,13 @@ function os.timezone(delta) end end +local timeformat = format("%%s%s",os.timezone(true)) +local dateformat = "!%Y-%m-%d %H:%M:%S" + +function os.fulltime(t) + return format(timeformat,date(dateformat,t)) +end + local memory = { } local function which(filename) @@ -3363,9 +3434,10 @@ setmetatable(escapes, { __index = function(t,k) return v end }) -local escaper = Cs((R("09","AZ","az") + P(" ")/"%%20" + S("-./_") + P(1) / escapes)^0) -- space happens most +local escaper = Cs((R("09","AZ","az")^1 + P(" ")/"%%20" + S("-./_")^1 + P(1) / escapes)^0) -- space happens most local unescaper = Cs((escapedchar + 1)^0) +lpegpatterns.urlunescaped = escapedchar lpegpatterns.urlescaper = escaper lpegpatterns.urlunescaper = unescaper @@ -4030,11 +4102,27 @@ if not modules then modules = { } end modules ['l-unicode'] = { if not unicode then - unicode = { utf8 = { } } + unicode = { } + +end + +local unicode = unicode + +utf = utf or unicode.utf8 + +if not utf then + + utf8 = { } + unicode.utf8 = utf8 + utf = utf8 + +end + +if not utf.char then local floor, char = math.floor, string.char - function unicode.utf8.utfchar(n) + function utf.char(n) if n < 0x80 then return char(n) elseif n < 0x800 then @@ -4069,10 +4157,6 @@ if not unicode then end -local unicode = unicode - -utf = utf or unicode.utf8 - local concat = table.concat local utfchar, utfbyte, utfgsub = utf.char, utf.byte, utf.gsub local char, byte, find, bytepairs, utfvalues, format = string.char, string.byte, string.find, string.bytepairs, string.utfvalues, string.format @@ -4377,6 +4461,16 @@ function string.validutf(str) end +utf.length = string.utflength +utf.split = string.utfsplit +utf.splitines = string.utfsplitlines +utf.valid = string.validutf + +if not utf.len then + utf.len = utf.length +end + + end -- of closure do -- create closure to overcome 200 locals limit @@ -4433,10 +4527,11 @@ utilities = utilities or {} utilities.tables = utilities.tables or { } local tables = utilities.tables -local format, gmatch, rep = string.format, string.gmatch, string.rep +local format, gmatch, rep, gsub = string.format, string.gmatch, string.rep, string.gsub local concat, insert, remove = table.concat, table.insert, table.remove local setmetatable, getmetatable, tonumber, tostring = setmetatable, getmetatable, tonumber, tostring local type, next, rawset, tonumber = type, next, rawset, tonumber +local lpegmatch = lpeg.match function tables.definetable(target) -- defines undefined tables local composed, t, n = nil, { }, 0 @@ -4590,6 +4685,48 @@ function tables.encapsulate(core,capsule,protect) end end +local function serialize(t,r) -- no mixes + r[#r+1] = "{" + local n = #t + if n > 0 then + for i=1,n do + local v = t[i] + local tv = type(v) + if tv == "table" then + serialize(v,r) + elseif tv == "string" then + r[#r+1] = format("%q,",v) + elseif tv == "number" then + r[#r+1] = format("%s,",v) + elseif tv == "boolean" then + r[#r+1] = format("%s,",tostring(v)) + end + end + else + for k, v in next, t do + local tv = type(v) + if tv == "table" then + r[#r+1] = format("[%q]=",k) + serialize(v,r) + elseif tv == "string" then + r[#r+1] = format("[%q]=%q,",k,v) + elseif tv == "number" then + r[#r+1] = format("[%q]=%s,",k,v) + elseif tv == "boolean" then + r[#r+1] = format("[%q]=%s,",k,tostring(v)) + end + end + end + r[#r+1] = "}" + return r +end + +function table.fastserialize(t,prefix) + return concat(serialize(t,{ prefix })) +end + +-- inspect(table.fastserialize { a = 1, b = { 4, { 5, 6 } }, c = { d = 7 } }) + end -- of closure @@ -5649,7 +5786,7 @@ if not modules then modules = { } end modules ['trac-inf'] = { local format, lower = string.format, string.lower local clock = os.gettimeofday or os.clock -- should go in environment -local write_nl = texio.write_nl +local write_nl = texio and texio.write_nl or print statistics = statistics or { } local statistics = statistics @@ -7267,9 +7404,6 @@ end local function checkstrip(filename) local modu = modules[file.nameonly(filename)] --- if not modu then --- print(">>>>>>>>>>>>>>>>>>>>>>>>",filename) --- end return modu and modu.dataonly end @@ -7385,7 +7519,7 @@ local utf = unicode.utf8 local concat, remove, insert = table.concat, table.remove, table.insert local type, next, setmetatable, getmetatable, tonumber = type, next, setmetatable, getmetatable, tonumber local format, lower, find, match, gsub = string.format, string.lower, string.find, string.match, string.gsub -local utfchar, utffind, utfgsub = utf.char, utf.find, utf.gsub +local utfchar, utfgsub = utf.char, utf.gsub local lpegmatch = lpeg.match local P, S, R, C, V, C, Cs = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.C, lpeg.Cs @@ -7638,10 +7772,8 @@ local privates_n = { local function escaped(s) if s == "" then return "" - else -- if utffind(s,privates_u) then + else return (utfgsub(s,".",privates_u)) - -- else - -- return s end end @@ -16141,7 +16273,6 @@ function environment.make_format(name) end function environment.run_format(name,data,more) - -- hm, rather old code here; we can now use the file.whatever functions if name and name ~= "" then local barename = file.removesuffix(name) local fmtname = caches.getfirstreadablefile(file.addsuffix(barename,"fmt"),"formats") @@ -16195,6 +16326,8 @@ local report_template = logs.reporter("template") local P, C, Cs, Carg, lpegmatch = lpeg.P, lpeg.C, lpeg.Cs, lpeg.Carg, lpeg.match +local replacer + local function replacekey(k,t) local v = t[k] if not v then @@ -16206,7 +16339,8 @@ local function replacekey(k,t) if trace_template then report_template("setting key %q to value %q",k,v) end - return v + -- return v + return lpegmatch(replacer,v,1,t) -- recursive end end @@ -16219,21 +16353,41 @@ local rightmarker = P("%") / "" local key = leftmarker * (C((1-rightmarker)^1 * Carg(1))/replacekey) * rightmarker local any = P(1) -local replacer = Cs((escape + key + any)^0) + replacer = Cs((escape + key + any)^0) -function templates.replace(str,mapping) - return mapping and lpegmatch(replacer,str,1,mapping) or str +local function replace(str,mapping) + if mapping then + return lpegmatch(replacer,str,1,mapping) or str + else + return str + end end +templates.replace = replace + function templates.load(filename,mapping) local data = io.loaddata(filename) or "" if mapping and next(mapping) then - return templates.replace(data,mapping) + return replace(data,mapping) else return data end end +function templates.resolve(t,mapping) + if not mapping then + mapping = t + end + for k, v in next, t do + t[k] = replace(v,mapping) + end + return t +end + +-- inspect(utilities.templates.replace("test %one% test", { one = "%two%", two = "two" })) +-- inspect(utilities.templates.resolve({ one = "%two%", two = "two" })) + + end -- of closure -- end library merge |