Skip to content
This repository has been archived by the owner on Aug 22, 2022. It is now read-only.
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time
/*
* save.c
* Luabins save code
* See copyright notice in luabins.h
*/
#include "luaheaders.h"
#include "luabins.h"
#include "saveload.h"
#include "savebuffer.h"
#include "write.h"
/* TODO: Test this with custom allocator! */
#if 0
#define SPAM(a) printf a
#else
#define SPAM(a) (void)0
#endif
static int save_value(
lua_State * L,
luabins_SaveBuffer * sb,
int index,
int nesting
);
/* Returns 0 on success, non-zero on failure */
static int save_table(
lua_State * L,
luabins_SaveBuffer * sb,
int index,
int nesting
)
{
int result = LUABINS_ESUCCESS;
int header_pos = 0;
int total_size = 0;
if (nesting > LUABINS_MAXTABLENESTING)
{
return LUABINS_ETOODEEP;
}
/* TODO: Hauling stack for key and value removal
may get too heavy for larger tables. Think out a better way.
*/
header_pos = lbsSB_length(sb);
result = lbs_writeTableHeader(sb, 0, 0);
result = lbsSB_grow(sb, LUABINS_LINT + LUABINS_LINT);
if (result == LUABINS_ESUCCESS)
{
lua_checkstack(L, 2); /* Key and value */
lua_pushnil(L); /* key for lua_next() */
}
while (result == LUABINS_ESUCCESS && lua_next(L, index) != 0)
{
int value_pos = lua_gettop(L); /* We need absolute values */
int key_pos = value_pos - 1;
/* Save key. */
result = save_value(L, sb, key_pos, nesting);
/* Save value. */
if (result == LUABINS_ESUCCESS)
{
result = save_value(L, sb, value_pos, nesting);
}
if (result == LUABINS_ESUCCESS)
{
/* Remove value from stack, leave key for the next iteration. */
lua_pop(L, 1);
++total_size;
}
}
if (result == LUABINS_ESUCCESS)
{
/*
Note that if array has holes, lua_objlen() may report
larger than actual array size. So we need to adjust.
TODO: Note inelegant downsize from size_t to int.
Handle integer overflow here.
*/
int array_size = luabins_min(total_size, (int)lua_objlen(L, index));
int hash_size = luabins_max(0, total_size - array_size);
result = lbs_writeTableHeaderAt(sb, header_pos, array_size, hash_size);
}
return result;
}
/* Returns 0 on success, non-zero on failure */
static int save_value(
lua_State * L,
luabins_SaveBuffer * sb,
int index,
int nesting
)
{
int result = LUABINS_ESUCCESS;
switch (lua_type(L, index))
{
case LUA_TNIL:
result = lbs_writeNil(sb);
break;
case LUA_TBOOLEAN:
result = lbs_writeBoolean(sb, lua_toboolean(L, index));
break;
case LUA_TNUMBER:
result = lbs_writeNumber(sb, lua_tonumber(L, index));
break;
case LUA_TSTRING:
{
size_t len = 0;
const char * buf = lua_tolstring(L, index, &len);
result = lbs_writeString(sb, buf, len);
}
break;
case LUA_TTABLE:
result = save_table(L, sb, index, nesting + 1);
break;
case LUA_TNONE:
case LUA_TFUNCTION:
case LUA_TTHREAD:
case LUA_TUSERDATA:
default:
result = LUABINS_EBADTYPE;
}
return result;
}
int luabins_save(lua_State * L, int index_from, int index_to)
{
unsigned char num_to_save = 0;
int index = index_from;
int base = lua_gettop(L);
luabins_SaveBuffer sb;
/*
* TODO: If lua_error() would happen below, would leak the buffer.
*/
if (index_to - index_from > LUABINS_MAXTUPLE)
{
lua_pushliteral(L, "can't save that many items");
return LUABINS_EFAILURE;
}
/* Allowing to call luabins_save(L, 1, lua_gettop(L))
from C function, called from Lua with no arguments
(when lua_gettop() would return 0)
*/
if (index_to < index_from)
{
index_from = 0;
index_to = 0;
num_to_save = 0;
}
else
{
if (
index_from < 0 || index_from > base ||
index_to < 0 || index_to > base
)
{
lua_pushliteral(L, "can't save: inexistant indices");
return LUABINS_EFAILURE;
}
num_to_save = index_to - index_from + 1;
}
{
void * alloc_ud = NULL;
lua_Alloc alloc_fn = lua_getallocf(L, &alloc_ud);
lbsSB_init(&sb, alloc_fn, alloc_ud);
}
lbs_writeTupleSize(&sb, num_to_save);
for ( ; index <= index_to; ++index)
{
int result = 0;
result = save_value(L, &sb, index, 0);
if (result != LUABINS_ESUCCESS)
{
switch (result)
{
case LUABINS_EBADTYPE:
lua_pushliteral(L, "can't save: unsupported type detected");
break;
case LUABINS_ETOODEEP:
lua_pushliteral(L, "can't save: nesting is too deep");
break;
case LUABINS_ETOOLONG:
lua_pushliteral(L, "can't save: not enough memory");
break;
default: /* Should not happen */
lua_pushliteral(L, "save failed");
break;
}
lbsSB_destroy(&sb);
return result;
}
}
{
size_t len = 0UL;
const unsigned char * buf = lbsSB_buffer(&sb, &len);
lua_pushlstring(L, (const char *)buf, len);
lbsSB_destroy(&sb);
}
return LUABINS_ESUCCESS;
}