diff options
Diffstat (limited to 'tex/context/base/trac-log.lua')
-rw-r--r-- | tex/context/base/trac-log.lua | 1632 |
1 files changed, 816 insertions, 816 deletions
diff --git a/tex/context/base/trac-log.lua b/tex/context/base/trac-log.lua index 1f2520130..73e302e26 100644 --- a/tex/context/base/trac-log.lua +++ b/tex/context/base/trac-log.lua @@ -1,816 +1,816 @@ -if not modules then modules = { } end modules ['trac-log'] = { - version = 1.001, - comment = "companion to trac-log.mkiv", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - --- if tex and (tex.jobname or tex.formatname) then --- --- -- quick hack, awaiting speedup in engine (8 -> 6.4 sec for --make with console2) --- -- still needed for luajittex --- --- local texio_write_nl = texio.write_nl --- local texio_write = texio.write --- local io_write = io.write - --- local write_nl = function(target,...) --- if not io_write then --- io_write = io.write --- end --- if target == "term and log" then --- texio_write_nl("log",...) --- texio_write_nl("term","") --- io_write(...) --- elseif target == "log" then --- texio_write_nl("log",...) --- elseif target == "term" then --- texio_write_nl("term","") --- io_write(...) --- else --- texio_write_nl("log",target,...) --- texio_write_nl("term","") --- io_write(target,...) --- end --- end - --- local write = function(target,...) --- if not io_write then --- io_write = io.write --- end --- if target == "term and log" then --- texio_write("log",...) --- io_write(...) --- elseif target == "log" then --- texio_write("log",...) --- elseif target == "term" then --- io_write(...) --- else --- texio_write("log",target,...) --- io_write(target,...) --- end --- end - --- texio.write = write --- texio.write_nl = write_nl --- --- else --- --- -- texlua or just lua --- --- end - --- todo: less categories, more subcategories (e.g. nodes) --- todo: split into basics and ctx specific - -local write_nl, write = texio and texio.write_nl or print, texio and texio.write or io.write -local format, gmatch, find = string.format, string.gmatch, string.find -local concat, insert, remove = table.concat, table.insert, table.remove -local topattern = string.topattern -local texcount = tex and tex.count -local next, type, select = next, type, select -local utfchar = utf.char - -local setmetatableindex = table.setmetatableindex -local formatters = string.formatters - ---[[ldx-- -<p>This is a prelude to a more extensive logging module. We no longer -provide <l n='xml'/> based logging as parsing is relatively easy anyway.</p> ---ldx]]-- - -logs = logs or { } -local logs = logs - -local moreinfo = [[ -More information about ConTeXt and the tools that come with it can be found at: -]] .. "\n" .. [[ -maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context -webpage : http://www.pragma-ade.nl / http://tex.aanhet.net -wiki : http://contextgarden.net -]] - --- -- we extend the formatters: --- --- function utilities.strings.unichr(s) return "U+" .. format("%05X",s) .. " (" .. utfchar(s) .. ")" end --- function utilities.strings.chruni(s) return utfchar(s) .. " (U+" .. format("%05X",s) .. ")" end --- --- utilities.strings.formatters.add ( --- string.formatters, "uni", --- [[unichr(%s)]], --- [[local unichr = utilities.strings.unichr]] --- ) --- --- utilities.strings.formatters.add ( --- string.formatters, "chr", --- [[chruni(%s)]], --- [[local chruni = utilities.strings.chruni]] --- ) - -utilities.strings.formatters.add ( - formatters, "unichr", - [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]] -) - -utilities.strings.formatters.add ( - formatters, "chruni", - [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]] -) - --- print(formatters["Missing character %!chruni! in font."](234)) --- print(formatters["Missing character %!unichr! in font."](234)) - --- basic loggers - -local function ignore() end - -setmetatableindex(logs, function(t,k) t[k] = ignore ; return ignore end) - -local report, subreport, status, settarget, setformats, settranslations - -local direct, subdirect, writer, pushtarget, poptarget - -if tex and (tex.jobname or tex.formatname) then - - -- local format = string.formatter - - local valueiskey = { __index = function(t,k) t[k] = k return k end } -- will be helper - - local target = "term and log" - - logs.flush = io.flush - - local formats = { } setmetatable(formats, valueiskey) - local translations = { } setmetatable(translations,valueiskey) - - writer = function(...) - write_nl(target,...) - end - - newline = function() - write_nl(target,"\n") - end - - local f_one = formatters["%-15s > %s\n"] - local f_two = formatters["%-15s >\n"] - - -- we can use formatters but best check for % then because for simple messages - -- we con't want this overhead for single messages (not that there are that - -- many; we could have a special weak table) - - report = function(a,b,c,...) - if c then - write_nl(target,f_one(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,f_one(translations[a],formats[b])) - elseif a then - write_nl(target,f_two(translations[a])) - else - write_nl(target,"\n") - end - end - - local f_one = formatters["%-15s > %s"] - local f_two = formatters["%-15s >"] - - direct = function(a,b,c,...) - if c then - return f_one(translations[a],formatters[formats[b]](c,...)) - elseif b then - return f_one(translations[a],formats[b]) - elseif a then - return f_two(translations[a]) - else - return "" - end - end - - local f_one = formatters["%-15s > %s > %s\n"] - local f_two = formatters["%-15s > %s >\n"] - - subreport = function(a,s,b,c,...) - if c then - write_nl(target,f_one(translations[a],translations[s],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,f_one(translations[a],translations[s],formats[b])) - elseif a then - write_nl(target,f_two(translations[a],translations[s])) - else - write_nl(target,"\n") - end - end - - local f_one = formatters["%-15s > %s > %s"] - local f_two = formatters["%-15s > %s >"] - - subdirect = function(a,s,b,c,...) - if c then - return f_one(translations[a],translations[s],formatters[formats[b]](c,...)) - elseif b then - return f_one(translations[a],translations[s],formats[b]) - elseif a then - return f_two(translations[a],translations[s]) - else - return "" - end - end - - local f_one = formatters["%-15s : %s\n"] - local f_two = formatters["%-15s :\n"] - - status = function(a,b,c,...) - if c then - write_nl(target,f_one(translations[a],formatters[formats[b]](c,...))) - elseif b then - write_nl(target,f_one(translations[a],formats[b])) - elseif a then - write_nl(target,f_two(translations[a])) - else - write_nl(target,"\n") - end - end - - local targets = { - logfile = "log", - log = "log", - file = "log", - console = "term", - terminal = "term", - both = "term and log", - } - - settarget = function(whereto) - target = targets[whereto or "both"] or targets.both - if target == "term" or target == "term and log" then - logs.flush = io.flush - else - logs.flush = ignore - end - end - - local stack = { } - - pushtarget = function(newtarget) - insert(stack,target) - settarget(newtarget) - end - - poptarget = function() - if #stack > 0 then - settarget(remove(stack)) - end - end - - setformats = function(f) - formats = f - end - - settranslations = function(t) - translations = t - end - -else - - logs.flush = ignore - - writer = write_nl - - newline = function() - write_nl("\n") - end - - local f_one = formatters["%-15s | %s"] - local f_two = formatters["%-15s |"] - - report = function(a,b,c,...) - if c then - write_nl(f_one(a,formatters[b](c,...))) - elseif b then - write_nl(f_one(a,b)) - elseif a then - write_nl(f_two(a)) - else - write_nl("") - end - end - - local f_one = formatters["%-15s | %s | %s"] - local f_two = formatters["%-15s | %s |"] - - subreport = function(a,sub,b,c,...) - if c then - write_nl(f_one(a,sub,formatters[b](c,...))) - elseif b then - write_nl(f_one(a,sub,b)) - elseif a then - write_nl(f_two(a,sub)) - else - write_nl("") - end - end - - local f_one = formatters["%-15s : %s\n"] - local f_two = formatters["%-15s :\n"] - - status = function(a,b,c,...) -- not to be used in lua anyway - if c then - write_nl(f_one(a,formatters[b](c,...))) - elseif b then - write_nl(f_one(a,b)) -- b can have %'s - elseif a then - write_nl(f_two(a)) - else - write_nl("\n") - end - end - - direct = ignore - subdirect = ignore - - settarget = ignore - pushtarget = ignore - poptarget = ignore - setformats = ignore - settranslations = ignore - -end - -logs.report = report -logs.subreport = subreport -logs.status = status -logs.settarget = settarget -logs.pushtarget = pushtarget -logs.poptarget = poptarget -logs.setformats = setformats -logs.settranslations = settranslations - -logs.direct = direct -logs.subdirect = subdirect -logs.writer = writer -logs.newline = newline - --- installer - --- todo: renew (un) locks when a new one is added and wildcard - -local data, states = { }, nil - -function logs.reporter(category,subcategory) - local logger = data[category] - if not logger then - local state = false - if states == true then - state = true - elseif type(states) == "table" then - for c, _ in next, states do - if find(category,c) then - state = true - break - end - end - end - logger = { - reporters = { }, - state = state, - } - data[category] = logger - end - local reporter = logger.reporters[subcategory or "default"] - if not reporter then - if subcategory then - reporter = function(...) - if not logger.state then - subreport(category,subcategory,...) - end - end - logger.reporters[subcategory] = reporter - else - local tag = category - reporter = function(...) - if not logger.state then - report(category,...) - end - end - logger.reporters.default = reporter - end - end - return reporter -end - -logs.new = logs.reporter -- for old times sake - --- context specicific: this ends up in the macro stream - -local ctxreport = logs.writer - -function logs.setmessenger(m) - ctxreport = m -end - -function logs.messenger(category,subcategory) - -- we need to avoid catcode mess (todo: fast context) - if subcategory then - return function(...) - ctxreport(subdirect(category,subcategory,...)) - end - else - return function(...) - ctxreport(direct(category,...)) - end - end -end - --- so far - -local function setblocked(category,value) - if category == true then - -- lock all - category, value = "*", true - elseif category == false then - -- unlock all - category, value = "*", false - elseif value == nil then - -- lock selective - value = true - end - if category == "*" then - states = value - for k, v in next, data do - v.state = value - end - else - states = utilities.parsers.settings_to_hash(category) - for c, _ in next, states do - if data[c] then - v.state = value - else - c = topattern(c,true,true) - for k, v in next, data do - if find(k,c) then - v.state = value - end - end - end - end - end -end - -function logs.disable(category,value) - setblocked(category,value == nil and true or value) -end - -function logs.enable(category) - setblocked(category,false) -end - -function logs.categories() - return table.sortedkeys(data) -end - -function logs.show() - local n, c, s, max = 0, 0, 0, 0 - for category, v in table.sortedpairs(data) do - n = n + 1 - local state = v.state - local reporters = v.reporters - local nc = #category - if nc > c then - c = nc - end - for subcategory, _ in next, reporters do - local ns = #subcategory - if ns > c then - s = ns - end - local m = nc + ns - if m > max then - max = m - end - end - local subcategories = concat(table.sortedkeys(reporters),", ") - if state == true then - state = "disabled" - elseif state == false then - state = "enabled" - else - state = "unknown" - end - -- no new here - report("logging","category %a, subcategories %a, state %a",category,subcategories,state) - end - report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max) -end - -local delayed_reporters = { } - -setmetatableindex(delayed_reporters,function(t,k) - local v = logs.reporter(k.name) - t[k] = v - return v -end) - -function utilities.setters.report(setter,...) - delayed_reporters[setter](...) -end - -directives.register("logs.blocked", function(v) - setblocked(v,true) -end) - -directives.register("logs.target", function(v) - settarget(v) -end) - --- tex specific loggers (might move elsewhere) - -local report_pages = logs.reporter("pages") -- not needed but saves checking when we grep for it - -local real, user, sub - -function logs.start_page_number() - real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno --- real, user, sub = 0, 0, 0 -end - -local timing = false -local starttime = nil -local lasttime = nil - -trackers.register("pages.timing", function(v) -- only for myself (diagnostics) - starttime = os.clock() - timing = true -end) - -function logs.stop_page_number() -- the first page can includes the initialization so we omit this in average - if timing then - local elapsed, average - local stoptime = os.clock() - if not lasttime or real < 2 then - elapsed = stoptime - average = stoptime - starttime = stoptime - else - elapsed = stoptime - lasttime - average = (stoptime - starttime) / (real - 1) - end - lasttime = stoptime - if real <= 0 then - report_pages("flushing page, time %0.04f / %0.04f",elapsed,average) - elseif user <= 0 then - report_pages("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average) - elseif sub <= 0 then - report_pages("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average) - else - report_pages("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average) - end - else - if real <= 0 then - report_pages("flushing page") - elseif user <= 0 then - report_pages("flushing realpage %s",real) - elseif sub <= 0 then - report_pages("flushing realpage %s, userpage %s",real,user) - else - report_pages("flushing realpage %s, userpage %s, subpage %s",real,user,sub) - end - end - logs.flush() -end - --- we don't have show_open and show_close callbacks yet - -local report_files = logs.reporter("files") -local nesting = 0 -local verbose = false -local hasscheme = url.hasscheme - -function logs.show_open(name) - -- if hasscheme(name) ~= "virtual" then - -- if verbose then - -- nesting = nesting + 1 - -- report_files("level %s, opening %s",nesting,name) - -- else - -- write(formatters["(%s"](name)) -- tex adds a space - -- end - -- end -end - -function logs.show_close(name) - -- if hasscheme(name) ~= "virtual" then - -- if verbose then - -- report_files("level %s, closing %s",nesting,name) - -- nesting = nesting - 1 - -- else - -- write(")") -- tex adds a space - -- end - -- end -end - -function logs.show_load(name) - -- if hasscheme(name) ~= "virtual" then - -- if verbose then - -- report_files("level %s, loading %s",nesting+1,name) - -- else - -- write(formatters["(%s)"](name)) - -- end - -- end -end - --- there may be scripts out there using this: - -local simple = logs.reporter("comment") - -logs.simple = simple -logs.simpleline = simple - --- obsolete - -function logs.setprogram () end -- obsolete -function logs.extendbanner() end -- obsolete -function logs.reportlines () end -- obsolete -function logs.reportbanner() end -- obsolete -function logs.reportline () end -- obsolete -function logs.simplelines () end -- obsolete -function logs.help () end -- obsolete - --- applications - --- local function reportlines(t,str) --- if str then --- for line in gmatch(str,"([^\n\r]*)[\n\r]") do --- t.report(line) --- end --- end --- end - -local Carg, C, lpegmatch = lpeg.Carg, lpeg.C, lpeg.match -local p_newline = lpeg.patterns.newline - -local linewise = ( - Carg(1) * C((1-p_newline)^1) / function(t,s) t.report(s) end - + Carg(1) * p_newline^2 / function(t) t.report() end - + p_newline -)^1 - -local function reportlines(t,str) - if str then - lpegmatch(linewise,str,1,t) - end -end - -local function reportbanner(t) - local banner = t.banner - if banner then - t.report(banner) - t.report() - end -end - -local function reportversion(t) - local banner = t.banner - if banner then - t.report(banner) - end -end - -local function reporthelp(t,...) - local helpinfo = t.helpinfo - if type(helpinfo) == "string" then - reportlines(t,helpinfo) - elseif type(helpinfo) == "table" then - for i=1,select("#",...) do - reportlines(t,t.helpinfo[select(i,...)]) - if i < n then - t.report() - end - end - end -end - -local function reportinfo(t) - t.report() - reportlines(t,t.moreinfo) -end - -local function reportexport(t,method) - report(t.helpinfo) -end - -local reporters = { - lines = reportlines, -- not to be overloaded - banner = reportbanner, - version = reportversion, - help = reporthelp, - info = reportinfo, - export = reportexport, -} - -local exporters = { - -- empty -} - -logs.reporters = reporters -logs.exporters = exporters - -function logs.application(t) - t.name = t.name or "unknown" - t.banner = t.banner - t.moreinfo = moreinfo - t.report = logs.reporter(t.name) - t.help = function(...) - reporters.banner(t) - reporters.help(t,...) - reporters.info(t) - end - t.export = function(...) - reporters.export(t,...) - end - t.identify = function() - reporters.banner(t) - end - t.version = function() - reporters.version(t) - end - return t -end - --- somewhat special .. will be redone (already a better solution in place in lmx) - --- logging to a file - --- local syslogname = "oeps.xxx" --- --- for i=1,10 do --- logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123") --- end - -function logs.system(whereto,process,jobname,category,...) - local message = formatters["%s %s => %s => %s => %s\r"](os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...)) - for i=1,10 do - local f = io.open(whereto,"a") -- we can consider keeping the file open - if f then - f:write(message) - f:close() - break - else - sleep(0.1) - end - end -end - -local report_system = logs.reporter("system","logs") - -function logs.obsolete(old,new) - local o = loadstring("return " .. new)() - if type(o) == "function" then - return function(...) - report_system("function %a is obsolete, use %a",old,new) - loadstring(old .. "=" .. new .. " return ".. old)()(...) - end - elseif type(o) == "table" then - local t, m = { }, { } - m.__index = function(t,k) - report_system("table %a is obsolete, use %a",old,new) - m.__index, m.__newindex = o, o - return o[k] - end - m.__newindex = function(t,k,v) - report_system("table %a is obsolete, use %a",old,new) - m.__index, m.__newindex = o, o - o[k] = v - end - if libraries then - libraries.obsolete[old] = t -- true - end - setmetatable(t,m) - return t - end -end - -if utilities then - utilities.report = report_system -end - -if tex and tex.error then - function logs.texerrormessage(...) -- for the moment we put this function here - tex.error(format(...), { }) - end -else - function logs.texerrormessage(...) - print(format(...)) - end -end - --- this is somewhat slower but prevents out-of-order messages when print is mixed --- with texio.write - -io.stdout:setvbuf('no') -io.stderr:setvbuf('no') - --- windows: > nul 2>&1 --- unix : > null 2>&1 - -if package.helpers.report then - package.helpers.report = logs.reporter("package loader") -- when used outside mtxrun -end +if not modules then modules = { } end modules ['trac-log'] = {
+ version = 1.001,
+ comment = "companion to trac-log.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- if tex and (tex.jobname or tex.formatname) then
+--
+-- -- quick hack, awaiting speedup in engine (8 -> 6.4 sec for --make with console2)
+-- -- still needed for luajittex
+--
+-- local texio_write_nl = texio.write_nl
+-- local texio_write = texio.write
+-- local io_write = io.write
+
+-- local write_nl = function(target,...)
+-- if not io_write then
+-- io_write = io.write
+-- end
+-- if target == "term and log" then
+-- texio_write_nl("log",...)
+-- texio_write_nl("term","")
+-- io_write(...)
+-- elseif target == "log" then
+-- texio_write_nl("log",...)
+-- elseif target == "term" then
+-- texio_write_nl("term","")
+-- io_write(...)
+-- else
+-- texio_write_nl("log",target,...)
+-- texio_write_nl("term","")
+-- io_write(target,...)
+-- end
+-- end
+
+-- local write = function(target,...)
+-- if not io_write then
+-- io_write = io.write
+-- end
+-- if target == "term and log" then
+-- texio_write("log",...)
+-- io_write(...)
+-- elseif target == "log" then
+-- texio_write("log",...)
+-- elseif target == "term" then
+-- io_write(...)
+-- else
+-- texio_write("log",target,...)
+-- io_write(target,...)
+-- end
+-- end
+
+-- texio.write = write
+-- texio.write_nl = write_nl
+--
+-- else
+--
+-- -- texlua or just lua
+--
+-- end
+
+-- todo: less categories, more subcategories (e.g. nodes)
+-- todo: split into basics and ctx specific
+
+local write_nl, write = texio and texio.write_nl or print, texio and texio.write or io.write
+local format, gmatch, find = string.format, string.gmatch, string.find
+local concat, insert, remove = table.concat, table.insert, table.remove
+local topattern = string.topattern
+local texcount = tex and tex.count
+local next, type, select = next, type, select
+local utfchar = utf.char
+
+local setmetatableindex = table.setmetatableindex
+local formatters = string.formatters
+
+--[[ldx--
+<p>This is a prelude to a more extensive logging module. We no longer
+provide <l n='xml'/> based logging as parsing is relatively easy anyway.</p>
+--ldx]]--
+
+logs = logs or { }
+local logs = logs
+
+local moreinfo = [[
+More information about ConTeXt and the tools that come with it can be found at:
+]] .. "\n" .. [[
+maillist : ntg-context@ntg.nl / http://www.ntg.nl/mailman/listinfo/ntg-context
+webpage : http://www.pragma-ade.nl / http://tex.aanhet.net
+wiki : http://contextgarden.net
+]]
+
+-- -- we extend the formatters:
+--
+-- function utilities.strings.unichr(s) return "U+" .. format("%05X",s) .. " (" .. utfchar(s) .. ")" end
+-- function utilities.strings.chruni(s) return utfchar(s) .. " (U+" .. format("%05X",s) .. ")" end
+--
+-- utilities.strings.formatters.add (
+-- string.formatters, "uni",
+-- [[unichr(%s)]],
+-- [[local unichr = utilities.strings.unichr]]
+-- )
+--
+-- utilities.strings.formatters.add (
+-- string.formatters, "chr",
+-- [[chruni(%s)]],
+-- [[local chruni = utilities.strings.chruni]]
+-- )
+
+utilities.strings.formatters.add (
+ formatters, "unichr",
+ [["U+" .. format("%%05X",%s) .. " (" .. utfchar(%s) .. ")"]]
+)
+
+utilities.strings.formatters.add (
+ formatters, "chruni",
+ [[utfchar(%s) .. " (U+" .. format("%%05X",%s) .. ")"]]
+)
+
+-- print(formatters["Missing character %!chruni! in font."](234))
+-- print(formatters["Missing character %!unichr! in font."](234))
+
+-- basic loggers
+
+local function ignore() end
+
+setmetatableindex(logs, function(t,k) t[k] = ignore ; return ignore end)
+
+local report, subreport, status, settarget, setformats, settranslations
+
+local direct, subdirect, writer, pushtarget, poptarget
+
+if tex and (tex.jobname or tex.formatname) then
+
+ -- local format = string.formatter
+
+ local valueiskey = { __index = function(t,k) t[k] = k return k end } -- will be helper
+
+ local target = "term and log"
+
+ logs.flush = io.flush
+
+ local formats = { } setmetatable(formats, valueiskey)
+ local translations = { } setmetatable(translations,valueiskey)
+
+ writer = function(...)
+ write_nl(target,...)
+ end
+
+ newline = function()
+ write_nl(target,"\n")
+ end
+
+ local f_one = formatters["%-15s > %s\n"]
+ local f_two = formatters["%-15s >\n"]
+
+ -- we can use formatters but best check for % then because for simple messages
+ -- we con't want this overhead for single messages (not that there are that
+ -- many; we could have a special weak table)
+
+ report = function(a,b,c,...)
+ if c then
+ write_nl(target,f_one(translations[a],formatters[formats[b]](c,...)))
+ elseif b then
+ write_nl(target,f_one(translations[a],formats[b]))
+ elseif a then
+ write_nl(target,f_two(translations[a]))
+ else
+ write_nl(target,"\n")
+ end
+ end
+
+ local f_one = formatters["%-15s > %s"]
+ local f_two = formatters["%-15s >"]
+
+ direct = function(a,b,c,...)
+ if c then
+ return f_one(translations[a],formatters[formats[b]](c,...))
+ elseif b then
+ return f_one(translations[a],formats[b])
+ elseif a then
+ return f_two(translations[a])
+ else
+ return ""
+ end
+ end
+
+ local f_one = formatters["%-15s > %s > %s\n"]
+ local f_two = formatters["%-15s > %s >\n"]
+
+ subreport = function(a,s,b,c,...)
+ if c then
+ write_nl(target,f_one(translations[a],translations[s],formatters[formats[b]](c,...)))
+ elseif b then
+ write_nl(target,f_one(translations[a],translations[s],formats[b]))
+ elseif a then
+ write_nl(target,f_two(translations[a],translations[s]))
+ else
+ write_nl(target,"\n")
+ end
+ end
+
+ local f_one = formatters["%-15s > %s > %s"]
+ local f_two = formatters["%-15s > %s >"]
+
+ subdirect = function(a,s,b,c,...)
+ if c then
+ return f_one(translations[a],translations[s],formatters[formats[b]](c,...))
+ elseif b then
+ return f_one(translations[a],translations[s],formats[b])
+ elseif a then
+ return f_two(translations[a],translations[s])
+ else
+ return ""
+ end
+ end
+
+ local f_one = formatters["%-15s : %s\n"]
+ local f_two = formatters["%-15s :\n"]
+
+ status = function(a,b,c,...)
+ if c then
+ write_nl(target,f_one(translations[a],formatters[formats[b]](c,...)))
+ elseif b then
+ write_nl(target,f_one(translations[a],formats[b]))
+ elseif a then
+ write_nl(target,f_two(translations[a]))
+ else
+ write_nl(target,"\n")
+ end
+ end
+
+ local targets = {
+ logfile = "log",
+ log = "log",
+ file = "log",
+ console = "term",
+ terminal = "term",
+ both = "term and log",
+ }
+
+ settarget = function(whereto)
+ target = targets[whereto or "both"] or targets.both
+ if target == "term" or target == "term and log" then
+ logs.flush = io.flush
+ else
+ logs.flush = ignore
+ end
+ end
+
+ local stack = { }
+
+ pushtarget = function(newtarget)
+ insert(stack,target)
+ settarget(newtarget)
+ end
+
+ poptarget = function()
+ if #stack > 0 then
+ settarget(remove(stack))
+ end
+ end
+
+ setformats = function(f)
+ formats = f
+ end
+
+ settranslations = function(t)
+ translations = t
+ end
+
+else
+
+ logs.flush = ignore
+
+ writer = write_nl
+
+ newline = function()
+ write_nl("\n")
+ end
+
+ local f_one = formatters["%-15s | %s"]
+ local f_two = formatters["%-15s |"]
+
+ report = function(a,b,c,...)
+ if c then
+ write_nl(f_one(a,formatters[b](c,...)))
+ elseif b then
+ write_nl(f_one(a,b))
+ elseif a then
+ write_nl(f_two(a))
+ else
+ write_nl("")
+ end
+ end
+
+ local f_one = formatters["%-15s | %s | %s"]
+ local f_two = formatters["%-15s | %s |"]
+
+ subreport = function(a,sub,b,c,...)
+ if c then
+ write_nl(f_one(a,sub,formatters[b](c,...)))
+ elseif b then
+ write_nl(f_one(a,sub,b))
+ elseif a then
+ write_nl(f_two(a,sub))
+ else
+ write_nl("")
+ end
+ end
+
+ local f_one = formatters["%-15s : %s\n"]
+ local f_two = formatters["%-15s :\n"]
+
+ status = function(a,b,c,...) -- not to be used in lua anyway
+ if c then
+ write_nl(f_one(a,formatters[b](c,...)))
+ elseif b then
+ write_nl(f_one(a,b)) -- b can have %'s
+ elseif a then
+ write_nl(f_two(a))
+ else
+ write_nl("\n")
+ end
+ end
+
+ direct = ignore
+ subdirect = ignore
+
+ settarget = ignore
+ pushtarget = ignore
+ poptarget = ignore
+ setformats = ignore
+ settranslations = ignore
+
+end
+
+logs.report = report
+logs.subreport = subreport
+logs.status = status
+logs.settarget = settarget
+logs.pushtarget = pushtarget
+logs.poptarget = poptarget
+logs.setformats = setformats
+logs.settranslations = settranslations
+
+logs.direct = direct
+logs.subdirect = subdirect
+logs.writer = writer
+logs.newline = newline
+
+-- installer
+
+-- todo: renew (un) locks when a new one is added and wildcard
+
+local data, states = { }, nil
+
+function logs.reporter(category,subcategory)
+ local logger = data[category]
+ if not logger then
+ local state = false
+ if states == true then
+ state = true
+ elseif type(states) == "table" then
+ for c, _ in next, states do
+ if find(category,c) then
+ state = true
+ break
+ end
+ end
+ end
+ logger = {
+ reporters = { },
+ state = state,
+ }
+ data[category] = logger
+ end
+ local reporter = logger.reporters[subcategory or "default"]
+ if not reporter then
+ if subcategory then
+ reporter = function(...)
+ if not logger.state then
+ subreport(category,subcategory,...)
+ end
+ end
+ logger.reporters[subcategory] = reporter
+ else
+ local tag = category
+ reporter = function(...)
+ if not logger.state then
+ report(category,...)
+ end
+ end
+ logger.reporters.default = reporter
+ end
+ end
+ return reporter
+end
+
+logs.new = logs.reporter -- for old times sake
+
+-- context specicific: this ends up in the macro stream
+
+local ctxreport = logs.writer
+
+function logs.setmessenger(m)
+ ctxreport = m
+end
+
+function logs.messenger(category,subcategory)
+ -- we need to avoid catcode mess (todo: fast context)
+ if subcategory then
+ return function(...)
+ ctxreport(subdirect(category,subcategory,...))
+ end
+ else
+ return function(...)
+ ctxreport(direct(category,...))
+ end
+ end
+end
+
+-- so far
+
+local function setblocked(category,value)
+ if category == true then
+ -- lock all
+ category, value = "*", true
+ elseif category == false then
+ -- unlock all
+ category, value = "*", false
+ elseif value == nil then
+ -- lock selective
+ value = true
+ end
+ if category == "*" then
+ states = value
+ for k, v in next, data do
+ v.state = value
+ end
+ else
+ states = utilities.parsers.settings_to_hash(category)
+ for c, _ in next, states do
+ if data[c] then
+ v.state = value
+ else
+ c = topattern(c,true,true)
+ for k, v in next, data do
+ if find(k,c) then
+ v.state = value
+ end
+ end
+ end
+ end
+ end
+end
+
+function logs.disable(category,value)
+ setblocked(category,value == nil and true or value)
+end
+
+function logs.enable(category)
+ setblocked(category,false)
+end
+
+function logs.categories()
+ return table.sortedkeys(data)
+end
+
+function logs.show()
+ local n, c, s, max = 0, 0, 0, 0
+ for category, v in table.sortedpairs(data) do
+ n = n + 1
+ local state = v.state
+ local reporters = v.reporters
+ local nc = #category
+ if nc > c then
+ c = nc
+ end
+ for subcategory, _ in next, reporters do
+ local ns = #subcategory
+ if ns > c then
+ s = ns
+ end
+ local m = nc + ns
+ if m > max then
+ max = m
+ end
+ end
+ local subcategories = concat(table.sortedkeys(reporters),", ")
+ if state == true then
+ state = "disabled"
+ elseif state == false then
+ state = "enabled"
+ else
+ state = "unknown"
+ end
+ -- no new here
+ report("logging","category %a, subcategories %a, state %a",category,subcategories,state)
+ end
+ report("logging","categories: %s, max category: %s, max subcategory: %s, max combined: %s",n,c,s,max)
+end
+
+local delayed_reporters = { }
+
+setmetatableindex(delayed_reporters,function(t,k)
+ local v = logs.reporter(k.name)
+ t[k] = v
+ return v
+end)
+
+function utilities.setters.report(setter,...)
+ delayed_reporters[setter](...)
+end
+
+directives.register("logs.blocked", function(v)
+ setblocked(v,true)
+end)
+
+directives.register("logs.target", function(v)
+ settarget(v)
+end)
+
+-- tex specific loggers (might move elsewhere)
+
+local report_pages = logs.reporter("pages") -- not needed but saves checking when we grep for it
+
+local real, user, sub
+
+function logs.start_page_number()
+ real, user, sub = texcount.realpageno, texcount.userpageno, texcount.subpageno
+-- real, user, sub = 0, 0, 0
+end
+
+local timing = false
+local starttime = nil
+local lasttime = nil
+
+trackers.register("pages.timing", function(v) -- only for myself (diagnostics)
+ starttime = os.clock()
+ timing = true
+end)
+
+function logs.stop_page_number() -- the first page can includes the initialization so we omit this in average
+ if timing then
+ local elapsed, average
+ local stoptime = os.clock()
+ if not lasttime or real < 2 then
+ elapsed = stoptime
+ average = stoptime
+ starttime = stoptime
+ else
+ elapsed = stoptime - lasttime
+ average = (stoptime - starttime) / (real - 1)
+ end
+ lasttime = stoptime
+ if real <= 0 then
+ report_pages("flushing page, time %0.04f / %0.04f",elapsed,average)
+ elseif user <= 0 then
+ report_pages("flushing realpage %s, time %0.04f / %0.04f",real,elapsed,average)
+ elseif sub <= 0 then
+ report_pages("flushing realpage %s, userpage %s, time %0.04f / %0.04f",real,user,elapsed,average)
+ else
+ report_pages("flushing realpage %s, userpage %s, subpage %s, time %0.04f / %0.04f",real,user,sub,elapsed,average)
+ end
+ else
+ if real <= 0 then
+ report_pages("flushing page")
+ elseif user <= 0 then
+ report_pages("flushing realpage %s",real)
+ elseif sub <= 0 then
+ report_pages("flushing realpage %s, userpage %s",real,user)
+ else
+ report_pages("flushing realpage %s, userpage %s, subpage %s",real,user,sub)
+ end
+ end
+ logs.flush()
+end
+
+-- we don't have show_open and show_close callbacks yet
+
+local report_files = logs.reporter("files")
+local nesting = 0
+local verbose = false
+local hasscheme = url.hasscheme
+
+function logs.show_open(name)
+ -- if hasscheme(name) ~= "virtual" then
+ -- if verbose then
+ -- nesting = nesting + 1
+ -- report_files("level %s, opening %s",nesting,name)
+ -- else
+ -- write(formatters["(%s"](name)) -- tex adds a space
+ -- end
+ -- end
+end
+
+function logs.show_close(name)
+ -- if hasscheme(name) ~= "virtual" then
+ -- if verbose then
+ -- report_files("level %s, closing %s",nesting,name)
+ -- nesting = nesting - 1
+ -- else
+ -- write(")") -- tex adds a space
+ -- end
+ -- end
+end
+
+function logs.show_load(name)
+ -- if hasscheme(name) ~= "virtual" then
+ -- if verbose then
+ -- report_files("level %s, loading %s",nesting+1,name)
+ -- else
+ -- write(formatters["(%s)"](name))
+ -- end
+ -- end
+end
+
+-- there may be scripts out there using this:
+
+local simple = logs.reporter("comment")
+
+logs.simple = simple
+logs.simpleline = simple
+
+-- obsolete
+
+function logs.setprogram () end -- obsolete
+function logs.extendbanner() end -- obsolete
+function logs.reportlines () end -- obsolete
+function logs.reportbanner() end -- obsolete
+function logs.reportline () end -- obsolete
+function logs.simplelines () end -- obsolete
+function logs.help () end -- obsolete
+
+-- applications
+
+-- local function reportlines(t,str)
+-- if str then
+-- for line in gmatch(str,"([^\n\r]*)[\n\r]") do
+-- t.report(line)
+-- end
+-- end
+-- end
+
+local Carg, C, lpegmatch = lpeg.Carg, lpeg.C, lpeg.match
+local p_newline = lpeg.patterns.newline
+
+local linewise = (
+ Carg(1) * C((1-p_newline)^1) / function(t,s) t.report(s) end
+ + Carg(1) * p_newline^2 / function(t) t.report() end
+ + p_newline
+)^1
+
+local function reportlines(t,str)
+ if str then
+ lpegmatch(linewise,str,1,t)
+ end
+end
+
+local function reportbanner(t)
+ local banner = t.banner
+ if banner then
+ t.report(banner)
+ t.report()
+ end
+end
+
+local function reportversion(t)
+ local banner = t.banner
+ if banner then
+ t.report(banner)
+ end
+end
+
+local function reporthelp(t,...)
+ local helpinfo = t.helpinfo
+ if type(helpinfo) == "string" then
+ reportlines(t,helpinfo)
+ elseif type(helpinfo) == "table" then
+ for i=1,select("#",...) do
+ reportlines(t,t.helpinfo[select(i,...)])
+ if i < n then
+ t.report()
+ end
+ end
+ end
+end
+
+local function reportinfo(t)
+ t.report()
+ reportlines(t,t.moreinfo)
+end
+
+local function reportexport(t,method)
+ report(t.helpinfo)
+end
+
+local reporters = {
+ lines = reportlines, -- not to be overloaded
+ banner = reportbanner,
+ version = reportversion,
+ help = reporthelp,
+ info = reportinfo,
+ export = reportexport,
+}
+
+local exporters = {
+ -- empty
+}
+
+logs.reporters = reporters
+logs.exporters = exporters
+
+function logs.application(t)
+ t.name = t.name or "unknown"
+ t.banner = t.banner
+ t.moreinfo = moreinfo
+ t.report = logs.reporter(t.name)
+ t.help = function(...)
+ reporters.banner(t)
+ reporters.help(t,...)
+ reporters.info(t)
+ end
+ t.export = function(...)
+ reporters.export(t,...)
+ end
+ t.identify = function()
+ reporters.banner(t)
+ end
+ t.version = function()
+ reporters.version(t)
+ end
+ return t
+end
+
+-- somewhat special .. will be redone (already a better solution in place in lmx)
+
+-- logging to a file
+
+-- local syslogname = "oeps.xxx"
+--
+-- for i=1,10 do
+-- logs.system(syslogname,"context","test","fonts","font %s recached due to newer version (%s)","blabla","123")
+-- end
+
+function logs.system(whereto,process,jobname,category,...)
+ local message = formatters["%s %s => %s => %s => %s\r"](os.date("%d/%m/%y %H:%m:%S"),process,jobname,category,format(...))
+ for i=1,10 do
+ local f = io.open(whereto,"a") -- we can consider keeping the file open
+ if f then
+ f:write(message)
+ f:close()
+ break
+ else
+ sleep(0.1)
+ end
+ end
+end
+
+local report_system = logs.reporter("system","logs")
+
+function logs.obsolete(old,new)
+ local o = loadstring("return " .. new)()
+ if type(o) == "function" then
+ return function(...)
+ report_system("function %a is obsolete, use %a",old,new)
+ loadstring(old .. "=" .. new .. " return ".. old)()(...)
+ end
+ elseif type(o) == "table" then
+ local t, m = { }, { }
+ m.__index = function(t,k)
+ report_system("table %a is obsolete, use %a",old,new)
+ m.__index, m.__newindex = o, o
+ return o[k]
+ end
+ m.__newindex = function(t,k,v)
+ report_system("table %a is obsolete, use %a",old,new)
+ m.__index, m.__newindex = o, o
+ o[k] = v
+ end
+ if libraries then
+ libraries.obsolete[old] = t -- true
+ end
+ setmetatable(t,m)
+ return t
+ end
+end
+
+if utilities then
+ utilities.report = report_system
+end
+
+if tex and tex.error then
+ function logs.texerrormessage(...) -- for the moment we put this function here
+ tex.error(format(...), { })
+ end
+else
+ function logs.texerrormessage(...)
+ print(format(...))
+ end
+end
+
+-- this is somewhat slower but prevents out-of-order messages when print is mixed
+-- with texio.write
+
+io.stdout:setvbuf('no')
+io.stderr:setvbuf('no')
+
+-- windows: > nul 2>&1
+-- unix : > null 2>&1
+
+if package.helpers.report then
+ package.helpers.report = logs.reporter("package loader") -- when used outside mtxrun
+end
|