File indexing completed on 2025-01-12 06:47:30
0001 // 0002 // C++ Implementation: cscripteval 0003 // 0004 // Description: 0005 // 0006 /* 0007 Copyright 2010-2011 Tomas Mecir <kmuddy@kmuddy.com> 0008 0009 This program is free software; you can redistribute it and/or 0010 modify it under the terms of the GNU General Public License as 0011 published by the Free Software Foundation; either version 2 of 0012 the License, or (at your option) any later version. 0013 0014 This program is distributed in the hope that it will be useful, 0015 but WITHOUT ANY WARRANTY; without even the implied warranty of 0016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 0017 GNU General Public License for more details. 0018 0019 You should have received a copy of the GNU General Public License 0020 along with this program. If not, see <http://www.gnu.org/licenses/>. 0021 */ 0022 0023 #include "cscripteval.h" 0024 #include <QCoreApplication> 0025 #include <QScriptContext> 0026 #include <QScriptEngine> 0027 #include <QScriptSyntaxCheckResult> 0028 0029 class TooLongEvent : public QEvent { public: TooLongEvent() : QEvent(QEvent::User) {}; }; 0030 0031 class cScriptEval::Private { 0032 public: 0033 0034 QScriptEngine *engine; 0035 0036 void doEval (QString script, QMap<QString, QVariant> variables, cScriptEval *obj) 0037 { 0038 QScriptContext *context = engine->pushContext(); 0039 0040 QMapIterator<QString, QVariant> it(variables); 0041 while (it.hasNext()) { 0042 it.next(); 0043 QScriptValue val; 0044 if (it.value().type() == QVariant::StringList) 0045 val = engine->toScriptValue (it.value().toStringList()); 0046 else 0047 val = engine->newVariant (it.value()); 0048 context->activationObject().setProperty (it.key(), val); 0049 } 0050 0051 QCoreApplication::postEvent (obj, new TooLongEvent, 50); // a super high-priority event 0052 engine->evaluate (script); 0053 engine->popContext(); 0054 0055 if (engine->hasUncaughtException()) { 0056 obj->invokeEvent ("message", obj->sess(), "Error in script: " + engine->uncaughtException().toString()); 0057 engine->clearExceptions (); 0058 } 0059 } 0060 }; 0061 0062 cScriptEval::cScriptEval (int sess) : cActionBase ("scripteval", sess) 0063 { 0064 d = new Private; 0065 d->engine = new QScriptEngine; 0066 d->engine->setProcessEventsInterval (4000); 0067 } 0068 0069 cScriptEval::~cScriptEval () 0070 { 0071 abort (); 0072 0073 delete d->engine; 0074 delete d; 0075 } 0076 0077 void cScriptEval::addObject (QString name, QObject *object) 0078 { 0079 d->engine->globalObject().setProperty (name, d->engine->newQObject (object)); 0080 } 0081 0082 void cScriptEval::eval (QString script, QMap<QString, QVariant> variables) 0083 { 0084 d->doEval (script, variables, this); 0085 } 0086 0087 QString cScriptEval::validate (QString script) 0088 { 0089 QScriptSyntaxCheckResult res = QScriptEngine::checkSyntax (script); 0090 if (res.state() == QScriptSyntaxCheckResult::Valid) return QString(); 0091 if (res.state() != QScriptSyntaxCheckResult::Error) return QString("(unfinished)"); 0092 // errorMessage() only returns an empty string, so I can't use it. No idea why. 0093 // return "At line "+QString::number(res.errorLineNumber())+": " + res.errorMessage(); 0094 return "Error at line "+QString::number(res.errorLineNumber()); 0095 } 0096 0097 void cScriptEval::abort () 0098 { 0099 if (d->engine->isEvaluating()) 0100 d->engine->abortEvaluation(); 0101 } 0102 0103 bool cScriptEval::event (QEvent *e) 0104 { 0105 if (!dynamic_cast<TooLongEvent *>(e)) return QObject::event (e); 0106 0107 if (!d->engine->isEvaluating()) return true; 0108 0109 invokeEvent ("message", sess(), "Script execution is taking too long, aborting."); 0110 abort(); 0111 return true; 0112 } 0113 0114 #include "moc_cscripteval.cpp"