1 //=============================================================================
2 //
3 //   File : KviKvsParameterProcessor.cpp
4 //   Creation date : Sun 17 Apr 2005 16:47:09 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 
25 #include "KviKvsParameterProcessor.h"
26 #include "KviKvsVariantList.h"
27 #include "KviKvsRunTimeContext.h"
28 #include "KviKvsArray.h"
29 #include "KviKvsArrayCast.h"
30 #include "KviKvsHash.h"
31 #include "KviKvsObject.h"
32 #include "KviQString.h"
33 #include "KviLocale.h"
34 #include "KviPointerList.h"
35 
36 #include <QStringList>
37 
38 namespace KviKvsParameterProcessor
39 {
setDefaultValue(KviKvsParameterProcessor::ParameterFormat * pFmtArray)40 	void setDefaultValue(KviKvsParameterProcessor::ParameterFormat * pFmtArray)
41 	{
42 		switch(pFmtArray->uType)
43 		{
44 			case KVS_PT_STRING:
45 			case KVS_PT_NONEMPTYSTRING:
46 				*((QString *)(pFmtArray->pContainer)) = QString();
47 				break;
48 			case KVS_PT_INT:
49 				*((kvs_int_t *)(pFmtArray->pContainer)) = 0;
50 				break;
51 			case KVS_PT_UINT:
52 				*((kvs_uint_t *)(pFmtArray->pContainer)) = 0;
53 				break;
54 			case KVS_PT_DOUBLE:
55 				*((kvs_real_t *)(pFmtArray->pContainer)) = 0.0;
56 				break;
57 			case KVS_PT_BOOL:
58 				*((bool *)(pFmtArray->pContainer)) = false;
59 				break;
60 			case KVS_PT_HASH:
61 				*((KviKvsHash **)(pFmtArray->pContainer)) = nullptr;
62 				break;
63 			case KVS_PT_ARRAY:
64 				*((KviKvsArray **)(pFmtArray->pContainer)) = nullptr;
65 				break;
66 			case KVS_PT_ARRAYCAST:
67 				((KviKvsArrayCast *)(pFmtArray->pContainer))->clear();
68 				break;
69 			case KVS_PT_VARIANT:
70 				*((KviKvsVariant **)(pFmtArray->pContainer)) = nullptr;
71 				break;
72 			case KVS_PT_CSTRING:
73 			case KVS_PT_NONEMPTYCSTRING:
74 				*((QByteArray *)(pFmtArray->pContainer)) = nullptr;
75 				break;
76 			case KVS_PT_STRINGLIST:
77 				((QStringList *)(pFmtArray->pContainer))->clear();
78 				break;
79 			case KVS_PT_VARIANTLIST:
80 				((KviKvsVariantList *)(pFmtArray->pContainer))->clear();
81 				((KviKvsVariantList *)(pFmtArray->pContainer))->setAutoDelete(false);
82 				break;
83 			case KVS_PT_HOBJECT:
84 				*((kvs_hobject_t *)(pFmtArray->pContainer)) = (kvs_hobject_t) nullptr;
85 				break;
86 			case KVS_PT_IGNORE:
87 				// ignore :)
88 				break;
89 			default:
90 				qDebug("Internal error in KviKvsParameterProcessor::setDefaultValue(): unknown parameter type %d", pFmtArray->uType);
91 				break;
92 		}
93 	}
94 
handleParameterTypeError(KviKvsRunTimeContext * pContext,KviKvsParameterProcessor::ParameterFormat * pFmtArray,KviKvsVariant * v,const char * szExpectedType)95 	bool handleParameterTypeError(KviKvsRunTimeContext * pContext, KviKvsParameterProcessor::ParameterFormat * pFmtArray, KviKvsVariant * v, const char * szExpectedType)
96 	{
97 		if(pFmtArray->uFlags & KVS_PF_OPTIONAL)
98 		{
99 			if(v->isEmpty())
100 			{
101 				setDefaultValue(pFmtArray);
102 				return true; // empty optional
103 			}
104 		}
105 
106 		QString szError = QString(__tr2qs_ctx("Invalid data type for parameter \"%1\"", "kvs")).arg(pFmtArray->szName);
107 		szError += ": ";
108 
109 		if(v->isString())
110 		{
111 			QString tmp = v->string();
112 			if(tmp.isEmpty())
113 			{
114 				KviQString::appendFormatted(szError, __tr2qs_ctx("found empty string where type '%s' was expected", "kvs"), &tmp, szExpectedType);
115 			}
116 			else
117 			{
118 				if(tmp.length() > 15)
119 				{
120 					tmp.truncate(15);
121 					tmp.append("...");
122 				}
123 				KviQString::appendFormatted(szError, __tr2qs_ctx("found string value \"%Q\" where type '%s' was expected", "kvs"), &tmp, szExpectedType);
124 			}
125 		}
126 		else
127 		{
128 			QString tmp;
129 			v->getTypeName(tmp);
130 			KviQString::appendFormatted(szError, __tr2qs_ctx("found type %Q where type '%s' was expected", "kvs"), &tmp, szExpectedType);
131 		}
132 		pContext->error(szError);
133 		return false;
134 	}
135 
process(KviKvsVariantList * pVariantList,KviKvsRunTimeContext * pContext,KviKvsParameterProcessor::ParameterFormat * pFmtArray)136 	bool process(KviKvsVariantList * pVariantList, KviKvsRunTimeContext * pContext, KviKvsParameterProcessor::ParameterFormat * pFmtArray)
137 	{
138 		KviKvsVariant * v = pVariantList->first();
139 
140 		while(pFmtArray->szName)
141 		{
142 			if(!v)
143 			{
144 				// parameter not present
145 				// it MUST be optional
146 				if(!(pFmtArray->uFlags & KVS_PF_OPTIONAL))
147 				{
148 					// bad luck
149 					QString szError = QString(__tr2qs_ctx("Missing non-optional parameter \"%1\"", "kvs")).arg(pFmtArray->szName);
150 					pContext->error(szError);
151 					return false;
152 				}
153 				// ok, missing but optional (all the following are implicitly optional too)
154 				// set to default values
155 				do
156 				{
157 					setDefaultValue(pFmtArray);
158 					pFmtArray++;
159 				} while(pFmtArray->szName);
160 				return true;
161 			}
162 			// here we do only "light" casts: hard ones must be done explicitly by the user
163 			switch(pFmtArray->uType)
164 			{
165 				case KVS_PT_STRING:
166 					v->asString(*((QString *)(pFmtArray->pContainer)));
167 					if(pFmtArray->uFlags & KVS_PF_APPENDREMAINING)
168 					{
169 						v = pVariantList->next();
170 						while(v)
171 						{
172 							*((QString *)(pFmtArray->pContainer)) += QChar(' ');
173 							v->appendAsString(*((QString *)(pFmtArray->pContainer)));
174 							v = pVariantList->next();
175 						}
176 						return true;
177 					}
178 					break;
179 				case KVS_PT_STRINGLIST:
180 				{
181 					((QStringList *)(pFmtArray->pContainer))->clear();
182 					QString pSz;
183 					v->asString(pSz);
184 					((QStringList *)(pFmtArray->pContainer))->append(pSz);
185 					v = pVariantList->next();
186 					while(v)
187 					{
188 						v->asString(pSz);
189 						((QStringList *)(pFmtArray->pContainer))->append(pSz);
190 						v = pVariantList->next();
191 					}
192 					return true;
193 				}
194 				break;
195 				case KVS_PT_VARIANTLIST:
196 				{
197 					((KviKvsVariantList *)(pFmtArray->pContainer))->clear();
198 					((KviKvsVariantList *)(pFmtArray->pContainer))->setAutoDelete(false);
199 					((KviKvsVariantList *)(pFmtArray->pContainer))->append(v);
200 					v = pVariantList->next();
201 					while(v)
202 					{
203 						((KviKvsVariantList *)(pFmtArray->pContainer))->append(v);
204 						v = pVariantList->next();
205 					}
206 					return true;
207 				}
208 				break;
209 				case KVS_PT_NONEMPTYSTRING:
210 				{
211 					v->asString(*((QString *)(pFmtArray->pContainer)));
212 					bool bDoReturn = false;
213 					if(pFmtArray->uFlags & KVS_PF_APPENDREMAINING)
214 					{
215 						v = pVariantList->next();
216 						while(v)
217 						{
218 							*((QString *)(pFmtArray->pContainer)) += QChar(' ');
219 							v->appendAsString(*((QString *)(pFmtArray->pContainer)));
220 							v = pVariantList->next();
221 						}
222 						bDoReturn = true;
223 					}
224 					if(((QString *)(pFmtArray->pContainer))->isEmpty())
225 					{
226 						QString szError = QString(__tr2qs_ctx("Invalid data type for parameter \"%1\": found empty string while a non empty one was expected", "kvs")).arg(pFmtArray->szName);
227 						pContext->error(szError);
228 						return false;
229 					}
230 					if(bDoReturn)
231 						return true;
232 				}
233 				break;
234 				case KVS_PT_CSTRING:
235 				{
236 					QString tmp;
237 					v->asString(tmp);
238 					if(pFmtArray->uFlags & KVS_PF_APPENDREMAINING)
239 					{
240 						v = pVariantList->next();
241 						while(v)
242 						{
243 							*((QByteArray *)(pFmtArray->pContainer)) += ' ';
244 							v->appendAsString(tmp);
245 							v = pVariantList->next();
246 						}
247 						*((QByteArray *)(pFmtArray->pContainer)) = tmp.toUtf8();
248 						return true;
249 					}
250 					*((QByteArray *)(pFmtArray->pContainer)) = tmp.toUtf8();
251 				}
252 				break;
253 				case KVS_PT_NONEMPTYCSTRING:
254 				{
255 					QString tmp;
256 					v->asString(tmp);
257 					bool bDoReturn = false;
258 					if(pFmtArray->uFlags & KVS_PF_APPENDREMAINING)
259 					{
260 						v = pVariantList->next();
261 						while(v)
262 						{
263 							*((QByteArray *)(pFmtArray->pContainer)) += ' ';
264 							v->appendAsString(tmp);
265 							v = pVariantList->next();
266 						}
267 						*((QByteArray *)(pFmtArray->pContainer)) = tmp.toUtf8();
268 						bDoReturn = true;
269 					}
270 					*((QByteArray *)(pFmtArray->pContainer)) = tmp.toUtf8();
271 					if(((QByteArray *)(pFmtArray->pContainer))->isEmpty())
272 					{
273 						QString szError = QString(__tr2qs_ctx("Invalid data type for parameter \"%1\": found empty string while a non empty one was expected", "kvs")).arg(pFmtArray->szName);
274 						pContext->error(szError);
275 						return false;
276 					}
277 					if(bDoReturn)
278 						return true;
279 				}
280 				break;
281 				case KVS_PT_INT:
282 					if(!v->asInteger(*((kvs_int_t *)(pFmtArray->pContainer))))
283 					{
284 						if(!handleParameterTypeError(pContext, pFmtArray, v, "integer"))
285 							return false;
286 					}
287 					break;
288 				case KVS_PT_UINT:
289 				{
290 					kvs_int_t iTmp;
291 					if(!v->asInteger(iTmp))
292 					{
293 						if(!handleParameterTypeError(pContext, pFmtArray, v, "unsigned integer"))
294 							return false;
295 					}
296 					if(iTmp < 0)
297 					{
298 						QString szError = QString(__tr2qs_ctx("Invalid data type for parameter \"%1\": found signed integer \"%2\" where type 'unsigned integer' was expected", "kvs")).arg(pFmtArray->szName).arg(iTmp);
299 						pContext->error(szError);
300 						return false;
301 					}
302 					*((kvs_uint_t *)(pFmtArray->pContainer)) = (kvs_uint_t)iTmp;
303 				}
304 				break;
305 				case KVS_PT_DOUBLE:
306 					if(!v->asReal(*((kvs_real_t *)(pFmtArray->pContainer))))
307 					{
308 						if(!handleParameterTypeError(pContext, pFmtArray, v, "real"))
309 							return false;
310 					}
311 					break;
312 				case KVS_PT_HASH:
313 					if(!v->isHash())
314 					{
315 						if(!handleParameterTypeError(pContext, pFmtArray, v, "hash"))
316 							return false;
317 					}
318 					else
319 					{
320 						*((KviKvsHash **)(pFmtArray->pContainer)) = v->hash();
321 					}
322 					break;
323 				case KVS_PT_ARRAYCAST:
324 					v->castToArray((KviKvsArrayCast *)(pFmtArray->pContainer));
325 					break;
326 				case KVS_PT_ARRAY:
327 					if(!v->isArray())
328 					{
329 						if(!handleParameterTypeError(pContext, pFmtArray, v, "array"))
330 							return false;
331 					}
332 					else
333 					{
334 						*((KviKvsArray **)(pFmtArray->pContainer)) = v->array();
335 					}
336 					break;
337 				case KVS_PT_BOOL:
338 					// this never fails: anything is converted to a boolean
339 					*((bool *)(pFmtArray->pContainer)) = v->asBoolean();
340 					break;
341 				case KVS_PT_VARIANT:
342 					*((KviKvsVariant **)(pFmtArray->pContainer)) = v;
343 					break;
344 				case KVS_PT_HOBJECT:
345 					if(!v->asHObject(*((kvs_hobject_t *)(pFmtArray->pContainer))))
346 					{
347 						if(!handleParameterTypeError(pContext, pFmtArray, v, "hobject"))
348 							return false;
349 					}
350 					break;
351 				case KVS_PT_IGNORE:
352 					// ignore
353 					break;
354 				default:
355 					qDebug("Internal error in KviKvsParameterProcessor::processAsParameters(): unknown parameter type %d", pFmtArray->uType);
356 					return false;
357 					break;
358 			}
359 			pFmtArray++;
360 			v = pVariantList->next();
361 		}
362 		return true;
363 	}
364 };
365