Lua Printf

lua-users home
wiki

The page demonstrates how to partially emulate the C printf string formatting function in Lua.

In Lua

It's easy to write formatted text in Lua using io.write(), print() and string.format(). io.write is similar to print except io.write does not follow each output with a new line. The C function printf() can be emulated as:

> io.write(string.format("Hello from %s on %s\n",_VERSION,os.date()))
Hello from Lua 5.1 on Mon Jan  1 22:11:56 2007

Or, this can be wrapped in a function as:

printf = function(s,...)
           return io.write(s:format(...))
         end -- function

and then used as

printf("Hello from %s on %s\n",_VERSION,date())

In the above example the format string and the variable argument list from printf() are passed to string.format(). write() prints the resulting formatted string. [*1]

It is interesting to note how the Lua 5.1 syntax for string methods forces the separate treatment of the first argument. This makes sense, because it has a quite separate role from the others.

Note that Lua's string.format function doesn't support the full C format specification [1], so this function is not a drop-in replacement. If you want the full capabilities of the C format specification, you might want to do the printf call in C code and call that from Lua. Alternately, you may using the C string functions to emulate the behavior you need entirely in Lua (more work).

In C

The above example could be coded in C as follows. This also optimizes by capturing the two standard library functions as upvalues, rather than looking them up each time (although looking them up each time has the advantage of being more dynamic). You may just want to use the Lua version though.

static int l_printf (lua_State *L) {
  lua_pushvalue(L, lua_upvalueindex(2));
  lua_insert(L, 1);
  lua_call(L, lua_gettop(L) - 1, 1);
  lua_pushvalue(L, lua_upvalueindex(1));
  lua_pushvalue(L, -2);
  lua_call(L, 1, 0);
  return 0;
}

int luaopen_printf (lua_State *L) {
  lua_getglobal(L, "io");
  lua_getglobal(L, "string");
  lua_pushliteral(L, "write");
  lua_gettable(L, -3);
  lua_pushliteral(L, "format");
  lua_gettable(L, -3);
  lua_pushcclosure(L, l_printf, 2);
  /* With 5.1, I'd probably just return 1 at this point */
  lua_setglobal(L, "printf");
  return 0;
}

A C function l_printf is registered with Lua as printf. When l_printf is called from Lua, format() is called with the given arguments, then write() is called with the result of format and finally the number of results returned.


-- Thanks to lhf for the examples.

Footnotes

[*1] The Lua 4 versions were

function printf(...)
  write(call(format,arg))
end

static int l_printf (lua_State *l)
{
    lua_getglobal(L,"format");
    lua_insert(L,1);
    lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
    lua_getglobal(L,"write");
    lua_insert(L,1);
    lua_call(L,lua_gettop(L)-1,LUA_MULTRET);
    return lua_gettop(L);
}

lua_register(L,"printf",l_printf);


-- Sirmabus: September 13, 2009 - An improvement to the Lua code above is to use a pcall() wrapper to catch errors and point back to the offending printf(). Otherwise it's difficult to know exactly where the error came from.

function printf(...)
   local function wrapper(...) io.write(string.format(...)) end
   local status, result = pcall(wrapper, ...)
   if not status then error(result, 2) end
end

RecentChanges · preferences
edit · history
Last edited September 14, 2009 1:13 am GMT (diff)