Friday, January 27, 2012
99 ways to program a hex, Part 19: Lua, recursion, closure as callback
Now, instead of passing along data
just to be passed to the callback function, we can include such data as
part of a closure
to the function we pass to the do_dump() function.
#!/usr/bin/env lua
-- ***************************************************************
--
-- Copyright 2010 by Sean Conner. All Rights Reserved.
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--
-- Comments, questions and criticisms can be sent to: sean@conman.org
--
-- ********************************************************************
-- Style: Lua 5.1, recursion, closure as callback
function do_dump(fpout,offset,callback)
local line = callback(offset)
if line == nil then return end
fpout:write(
string.format("%08X: ",offset),
line:gsub(".",function(c) return string.format("%02X ",c:byte()) end),
string.rep(" ",3 * (16 - line:len())),
line:gsub("%c","."),
"\n"
)
return do_dump(fpout,offset + 16,callback)
end
-- **********************************************************************
if #arg == 0 then
print("-----stdin-----")
do_dump(io.stdout,0,cb,io.stdin)
else
for i = 1 , #arg do
local f = io.open(arg[1],"r")
io.stdout:write("-----",arg[1],"-----","\n")
do_dump(io.stdout,0,function(offset) return f:read(16) end)
f:close()
end
end
os.exit(0)
Here, our function (which is not named, as you don't really need to name
functions in Lua)
references our open file f, but in order to do so, Lua needs to
include a reference to f to the function when said function is
passed to do_dump(). It does so by creating what's called a
“closure”—think of a closure as both a pointer (or reference) to a
function, plus a pointer (or reference) to data that is outside the normal
lexical
scope of the function.
And why do I pass in the offset when my unnamed (“anonymous”) function doesn't use it? Because it might be useful in some contexts to know where to pull the data (say from a block of memory).
![Glasses. Titanium, not steel. [Self-portrait with my new glasses]](https://www.conman.org/people/spc/about/2025/0925.t.jpg)