lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


> Hi. Does anyone have some tips (or code, preferable :D) on how to 
> traverse a table using lua_next while adding stuff to a luaL_Buffer ?
> The fact that the buffer operations may change my stack top is giving me 
> trouble. I thought of saving the positions of the key and value after 
> lua_next, adding stuff to the buffer and then lua_remove(L, value_pos) 
> and bringing the key to the top of the stack. I haven't tried this, but 
> I'm afraid that it might break the buffer operations.

I had a similar problem in my take on unrope for ropes implemented as
Lua tables. In the end I had to reserve some stack space before the 
Lua buffer data. The final C code is below. The original thread started
at http://lua-users.org/lists/lua-l/2008-12/msg00055.html but the initial
versions had bugs...

/*
* lrope.c
* provides unrope
* Luiz Henrique de Figueiredo <lhf@tecgraf.puc-rio.br>
* 06 Dec 2008 00:13:56
* This code is hereby placed in the public domain.
*/

#include "lua.h"
#include "lauxlib.h"

#define MAXLEVEL 30

static int doconcat (lua_State *L, luaL_Buffer *b, int t, int needsep) {
  int i;
  if (t>MAXLEVEL+1) luaL_error(L,"table too deep for "LUA_QL("unrope"));
  for (i=1;; i++)
  {
    lua_rawgeti(L,t,i);
    switch (lua_type(L,-1))
    {
      case LUA_TNIL:
        lua_pop(L,1);
        return needsep;
      case LUA_TNUMBER:
      case LUA_TSTRING:
        if (needsep) {lua_pushvalue(L,1); luaL_addvalue(b);}
        luaL_addvalue(b);
        needsep=1;
        break;
      case LUA_TTABLE:
        lua_replace(L,t+1);
        needsep=doconcat(L,b,t+1,needsep);
        break;
      default:
        lua_pop(L,1);
    }
 }
}

static int unrope (lua_State *L) {
  luaL_Buffer b;
  luaL_checktype(L,1,LUA_TTABLE);
  lua_settop(L,2);
  if (lua_isnil(L,2)) {lua_pushliteral(L,""); lua_replace(L,2);} 
  else luaL_checkstring(L,2);
  lua_insert(L,1);
  luaL_checkstack(L,MAXLEVEL-1+LUA_MINSTACK,"cannot grow stack");
  lua_settop(L,MAXLEVEL+1);
  luaL_buffinit(L,&b);
  doconcat(L,&b,2,0);
  luaL_pushresult(&b);
  return 1;
}

LUALIB_API int luaopen_rope (lua_State *L) {
  lua_register(L,"unrope",unrope);
  return 0;
}