I'll elaborate a bit.
void call_va( lua_State *L, const char *func, const char *sig, ...)
{
va_list v1;
int narg, nres;
va_start(v1, sig);
lua_getglobal(L, func);
// push argument
for(narg = 0; *sig; narg++)
{
luaL_checkstack(L, 1, "too many arguments");
switch(*sig++)
{
case 'd':
lua_pushnumber(L, va_arg(v1, double));
break;
case 'i':
lua_pushinteger(L, va_arg(v1, int));
break;
case 's':
lua_pushstring(L, va_arg(v1, char *));
break;
case '>':
goto endargs;
default:
luaL_error(L, "invalid option (%c)", *(sig -1));
}
}
endargs:
nres = strlen(sig);
if(lua_pcall(L, narg, nres, 0) != 0)
luaL_error(L, "error calling '%s': %s", func, lua_tostring(L, -1));
// results
nres = -nres;
while (*sig)
{
switch(*sig++)
{
case 'd':
if(!lua_isnumber(L, nres))
luaL_error(L, "wrong result type, double expected.");
*va_arg(v1, double *) = lua_tonumber(L, nres);
break;
case 'i':
if(!lua_isnumber(L, nres))
luaL_error(L, "wrong result type, integer expected.");
*va_arg(v1, int *) = lua_tointeger(L, nres);
break;
case 's':
if(!lua_isstring(L, nres))
luaL_error(L, "wrong result type, string expected.");
*va_arg(v1, const char **) = lua_tostring(L, nres);
break;
default:
luaL_error(L, "invalid option (%c)", *(sig -1));
}
nres++;
}
va_end(v1);
}
This is almost verbatim from the book. I had to add the lua_State to the arguments list.
This is used like this:
else if (obj->item_type == ITEM_LIGHT)
{
call_va(L_mud, "generate_random_item", "ii>s", obj->item_type, FALSE, &name);
// yadda yadda...
sprintf( buf, obj->short_descr, name );
STRFREE( obj->short_descr );
obj->short_descr = str_alloc( buf );
sprintf( buf, "%s", obj->short_descr );
STRFREE( obj->name );
obj->name = str_alloc( buf );
STRFREE( obj->description );
sprintf( buf, "%s lies here.", capitalize( obj->short_descr ) );
obj->description = str_alloc( buf );
Which then calls the Lua function
function gr(list)
return list[math.random(1, #list)]
end
function generate_random_item(iType, bool)
if iType == itype.armor or iType == itype.artarmor then
if bool == 1 then
local x = math.random(1,#metalarmors)
name = string.format("%s %s", gr(metalarmor_mods), metalarmors[x].name)
ac = metalarmors[x].ac
weight = metalarmors[x].weight
else
local x = math.random(1, #otherarmor_types)
name = string.format("%s %s", gr(otherarmor_mods), otherarmor_types[x].name)
ac = otherarmor_types[x].ac
weight = otherarmor_types[x].weight
end
return name, ac, weight
end
if iType == itype.worn or iType == itype.artworn then
return gr(badges)
end
if iType == itype.weapon or iType == itype.artweapon then
local w = gr(weapons)
return w.name, w.weight, w.roll, w.dam
end
if iType == itype.treasure or iType == itype.arttreasure then
if bool == 1 then
name = string.format("%s %s %s", gr(treasureadj1), gr(treasureadj2), gr(trinket))
else
name = string.format("%s %s", gr(treasureadj1), gr(treasureadj2))
end
return name
end
if iType == itype.light or iType == itype.artlight then
name = string.format("%s %s", gr(treasureadj1), gr(treasureadj2))
return name
end
end
Name is returned to C containing something like (for a light item) "a warm onyx" which is then sprintf'd into the buf variable through the chosen item's generic short description such as %s orb, resulting in "a warm onyx orb".
I'm just wondering if I can just bypass the STRFREE and str_alloc calls and just pass &obj->short_descr to Lua instead of the name variable. Or will there be memory issues arrising from doing that? |