📄 config.cpp
字号:
// config.cpp -- by Thatcher Ulrich <tu@tulrich.com> 22 July 2001
// This source code has been donated to the Public Domain. Do
// whatever you want with it.
// Configuration glue. C++ interface to Lua scripting library.
// @@ move/finish this later...
#if 0
#include "config.h"
extern "C" {
#include <lualib.h>
}
#include "utility.h"
namespace config {
static const int LUA_STACK_SIZE = 2048;
static bool s_open = false;
lua_State* L = NULL;
int g_cfloat_tag = 0;
static int cfloat_get( lua_State* L )
// Lua CFunction which returns the value of the cfloat passed in on
// the top of the Lua stack. Attach this to the "getglobal" event for
// cfloats.
{
// arg 1: varname
// arg 2: raw var value (in this case the cfloat*)
cfloat* cf = static_cast<cfloat*>( lua_touserdata( L, 2 ) );
lua_pushnumber( L, float( *cf ) );
return 1;
}
static int cfloat_set( lua_State* L )
// Lua CFunction which sets the value of the given cfloat to the given lua
// number.
{
// arg 1: varname
// arg 2: previous var value (in this case the cfloat*)
// arg 3: new var value
cfloat* cf = static_cast<cfloat*>( lua_touserdata( L, 2 ) );
*cf = float(lua_tonumber( L, 3 ));
return 0;
}
void open()
// Initialize the config subsystem. ...
{
if ( s_open == true ) return;
//
// Initialize Lua.
//
L = lua_open( LUA_STACK_SIZE );
// Init the standard Lua libs.
lua_baselibopen( L );
lua_iolibopen( L );
lua_strlibopen( L );
lua_mathlibopen( L );
//
// Attach the cfloat hooks
//
g_cfloat_tag = lua_newtag( config::L );
lua_pushcfunction( config::L, cfloat_get );
lua_settagmethod( config::L, config::g_cfloat_tag, "getglobal" ); // xxx is "getglobal" right?
lua_pushcfunction( config::L, cfloat_set );
lua_settagmethod( config::L, config::g_cfloat_tag, "setglobal" ); // xxx is "setglobal" right?
// set tag methods for add, sub, mul, div, pow, unm, lt
// gettable{ min, max, default, comment }
// settable{ min, max, default, comment }
s_open = true;
}
void close()
// Close the config subsystem.
{
// Nothing really to do here.
}
}; // end namespace config
//
// cvar
//
void cvar::init( const char* name )
// Initializes a chain of references to Lua strings, for looking up
// the value of the specified name.
//
// The name can contain embedded '.' separators, to refer to values
// within nested tables. For example, a name of
// "player.spaceship.health" would refer to the "health" member of the
// "player.spaceship" table (where the "player.spaceship" table is
// found by looking up the "spaceship" member of the "player" table).
{
config::open();
// Count the number of keys in the name (keys are separated by '.'
// chars).
m_lua_key_count = 1;
const char* p = name;
while (*p) {
if (*p == '.') {
m_lua_key_count++;
}
p++;
}
// Allocate array for references.
m_lua_key_reference = new int[m_lua_key_count];
// Now initialize the keys.
const char* varname = name;
int key_index = 0;
p = name;
while (*p) {
if (*p == '.') {
if (varname == p) {
// null string for a key.
// warning("something or other");
assert(0); // TODO: recover somehow.
}
// Reference the name of the table.
lua_pushlstring(config::L, varname, p - varname);
m_lua_key_reference[key_index] = lua_ref(config::L, 1);
key_index++;
varname = p + 1;
}
p++;
}
// Get a reference to the last key name.
assert(varname != p); // else...
lua_pushlstring(config::L, varname, p - varname);
m_lua_key_reference[key_index] = lua_ref(config::L, 1);
}
void cvar::push_table_and_key() const
// Traverse our key names, and push the table and keyname of our value
// onto the Lua stack.
//
// Creates empty tables if necessary to fill in missing links in the
// chain.
{
lua_getglobals(config::L); // Start with the global table.
// Chain through additional tables.
int i;
for (i = 0; i < m_lua_key_count - 1; i++) {
lua_getref(config::L, m_lua_key_reference[i]);
lua_gettable(config::L, -2);
if (lua_isnil(config::L, -1)) {
// Tablename is undefined, so create a new empty table for it.
lua_pop(config::L, 1); // pop the nil.
lua_getref(config::L, m_lua_key_reference[i]);
lua_newtable(config::L);
lua_settable(config::L, -3);
// Get the newly created table and put it on the top
// of stack.
lua_getref(config::L, m_lua_key_reference[i]);
lua_gettable(config::L, -2);
}
lua_remove(config::L, -2); // previous table that we just chained from
}
// push the final key, on top of the table we just pushed.
lua_getref(config::L, m_lua_key_reference[i]);
}
cvar::cvar( const char* name )
// Constructor; leaves existing value, if any (otherwise it's 'nil').
{
init(name);
}
cvar::cvar( const char* name, const cvalue& val )
// Constructor; initializes to given Lua value.
{
init(name);
*this = val; // invoke operator=(const cvalue& val)
}
cvar::cvar( const char* name, const char* val )
// Constructor; initializes to given string value.
{
init(name);
*this = val; // invoke operator=(const char*)
}
cvar::cvar( const char* name, float val )
// Constructor; initializes to given float value.
{
init(name);
*this = val; // invoke operator=(float f)
}
cvar::~cvar()
// Destructor; make sure our references are released.
{
// drop lua references, so table & name can be gc'd if not
// referenced elsewhere.
for (int i = 0; i < m_lua_key_count; i++) {
lua_unref(config::L, m_lua_key_reference[i]);
}
m_lua_key_count = 0;
m_lua_key_reference = NULL;
}
#if 0
const char* cvar::get_name() const
// Return our name. The char[] storage is valid at least as long
// as this variable is alive.
{
lua_getref( config::L, m_lua_name_reference );
return lua_tostring( config::L, -1 );
}
#endif // 0
cvar::operator float() const
// Convert the variable to a float and return it.
{
push_table_and_key();
lua_gettable( config::L, -2 ); // get the value of our variable from the table.
float f = float(lua_tonumber( config::L, -1 ));
lua_pop( config::L, 2 ); // pop table & the number result.
return f;
}
void cvar::operator=( float f )
// Assign a float to this lua variable.
{
push_table_and_key();
lua_pushnumber( config::L, f );
lua_settable( config::L, -3 );
lua_pop( config::L, 1 ); // pop the table.
}
cvar::operator const char*() const
// Convert to a string.
//
// xxx there are garbage-collection issues here! Returned string
// has no valid reference once stack is cleared!
// Possible fixes:
// - return some kind of proxy object that holds a locked Lua ref
// - return a C++ "string" value; i.e. make a copy
// - hold a locked reference in this instance; drop it on next call to this conversion operator (blech).
{
push_table_and_key();
lua_gettable( config::L, -2 ); // get the value of our variable from the table.
const char* c = lua_tostring( config::L, -1 );
// TODO: grab a locked reference to the string! Or copy it!
lua_pop( config::L, 2 ); // discard table & the string result.
return c;
}
void cvar::operator=( const cvalue& val )
// Assign a Lua value to this lua global variable.
{
push_table_and_key();
val.lua_push();
lua_settable( config::L, -3 );
lua_pop( config::L, 1 ); // pop the table.
}
void cvar::operator=( const char* s )
// Assign a string to this lua variable.
{
push_table_and_key();
lua_pushstring( config::L, s );
lua_settable( config::L, -3 );
lua_pop( config::L, 1 ); // pop the table.
}
cvar::operator cvalue() const
// Return a reference to our value.
{
push_table_and_key();
cvalue c = cvalue::lua_stacktop_reference();
lua_pop( config::L, 1 ); // pop the table.
return c;
}
// void operator=( const cvar c );
//
// cvalue
//
cvalue::cvalue( const char* lua_constructor )
// Evaluates the given code and takes a reference to the result.
{
config::open();
lua_dostring( config::L, lua_constructor ); // @@ could check for error return codes, presence of return value, etc.
m_lua_ref = lua_ref( config::L, 1 );
}
cvalue::cvalue( const cvalue& c )
{
lua_getref( config::L, c.m_lua_ref );
m_lua_ref = lua_ref( config::L, 1 );
}
cvalue::cvalue()
// Creates an reference to nothing. Use this only in special
// circumstances; i.e. when you're about to set m_lua_ref manually.
{
config::open();
m_lua_ref = LUA_NOREF;
}
cvalue cvalue::lua_stacktop_reference()
// Factory function; pops the value off the top of the Lua stack, and
// return a cvalue that references the popped value.
{
cvalue c;
c.m_lua_ref = lua_ref( config::L, 1 );
return c;
}
cvalue::~cvalue()
// Drop our Lua reference, to allow our value to be gc'd.
{
lua_unref( config::L, m_lua_ref );
m_lua_ref = LUA_NOREF;
}
void cvalue::lua_push() const
// Push our value onto the top of the Lua stack.
{
assert( m_lua_ref != LUA_NOREF );
lua_getref( config::L, m_lua_ref );
}
void cvalue::operator=( const char* str )
// Transfer our reference to the given string.
{
lua_unref( config::L, m_lua_ref );
lua_pushstring( config::L, str );
m_lua_ref = lua_ref( config::L, 1 );
}
void cvalue::operator=( const cvalue& c )
// Reference the thing that c references.
{
lua_unref( config::L, m_lua_ref );
lua_getref( config::L, c.m_lua_ref );
m_lua_ref = lua_ref( config::L, 1 );
}
cvalue::operator float() const
// Converts this Lua value to a number, and returns it.
{
lua_getref( config::L, m_lua_ref );
float f = float(lua_tonumber( config::L, -1 ));
lua_pop( config::L, 1 );
return f;
}
cvalue::operator const char*() const
// Converts this Lua value to a string, and returns it.
{
lua_getref( config::L, m_lua_ref );
const char* str = lua_tostring( config::L, -1 );
lua_pop( config::L, 1 ); // @@ I'm pretty sure this imperils the string, if we just had to do a tostring() conversion! Look into this, and/or make a copy of the string.
return str;
}
cvalue cvalue::get( const char* index )
// Does a table lookup. *this should be a Lua table, and index is its
// key.
{
lua_getref( config::L, m_lua_ref );
lua_pushstring( config::L, index );
lua_gettable( config::L, -2 );
cvalue c = cvalue::lua_stacktop_reference(); // references the value on the top of the Lua stack.
lua_pop( config::L, 1 );
return c;
}
#endif // 0
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -