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).