2013-08-14 14:17:44 +02:00
|
|
|
/***************************************************************************
|
|
|
|
|
* Copyright (C) 2013 by Chris Mitchell *
|
2014-08-15 02:11:43 -07:00
|
|
|
* Copyright (C) 2014 by Ahmed Charles - acharles@outlook.com *
|
2013-08-14 14:17:44 +02:00
|
|
|
* *
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
|
|
|
* it under the terms of the GNU General Public License as published by *
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or *
|
|
|
|
|
* (at your option) any later version. *
|
|
|
|
|
* *
|
|
|
|
|
* This program is distributed in the hope that it will be useful, *
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
|
|
|
* GNU General Public License for more details. *
|
|
|
|
|
* *
|
|
|
|
|
* You should have received a copy of the GNU General Public License *
|
|
|
|
|
* along with this program; if not, write to the *
|
|
|
|
|
* Free Software Foundation, Inc., *
|
|
|
|
|
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|
|
|
|
***************************************************************************/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "LuaInterface.h"
|
2014-08-15 02:11:43 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
#include "Host.h"
|
2013-08-14 14:17:44 +02:00
|
|
|
#include "VarUnit.h"
|
2014-08-15 02:11:43 -07:00
|
|
|
|
|
|
|
|
#include "pre_guard.h"
|
2013-08-14 14:17:44 +02:00
|
|
|
#include <QTime>
|
2014-08-15 02:11:43 -07:00
|
|
|
#include "post_guard.h"
|
|
|
|
|
|
|
|
|
|
#include <setjmp.h>
|
|
|
|
|
|
2013-08-14 14:17:44 +02:00
|
|
|
|
|
|
|
|
static jmp_buf buf;
|
|
|
|
|
|
|
|
|
|
LuaInterface::LuaInterface(Host * pH)
|
|
|
|
|
:mpHost(pH)
|
2017-04-14 23:56:24 -07:00
|
|
|
, L()
|
|
|
|
|
, depth()
|
2013-08-14 14:17:44 +02:00
|
|
|
{
|
|
|
|
|
interpreter = mpHost->getLuaInterpreter();
|
|
|
|
|
mHostID = mpHost->getHostID();
|
2014-09-29 04:08:18 -07:00
|
|
|
varUnit.reset(new VarUnit());
|
2013-08-14 14:17:44 +02:00
|
|
|
//set our panic function
|
|
|
|
|
lua_atpanic( interpreter->pGlobalLua, &onPanic );
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-29 04:08:18 -07:00
|
|
|
LuaInterface::~LuaInterface() {}
|
|
|
|
|
|
2013-08-14 14:17:44 +02:00
|
|
|
int LuaInterface::onPanic( lua_State * L )
|
|
|
|
|
{
|
|
|
|
|
QString error = "Lua Panic, No error information";
|
|
|
|
|
if ( lua_isstring( L, -1 ) )
|
|
|
|
|
{
|
|
|
|
|
error = lua_tostring( L, -1 );
|
2014-01-10 21:41:20 -05:00
|
|
|
//there's never anything but the error on the stack, nothing to report
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to user qDebug()<<"PANIC ERROR:"<<error;
|
2013-08-14 14:17:44 +02:00
|
|
|
longjmp(buf, 1);
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
VarUnit * LuaInterface::getVarUnit(){
|
2014-09-29 04:08:18 -07:00
|
|
|
return varUnit.data();
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QStringList LuaInterface::varName(TVar * var){
|
|
|
|
|
QStringList names;
|
|
|
|
|
if (var->getName() == "_G"){
|
|
|
|
|
names << "";
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
names << var->getName();
|
|
|
|
|
TVar * p = var->getParent();
|
|
|
|
|
while (p && p->getName() != "_G"){
|
|
|
|
|
names.insert(0,p->getName());
|
|
|
|
|
p = p->getParent();
|
|
|
|
|
}
|
|
|
|
|
return names;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::validMove(QTreeWidgetItem * p){
|
|
|
|
|
TVar * newParent = varUnit->getWVar(p);
|
|
|
|
|
if (newParent && newParent->getValueType() != LUA_TTABLE)
|
|
|
|
|
return false;
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::getAllChildren( TVar * var, QList<TVar *> * list){
|
BugFix: fix crash on profile auto-load (bug 1624720) (#318)
* BugFix: fix crash on profile auto-load (bug 1624720)
The uninitialised TVar::parent member in the default constructor is used
in the profile auto-load (but not the normal one apparently) and was the
cause for segment violations. In fixing THIS I noted that several other
members of that Class {and worryingly, quite a few *other* classes
throughout the Mudlet application!!!) were not being initialised to
sensible defaults either. This commit addresses the TVar class, but ONLY
that Class...!
In checking also found that (void) TVar::setNewName( QString ) is not used
{only the two argument (void) TVar::setNewName( QString, int ) that takes
a Lua Type number as a second argument IS used} so commented it out. Also
found that (int) TVar::nvType and (QString) TVar::nValue members are not
used so removed them as well.
Also fixed a (subtle ?) bug in local functor TVarLessThan(TVar *, TVar *) which
tested the number value of the "name" of each argument when converted to a
number without checking that the "name" could be converted to a number.
Consequently, when a non-number name was encountered it would convert to
zero and THAT zero value would be compared to the other one. If BOTH
arguments were not numbers then the caller would ALWAYS be told the first
argument was less than the second argument whereas the wanted result was
a String comparison of "lessnessness".
Refactor TVar class methods that return a "bool" type to actually return
such a thing rather than (int)(0) for false or, more suspiciously, (int)(1)
for true - though subsequent research revealed that that is how C++ does
it, (as a C ex-pat I just think of anything that isn't zero is true)! This
affects:
* (bool) TVar::setValue( const QString )
* (bool) TVar::setValue( const QString, const int )
* (bool) TVar::setValueType( const int )
Similarly, where an argument was an int type but was being used in a
binary/boolean manner I've changed it to the latter type. This affected:
* (QList<TVar *>) TVar::getChildren( const bool )
This affects what are now:
* (void) VarUnit::buildVarTree( QTreeWidgetItem *, TVar *, bool )
* (bool) XMLexport::writeHost( Host * )
* (bool) XMLexport::writeVariable( TVar *, LuaInterface *, VarUnit * )
* (void) dlgTriggerEditor::slot_search_triggers( const QString )
* (int) dlgTriggerEditor::canRecast( QTreeWidgetItem *, int, int )
* (void) dlgTriggerEditor::recurseVariablesDown( TVar *, QList<TVar *> &,
bool)
* (void) LuaInterface::getAllChildren( TVar *, QList<TVar *> *)
Tidies up code layout of TVar implementation to current coding style.
Adds const where possible to TVar class method parameters.
__This commit is a squashed down one as some later ones of the original commits were reverted directly on GitHub in the reverse of their application - this comment contains the text for the remaining parts and hopefully still make sense!__
Signed-off-by: Stephen Lyons <slysven@virginmedia.com>
2016-10-04 03:15:27 +01:00
|
|
|
QListIterator<TVar *> it(var->getChildren(true));
|
2013-08-14 14:17:44 +02:00
|
|
|
if (varUnit->isSaved(var) || var->saved)
|
|
|
|
|
list->append(var);
|
|
|
|
|
while (it.hasNext()){
|
|
|
|
|
TVar * child = it.next();
|
|
|
|
|
if (child->getValueType() == LUA_TTABLE)
|
|
|
|
|
getAllChildren( child, list);
|
|
|
|
|
else if (varUnit->isSaved(child) || var->saved)
|
|
|
|
|
list->append(child);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::loadKey(lua_State * L, TVar * var){
|
|
|
|
|
if (setjmp(buf) == 0){
|
|
|
|
|
int kType = var->getKeyType();
|
|
|
|
|
if ( var->isReference() ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE ){
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TBOOLEAN ){
|
|
|
|
|
lua_pushboolean(L, var->getName().toLower() == "true" ? 1 : 0 );
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_pushstring(L, var->getName().toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return lua_type(L, -1) == kType;
|
|
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::loadValue(lua_State * L, TVar * var, int index){
|
|
|
|
|
//puts a value on stack
|
|
|
|
|
if (setjmp(buf) == 0){
|
|
|
|
|
if (loadKey(L, var)){
|
|
|
|
|
//everything is tabled in lua, we need to just find what table
|
|
|
|
|
//we're using, if index == 0, we iterate to the closest table
|
|
|
|
|
if (index)
|
|
|
|
|
lua_gettable(L, index);
|
|
|
|
|
else{
|
|
|
|
|
for (int j=1;j<=lua_gettop(L);j++){
|
|
|
|
|
if (lua_type(L,j*-1) == LUA_TTABLE){
|
|
|
|
|
lua_gettable(L, j*-1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return false;
|
2014-09-15 16:59:25 -04:00
|
|
|
if(lua_gettop(L))
|
|
|
|
|
return lua_type(L, -1) == var->getValueType();
|
|
|
|
|
return false;
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::reparentCVariable(TVar * from , TVar * to, TVar * curVar){
|
|
|
|
|
//get the old parent on the stack
|
|
|
|
|
if (setjmp(buf) == 0){
|
2017-04-12 15:14:08 -07:00
|
|
|
if (!from || !to || (from==to))//moving from global to global or nowhere
|
2013-08-14 14:17:44 +02:00
|
|
|
return true;
|
|
|
|
|
int stackSize = lua_gettop(L);
|
|
|
|
|
bool isSaved = varUnit->isSaved(curVar);
|
|
|
|
|
if (isSaved){
|
|
|
|
|
QList<TVar *> list;
|
|
|
|
|
getAllChildren(curVar, &list);
|
|
|
|
|
QListIterator<TVar *> it(list);
|
|
|
|
|
while (it.hasNext()){
|
|
|
|
|
TVar * t = it.next();
|
|
|
|
|
varUnit->removeSavedVar(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
QList<TVar *> vars = varOrder(curVar);
|
|
|
|
|
lua_getglobal(L, (vars[0]->getName()).toLatin1().data());
|
|
|
|
|
int i=1;
|
|
|
|
|
for( ; i<vars.size(); i++ ){
|
|
|
|
|
if (!loadValue(L, vars[i], -2)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//redo the parenting in TVar
|
|
|
|
|
from->removeChild(curVar);
|
|
|
|
|
curVar->setParent(to);
|
|
|
|
|
to->addChild(curVar);
|
|
|
|
|
vars = varOrder(curVar);
|
|
|
|
|
//do the actual reparenting part
|
|
|
|
|
if (to == varUnit->getBase()){
|
|
|
|
|
//we're going global
|
|
|
|
|
lua_setglobal(L, curVar->getName().toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_getglobal(L, (vars[0]->getName()).toLatin1().data());
|
|
|
|
|
i=1;
|
|
|
|
|
for( ; i<vars.size()-1; i++ ){
|
|
|
|
|
if (!loadValue(L, vars[i], -2)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lua_remove(L, -2);
|
|
|
|
|
}
|
|
|
|
|
lua_insert(L, -2);
|
|
|
|
|
if (!loadKey(L, curVar)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lua_insert(L, -2);
|
|
|
|
|
if (!lua_istable(L,-3)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
//delete the old copy
|
|
|
|
|
if (from == varUnit->getBase()){
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_setglobal(L, curVar->getName().toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
if (!loadKey(L, curVar)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
if (!lua_istable(L,-3)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
}
|
|
|
|
|
if (isSaved){
|
|
|
|
|
QList<TVar *> list;
|
|
|
|
|
list.append(to);
|
|
|
|
|
getAllChildren(curVar, &list);
|
|
|
|
|
QListIterator<TVar *> it(list);
|
|
|
|
|
while (it.hasNext()){
|
|
|
|
|
TVar * t = it.next();
|
|
|
|
|
varUnit->addSavedVar(t);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
2014-01-10 21:41:20 -05:00
|
|
|
return false;
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::reparentVariable(QTreeWidgetItem * newP, QTreeWidgetItem * cItem, QTreeWidgetItem * oldP){
|
|
|
|
|
//if oldParent doesn't exist:
|
|
|
|
|
//this means we were moved to a table from the global namespace
|
|
|
|
|
//if newParent doesn't exist:
|
|
|
|
|
//we were moved to the global namespace
|
|
|
|
|
//if both exist:
|
|
|
|
|
//this means we were moved from inside a table to inside another table
|
|
|
|
|
//and in both instances, this table was not _G
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
TVar * newParent = varUnit->getWVar(newP);
|
|
|
|
|
TVar * curVar = varUnit->getWVar(cItem);
|
|
|
|
|
TVar * oldParent = varUnit->getWVar(oldP);
|
|
|
|
|
TVar * from = oldParent;
|
|
|
|
|
TVar * to = newParent;
|
|
|
|
|
if ( newParent && newParent->getValueType() != LUA_TTABLE ){
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report why this fails to user
|
2013-08-14 14:17:44 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
if ( !newParent && !oldParent ){
|
|
|
|
|
//happens when we move from _G to _G
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else if ( !oldParent ){
|
|
|
|
|
from = varUnit->getBase();
|
|
|
|
|
to = newParent;
|
|
|
|
|
}
|
|
|
|
|
else if ( !newParent ){
|
|
|
|
|
from = oldParent;
|
|
|
|
|
to = varUnit->getBase();
|
|
|
|
|
}
|
2017-04-20 00:35:59 -07:00
|
|
|
if (!from && !to) {
|
2013-08-14 14:17:44 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2017-04-20 00:35:59 -07:00
|
|
|
return reparentCVariable( from, to, curVar);
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QList<TVar *> LuaInterface::varOrder(TVar * var){
|
|
|
|
|
QList<TVar *> vars;
|
|
|
|
|
if (var->getName() == "_G"){
|
|
|
|
|
return vars;
|
|
|
|
|
}
|
|
|
|
|
vars << var;
|
|
|
|
|
TVar * p = var->getParent();
|
|
|
|
|
while (p && p->getName() != "_G"){
|
|
|
|
|
vars.insert(0,p);
|
|
|
|
|
p = p->getParent();
|
|
|
|
|
}
|
|
|
|
|
return vars;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::createVar( TVar * var ){
|
|
|
|
|
setValue( var );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::setCValue( QList<TVar *> vars ){
|
|
|
|
|
//make the new stack
|
|
|
|
|
TVar * var = vars.back();
|
|
|
|
|
if (setjmp(buf) == 0){
|
|
|
|
|
int stackSize = lua_gettop(L);
|
|
|
|
|
lua_getglobal(L, (vars[0]->getName()).toLatin1().data());
|
|
|
|
|
int i=1;
|
|
|
|
|
for( ; i<vars.size()-1; i++ ){
|
|
|
|
|
if (!loadValue(L, vars[i], -2)){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//push our value onto the stack
|
|
|
|
|
switch ( var->getValueType() ){
|
|
|
|
|
case LUA_TSTRING:
|
|
|
|
|
lua_pushstring(L, var->getValue().toLatin1().data());
|
|
|
|
|
break;
|
|
|
|
|
case LUA_TNUMBER:
|
|
|
|
|
lua_pushnumber(L, var->getValue().toInt());
|
|
|
|
|
break;
|
|
|
|
|
case LUA_TBOOLEAN:
|
|
|
|
|
lua_pushboolean(L, var->getValue().toLower() == "true" ? 1 : 0);
|
|
|
|
|
break;
|
|
|
|
|
case LUA_TTABLE:
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
//set it up
|
|
|
|
|
if (lua_type(L, -1) != var->getValueType()){
|
|
|
|
|
lua_settop(L, stackSize);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
}
|
2014-01-10 21:41:20 -05:00
|
|
|
return false;
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::setValue( TVar * var ){
|
|
|
|
|
//This function assumes the var has been modified and then called
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
|
|
|
|
|
QList<TVar *> vars = varOrder(var);
|
|
|
|
|
QString newName = vars[0]->getName();
|
|
|
|
|
for(int i=1;i<vars.size();i++){
|
|
|
|
|
if (vars[i]->isReference())
|
|
|
|
|
return setCValue( vars );
|
|
|
|
|
if (vars[i]->getKeyType() == LUA_TNUMBER){
|
|
|
|
|
newName.append("["+vars[i]->getName()+"]");
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
newName.append("[\""+vars[i]->getName()+"\"]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
switch ( var->getValueType() ){
|
|
|
|
|
case LUA_TSTRING:
|
|
|
|
|
newName.append(QString(" = [["+var->getValue()+"]]"));
|
|
|
|
|
break;
|
|
|
|
|
case LUA_TNUMBER:
|
|
|
|
|
newName.append(QString(" = "+var->getValue()));
|
|
|
|
|
break;
|
|
|
|
|
case LUA_TBOOLEAN:
|
|
|
|
|
newName.append(QString(" = "+var->getValue()));
|
|
|
|
|
break;
|
|
|
|
|
case LUA_TTABLE:
|
|
|
|
|
newName.append(QString(" = {}"));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
luaL_loadstring(L, newName.toLatin1().data());
|
|
|
|
|
int error = lua_pcall(L, 0, LUA_MULTRET, 0);
|
|
|
|
|
if (error){
|
|
|
|
|
QString emsg = lua_tostring(L, -1);
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to user qDebug()<<"error msg"<<emsg;
|
2013-08-14 14:17:44 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::deleteVar( TVar * var ){
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
QList<TVar *> vars = varOrder(var);
|
|
|
|
|
QString oldName = vars[0]->getName();
|
|
|
|
|
for(int i=1;i<vars.size();i++){
|
|
|
|
|
if (vars[i]->getKeyType() == LUA_TNUMBER){
|
|
|
|
|
oldName.append("["+vars[i]->getName()+"]");
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
oldName.append("[\""+vars[i]->getName()+"\"]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
//delete it
|
|
|
|
|
oldName.append(QString(" = nil"));
|
|
|
|
|
luaL_loadstring(L, oldName.toLatin1().data());
|
|
|
|
|
int error = lua_pcall(L, 0, LUA_MULTRET, 0);
|
|
|
|
|
if (error){
|
|
|
|
|
QString emsg = lua_tostring(L, -1);
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to userqDebug()<<"error msg"<<emsg;
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::renameCVar( QList<TVar *> vars ){
|
|
|
|
|
//uses C Api to rename a variable.
|
|
|
|
|
//dangerous function since you can get an api panic
|
|
|
|
|
//and trash the stack
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
TVar * var = vars.back();
|
|
|
|
|
//make the new stack
|
|
|
|
|
lua_getglobal(L, (vars[0]->getName()).toLatin1().data());
|
|
|
|
|
if (setjmp(buf) == 0){
|
|
|
|
|
int i=1;
|
|
|
|
|
int pushCount=0;
|
|
|
|
|
int kType;
|
|
|
|
|
for( ; i<vars.size()-1; i++ ){
|
|
|
|
|
kType = vars[i]->getKeyType();
|
|
|
|
|
if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, QString(vars[i]->getName()).toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, vars[i]->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_pushstring(L, QString(vars[i]->getName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
|
if (lua_isnil(L, -1)){
|
|
|
|
|
//value didn't exist, make it
|
|
|
|
|
lua_pop(L, -1);
|
|
|
|
|
if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, QString(vars[i]->getName()).toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE || kType == LUA_TFUNCTION){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, vars[i]->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_pushstring(L, QString(vars[i]->getName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
lua_newtable(L);
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
i--;//decrement since we want to reput this table on the stack on next iteration
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kType = var->getKeyType();
|
|
|
|
|
if ( kType == LUA_TSTRING ){
|
|
|
|
|
lua_pushstring(L, QString(var->getNewName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, var->getNewName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to user qDebug()<<"unknown key type"<<var->getKeyType();
|
2013-08-14 14:17:44 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//put the old value on the stack
|
|
|
|
|
lua_getglobal(L, (vars[0]->getName()).toLatin1().data());
|
|
|
|
|
i=1;
|
|
|
|
|
for( ; i<vars.size()-1; i++ ){
|
|
|
|
|
kType = vars[i]->getKeyType();
|
|
|
|
|
if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, QString(vars[i]->getName()).toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE || kType == LUA_TFUNCTION){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, vars[i]->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_pushstring(L, QString(vars[i]->getName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
|
pushCount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
kType = var->getKeyType();
|
|
|
|
|
if ( kType == LUA_TSTRING ){
|
|
|
|
|
lua_pushstring(L, QString(var->getName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE || kType == LUA_TFUNCTION ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to user qDebug()<<"unknown key type"<<var->getKeyType();
|
2013-08-14 14:17:44 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
|
pushCount++;
|
|
|
|
|
//old value is @ -1 now
|
|
|
|
|
//we want to put our new named key @ -2
|
|
|
|
|
kType = var->getKeyType();
|
|
|
|
|
if ( kType == LUA_TSTRING ){
|
|
|
|
|
lua_pushstring(L, QString(var->getNewName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, var->getNewName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to userqDebug()<<"unknown key type"<<var->getKeyType();
|
2013-08-14 14:17:44 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pushCount++;
|
|
|
|
|
lua_insert(L, -2);
|
|
|
|
|
lua_settable(L, -3-pushCount);
|
|
|
|
|
//key & value popped
|
|
|
|
|
//delete it, so we put the old key back on the stack and set to nil
|
|
|
|
|
kType = var->getKeyType();
|
|
|
|
|
if ( kType == LUA_TSTRING ){
|
|
|
|
|
lua_pushstring(L, QString(var->getName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE || kType == LUA_TFUNCTION ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to userqDebug()<<"unknown key type"<<var->getKeyType();
|
2013-08-14 14:17:44 +02:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
lua_settable(L, -3);
|
|
|
|
|
var->clearNewName();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool LuaInterface::loadVar( TVar* var ){
|
|
|
|
|
//puts the value of a variable on the -1 position of the stack
|
|
|
|
|
if (setjmp(buf) == 0){
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
int kType = var->getKeyType();
|
|
|
|
|
int vType = var->getValueType();
|
|
|
|
|
if (vType == LUA_TTABLE){
|
|
|
|
|
if ( kType == LUA_TNUMBER ){
|
|
|
|
|
lua_pushnumber(L, QString(var->getName()).toInt());
|
|
|
|
|
}
|
|
|
|
|
else if ( kType == LUA_TTABLE ){
|
|
|
|
|
lua_rawgeti(L, LUA_REGISTRYINDEX, var->getName().toInt());
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_pushstring(L, QString(var->getName()).toLatin1().data());
|
|
|
|
|
}
|
|
|
|
|
if (lua_istable(L,-2)){
|
|
|
|
|
lua_gettable(L, -2);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if ( vType == LUA_TNUMBER )
|
|
|
|
|
lua_pushnumber(L, QString(var->getValue()).toInt());
|
|
|
|
|
else if ( vType == LUA_TBOOLEAN )
|
|
|
|
|
lua_pushboolean(L, var->getValue().toLower() == "true" ? 1 : 0);
|
|
|
|
|
else if ( vType == LUA_TSTRING )
|
|
|
|
|
lua_pushstring(L, QString(var->getName()).toLatin1().data());
|
|
|
|
|
else
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
else{
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to user qDebug()<<"panic in loadVar";
|
2013-08-14 14:17:44 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
2013-08-19 12:25:26 +02:00
|
|
|
return true;
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::renameVar( TVar * var ){
|
|
|
|
|
//this assumes anything like reparenting has been done
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
QList<TVar *> vars = varOrder(var);
|
|
|
|
|
QString oldName = vars[0]->getName();
|
|
|
|
|
QString newName;
|
|
|
|
|
if (vars.size() > 1)
|
|
|
|
|
newName = vars[0]->getName();
|
|
|
|
|
for(int i=1;i<vars.size();i++){
|
|
|
|
|
int kType = vars[i]->getKeyType();
|
|
|
|
|
if (kType == LUA_TNUMBER){
|
|
|
|
|
oldName.append("["+vars[i]->getName()+"]");
|
|
|
|
|
if (i < vars.size()-1 )
|
|
|
|
|
newName.append("["+vars[i]->getName()+"]");
|
|
|
|
|
}
|
|
|
|
|
else if (kType == LUA_TTABLE){
|
|
|
|
|
renameCVar(vars);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
oldName.append("[\""+vars[i]->getName()+"\"]");
|
|
|
|
|
if (i < vars.size()-1 )
|
|
|
|
|
newName.append("[\""+vars[i]->getName()+"\"]");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (var->getNewKeyType() == LUA_TNUMBER)
|
|
|
|
|
newName.append("["+vars.back()->getNewName()+"]");
|
|
|
|
|
else
|
|
|
|
|
newName.append("[\""+vars.back()->getNewName()+"\"]");
|
|
|
|
|
QString addString = QString(newName+" = "+oldName);
|
|
|
|
|
luaL_loadstring(L, addString.toLatin1().data());
|
|
|
|
|
int error = lua_pcall(L, 0, LUA_MULTRET, 0);
|
|
|
|
|
if (error){
|
|
|
|
|
QString emsg = lua_tostring(L, -1);
|
|
|
|
|
var->clearNewName();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
//delete it
|
|
|
|
|
oldName.append(QString(" = nil"));
|
|
|
|
|
luaL_loadstring(L, oldName.toLatin1().data());
|
|
|
|
|
error = lua_pcall(L, 0, LUA_MULTRET, 0);
|
|
|
|
|
if (error){
|
|
|
|
|
QString emsg = lua_tostring(L, -1);
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: report error to userqDebug()<<"error msg"<<emsg;
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|
|
|
|
|
var->clearNewName();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
QString LuaInterface::getValue( TVar * var ){
|
|
|
|
|
if (setjmp(buf) == 0){
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
QList<TVar *> vars = varOrder(var);
|
|
|
|
|
if (vars.empty())
|
|
|
|
|
return "";
|
|
|
|
|
int pCount = vars.size();//how many things we need to pop at the end
|
|
|
|
|
//load from _G first
|
|
|
|
|
lua_getglobal(L, (vars[0]->getName()).toLatin1().data());
|
|
|
|
|
for(int i=1; i<vars.size(); i++ ){
|
|
|
|
|
if (!loadValue(L, vars[i], -2))
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
int vType = lua_type(L, -1);
|
|
|
|
|
QString value = "";
|
|
|
|
|
if (vType == LUA_TBOOLEAN)
|
|
|
|
|
value = lua_toboolean(L, -1) == 0 ? "false" : "true";
|
|
|
|
|
else if (vType == LUA_TNUMBER || vType == LUA_TSTRING)
|
|
|
|
|
value = lua_tostring(L, -1);
|
|
|
|
|
lua_pop(L,pCount);
|
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::iterateTable(lua_State * L, int index, TVar * tVar, bool hide){
|
|
|
|
|
depth++;
|
|
|
|
|
while(lua_next(L, index)){
|
|
|
|
|
int vType = lua_type(L, -1);
|
|
|
|
|
int kType = lua_type(L, -2);
|
|
|
|
|
lua_pushvalue(L, -2);//we do this because extracting the key with tostring changes it
|
|
|
|
|
QString keyName;
|
|
|
|
|
QString valueName;
|
2017-04-09 19:49:02 +02:00
|
|
|
auto var = new TVar();
|
2013-08-14 14:17:44 +02:00
|
|
|
if ( kType == LUA_TTABLE ){
|
|
|
|
|
keyName = QString::number(luaL_ref(L, LUA_REGISTRYINDEX));//this function pops the top item
|
|
|
|
|
lrefs.append(keyName.toInt());
|
|
|
|
|
var->setReference(true);
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
keyName = lua_tostring(L, -1);
|
|
|
|
|
if ( kType == LUA_TFUNCTION && keyName.isEmpty() ){
|
|
|
|
|
//we lost the reference
|
|
|
|
|
keyName = QString::number(luaL_ref(L, LUA_REGISTRYINDEX));
|
|
|
|
|
lrefs.append(keyName.toInt());
|
|
|
|
|
var->setReference(true);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
if (keyName == "package" && depth == 1){//don't load in the 'package' table
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
tVar->removeChild(var);
|
|
|
|
|
delete var;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
var->setName(keyName, kType);
|
|
|
|
|
var->setValueType(vType);
|
|
|
|
|
var->setParent(tVar);
|
|
|
|
|
var->hidden = hide;
|
|
|
|
|
tVar->addChild(var);
|
|
|
|
|
const void* kp = lua_topointer(L, -1);
|
|
|
|
|
var->kpointer = kp;
|
|
|
|
|
const void* vp = lua_topointer(L, -2);
|
|
|
|
|
var->vpointer = vp;
|
|
|
|
|
if ( varUnit->varExists(var) || keyName == "_G" ){
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
tVar->removeChild(var);
|
|
|
|
|
delete var;
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
varUnit->addVariable(var);
|
|
|
|
|
|
|
|
|
|
varUnit->addPointer(kp);
|
|
|
|
|
|
|
|
|
|
varUnit->addPointer(vp);
|
|
|
|
|
if (vType == LUA_TTABLE){
|
|
|
|
|
if (depth<=99 && lua_checkstack(L,3)){//depth is historical now
|
|
|
|
|
//put the table on top
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
var->setValue("{}", LUA_TTABLE);
|
|
|
|
|
iterateTable(L, -2, var, hide);
|
|
|
|
|
depth--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (vType == LUA_TSTRING || vType == LUA_TNUMBER){
|
|
|
|
|
lua_pushvalue(L,-1);
|
|
|
|
|
valueName = lua_tostring(L,-1);
|
|
|
|
|
var->setValue(valueName);
|
|
|
|
|
lua_pop(L,1);
|
|
|
|
|
}
|
|
|
|
|
else if (vType == LUA_TBOOLEAN){
|
|
|
|
|
valueName = lua_toboolean(L, -1) == 0 ? "false" : "true";
|
|
|
|
|
var->setValue(valueName);
|
|
|
|
|
}
|
|
|
|
|
else if (vType == LUA_TFUNCTION &&
|
|
|
|
|
(!keyName.toLower().startsWith("alias") && !keyName.toLower().startsWith("trigger") &&
|
|
|
|
|
!keyName.toLower().startsWith("action") && !keyName.toLower().startsWith("timer") &&
|
|
|
|
|
!keyName.toLower().startsWith("key"))){
|
|
|
|
|
//functions are compiled to bytecode so there is no reference
|
|
|
|
|
var->setValue("function");
|
|
|
|
|
}
|
|
|
|
|
else{
|
|
|
|
|
tVar->removeChild(var);
|
|
|
|
|
varUnit->removeVariable(var);
|
|
|
|
|
delete var;
|
|
|
|
|
}
|
|
|
|
|
lua_pop(L, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void LuaInterface::getVars( bool hide ){
|
|
|
|
|
//returns the base item
|
|
|
|
|
QTime t;
|
|
|
|
|
t.start();
|
|
|
|
|
L = interpreter->pGlobalLua;
|
|
|
|
|
lua_pushnil(L);
|
|
|
|
|
depth = 0;
|
2017-04-09 19:49:02 +02:00
|
|
|
auto g = new TVar();
|
2013-08-14 14:17:44 +02:00
|
|
|
g->setName("_G", LUA_TSTRING);
|
|
|
|
|
g->setValue("{}", LUA_TTABLE);
|
|
|
|
|
QListIterator<int> it(lrefs);
|
|
|
|
|
while(it.hasNext()){
|
|
|
|
|
int ref = it.next();
|
|
|
|
|
luaL_unref(L, LUA_REGISTRYINDEX, ref);
|
|
|
|
|
}
|
|
|
|
|
varUnit->clear();
|
|
|
|
|
varUnit->setBase(g);
|
|
|
|
|
varUnit->addVariable(g);
|
|
|
|
|
iterateTable( L, LUA_GLOBALSINDEX, g, hide );
|
2014-01-10 21:41:20 -05:00
|
|
|
//FIXME: possible to keep and report? qDebug()<<"took"<<t.elapsed()<<"to get variables in";
|
2013-08-14 14:17:44 +02:00
|
|
|
}
|