summaryrefslogtreecommitdiff
path: root/tex/context/base/luat-cbk.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/luat-cbk.lua')
-rw-r--r--tex/context/base/luat-cbk.lua146
1 files changed, 108 insertions, 38 deletions
diff --git a/tex/context/base/luat-cbk.lua b/tex/context/base/luat-cbk.lua
index 8c224ad2c..65319c333 100644
--- a/tex/context/base/luat-cbk.lua
+++ b/tex/context/base/luat-cbk.lua
@@ -6,15 +6,11 @@ if not modules then modules = { } end modules ['luat-cbk'] = {
license = "see context related readme files"
}
-local insert, remove, find, format = table.insert, table.remove, string.find, string.format
+local insert, remove, concat = table.insert, table.remove, table.concat
+local find, format = string.find, string.format
local collectgarbage, type, next = collectgarbage, type, next
local round = math.round
-local sortedhash, tohash = table.sortedhash, table.tohash
-
-local trace_checking = false trackers.register("memory.checking", function(v) trace_checking = v end)
-
-local report_callbacks = logs.reporter("system","callbacks")
-local report_memory = logs.reporter("system","memory")
+local sortedhash, sortedkeys, tohash = table.sortedhash, table.sortedkeys, table.tohash
--[[ldx--
<p>Callbacks are the real asset of <l n='luatex'/>. They permit you to hook
@@ -28,23 +24,61 @@ local callbacks = callbacks
--[[ldx--
<p>When you (temporarily) want to install a callback function, and after a
while wants to revert to the original one, you can use the following two
-functions.</p>
+functions. This only works for non-frozen ones.</p>
--ldx]]--
-local trace_callbacks = false trackers.register("system.callbacks", function(v) trace_callbacks = v end)
-local trace_calls = false -- only used when analyzing performance and initializations
+local trace_callbacks = false trackers.register("system.callbacks", function(v) trace_callbacks = v end)
+local trace_calls = false -- only used when analyzing performance and initializations
+local trace_checking = false trackers.register("memory.checking", function(v) trace_checking = v end)
+
+local report_system = logs.reporter("system")
+local report_callbacks = logs.reporter("system","callbacks")
+local report_memory = logs.reporter("system","memory")
local register_callback = callback.register
local find_callback = callback.find
local list_callbacks = callback.list
+local register_usercall = false
+local original_register = register_callback
-local frozen, stack, list = { }, { }, callbacks.list
+local frozen = { }
+local stack = { }
+local list = callbacks.list
+local permit_overloads = false
+local block_overloads = false
+
+--[[ldx--
+<p>By now most callbacks are frozen and most provide a way to plug in your own code. For instance
+all node list handlers provide before/after namespaces and the file handling code can be extended
+by adding schemes and if needed I can add more hooks. So there is no real need to overload a core
+callback function. It might be ok for quick and dirty testing but anyway you're on your own if
+you permanently overload callback functions.</p>
+--ldx]]--
+
+-- This might become a configuration file only option when it gets abused too much.
+
+directives.register("system.callbacks.permitoverloads", function(v)
+ if block_overloads or permit_overloads then
+ -- once bad news, always bad news
+ elseif v then
+ permit_overloads = { }
+ report_system()
+ report_system("The callback system has been brought in an unprotected state. As a result of directly")
+ report_system("setting of callbacks subsystems of ConTeXt can stop working. There is no support for")
+ report_system("bugs resulting from this state. It's better to use the official extension mechanisms.")
+ report_system()
+ end
+end)
+
+sandbox.initializer(function()
+ block_overloads = true
+end)
if not list then -- otherwise counters get reset
list = utilities.storage.allocate(list_callbacks())
- for k, _ in next, list do
+ for k in next, list do
list[k] = 0
end
@@ -56,11 +90,9 @@ local delayed = tohash {
"buildpage_filter",
}
-
if trace_calls then
local functions = { }
- local original = register_callback
register_callback = function(name,func)
if type(func) == "function" then
@@ -73,21 +105,45 @@ if trace_calls then
list[name] = list[name] + 1
return functions[name](...)
end
- return original(name,cnuf)
+ return original_register(name,cnuf)
end
else
- return original(name,func)
+ return original_register(name,func)
end
end
end
+local reported = { }
+
+local function register_usercall(what,name,func)
+ if list[name] then
+ if trace_callbacks or not reported[name] then
+ report_system()
+ report_system("disabling core code by %s user function into callback '%s' (reported only once)",what,name)
+ report_system()
+ reported[name] = true
+ end
+ permit_overloads[name] = true
+ return original_register(name,function(...)
+ if trace_callbacks then
+ report_callbacks("calling user function from '%s'",name)
+ end
+ return func(...)
+ end)
+ else
+ report_callbacks("not %s function into invalid callback '%s'",name)
+ return nil, format("unknown callback '%s'",name)
+ end
+end
+
local function frozen_message(what,name)
- report_callbacks("not %s frozen %a to %a",what,name,frozen[name])
+ report_callbacks("not %s frozen %a",what,name)
end
local function frozen_callback(name)
- return nil, format("callback '%s' is frozen to '%s'",name,frozen[name]) -- no formatter yet
+ frozen_message("registering",name)
+ return nil, format("callback '%s' is frozen",name) -- no formatter yet
end
local function state(name)
@@ -117,25 +173,28 @@ function callbacks.report()
end
function callbacks.freeze(name,freeze)
- freeze = type(freeze) == "string" and freeze
- if find(name,"*",1,true) then
- local pattern = name
- for name, _ in next, list do
- if find(name,pattern) then
- frozen[name] = freeze or frozen[name] or "frozen"
+ if not permit_overloads then
+ freeze = type(freeze) == "string" and freeze
+ if find(name,"*",1,true) then
+ local pattern = name
+ for name, _ in next, list do
+ if find(name,pattern) then
+ frozen[name] = freeze or frozen[name] or "frozen"
+ end
end
+ else
+ frozen[name] = freeze or frozen[name] or "frozen"
end
- else
- frozen[name] = freeze or frozen[name] or "frozen"
end
end
function callbacks.register(name,func,freeze)
if frozen[name] then
- if trace_callbacks then
- frozen_message("registering",name)
+ if permit_overloads then
+ return register_usercall("registering",name,func)
+ else
+ return frozen_callback(name)
end
- return frozen_callback(name)
elseif freeze then
frozen[name] = type(freeze) == "string" and freeze or "registered"
end
@@ -148,36 +207,41 @@ end
function callback.register(name,func) -- original
if not frozen[name] then
return register_callback(name,func)
- elseif trace_callbacks then
- frozen_message("registering",name)
+ elseif permit_overloads then
+ return register_usercall("registering",name,func)
+ else
+ return frozen_callback(name)
end
- return frozen_callback(name)
end
function callbacks.push(name,func)
- if not frozen[name] then
+ if not frozen[name] or permit_overloads then
local sn = stack[name]
if not sn then
sn = { }
stack[name] = sn
end
insert(sn,find_callback(name))
- register_callback(name, func)
- elseif trace_callbacks then
+ if permit_overloads then
+ register_usercall("pushing",name,func)
+ else
+ register_callback(name,func)
+ end
+ else
frozen_message("pushing",name)
end
end
function callbacks.pop(name)
- if not frozen[name] then
+ if not frozen[name] or permit_overloads then
local sn = stack[name]
if not sn or #sn == 0 then
-- some error
- register_callback(name, nil) -- ! really needed
+ register_callback(name,nil) -- ! really needed
else
-- this fails: register_callback(name, remove(stack[name]))
local func = remove(sn)
- register_callback(name, func)
+ register_callback(name,func)
end
end
end
@@ -194,6 +258,12 @@ if trace_calls then
end)
end
+statistics.register("callbacks overloaded by user", function()
+ if permit_overloads then
+ return concat(sortedkeys(permit_overloads)," ")
+ end
+end)
+
-- -- somehow crashes later on
--
-- callbacks.freeze("find_.*_file","finding file")