1 //=============================================================================
2 //
3 // File : KviKvsTreeNodeSpecialCommandClass.cpp
4 // Creation date : Fri 12 Aug 2005 03:23:31 by Szymon Stefanek
5 //
6 // This file is part of the KVIrc IRC Client distribution
7 // Copyright (C) 2005-2010 Szymon Stefanek <pragma at kvirc dot net>
8 //
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 option) any later version.
13 //
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.
18 //
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.
22 //
23 //=============================================================================
24 #include "KviLocale.h"
25 #include "KviKvsVariantList.h"
26 #include "KviKvsVariant.h"
27 #include "KviKvsTreeNodeSpecialCommandClass.h"
28 #include "KviKvsKernel.h"
29 #include "KviKvsObjectController.h"
30 #include "KviKvsObjectClass.h"
31
KviKvsTreeNodeSpecialCommandClassFunctionDefinition(const QChar * pLocation,const QString & szName,const QString & szBuffer,const QString & szReminder,unsigned int uHandlerFlags)32 KviKvsTreeNodeSpecialCommandClassFunctionDefinition::KviKvsTreeNodeSpecialCommandClassFunctionDefinition(const QChar * pLocation, const QString & szName, const QString & szBuffer, const QString & szReminder, unsigned int uHandlerFlags)
33 : KviKvsTreeNode(pLocation)
34 {
35 m_uHandlerFlags = uHandlerFlags;
36 m_szName = szName;
37 m_szReminder = szReminder;
38 m_szBuffer = szBuffer;
39 }
40
dump(const char * prefix)41 void KviKvsTreeNodeSpecialCommandClassFunctionDefinition::dump(const char * prefix)
42 {
43 qDebug("%s SpecialCommandClassFunctionDefinition(%s)", prefix, m_szName.toUtf8().data());
44 qDebug("%s (command buffer with %d characters)", prefix, m_szBuffer.length());
45 }
46
contextDescription(QString & szBuffer)47 void KviKvsTreeNodeSpecialCommandClassFunctionDefinition::contextDescription(QString & szBuffer)
48 {
49 szBuffer = QString("Object Member Function Definition '%1'").arg(m_szName);
50 }
51
KviKvsTreeNodeSpecialCommandClass(const QChar * pLocation,KviKvsTreeNodeDataList * pParams)52 KviKvsTreeNodeSpecialCommandClass::KviKvsTreeNodeSpecialCommandClass(const QChar * pLocation, KviKvsTreeNodeDataList * pParams)
53 : KviKvsTreeNodeSpecialCommand(pLocation, "class")
54 {
55 m_pParams = pParams;
56 m_pParams->setParent(this);
57 m_pFunctions = new KviPointerList<KviKvsTreeNodeSpecialCommandClassFunctionDefinition>;
58 m_pFunctions->setAutoDelete(true);
59 }
60
~KviKvsTreeNodeSpecialCommandClass()61 KviKvsTreeNodeSpecialCommandClass::~KviKvsTreeNodeSpecialCommandClass()
62 {
63 delete m_pParams;
64 delete m_pFunctions;
65 }
66
addFunctionDefinition(KviKvsTreeNodeSpecialCommandClassFunctionDefinition * pDef)67 void KviKvsTreeNodeSpecialCommandClass::addFunctionDefinition(KviKvsTreeNodeSpecialCommandClassFunctionDefinition * pDef)
68 {
69 pDef->setParent(this);
70 m_pFunctions->append(pDef);
71 }
72
contextDescription(QString & szBuffer)73 void KviKvsTreeNodeSpecialCommandClass::contextDescription(QString & szBuffer)
74 {
75 szBuffer = "Special Command 'class'";
76 }
77
dump(const char * prefix)78 void KviKvsTreeNodeSpecialCommandClass::dump(const char * prefix)
79 {
80 qDebug("%s SpecialCommandClass", prefix);
81 QString tmp = prefix;
82 tmp.append(" ");
83 m_pParams->dump(tmp.toUtf8().data());
84 for(KviKvsTreeNodeSpecialCommandClassFunctionDefinition * d = m_pFunctions->first(); d; d = m_pFunctions->next())
85 d->dump(tmp.toUtf8().data());
86 }
87
execute(KviKvsRunTimeContext * c)88 bool KviKvsTreeNodeSpecialCommandClass::execute(KviKvsRunTimeContext * c)
89 {
90 KviKvsVariantList l;
91 if(!m_pParams->evaluate(c, &l))
92 return false;
93
94 KviKvsVariant * pClassName = l.first();
95 if(!pClassName)
96 {
97 c->error(this, __tr2qs_ctx("Missing class name", "kvs"));
98 return false;
99 }
100
101 KviKvsVariant * pBaseClassName = l.next();
102
103 QString szClassName;
104 QString szBaseClassName;
105 pClassName->asString(szClassName);
106 QRegExp re("[\\w:]+");
107 if(!re.exactMatch(szClassName))
108 {
109 c->error(this, __tr2qs_ctx("Class names can contain only letters, digits, underscores and '::' namespace separators", "kvs"));
110 return false;
111 }
112 if(pBaseClassName)
113 pBaseClassName->asString(szBaseClassName);
114
115 if(szClassName.isEmpty())
116 {
117 c->error(this, __tr2qs_ctx("Missing class name", "kvs"));
118 return false;
119 }
120
121 if(szBaseClassName.isEmpty())
122 szBaseClassName = "object";
123
124 // avoid infinite recursion in loading the base class
125 if(KviQString::equalCI(szBaseClassName, szClassName))
126 {
127 c->error(__tr2qs_ctx("A class can't be a subclass of itself", "kvs"));
128 return false;
129 }
130
131 KviKvsObjectClass * pBaseClass = KviKvsKernel::instance()->objectController()->lookupClass(szBaseClassName);
132 if(!pBaseClass)
133 {
134 c->error(this, __tr2qs_ctx("Couln't find base class named '%Q'", "kvs"), &szBaseClassName);
135 return false;
136 }
137
138 // walk the inheritance tree of the base class in order to detect loops
139 KviKvsObjectClass * pClass = pBaseClass;
140 while(pClass)
141 {
142 if(KviQString::equalCI(pClass->name(), szClassName))
143 {
144 c->error(this, __tr2qs_ctx("Detected a loop in the inheritance tree of the base class '%Q': redefine that class first", "kvs"), &szBaseClassName);
145 return false;
146 }
147 pClass = pClass->parentClass();
148 }
149
150 KviKvsObjectClass * pActualClass = KviKvsKernel::instance()->objectController()->lookupClass(szClassName, true);
151 if(pActualClass)
152 {
153 c->error(this, __tr2qs_ctx("Can't override the builtin class '%Q'", "kvs"), &szClassName);
154 return false;
155 }
156 pActualClass = new KviKvsObjectClass(pBaseClass, szClassName, nullptr, false);
157
158 for(KviKvsTreeNodeSpecialCommandClassFunctionDefinition * d = m_pFunctions->first(); d; d = m_pFunctions->next())
159 {
160 pActualClass->registerFunctionHandler(d->name(), d->buffer(), d->reminder(), d->handlerFlags());
161 }
162 return true;
163 }
164