1
//=============================================================================
3
// File : KviKvsScript.cpp
4
// Creation date : Thu 25 Sep 2003 05.12 CEST by Szymon Stefanek
6
// This file is part of the KVIrc irc client distribution
7
// Copyright (C) 2003-2010 Szymon Stefanek (pragma at kvirc dot net)
9
// This program is FREE software. You can redistribute it and/or
10
// modify it under the terms of the GNU General Public License
11
// as published by the Free Software Foundation; either version 2
12
// of the License, or (at your opinion) any later version.
14
// This program is distributed in the HOPE that it will be USEFUL,
15
// but WITHOUT ANY WARRANTY; without even the implied warranty of
16
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
// See the GNU General Public License for more details.
19
// You should have received a copy of the GNU General Public License
20
// along with this program. If not, write to the Free Software Foundation,
21
// Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
23
//=============================================================================
26
#include "KviKvsScript.h"
27
#include "KviKvsParser.h"
28
#include "KviKvsReport.h"
29
#include "KviKvsRunTimeContext.h"
30
#include "KviKvsTreeNodeInstruction.h"
31
#include "KviKvsVariantList.h"
32
#include "KviKvsKernel.h"
33
#include "KviLocale.h"
34
#include "KviWindow.h"
35
#include "KviApplication.h"
37
//#warning "THERE IS SOME MESS WITH m_szBuffer and m_pBuffer : with some script copying we may get errors with negative char indexes!"
39
KviKvsScript::KviKvsScript(const QString & szName, const QString & szBuffer, ScriptType eType)
41
m_pData = new KviKvsScriptData;
43
m_pData->m_szName = szName;
44
m_pData->m_eType = eType;
45
m_pData->m_szBuffer = szBuffer;
46
if(m_pData->m_szBuffer.isNull())
47
m_pData->m_szBuffer = "";
49
m_pData->m_pBuffer = m_pData->m_szBuffer.constData(); // never 0
54
KviKvsScript::KviKvsScript(const QString & szName, const QString & szBuffer, KviKvsTreeNodeInstruction * pPreparsedTree, ScriptType eType)
56
m_pData = new KviKvsScriptData;
58
m_pData->m_szName = szName;
59
m_pData->m_szBuffer = szBuffer;
60
m_pData->m_eType = eType;
61
if(m_pData->m_szBuffer.isNull())
62
m_pData->m_szBuffer = "";
64
m_pData->m_pBuffer = m_pData->m_szBuffer.constData(); // never 0
66
m_pData->m_pTree = pPreparsedTree;
69
KviKvsScript::KviKvsScript(const KviKvsScript & src)
71
m_pData = src.m_pData;
75
KviKvsScript::~KviKvsScript()
77
if(m_pData->m_uRefs < 2)
79
if(m_pData->m_uLock)qDebug("WARNING: Destroying a locked KviKvsScript");
80
if(m_pData->m_pTree)delete m_pData->m_pTree;
87
void KviKvsScript::setName(const QString & szName)
89
if(m_pData->m_uRefs > 1)
91
m_pData->m_szName = szName;
94
const QString & KviKvsScript::name() const
96
return m_pData->m_szName;
99
const QString & KviKvsScript::code() const
101
return m_pData->m_szBuffer;
104
bool KviKvsScript::locked() const
106
return m_pData->m_uLock > 0;
109
void KviKvsScript::dump(const char * prefix)
112
m_pData->m_pTree->dump(prefix);
113
else qDebug("%s KviKvsScript : no tree to dump",prefix);
116
void KviKvsScript::detach()
118
if(m_pData->m_uRefs <= 1)
122
KviKvsScriptData * d = new KviKvsScriptData;
124
d->m_eType = m_pData->m_eType;
125
d->m_szBuffer = m_pData->m_szBuffer;
126
if(d->m_szBuffer.isNull())
129
d->m_szBuffer.resize(d->m_szBuffer.length());
130
d->m_pBuffer = d->m_szBuffer.constData(); // never 0
136
const QChar * KviKvsScript::buffer() const
138
return m_pData->m_pBuffer;
141
int KviKvsScript::run(const QString & szCode, KviWindow * pWindow, KviKvsVariantList * pParams, KviKvsVariant * pRetVal)
144
KviKvsScript s("kvirc::corecall(run)",szCode);
145
return s.run(pWindow,pParams,pRetVal,PreserveParams);
148
int KviKvsScript::evaluate(const QString & szCode, KviWindow * pWindow, KviKvsVariantList * pParams, KviKvsVariant * pRetVal)
151
KviKvsScript s("kvirc::corecall(evalutate)",szCode,Parameter);
152
return s.run(pWindow,pParams,pRetVal,PreserveParams);
155
int KviKvsScript::evaluateAsString(const QString & szCode, KviWindow * pWindow, KviKvsVariantList * pParams, QString & szRetVal)
159
KviKvsScript s("kvirc::corecall(evalutate)",szCode,Parameter);
160
int iRet = s.run(pWindow,pParams,&ret,PreserveParams);
161
ret.asString(szRetVal);
165
int KviKvsScript::run(KviWindow * pWnd, KviKvsVariantList * pParams, QString & szRetVal, int iRunFlags, KviKvsExtendedRunTimeData * pExtData)
167
KviKvsVariant retVal;
168
int iRet = run(pWnd,pParams,&retVal,iRunFlags,pExtData);
169
retVal.asString(szRetVal);
173
//static long int g_iTreeCacheHits = 0;
174
//static long int g_iTreeCacheMisses = 0;
176
int KviKvsScript::run(KviWindow * pWnd, KviKvsVariantList * pParams, KviKvsVariant * pRetVal, int iRunFlags, KviKvsExtendedRunTimeData * pExtData)
178
if(!m_pData->m_pTree)
180
//g_iTreeCacheMisses++;
181
//qDebug("CREATING TREE FOR SCRIPT %s",name().latin1());
182
//qDebug("TREE CACHE STATS: HITS=%d, MISSES=%d",g_iTreeCacheHits,g_iTreeCacheMisses);
183
if(!parse(pWnd,iRunFlags))
185
if(pParams && !(iRunFlags & PreserveParams))
190
//g_iTreeCacheHits++;
191
//qDebug("USING A CACHED TREE FOR SCRIPT %s",name().latin1());
192
//qDebug("TREE CACHE STATS: HITS=%d, MISSES=%d",g_iTreeCacheHits,g_iTreeCacheMisses);
195
return execute(pWnd,pParams,pRetVal,iRunFlags,pExtData);
198
int KviKvsScript::run(KviKvsRunTimeContext * pContext, int iRunFlags)
200
if(!m_pData->m_pTree)
202
//g_iTreeCacheMisses++;
203
//qDebug("CREATING TREE FOR SCRIPT %s",name().latin1());
204
//qDebug("TREE CACHE STATS: HITS=%d, MISSES=%d",g_iTreeCacheHits,g_iTreeCacheMisses);
205
if(!parse(pContext->window(),iRunFlags))
208
//g_iTreeCacheHits++;
209
//qDebug("USING A CACHED TREE FOR SCRIPT %s",name().latin1());
210
//qDebug("TREE CACHE STATS: HITS=%d, MISSES=%d",g_iTreeCacheHits,g_iTreeCacheMisses);
215
if(iRunFlags & Quiet)
217
bool bMustReEnable = !(pContext->reportingDisabled());
218
pContext->disableReporting();
219
iRet = executeInternal(pContext);
220
if(bMustReEnable)pContext->enableReporting();
222
iRet = executeInternal(pContext);
228
bool KviKvsScript::parse(KviWindow * pOutput, int iRunFlags)
232
// there is already a tree
233
// if we have more than one ref, detach!
234
if(m_pData->m_uRefs > 1)
236
// mmmh.. more than one ref! .. detach
239
// only a single ref: we're the owner of the tree
242
// ops... someone is locked in THIS script object
243
qDebug("WARNING: Trying to reparse a locked KviKvsScript!");
247
delete m_pData->m_pTree;
249
m_pData->m_pTree = 0;
251
} // else there is no tree at all, nobody can be locked inside
253
KviKvsParser p(this,(iRunFlags & Quiet) ? 0 : pOutput);
254
// parse never blocks
256
int iFlags = iRunFlags & AssumeLocals ? KviKvsParser::AssumeLocals : 0;
257
if(iRunFlags & Pedantic)iFlags |= KviKvsParser::Pedantic;
259
switch(m_pData->m_eType)
262
m_pData->m_pTree = p.parseAsExpression(m_pData->m_pBuffer,iFlags);
265
m_pData->m_pTree = p.parseAsParameter(m_pData->m_pBuffer,iFlags);
267
case InstructionList:
269
m_pData->m_pTree = p.parse(m_pData->m_pBuffer,iFlags);
273
//qDebug("\n\nDUMPING SCRIPT");
275
//qDebug("END OF SCRIPT DUMP\n\n");
280
int KviKvsScript::executeInternal(KviKvsRunTimeContext * pContext)
285
int iRunStatus = Success;
287
if(!m_pData->m_pTree->execute(pContext))
289
if(pContext->error())iRunStatus = Error;
291
// else just a halt, return or sth like that
292
if(pContext->haltCalled())
293
iRunStatus |= HaltEncountered;
297
// we can't block any longer: unlock
303
int KviKvsScript::execute(KviWindow * pWnd, KviKvsVariantList * pParams, KviKvsVariant * pRetVal, int iRunFlags, KviKvsExtendedRunTimeData * pExtData)
305
bool bDeleteParams = !(iRunFlags & PreserveParams);
307
// do we have a parsed tree ?
308
if(!m_pData->m_pTree)
310
if(pParams && bDeleteParams)
313
// this is intended for developers only
314
pWnd->outputNoFmt(KVI_OUT_PARSERERROR,"[developer error]: you must successfully call KviKvsScript::parse() before KviKvsScript::execute()");
318
// do we need to pass dummy params ?
321
pParams = KviKvsKernel::instance()->emptyParameterList();
322
bDeleteParams = false;
325
bool bDeleteRetVal = false;
329
pRetVal = new KviKvsVariant();
330
bDeleteRetVal = true;
333
KviKvsRunTimeContext ctx(this,pWnd,pParams,pRetVal,pExtData);
335
if(iRunFlags & Quiet)
336
ctx.disableReporting();
338
int iRunStatus = executeInternal(&ctx);
340
// don't forget to delete the params