Q: create a hookfunction in lua - lua

I want do a hookfunction for lua :
For explain i want hook the params and return the params when function called, like this :
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
a = hookfunction(func1, function(...) -- a = old function
local args = { ... }
print("Argument 1 =>", args[1])
print("Argument 2 =>", args[2])
return a(...)
end)
func1(12, 5)
Output :
Argument 1 => 12
Argument 2 => 5
17

There's two different things you can do. You can either create a wrapper just for that function, or you can actually set a debugging hook in the Lua runtime. Here's how you'd create a wrapper:
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
function wrapfunction(a) -- a = old function
return function(...)
local args = { ... }
print("Argument 1 =>", args[1])
print("Argument 2 =>", args[2])
return a(...)
end
end
func1 = wrapfunction(func1)
func1(12, 5)
And here's how you'd set a debugging hook:
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
function hookfunction(event)
if debug.getinfo(2, 'f').func == func1 then
print("Argument 1 =>", select(2, debug.getlocal(2, 1)))
print("Argument 2 =>", select(2, debug.getlocal(2, 2)))
end
end
debug.sethook(hookfunction, 'c')
func1(12, 5)

You can try this
function func1(x, y)
print(tonumber(x) + tonumber(y))
end
oldfunc1 = func1
function func1hook(x, y)
print("Argument x =>", x)
print("Argument y =>", y)
return oldfunc1(x, y)
end
func1 = func1hook
func1(4,4)
I'm not sure it works for C functions but you can try. If you want more universal hookfunction it's also possible.
https://www.lua.org/cgi-bin/demo

Related

map varargs function lua

I want to be able to map functions that take multiple arguments like
function(a, b) return a+b end
onto a table so that I can write stuff like
answer = varmap(function(a, b) return a+b end, {1, 7, 3}, {5, 4, 8}
but I am not comfortable with lua varargs and the code samples on wikibooks use table.getn, and when you replace them with # it doesn't work and returns "attempt to preform arithmatic on local 'a' (a nil value)"
One more possibility:
local unpack = table.unpack or unpack
--------------------------------------------------------------------------------
-- Python-like zip() iterator
--------------------------------------------------------------------------------
function zip(...)
local arrays, ans = {...}, {}
local index = 0
return
function()
index = index + 1
for i,t in ipairs(arrays) do
if type(t) == 'function' then ans[i] = t() else ans[i] = t[index] end
if ans[i] == nil then return end
end
return ans
end
end
--------------------------------------------------------------------------------
function map(f,...)
assert(type(f) == 'function','Function expected for 1st arg')
local t = {...}
return coroutine.wrap(
function()
for t in zip(unpack(t)) do
coroutine.yield(f(unpack(t)))
end
end)
end
--------------------------------------------------------------------------------
-- Example use
for item in map(function(a, b) return a+b end, {1, 7, 3}, {5, 4, 8}) do
print(item)
end
print()
for item in map(function(a) return a*2 end, {1, 7, 3}) do
print(item)
end
local function imap(func, ...) -- imap(func, src_table_1, src_table_2, ...)
local result = {}
local src_tables_arr = {...}
if #src_tables_arr == 1 then
for k, v in ipairs(src_tables_arr[1]) do
result[k] = func(v)
end
else
for k = 1, #src_tables_arr[1] do
result[k] = func(
(table.unpack or unpack)
(
imap(
function(src_t) return src_t[k] end,
src_tables_arr
)
)
)
end
end
return result
end
table.imap = imap
Usage:
local arr = table.imap(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
Perhaps you are looking for something like this:
function varmapn(func, ...)
local args, result = { ... }, {}
for arg_i = 1, #(args[1]) do
local call_args = {}
for arg_list = 1, #args do
table.insert(call_args, args[arg_list][arg_i])
end
table.insert(result, func(table.unpack(call_args)))
end
return result
end
Sample interaction:
> answer = varmapn(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
> print(answer)
table: 0x970eb0
> for i = 1, 3 do print(answer[i]) end
6
11
11
Or, here is a slightly more involved function that is more general. For argument lists it takes arrays, or it takes tables with arbitrary keys:
function mapn(func, ...)
local args, call_args = { ... }, {}
local result = {}
for k in pairs(args[1]) do
call_args[k] = {}
end
for arg_list, v in pairs(args) do
for k in pairs(args[1]) do
table.insert(call_args[k], v[k])
end
end
for k, v in pairs(call_args) do
result[k] = func(table.unpack(v))
end
return result
end
Sample interaction:
> answer = mapn(function (a, b) return a+b end, {x=1, y=7, z=3}, {x=5, y=4, z=8})
> for k,v in pairs(answer) do print(k .. " = " .. v) end
z = 11
y = 11
x = 6
> answer = mapn(function (a, b) return a+b end, {1, 7, 3}, {5, 4, 8})
> for i = 1, 3 do print(answer[i]) end
6
11
11

How to iterate Lua table from end?

How do I iterate a simple Lua table, that is a sequence, from end?
Example of wanted behavior:
local mytable = {'a', 'b', 'c'}
for i, value in reversedipairs(mytable) do
print(i .. ": " .. value)
end
should output
3: c
2: b
1: a
How to implement here reversedipairs?
Thank you, #Piglet, for useful link.
local function reversedipairsiter(t, i)
i = i - 1
if i ~= 0 then
return i, t[i]
end
end
function reversedipairs(t)
return reversedipairsiter, t, #t + 1
end
Actually, I figured out an easier way may be to
local mytable = {'a', 'b', 'c'}
for i = #mytable, 1, -1 do
value = mytable[i]
print(i .. ": " .. value)
end
Also you can use standard for statement with reversed index:
for i=1, #mytable do
print(mytable[#mytable + 1 - i])
end

pcall with variable argument in lua

I am looking for a way to pcall a function which has variable arguments in lua5.3.
I am hoping for something like this
function add(...)
local sum=arg + ...
return sum
end
stat,err=pcall(add,...)
thanks
function add(...)
local sum = 0
for _, v in ipairs{...} do
sum = sum + v
end
return sum
end
pcall(add, 1, 2, 3)
--> true 6
or maybe this is closer to what you wanted:
function add(acc, ...)
if not ... then
return acc
else
return add(acc + ..., select(2, ...))
end
end
pcall(add, 1, 2, 3)
--> true 6

How to shift all elements in a table?

I'm trying to think of an easy way to make all elements in a table shift up one. It is for a game I am playing, attempting to switch between all targets in a table!
For example, let's say I'm surrounded by three mooks who want to kill me, so I target all of them and they're added into an array like so:
{
"mook1",
"mook2",
"mook3",
}
What I want the function to do is change all indexes to go up one (or the amount I specify), and the last to go to the beginning, so the end result would be:
{
"mook3",
"mook1",
"mook2",
}
I attempted it on my own with a simple function like this:
local function nextIndex(tbl, amount)
local t = {}
for k,v in ipairs(tbl) do
if k < #tbl then
t[k+amount] = v
else
t[1] = v
end
end
return t
end
It works as long as the amount is set to 1. I'm sure there is a much smarter and more efficient way of doing this. Could anyone take a whack at it please?!
You can use a function like this:
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, table.remove( t, #t ) )
end
end
You can see a test run on codepad. or, if you're uncomfortable with nesting of function calls;
function wrap( t, l )
for i = 1, l do
table.insert( t, 1, t[#t] )
table.remove( t, #t )
end
end
would work the same way.
I worked a bit more and figured out how to do it. This is the code:
local function nextIndex(tbl, amount)
local t = {}
local i
for k,v in ipairs(tbl) do
i = k + amount
if i <= #tbl then
t[i] = v
else
t[i-#tbl] = v
end
end
return t
end
Is there an easier way to do it though?
So, the task is to rotate the last rot items to the front.
I added parameter n to allow overriding of the sequence end as determined by #t.
-- uses t[#t+1]...t[#t+rot%#t] as scratch space
local function rotate_mod(t, rot, n)
n = n or #t
rot = rot % n
if rot == 0 then return t end
for i = n, 1, -1 do
t[i + rot] = t[i]
end
for i = 1, rot do
t[i], t[i + n] = t[i + n]
end
return t
end
Or if you want a new array (just ignore parameter r):
local function rotate_new(t, rot, n, r)
n, r = n or #t, {}
rot = rot % n
for i = 1, rot do
r[i] = t[n - rot + i]
end
for i = rot + 1, n do
r[i] = t[i - rot]
end
return r
end
Here's a true "in-place" version. It does not need to temporarily enlarge the table:
local function reverse(t, i, j)
while i < j do
t[i], t[j] = t[j], t[i]
i, j = i+1, j-1
end
end
local function rotate_inplace(t, d, n)
n = n or #t
d = (d or 1) % n
reverse(t, 1, n)
reverse(t, 1, d)
reverse(t, d+1, n)
end

Lua table.concat

Is there a way to use the arg 2 value of table.concat to represent the current table index?
eg:
t = {}
t[1] = "a"
t[2] = "b"
t[3] = "c"
X = table.concat(t,"\n")
desired output of table concat (X):
"1 a\n2 b\n3 c\n"
Simple answer : no.
table.concat is something really basic, and really fast.
So you should do it in a loop anyhow.
If you want to avoid excessive string concatenation you can do:
function concatIndexed(tab,template)
template = template or '%d %s\n'
local tt = {}
for k,v in ipairs(tab) do
tt[#tt+1]=template:format(k,v)
end
return table.concat(tt)
end
X = concatIndexed(t) -- and optionally specify a certain per item format
Y = concatIndexed(t,'custom format %3d %s\n')
I don't think so: how would you tell it that the separator between keys and values is supposed to be a space, for example?
You can write a general mapping function to do what you'd like:
function map2(t, func)
local out = {}
for k, v in pairs(t) do
out[k] = func(k, v)
end
return out
end
function joinbyspace(k, v)
return k .. ' ' .. v
end
X = table.concat(map2(t, joinbyspace), "\n")
No. But there is a work around:
local n = 0
local function next_line_no()
n = n + 1
return n..' '
end
X = table.concat(t,'\0'):gsub('%f[%Z]',next_line_no):gsub('%z','\n')
function Util_Concat(tab, seperator)
if seperator == nil then return table.concat(tab) end
local buffer = {}
for i, v in ipairs(tab) do
buffer[#buffer + 1] = v
if i < #tab then
buffer[#buffer + 1] = seperator
end
end
return table.concat(buffer)
end
usage tab is where the table input is and seperator be both nil or string (if it nil it act like ordinary table.concat)
print(Util_Concat({"Hello", "World"}, "_"))
--Prints
--Hello_world

Resources