1 //=============================================================================
2 //
3 //   File : KviKvsParser.cpp
4 //   Creation date : Thu 25 Sep 2003 05.12 CEST by Szymon Stefanek
5 //
6 //   This file is part of the KVIrc IRC client distribution
7 //   Copyright (C) 2003-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 "KviKvsParser.h"
26 #include "KviKvsTreeNode.h"
27 #include "KviKvsReport.h"
28 #include "KviKvsKernel.h"
29 #include "KviKvsScript.h"
30 #include "KviKvsParserMacros.h"
31 #include "KviLocale.h"
32 #include "KviOptions.h"
33 
34 //FIXME: @ == $$-> == $this->
35 
KviKvsParser(KviKvsScript * pScript,KviWindow * pOutputWindow)36 KviKvsParser::KviKvsParser(KviKvsScript * pScript, KviWindow * pOutputWindow)
37 {
38 	m_pGlobals = nullptr;
39 	m_pScript = pScript;
40 	m_pWindow = pOutputWindow;
41 }
42 
~KviKvsParser()43 KviKvsParser::~KviKvsParser()
44 {
45 	if(m_pGlobals)
46 		delete m_pGlobals;
47 }
48 
init()49 void KviKvsParser::init()
50 {
51 	KviKvsKernel * pKern = KviKvsKernel::instance();
52 
53 #define _REG_CNTRL_CMD(__cntrlCmdName, __parsingRoutine)                                 \
54 	{                                                                                    \
55 		KviKvsSpecialCommandParsingRoutine * r = new KviKvsSpecialCommandParsingRoutine; \
56 		r->proc = KVI_PTR2MEMBER(KviKvsParser::__parsingRoutine);                        \
57 		pKern->registerSpecialCommandParsingRoutine(QString(__cntrlCmdName), r);         \
58 	}
59 
60 	_REG_CNTRL_CMD("break", parseSpecialCommandBreak);
61 	_REG_CNTRL_CMD("class", parseSpecialCommandClass);
62 	_REG_CNTRL_CMD("continue", parseSpecialCommandContinue);
63 	_REG_CNTRL_CMD("defpopup", parseSpecialCommandDefpopup);
64 	_REG_CNTRL_CMD("do", parseSpecialCommandDo);
65 	_REG_CNTRL_CMD("for", parseSpecialCommandFor);
66 	_REG_CNTRL_CMD("foreach", parseSpecialCommandForeach);
67 	_REG_CNTRL_CMD("global", parseSpecialCommandGlobal);
68 	_REG_CNTRL_CMD("help", parseSpecialCommandHelp);
69 	_REG_CNTRL_CMD("if", parseSpecialCommandIf);
70 	_REG_CNTRL_CMD("switch", parseSpecialCommandSwitch);
71 	_REG_CNTRL_CMD("unset", parseSpecialCommandUnset);
72 	_REG_CNTRL_CMD("while", parseSpecialCommandWhile);
73 #undef _REG_CNTRL_CMD
74 }
75 
report(bool bError,const QChar * pLocation,const QString & szMsgFmt,kvi_va_list va)76 void KviKvsParser::report(bool bError, const QChar * pLocation, const QString & szMsgFmt, kvi_va_list va)
77 {
78 	QString szMsg;
79 	KviQString::vsprintf(szMsg, szMsgFmt, va);
80 
81 	KviPointerList<QString> * pCodeListing = nullptr;
82 	QString szLocation;
83 
84 	if(pLocation)
85 	{
86 		pCodeListing = new KviPointerList<QString>;
87 		pCodeListing->setAutoDelete(true);
88 
89 		int iLine, iCol;
90 
91 		KviKvsReport::findLineColAndListing(m_pBuffer, pLocation, iLine, iCol, pCodeListing);
92 
93 		szLocation = QString(__tr2qs_ctx("line %1, near character %2", "kvs")).arg(iLine).arg(iCol);
94 	}
95 	else
96 	{
97 		szLocation = __tr2qs_ctx("beginning of input", "kvs");
98 	}
99 
100 	KviKvsReport rep(bError ? KviKvsReport::ParserError : KviKvsReport::ParserWarning, m_pScript->name(), szMsg, szLocation, m_pWindow);
101 	if(pCodeListing)
102 		rep.setCodeListing(pCodeListing);
103 
104 	KviKvsReport::report(&rep, m_pWindow);
105 }
106 
errorBadChar(const QChar * pLocation,char cExpected,const char * szCommandName)107 void KviKvsParser::errorBadChar(const QChar * pLocation, char cExpected, const char * szCommandName)
108 {
109 	if(pLocation->unicode())
110 		error(pLocation, __tr2qs_ctx("Found character '%q' (Unicode 0x%x) where '%c' was expected: see \"/help %s\" for the command syntax", "kvs"),
111 		    pLocation, pLocation->unicode(), cExpected, szCommandName);
112 	else
113 		error(pLocation, __tr2qs_ctx("Found end of input where character '%c' was expected: see \"/help %s\" for the command syntax", "kvs"),
114 		    cExpected, szCommandName);
115 }
116 
error(const QChar * pLocation,QString szMsgFmt,...)117 void KviKvsParser::error(const QChar * pLocation, QString szMsgFmt, ...)
118 {
119 	m_bError = true;
120 
121 	kvi_va_list va;
122 	kvi_va_start(va, szMsgFmt);
123 	report(true, pLocation, szMsgFmt, va);
124 	kvi_va_end(va);
125 }
126 
warning(const QChar * pLocation,QString szMsgFmt,...)127 void KviKvsParser::warning(const QChar * pLocation, QString szMsgFmt, ...)
128 {
129 	kvi_va_list va;
130 	kvi_va_start(va, szMsgFmt);
131 	report(false, pLocation, szMsgFmt, va);
132 	kvi_va_end(va);
133 }
134 
parse(const QChar * pBuffer,int iFlags)135 KviKvsTreeNodeInstruction * KviKvsParser::parse(const QChar * pBuffer, int iFlags)
136 {
137 	m_iFlags = iFlags;
138 
139 	m_bError = false;
140 	if(m_pGlobals)
141 		m_pGlobals->clear(); // this shouldn't be needed since this is a one time parser
142 
143 	m_pBuffer = pBuffer;
144 	m_ptr = pBuffer;
145 
146 	if(!pBuffer)
147 	{
148 		error(nullptr, __tr2qs_ctx("Empty script", "kvs"));
149 		return nullptr;
150 	}
151 	return parseInstructionList();
152 }
153 
parseAsExpression(const QChar * pBuffer,int iFlags)154 KviKvsTreeNodeInstruction * KviKvsParser::parseAsExpression(const QChar * pBuffer, int iFlags)
155 {
156 	m_iFlags = iFlags;
157 
158 	m_bError = false;
159 	if(m_pGlobals)
160 		m_pGlobals->clear(); // this shouldn't be needed since this is a one time parser
161 
162 	m_pBuffer = pBuffer;
163 	m_ptr = pBuffer;
164 
165 	if(!pBuffer)
166 	{
167 		error(nullptr, __tr2qs_ctx("Empty script", "kvs"));
168 		return nullptr;
169 	}
170 
171 	KviKvsTreeNodeExpression * expr = parseExpression(0);
172 	if(!expr)
173 		return nullptr;
174 	return new KviKvsTreeNodeExpressionReturn(pBuffer, expr);
175 }
176 
parseAsParameter(const QChar * pBuffer,int iFlags)177 KviKvsTreeNodeInstruction * KviKvsParser::parseAsParameter(const QChar * pBuffer, int iFlags)
178 {
179 	m_iFlags = iFlags;
180 
181 	m_bError = false;
182 	if(m_pGlobals)
183 		m_pGlobals->clear(); // this shouldn't be needed since this is a one time parser
184 
185 	m_pBuffer = pBuffer;
186 	m_ptr = pBuffer;
187 
188 	if(!pBuffer)
189 	{
190 		error(nullptr, __tr2qs_ctx("Empty script", "kvs"));
191 		return nullptr;
192 	}
193 
194 	KviKvsTreeNodeDataList * l = parseCommandParameterList();
195 	if(!l)
196 		return nullptr;
197 
198 	return new KviKvsTreeNodeParameterReturn(pBuffer, l);
199 }
200 
201 //
202 // THE REAL KVS
203 //
204 // <script> ::= <instruction list> '\0'
205 //
206 // <instruction list> ::= <instruction> [ <instruction list> ]
207 // <instruction> ::= <instruction block> | <command> | <operation> | <comment>
208 // <instruction block> ::= '{' <instruction list> '}'
209 //
210 // <comment> ::= <bash style line comment> | <c++ style comment> | <c style comment>
211 // <bash style comment> ::='#' <any char not including newline or null> <newline or null>
212 // <c++ style comment> ::= '//' <any char not including newline or null> <newline or null>
213 // <c style comment> ::= '/*' <any char not including null or the sequence */> '*/'
214 //
215 // <command> ::= <simple command> | <callback command> | <control command>
216 // <simple command> ::= <core command> | <module command> | <alias command>
217 // <core command> ::= <command identifier> <switch list> <command parameter list> <command terminator>
218 // <switch list> ::= '-'<switch body> [<switch list>]
219 // <command parameter list> ::= <command parameter>[<space><command parameter>]
220 // <command parameter> ::= <command parameter part>[<command parameter>]
221 // <command parameter part> ::= <command literal parameter> | <string parameter> | <data evaluation>
222 // <command literal parameter> ::= <anything except space, null, newline, ;, ", $ or %>
223 // <string parameter> ::= '"'<string parameter body>'"'
224 // <string parameter body> ::= <anything except '"' or null>...
225 // <command terminator> ::= ';' | '\n' | '\0'
226 //
227 
228 //
229 // <data> ::=
230 // <data_reference> ::= <function_call> | <structured_data>
231 // <structured_data> ::= <data_structure> | <variable> | <pointer_data>
232 // <data_structure> ::= <array> | <hash>
233 // <array> ::= '%'<identifier>'[]'
234 // <hash> ::= '%'<identifier>'{}'
235 // <variable> ::= '%'<identifier> | <array_element> | <hash_element>
236 // <array_element> ::= '%'<identifier>'['<expression>']'
237 // <hash_element> ::= '%'<identifier>'{'<key>'}'
238 // <function_call> ::= <simple_function_call> | <pointer_function_call>
239 // <simple_function_call> ::= '$'<identifier>'('<function_parameter_list>')'
240 // <pointer_function_call> ::= <variable>'->'<function_call> | <simple_function_call>'->'<function_call>
241 // <pointer_data> ::= <variable>'->'<data>' | <simple_function_call>'->'<data>
242 //
243 
244 //
245 // This must evaluate SCOPE OBJECT operators!
246 // thus...first evaluate the <data> or <simple_function_call>
247 // If it was <simple_function_call> or <data> evaluation results in returning a <variable>
248 // then check if there is a scope operator
249 // if there is then take it as the top of the tree, the <variable> or <simple_function_call>
250 // go at the left param of the scope operator and re-evaluate the right side <data> or <simple_function_call>
251 //
252 //
253 
254 /*
255 	@doc: kvs_introduction
256 	@type:
257 		language
258 	@keyterms:
259 		kvs, compilation
260 	@title:
261 		KVIrc scripting language introduction
262 	@short:
263 		KVS scripting language introduction
264 	@body:
265 		[b]KVS[/b] is the [b]KV[/b]Irc [b]S[/b]cripting language.
266 		It was inspired by C++, sh, Perl, PHP and mIRC scripting language implementations.
267 		It is a compromise between flexibility and speed, a [i]workaround[/i] for many intrinsic
268 		problems of an IRC-oriented scripting language.
269 		[br]
270 		KVS is semi-interpreted: the execution is done in two main stages.
271 		The first stage is the compilation where a syntactic tree is built.
272 		The second stage is the real execution and is performed by visiting the tree
273 		in the proper order. The syntactic trees are cached in memory so
274 		the next executions can jump directly into the second stage.
275 		This two-stage approach has been introduced in version 3.0.0, the previous
276 		versions of the language used a single-stage on-the-fly interpreter.
277 		[br]
278 		KVS allows you to:
279 		[ul]
280 		[li]Implement automated reactions to the events generated by an IRC network[/li]
281 		[li]Add new complex commands[/li]
282 		[li]Add interface elements like popups, toolbars, buttons...[/li]
283 		[li]Add advanced interface elements like complete dialogs or even widgets integrated in KVIrc[/li]
284 		[/ul]
285 		KVS contains all the common constructs of structured programming.
286 		You will find almost all the C control commands, sh/Perl-like variables, arrays and and functions.
287 		There are also some object-oriented characteristics: you will find C++ like
288 		objects with constructors, destructors and class inheritance.
289 		There are also more exotic concepts like the signal-slots inter-object communication.
290 		Obviously you will also find most of the RFC1459 IRC commands and
291 		other tools to [i]play[/i] with an IRC connection.[br]
292 		I'll try to explain the language by using examples instead of strict syntactic rules.[br]
293 		I have even tried to write the rules... take a look [doc:syntactic_rules]here[/doc][br][br]
294 		And please... forgive me for my [i]fantastic[/i] English :)
295 		Szymon Stefanek
296 */
297 
298 /*
299 	@doc: kvs_basicconcepts
300 	@type:
301 		language
302 	@keyterms:
303 		script
304 	@title:
305 		KVS basic concepts
306 	@short:
307 		KVS basic concepts
308 	@body:
309 		[big]Scripts[/big]
310 		You use KVS to implement [b]scripts[/b].
311 		A script is basically a finite list of KVS instructions.
312 		When you type a command in the KVIrc input window you in fact
313 		execute a small one-line script. You can store
314 		longer scripts in KVIrc memory and execute them at later time.
315 		Scripts can be also read from external files by the means of the
316 		[cmd]parse[/cmd] command.
317 		[br]
318 		There is an issue with the word [i]script[/i] that is worth clearing here.
319 		It is common usage to call [i]script[/i] a thing that is something more
320 		that a finite list of (some scripting language) instructions.
321 		In fact a set of scripts, documentation files, graphics or other multimedia
322 		files and sometimes executable binaries is still called a [i]script[/i]... just like
323 		the [i]PrincoScript[/i] or [i]dynamirc[/i] (tough this last one should be categorized as [i]malware[/i] instead).
324 		In KVIrc such a collection of items is called [i]addon[/i], but be prepared
325 		for both usages of the word in this documentation and around the web.[br]
326 		[doc:kvs_addons]Learn more about KVS addons[/doc].
327 		[big]Hello world![/big]
328 		This documentation contains a lot of script examples.
329 		They will appear like the following block of code:
330 		[example]
331 			[cmd]echo[/cmd] Hello world!
332 		[/example]
333 		The best way to experiment is to execute the scripts from an external file.
334 		Try to copy & paste the example above to a file and save it in
335 		a known place. Then in the command input window type
336 		[example]
337 			[b]/[/b][cmd]parse[/cmd] <filename>
338 		[/example]
339 		where <filename> stands for the name of the file you just have saved.
340 		Some simple examples (like the one above) can be also typed
341 		directly in the command input window.
342 		You must remember that the command input window needs
343 		a leading slash ('/') character to recognize a script.
344 		The command input window can also be put in multi-line mode by clicking
345 		on the button on the right.
346 		Another alternative for testing scripts is the code tester window.
347 		You can access it by selecting [i]New code tester[/i] from the Scripting menu
348 		at the top of the KVIrc window. You will soon have the opportunity to
349 		experiment with all the methods. Read on.
350 		[big]Basic syntax[/big]
351 		A script contains a list of instructions separated by newlines or ';' characters.
352 		Placing an instruction per line does not require a terminating character,
353 		placing more instructions in a single line require them to be separated by ';'.
354 		The most common instructions in KVS are [b]commands[/b]. A command is basically
355 		a keyword followed by a list of space separator parameters.
356 		The simplest (and the most useful) command in KVS is [cmd]echo[/cmd]; it prints
357 		all its parameters to a KVIrc window.[br]
358 		The following is an example of a valid script that uses only [cmd]echo[/cmd] commands.
359 		[example]
360 			echo "This is the first line"
361 			ECHO This is the second line;
362 			echo "This is the third line"; echo This is still on the third line;
363 			eChO "This is the fourth line"; Echo "This is still on the fourth line"
364 		[/example]
365 		You have probably noticed that the terminating ';' character is optional
366 		when the command is the last in a line.
367 		The commands are [b]case insensitive[/b]; 'echo' is equivalent to 'Echo',
368 		to 'ECHO' and to 'eChO'. In fact, most of KVS is case insensitive.
369 		(There are obvious unavoidable exceptions for this rule; for example,
370 		on UNIX systems file names are case sensitive and this must be
371 		also reflected in KVS).
372 		Another interesting thing is that when you execute the script you
373 		don't see the enclosing quotes around the printed text: more about this
374 		in the following sections.
375 		[note]
376 		Cryptic note (you may skip it for now):[br]
377 		Yes, the command terminator is a problem for those that want to use ';)' at the end
378 		of IRC commands like [cmd]msg[/cmd]. It is almost unavoidable (read: the cost for
379 		avoiding it is too high). Note that using '|' or any other character as command terminator
380 		will [b]not[/b] solve the problem: if the terminator is too difficult to type it will annoy the
381 		scripters (and me), if it is too easy then there will be always someone that wants to use it
382 		at the end (or in the middle) of a command with the original meaning.
383 		The solution is to escape the [b];[/b] character:
384 		[example]
385 			[cmd]echo[/cmd] You can do it now \;)
386 		[/example]
387 		[/note]
388 		[big]Parameter processing[/big]
389 		Most of the commands accept (and sometimes require) a list of parameters.
390 		For example, the [cmd]join[/cmd] command (that is used to join an IRC channel)
391 		accepts two parameters: the first one is the channel to join and the second is
392 		the password. The simplified syntax for join is:
393 		[example]
394 			[cmd]join[/cmd] <channel> [password]
395 		[/example]
396 		The line above is an example of syntax specification. All the commands
397 		are described by such syntax lines. [cmd]join[/cmd] is the command and it stands exactly
398 		for the literal string [i]join[/i] typed in a script. <channel> is in angular parenthesis
399 		and represents a mandatory parameter: you must substitute a real channel name in its place
400 		otherwise the command will fail and KVIrc will probably complain too.
401 		[password] is still a parameter but the square parentheses indicate that it is
402 		optional: if you specify it, then it will be interpreted as the channel password,
403 		if you don't then no password will be used.
404 		[note]
405 		The syntax is written in a simplified BNF. I say simplified because it is not
406 		totally strict around the KVIrc documentation. I just prefer the syntax to be
407 		clear and easy to read instead of being formally perfect.
408 		[/note]
409 		You can finally join a channel by writing:
410 		[example]
411 			[cmd]join[/cmd] #kvirc kvircrocks
412 		[/example]
413 		or, since #kvirc usually has no password, by writing:
414 		[example]
415 			[cmd]join[/cmd] #kvirc
416 		[/example]
417 		In the example above the optional parameter [password] is omitted.
418 		[note]
419 		In fact it is not really omitted: KVIrc interprets it as an empty string that later
420 		means [i]do not send the password to the server[/i].
421 		Empty strings are equivalent to omitted ones.
422 		[/note]
423 		[big]Parameters, spaces and quotes[/big]
424 		From the examples above is obvious that KVS command parameters are separated by spaces.
425 		What is not totally obvious is that multiple spaces are allowed but KVIrc
426 		will automatically reduce them to exactly one (just like HTML parsers or the shell
427 		interpreters do). This is an useful behaviour in an IRC client since spaces usually
428 		carry no information and in text oriented protocols make the parsing really harder (:D).
429 		[br]
430 		The spaces are simplified in normal processing but there are ways to force KVIrc
431 		to interpret the spaces just as they are.
432 		The first method are the quotation marks: all the spaces enclosed in quotation marks
433 		will be preserved.
434 		[example]
435 			[cmd]echo[/cmd] This &nbsp; &nbsp; text &nbsp; &nbsp; will &nbsp; &nbsp; have &nbsp; &nbsp; spaces &nbsp; &nbsp; simplified
436 			[cmd]echo[/cmd] But &nbsp; &nbsp; "this &nbsp; &nbsp; &nbsp; one &nbsp; &nbsp; not"
437 		[/example]
438 		The first example will print out with spaces simplified but the second not.
439 		The quotes are also a nice trick to embed spaces into a single parameter that
440 		would be obviously split in two or more.
441 		[example]
442 			[cmd]echo[/cmd] Parameter1 Parameter2 "Parameter  3 ( with spaces )" Parameter4
443 		[/example]
444 		By running the examples above you may have noticed that the spaces are preserved but the
445 		quotes are then stripped! Yes, this is another tricky behaviour. But don't be afraid:
446 		it is really easier to use than to explain.
447 		There is obviously a method to preserve the quotes too and it is also another
448 		method to preserve the spaces but that leads us to the next paragraph.
449 		[big]Escape character[/big]
450 		You may have already noticed that KVS treats some characters in a special way.
451 		For example the double-quote characters can be used to enclose strings
452 		and are stripped by the parser.
453 		Another example of a special character is the command terminator (';'):
454 		it has the [i]special[/i] meaning of terminating a command.
455 		If you want to enclose a literal quote in your text, you need to [b]escape[/b] it.
456 		Like in most other programming languages, the escaping character is the backslash ('\').
457 		[example]
458 			[cmd]echo[/cmd] You can smile this way too! \;)
459 		[/example]
460 		The above example will treat the ';' as a part of the parameters and print it.[br]
461 		In some languages the action of [i]escaping[/i] a character is called [i]quoting[/i].
462 		Although there is some confusion in this term, the meaning is to either use quotes
463 		or to use the escape character to remove special meaning from some characters.
464 		By quoting the spaces you can include them in a parameter, by escaping the quotes
465 		you can include them in a command.
466 		[example]
467 			[cmd]echo[/cmd] "And he said \"Hello world!\""
468 		[/example]
469 		The example above will have the internal quotes preserved.
470 		You can use the escape backslash to escape a newline:
471 		[example]
472 			[cmd]echo[/cmd] This text will be \
473 			&nbsp; &nbsp; printed on a single line!
474 		[/example]
475 		After an escaped newline all the leading space and tab characters are skipped,
476 		so you must include the needed spaces [b]before[/b] the escape character.
477 		The previous example will be printed as:[br][br]
478 		[i]This text will be printed on a single line[/i][br]
479 		Another example:
480 		[example]
481 			[cmd]echo[/cmd] "The new KVIrc &nbsp; &nbsp; &nbsp \
482 			&nbsp; &nbsp; IS OUT!"
483 			[cmd]echo[/cmd] Check it out at http://www.kvi \
484 			&nbsp; &nbsp; rc.net!
485 		[/example]
486 		This will be printed as:[br][br]
487 		[i]
488 		The new KVIrc &nbsp; &nbsp; &nbsp; IS OUT![br]
489 		Check it out at http://www.kvirc.net!
490 		[/i][br]
491 		Finally, you can escape an escape character to include it literally in a parameter (and
492 		this is really the end of these tricks :)
493 		Later we will discover other common usages of the backslash escape, such
494 		as preventing KVIrc from interpreting a literal percent character as a variable
495 		or separating variable names from the text.
496 		[big]Command switches[/big]
497 		Many commands accept switch parameters.
498 		[b]A switch modifies the behaviour of a command.[/b]
499 		Any switch can optionally accept a parameter, that must
500 		be specified after an equal ('=') sign.
501 		[example]
502 			[cmd]echo[/cmd] [b]-i = 2[/b] This text uses a specific color scheme
503 		[/example]
504 		The -i switch (just for example) changes the attributes
505 		and the icon of the printed text.
506 		[b]The switch must be specified immediately after the command keyword.[/b]
507 		[example]
508 			[cmd]echo[/cmd] This -i = 2 will obviously not work...
509 		[/example]
510 		If you want to start the first parameter of a command (that is not a switch)
511 		with a literal '-' you must again escape it:
512 		[example]
513 			[cmd]echo[/cmd] \--- This text has three minus signs on the left
514 		[/example]
515 		or use the quotes:
516 		[example]
517 			[cmd]echo[/cmd] "--- This text has three minus signs on the left"
518 		[/example]
519 		[big]Command blocks[/big]
520 		Commands can be 'grouped' in blocks by using the classic C++ braces.
521 		Here is a single line example:
522 		[example]
523 			{ [cmd]echo[/cmd] First command; [cmd]echo[/cmd] Second command; } [cmd]echo[/cmd] Third command
524 		[/example]
525 		Multi line example:
526 		[example]
527 			{
528 			    [cmd]echo[/cmd] First command
529 				[cmd]echo[/cmd] Second command
530 			}
531 			[cmd]echo[/cmd] Third command
532 		[/example]
533 		[note]
534 		Reminder: copy the example above to a text file
535 		and then use /[cmd]parse[/cmd] &lt;filename&gt;
536 		[/note]
537 		In this case the command block has no special meaning
538 		other than making the code more readable, but command blocks
539 		will be useful later (see [cmd]if[/cmd],[cmd]while[/cmd]...).
540 		[note]
541 		Unlike in C or C++, the braces do [b]not[/b] automatically define a variable scope
542 		(with few exceptions to this rule ... just to complicate the things a bit more).
543 		You will recall this last assertion later, when reading about [doc:data_structures]data structures[/doc].
544 		[/note]
545 		[big]Comments[/big]
546 		[p]
547 		KVIrc supports comments in command sequences.[br]
548 		A comment starts with the character '#' and terminates with a newline.
549 		You can start a comment anywhere a command can start.
550 		[example]
551 			# This is a comment, it occupies the whole line
552 			[cmd]echo[/cmd] After the comment!; # This is an end-line comment
553 		[/example]
554 		You can't escape newline characters in this case.
555 		(or better: escape characters have no meaning in comments...
556 		maybe one day I'll implement it).[br]
557 		Starting from version 3.0.0, KVIrc supports also C++ single line and C multi-line comments.[br]
558 		A C++ comment starts with two slashes [b]//[/b] and terminates with a newline.
559 		A multi-line C comment starts with [b]/ *[/b] and ends at the first [b]* /[/b] encountered.
560 		Since KVIrc has no pre-processor, the C/C++ comments usually can't be placed in the middle of a command:
561 		they must start where a command would start and end before the begin of another command.
562 		[big]Indentation[/big]
563 		You [b]should[/b] use spaces or [b]tabs[/b] to [b]indent[/b] your code. Note that the [b]should[/b]
564 		word is written in bold characters: I mean that you really should indent your code.
565 		Indenting helps both you (the script writer) and the reader (any other user that will
566 		read your script). A good indenting practice is the first step to become a great programmer :)
567 		[note]
568 		Please note that the command parameters should be separated by
569 		space characters (ASCII 32). Tabs are not granted to work as parameter separators.[br]
570 		[/note]
571 		[example]
572 			{
573 				&lt;tab&gt;[cmd]echo[/cmd] Indented command
574 				&lt;tab&gt;{
575 				&lt;tab&gt;&lt;tab&gt;# Comment
576 				&lt;tab&gt;&lt;tab&gt;[cmd]echo[/cmd] Really Really long indented \
577 				&lt;tab&gt;&lt;tab&gt;&lt;tab&gt;command
578 				&lt;tab&gt;}
579 			}
580 		[/example]
581 		Tabs behave better than spaces as indentation characters since other users can
582 		adjust the tab size to match their taste. I personally prefer 4 character tabs
583 		while most text/code editors usually come with 8 characters as default.
584 		[big]And now?[/big]
585 		[br]
586 		You're now ready to really start experimenting with KVS. You can take
587 		a look at the [doc:commands]command index[/doc] and start trying to use them
588 		while keeping in mind the rules described in this document.
589 		The next suggested lecture is the documentation about [doc:kvs_aliasesandfunctions]the aliases and the functions[/doc].
590 		Have fun :)
591 		[br]
592 */
593 
594 /*
595 	@doc: kvs_aliasesandfunctions
596 	@type:
597 		language
598 	@keyterms:
599 		aliases, functions
600 	@title:
601 		KVS Functions and aliases
602 	@short:
603 		KVS Functions and aliases
604 	@body:
605 		[big]Introduction[/big]
606 		Since you're here, you should already have read about the [doc:kvs_basicconcepts]KVS basic concepts[/doc]
607 		and have visited the [doc:commands]command index[/doc]. If you feel ready to take the next step
608 		then read on.
609 		[big]Functions[/big]
610 		KVS has many internal [doc]functions[/doc] that can be used as command parameters.[br]
611 		[b]All the function names start with a literal [b]$[/b] character.[/b]
612 		[example]
613 			[cmd]echo[/cmd] This window caption is [fnc]$window.caption[/fnc]
614 		[/example]
615 		The [fnc]$window.caption[/fnc] [doc:functions]function[/doc]
616 		is evaluated before the command executes,
617 		and it is changed into the current window caption text.
618 		The [doc]functions[/doc] can be used also as switch parameters.
619 		[example]
620 			[cmd]echo[/cmd] -w = [fnc]$window[/fnc] This text will be surely \
621 			&nbsp; &nbsp; printed in the current window
622 		[/example]
623 		The -w switch allows to redirect the echo text to a specified window --- in this
624 		case the one that you are typing in.[br]
625 		[i](Surprise: in this case the -w switch is useless,
626 		since echo prints text to the current window by default...
627 		but it will work correctly. :)[/i]
628 		[br]
629 		Normal function names can be made of [i]anycase[/i] letters, digits and underscores,
630 		with the restriction that the first character is not a digit.[br]
631 		Some kind of functions can contain a dot ([b].[/b]) character inside the name
632 		and these are assumed to be module references (see [doc:modules]the modules documentation[/doc]).[br]
633 		By now we have seen only simple functions, but there's more...[br]
634 		The functions can accept parameters; the general syntax for a function call is:[br]
635 		[b]$<function name>['('<parameter_list>')'][/b][br]
636 		where <parameter_list> is a list of comma separated parameters,
637 		eventually empty.
638 		[example]
639 			[cmd]echo[/cmd] The word 'neural' is [fnc]$str.len[/fnc](neural) characters long
640 		[/example]
641 		The function [fnc]$str.len[/fnc] accepts a single parameter and returns the
642 		length in characters of the parameter string. The returned value is always
643 		a string: in this case it can be also interpreted as a number.[br]
644 		When passing an empty list you can avoid the parenthesis.
645 		(And you have found the [i]simple[/i] functions shown above).
646 		So the following two calls are equal:
647 		[example]
648 			[cmd]echo[/cmd] [fnc]$window.caption[/fnc]
649 			[cmd]echo[/cmd] [fnc]$window.caption()[/fnc]
650 		[/example]
651 		If you want to pass an [i]empty[/i] string as the first parameter you have to use
652 		the following syntax:
653 		[example]
654 			[cmd]echo[/cmd] [fnc]$str.len[/fnc]("")
655 		[/example]
656 		Obviously a function is valid as a function parameter.
657 		[example]
658 			[cmd]echo[/cmd] [fnc]$str.len[/fnc]([fnc]$window.caption[/fnc])
659 		[/example]
660 		If you want to place a literal '(' or ')' in the function parameters
661 		you must escape it.
662 		A special case for when you want to use 'matching' parentheses:
663 		an opened '(' corresponds to a closed ')'.
664 		In this case you can omit the 'escape' character.
665 		[example]
666 			[cmd]echo[/cmd] The length of '(a+b)' is : [fnc]$str.len[/fnc]( (a+b) )
667 		[/example]
668 		This is useful for algebraic and boolean expressions, like the ones
669 		accepted by the special function $() (see next paragraphs).
670 		[big]Aliases[/big]
671 		An alias is a user defined command. It can be used to rename the builtin KVIrc commands or functions,
672 		to automate complex tasks or as a means for structured programming.
673 		Aliases can be created or destroyed by using the scriptcenter (graphic interface)
674 		or from the commandline (or script) by using the [cmd]alias[/cmd] command.
675 		Once created, an alias remains stored permanently in the KVIrc configuration files
676 		until it is explicitly deleted.
677 		A couple of examples will make the things clear.
678 		join is a really commonly used command - it might be a good idea to rename it to
679 		simply [b]j[/b] .. just to type it faster.
680 		Nothing easier in KVIrc: just try this commandline:
681 		[example]
682 			[cmd]alias[/cmd](j){ [cmd]join[/cmd] $0-; };
683 		[/example]
684 		This will create the alias [b]j[/b]. From this moment you can use /j as if it was a normal command.
685 		[example]
686 			j #kvirc
687 		[/example]
688 		You may have noticed the strange $0- function in the alias body - it stands for
689 		[i]all parameters passed to the alias[/i]. This means that when you call
690 		[example]
691 			j #kvirc testpassword
692 		[/example]
693 		then both the parameters (#kvirc and testpassword) are passed to the join command.
694 		The $N functions are special functions that return the positional parameters passed
695 		to the current script context. In an alias the script context is the script body and
696 		it is the alias caller that generates the parameters.
697 		$N (where N is a digit) returns the (N-1)-th positional parameter passed by the caller.
698 		It returns the parameter numbered N-1 and not N since the parameters are indexed starting
699 		from zero ($0 is the first parameter!).
700 		$N-M returns the parameters from (N-1)-th to the (M-1)-th (a parameter range) and $N- returns
701 		all the parameters from (N-1)-th to the last one. In the example above $0- stands for
702 		all the parameters starting from the first one.
703 		[br]
704 		To remove an alias, use the alias command again with an empty body:
705 		[example]
706 			[cmd]alias[/cmd](j){}
707 		[/example]
708 		This will remove the alias [b]j[/b] defined above.
709 		[br]
710 		A common task in channel management is the kick & ban action.
711 		You first ban a user from the channel and then eventually kick him
712 		(obviously assuming that he is actually on the channel).
713 		This involves using two commands - ban and then kick.
714 		It could be a nice idea to have a single [b]kb[/b] command to perform this action.
715 		Well...easy:
716 		[example]
717 			[cmd]alias[/cmd](kb){ [cmd]ban[/cmd] $0; [cmd]kick[/cmd] $0-; };
718 		[/example]
719 		This adds the [b]kb[/b] alias - it can be called as a normal command:
720 		[example]
721 			kb spammer You're not welcome here!
722 		[/example]
723 		This will first execute [i]ban spammer[/i] and then [i]kick spammer with; You're not welcome here[/i].
724 		Our kb is a really simple example... it doesn't check for the validity of the parameters -
725 		the server will warn us if the parameters passed to kb were empty.
726 		[br]
727 		The alias can be modified at any time by reusing the alias command.
728 		Let's make our [b]kb[/b] a bit more intelligent and add a check for the parameters.
729 		TIP: It is a good idea to write the following examples in a text file and then use /parse <filename> to execute it.
730 		[example]
731 			[cmd]alias[/cmd](kb)
732 			{
733 				[cmd]if[/cmd]("$0" == "")
734 				{
735 					[cmd]echo[/cmd] "Usage: /kb <nickname> <kick reason>"
736 					[cmd]return[/cmd]
737 				}
738 				[cmd]ban[/cmd] $0
739 				%reason = $1-
740 				[cmd]if[/cmd]("%reason" == "")%reason = "You're not welcome here!"
741 				[cmd]kick[/cmd] $0 %reason
742 			}
743 		[/example]
744 		The example above will first check the validity of the <nickname> passed to kb -
745 		if no nickname was passed, it will warn the user and stop.
746 		The next step will be the [i]ban <nickname>[/i] call. Another enhancement is the [i]default reason[/i] -
747 		we first assign the remaining parameters ($1- means [i]from $1 to the end[/i]) to a temporary variable,
748 		and if the variable is empty, a default kick reason is assigned.
749 		Finally the [i]kick <nickname> <reason>[/i] will be executed.
750 		Get used to looking at the single command documentation pages, they will give
751 		you the hints necessary to fully understand the above piece of code.
752 		[br]
753 		Aliases can be used as a means for structured programming.
754 		In large scripts you will [b]surely[/b] have [i]common tasks[/i] to perform (like having
755 		specially-colored output or calculating a value from a set of other values)...
756 		Aliases are the way of writing the common tasks - they are equivalent to the [i]procedures[/i]
757 		or [i]functions[/i] in many high-level programming languages.
758 		The alias as a procedure (subroutine or sub-task) has been shown in the [b]kb[/b] example above -
759 		it might be commonly called from more complex scripts or other aliases in the case that a
760 		kick & ban action is needed.
761 		[br]
762 		Aliases can be used also as functions.
763 		Assume that you often need to calculate the sum of three numbers - a function-alias is the way.
764 		[example]
765 			[cmd]alias[/cmd](sum3){ [cmd]return[/cmd] $($0 + $1 + $2); };
766 		[/example]
767 		This will add the alias [i]sum3[/i] and make it available both as a command and a function.
768 		The [i]return[/i] command sets the return value of a sequence of commands
769 		(an alias is a sequence of commands... remember?) and terminates the execution (by returning
770 		the control to the caller).
771 		So return $($0 + $1 + $2); will set the return value of the alias to the value
772 		computed by $($0 + $1 + $2), which is the sum of the first three parameters passed.
773 		You will then use it in the following way:
774 		[example]
775 			...
776 			%myfirstsum = $sum3(%somevalue,%someothervalue,4)
777 			%anothersum = $sum3(12,%somevalue,%anothervalue)
778 			...
779 		[/example]
780 		Oops! I've used some variables without actually explaining them, please forgive me and read on.
781 		This example is again really simple, but you might have more complex function-aliases.
782 		The function-aliases are also normal aliases... you can use it as a command:
783 		[example]
784 			/sum3 1 2 3
785 		[/example]
786 		The above is a perfectly valid call, however there will be no visible results
787 		(because a command call implies ignoring the return value.
788 		In fact there is no difference at all between function-aliases and normal-aliases -
789 		the caller makes the difference. By calling an alias as a command, the return value
790 		just disappears into hyperspace, however if you call an alias as a function, the return value
791 		is propagated (and in fact [i]used[/i]).
792 		There are some [i]nice[/i] exceptions to this rule...but you don't need to care about it, for now.
793 		If return is not called inside an alias body, the return value will be set to [fnc]$null[/fnc].
794 		[br]
795 		Aliases can accept switches just like any other command. The [fnc]$sw[/fnc] is there
796 		exactly for that purpose. Check it out.
797 		[big]Special functions[/big]
798 		We have already seen the positional parameter functions.
799 		The functions of type [b]$N[-[M]][/b] (where N and M are positive
800 		numbers starting from 0 and N < M) evaluate to the sequence of
801 		[b]positional parameters[/b] from Nth to Mth.[br]
802 		If M is omitted, the function evaluate to the sequence of [b]positional
803 		parameters[/b] from Nth to the last one. If the whole -M block is omitted
804 		the function evaluate to the Nth positional parameter.
805 		We will discover more on the [b]positional parameters[/b] when talking
806 		of aliases and events.
807 		[example]
808 			$0 evaluates to the 1st positional parameter
809 			$0-4 evaluates to the parameters from first to 5th
810 			$41- evaluates to the parameters from 41st to the last available
811 		[/example]
812 		The function [b]$#[/b] evaluates to the number of positional parameters available.
813 		The [b]positional parameter[/b] functions do not accept parameters.[br]
814 		The special function [b]$(<expression>)[/b], called the
815 		[i][doc:expressioneval]Expression evaluation identifier[/doc][/i], returns the result
816 		of the evaluation of the <expression>. In previous versions of KVIrc this
817 		function was called $calc().
818 		[example]
819 			[cmd]echo[/cmd] $(2 + (3 ^ 7) <= 1 * (3 && 2))
820 		[/example]
821 		The special function [b]${<command sequence>}[/b] evaluates to the
822 		return value of the <command sequence>.[br]
823 		The special function [b]$$[/b] evaluates to the current object ID,
824 		but it is too early to explain it here...
825 */
826 
827 /*
828 	@doc: command_rebinding
829 	@type:
830 		language
831 	@keyterms:
832 		Rebinding commands to another window
833 	@title:
834 		Standard rebinding switch
835 	@short:
836 		Standard rebinding switch
837 	@syntax:
838 		<command> -r=<window_id> <parameters>
839 	@body:
840 		The -r switch is standardized along all the commands. It rebinds a command
841 		to the windows specified by <window_id>. It is useful to launch commands
842 		in windows that are not the current one. For example, you might want to
843 		say something in a specific channel while processing an event bound to
844 		a console, or say something in all the channels bound to the current IRC context.
845 		The examples below will make everything clear.
846 	@examples:
847 		[example]
848 		[comment]# Run a command in the console of the current IRC context[/comment]
849 		[cmd]echo[/cmd] -r=$console This command is executed in the console ($window.caption)
850 		[comment]# Say something to all the channels of the current IRC context[/comment]
851 		[cmd]foreach[/cmd](%w,[fnc]$window.list[/fnc](channel))[cmd]say[/cmd] -r=%w Hi ppl on [fnc]$chan.name[/fnc]
852 		[/example]
853 */
854 
855 /*
856 	@doc: window_naming_conventions
857 	@type:
858 		language
859 	@title:
860 		Window naming conventions
861 	@keyterms:
862 		IRC context, window ID, frame window, connection ID
863 	@short:
864 		KVIrc window structure and the window naming conventions
865 	@body:
866 		[big]Introduction[/big]
867 		Starting from the release 3.0.0, KVIrc window structure has
868 		grown in complexity. Older releases allowed one connection
869 		per [i]frame window[/i] and thus had a dedicated command parser
870 		for each connection. Finding a window in that scenario
871 		was quite easy: it was enough to designate it by [i]name[/i]
872 		(that was exactly the text displayed in the window caption).
873 		It was sufficient to have an [i]unique[/i] name for ever window;
874 		condition that was granted by the underlying IRC protocol
875 		and by the KVIrc core design.[br]
876 		In this version, the unique window names are impossible to be granted.
877 		[big]Scenario[/big]
878 		The command parser is now [i]global[/i] to the application.
879 		There can be two or more consoles in each frame and the user
880 		is able to join the same channel with two different nicknames
881 		using two separate connections.
882 		[ul]
883 		[li]
884 		Application (Unique command parser)
885 			[ul]
886 			[li]
887 			Frame X
888 				[ul]
889 				[li]
890 				Console M (IRC context)
891 					[ul]
892 					[li]Channel windows[/li]
893 					[li]Query windows[/li]
894 					[li]Other connection related windows[/li]
895 					[/ul]
896 				[/li]
897 				[li]
898 				Console N (IRC context)
899 					[ul]
900 					[li]Channel windows[/li]
901 					[li]Query windows[/li]
902 					[li]Other connection related windows[/li]
903 					[/ul]
904 				[/li]
905 				[li]
906 				Other windows
907 				[/li]
908 				[li]
909 				...
910 				[/li]
911 				[/ul]
912 			[/li]
913 			[li]
914 			Frame Y
915 				[ul]
916 				[li]
917 				Console O (IRC context)
918 					[ul]
919 					[li]Channel windows[/li]
920 					[li]Query windows[/li]
921 					[li]Other connection related windows[/li]
922 					[/ul]
923 				[/li]
924 				[li]
925 				Console P (IRC context)
926 					[ul]
927 					[li]Channel windows[/li]
928 					[li]Query windows[/li]
929 					[li]Other connection related windows[/li]
930 					[/ul]
931 				[/li]
932 				[li]
933 				Other windows
934 				[/li]
935 				[li]
936 				...
937 				[/li]
938 				[/ul]
939 			[/li]
940 			[li]
941 			...
942 			[/li]
943 			[/ul]
944 		[/li]
945 		[/ul]
946 		[br]
947 		A naming convention has become necessary to resolve ambiguities.
948 		[big]Basic assumptions[/big]
949 		Every KVIrc window has four main properties:[br]
950 		-[b]an unique numeric identifier[/b][br]
951 		-[b]the logical name[/b][br]
952 		-[b]the type identifier[/b][br]
953 		-[b]the caption text[/b][br]
954 		The [b]numeric identifier[/b] is unique to the whole application,
955 		and is the one returned by the [fnc]$window[/fnc] function.[br]
956 		The identifier is assigned by KVIrc when the window is created
957 		and is not changed until the window is destroyed.
958 		This identifier will be referred as [b]window ID[/b].[br]
959 		The [b]logical name[/b] is a property of some kind of windows.
960 		It usually corresponds to the first part of the window caption.
961 		For example, for channel windows it is the channel name, for
962 		queries it is the list of the targets. For some other windows
963 		the logical name corresponds to the caption text. This will be discussed later.[br]
964 		The [b]type identifier[/b] describes the properties of a certain window.
965 		For channel windows the type identifier is [i]channel[/i], for query windows is [i]query[/i],
966 		for console windows it is [i]console[/i], etc.
967 		[big]IRC Contexts[/big]
968 		The KVIrc frame windows are numbered starting from 0 and named
969 		[i]frame_<number>[/i]. Each frame can contain an unlimited number of consoles.[br]
970 		Each console is bound to an [b]IRC context[/b]. (The part [i]is bound to[/i] could
971 		be substituted by [i]defines[/i] or [i]is contained in[/i]).[br]
972 		[i]An [b]IRC context[/b] is a set of resources that can deal with a single
973 		IRC connection.[/i][br]
974 		The association between an [b]IRC context[/b]
975 		and a console is bijective: each [b]IRC context[/b] is associated
976 		to a single console window.[br]
977 		An [b]IRC context[/b] can be in connected or not-connected state.
978 		When in connected state, it contains a set of windows beside the console:
979 		mainly channels and query windows.
980 		The channels and query windows can exist [b]only[/b] if the associated
981 		[b]IRC context[/b] exists.[br]
982 		Channels and queries have unique names inside a connection so
983 		there is no way to confuse it. (Theoretically there can
984 		be more than one query window with the same name, but in fact
985 		all the windows refer to the same target so they are instances
986 		of the same resource).
987 		All this creates a sort of namespace: the channels and queries can be identified
988 		as [i]bound[/i] to a specific [b]IRC context[/b].[br]
989 		An [b]IRC context[/b] can [i]contain[/i] other windows, such as the [i]sockets[/i]
990 		window or the [i]list[/i] window. KVIrc takes care of making them
991 		unique inside the [b]IRC context[/b] namespace.[br]
992 		Each [b]IRC context[/b] has its own unique [b]IRC context ID[/b] (see [fnc]$context[/fnc]).[br]
993 		Since to a single [b]IRC context[/b] may correspond only a single IRC connection,
994 		when in connected state, the [b]IRC context[/b] may be referred also as [b]connection[/b]
995 		or [b]connection context[/b], and the associated [b]IRC context Id[/b] can be
996 		referred as [b]connection ID[/b] or [b]connection context ID[/b].[br]
997 		There are classes of windows that are not bound to any [b]IRC context[/b]:
998 		this includes user created windows, DCC windows, browsers etc.[br]
999 		KVIrc will try to keep that windows with unique logical names.
1000 		[big]How to identify a window[/big]
1001 		So what we have until now is:
1002 		[ul]
1003 		[li]Each window has its own unique [b]window ID[/b]: we
1004 		will refer windows always using this identifier.[/li]
1005 		[li]Each window has a set of properties including:
1006 		window type, logical name.[/li]
1007 		[li]Subsets of windows are bound to a single [b]IRC context[/b][/li]
1008 		[/ul]
1009 		The simplest (but also the less significant) method of looking for
1010 		a window is to finding it by caption.[br]
1011 		The [fnc]$window[/fnc] function finds the first KVIrc window matching
1012 		the [i]caption text[/i] and returns its [b]window ID[/b].[br]
1013 		This method will likely fail when there are more windows with the same
1014 		caption text; for this reason several specific functions
1015 		have been added to allow finding the correct window.[br]
1016 		The [fnc]$console[/fnc] finds a console window bound to a specified
1017 		[b]IRC context[/b].[br]
1018 		The [fnc]$channel[/fnc] finds a channel window matching the specified
1019 		name and bound to a specified [b]IRC context[/b].[br]
1020 		The [fnc]$query[/fnc] finds a query window that has a specified target
1021 		and is bound to a specified [b]IRC context[/b].[br]
1022 */
1023 
1024 /*
1025 	@doc: connection_dependent_commands
1026 	@type:
1027 		language
1028 	@title:
1029 		Connection dependent commands
1030 	@keyterms:
1031 		IRC context, connection dependent commands
1032 	@body:
1033 		Many KVIrc commands are connection dependent:
1034 		you need an IRC connection to successfully execute them;
1035 		usually because some data needs to be sent to the server.
1036 		This includes commands like [cmd]whois[/cmd],[cmd]raw[/cmd],[cmd]query[/cmd],
1037 		[cmd]msg[/cmd],[cmd]notice[/cmd],[cmd]op[/cmd],[cmd]ctcp[/cmd]...[br]
1038 		These commands must be executed in a window that is bound to a
1039 		[b]connected [doc:window_naming_conventions]IRC context[/doc][/b].
1040 		You will obviously get an error message if you try to use them in a window
1041 		that has no associated IRC connection.[br]
1042 		For instance: [cmd]whois[/cmd] will work only if you execute it
1043 		in a console, channel or query window.[br]
1044 		If you want to use these commands in a window that is not associated to
1045 		any IRC context you may use the [doc:command_rebinding]standard -r switch[/doc].
1046 		You can use the same switch to execute a command in an [b]IRC context[/b] that is
1047 		not the current one.
1048 */
1049 
1050 /*
1051 	@doc: aliases
1052 	@type:
1053 		language
1054 	@keyterms:
1055 		aliases
1056 	@title:
1057 		Aliases
1058 	@short:
1059 		Aliases : user definable command sequences
1060 	@body:
1061 		An alias is a user defined command.  It can be used to rename the builtin KVIrc commands or functions,
1062 		to automate complex tasks or as structured programming mean.
1063 		Aliases can be created or destroyed by using the scriptcenter (graphic interface)
1064 		or from the commandline (or script) by using the [cmd]alias[/cmd] command.
1065 		Once created, an alias remains stored permanently in the KVIrc configuration files
1066 		until it is explicitly deleted.
1067 		A couple of examples will make the things clear.
1068 		join is a really commonly used command. It might be a good idea to rename it to
1069 		simply [b]j[/b] .. just to type it faster.
1070 		Nothing easier in KVIrc: just try this commandline:
1071 		[example]
1072 			[cmd]alias[/cmd](j){ [cmd]join[/cmd] $0-; };
1073 		[/example]
1074 		[br]
1075 		This will create the alias [b]j[/b]. From this moment you can use /j as it was a normal command.
1076 		[example]
1077 		j #kvirc
1078 		[/example]
1079 		You may have notices the strange $0- function in the alias body: it stands for
1080 		[i]all parameters passed to the alias[/i]. This means that when you call
1081 		[example]
1082 			j #kvirc testpassword
1083 		[/example]
1084 		then both the parameters (#kvirc and testpassword) are passed to the join command.
1085 		The $N functions are special functions that return the positional parameters passed
1086 		to the current script context. In an alias the script context is the script body and
1087 		it is the alias caller that generates the parameters.
1088 		$N (where N is a digit) returns the (N-1)-th positional parameter passed by the caller.
1089 		It returns the parameter numbered N-1 and not N since the parameters are indexed starting
1090 		from zero ($0 is the first parameter!).
1091 		$N-M returns the parameters from (N-1)-th to the (M-1)-th (a parameter range) and $N- returns
1092 		all the parameters from (N-1)-th to the last one. In the example above $0- stands for
1093 		all the parameters starting from the first one.
1094 		[br]
1095 		To remove an alias use again the alias command with an empty body:
1096 		[example]
1097 			[cmd]alias[/cmd](j){}
1098 		[/example]
1099 		This will remove the alias [b]j[/b] defined above.
1100 		[br]
1101 		A common task in channel management is the kick & ban action.
1102 		You first ban a user from the channel and then eventually kick him
1103 		(obviously assuming that he is actually on the channel).
1104 		This involves using two commands: ban and then kick.
1105 		It could be a nice idea to have a single [b]kb[/b] command to perform this action.
1106 		Well...easy:
1107 		[example]
1108 			[cmd]alias[/cmd](kb){ [cmd]ban[/cmd] $0; [cmd]kick[/cmd] $0-; };
1109 		[/example]
1110 		This adds the [b]kb[/b] alias: it can be called as a normal command:
1111 		[example]
1112 			kb spammer You're not welcome here!
1113 		[/example]
1114 		This will first execute [i]ban spammer[/i] and then [i]kick spammer with; You're not welcome here[/i].
1115 		Our kb is a really simple example... it doesn't check for the validity of the parameters:
1116 		the server will warn us if the parameters passed to kb were empty.
1117 		[br]
1118 		The alias can be modified at any time by re-using the alias command.
1119 		Let's make our [b]kb[/b] a bit more intelligent and add a check for the parameters.
1120 		TIP: It is a good idea to write the following examples in a text file and then use /parse <filename> to execute it.
1121 		[example]
1122 			[cmd]alias[/cmd](kb)
1123 			{
1124 				[cmd]if[/cmd]("$0" == "")
1125 				{
1126 					[cmd]echo[/cmd] "Usage: /kb <nickname> <kick reason>"
1127 					[cmd]return[/cmd]
1128 				}
1129 				[cmd]ban[/cmd] $0
1130 				%reason = $1-
1131 				[cmd]if[/cmd]("%reason" == "")%reason = "You're not welcome here!"
1132 				[cmd]kick[/cmd] $0 %reason
1133 			}
1134 		[/example]
1135 		The example above will first check the validity of the <nickname> passed to kb:
1136 		if no nickname was passed, it will warn the user and stop.
1137 		The next step will be the [i]ban <nickname>[/i] call. Another enhancement is the [i]default reason[/i]:
1138 		we first assign the remaining parameters ($1- means [i]from $1 to the end[/i]) to a temporary variable,
1139 		if the variable is empty, a default kick reason is assigned.
1140 		Finally the [i]kick <nickname> <reason>[/i] will be executed.
1141 		Get used to looking at the single command documentation pages, they will give
1142 		you the hints necessary to fully understand the above piece of code.
1143 		[br]
1144 		Aliases can be used as a mean for structured programming.
1145 		In large scripts you will [b]surely[/b] have [i]common tasks[/i] to perform (like having specially
1146 		colored output or calculating a value from a set of other values)...
1147 		Aliases are the way of writing the common tasks: they are equivalent to the [i]procedures[/i]
1148 		or [i]functions[/i] in many high-level programming languages.
1149 		The alias as a procedure (subroutine or sub-task) has been shown in the [b]kb[/b] example above:
1150 		it might be commonly called from more complex scripts or other aliases in case that a
1151 		kick & ban action is needed.
1152 		[br]
1153 		The aliases can be used also as functions.
1154 		Assume that you need really often to calculate the sum of three numbers: a function-alias is the way.
1155 		[example]
1156 			[cmd]alias[/cmd](sum3){ [cmd]return[/cmd] $($0 + $1 + $2); };
1157 		[/example]
1158 		This will add the alias [i]sum3[/i] and make it available both as a command and a function.
1159 		The [i]return[/i] command sets the return value of a sequence of commands
1160 		(an alias is a sequence of commands...remember?) and terminates the execution (by returning
1161 		the control to the caller).
1162 		So return $($0 + $1 + $2); will set the return value of the alias to the value
1163 		computed by $($0 + $1 + $2) that actually is the sum of the first three parameters passed.
1164 		You will then use it in the following way:
1165 		[example]
1166 			...
1167 			%myfirstsum = $sum3(%somevalue,%someothervalue,4)
1168 			%anothersum = $sum3(12,%somevalue,%anothervalue)
1169 			...
1170 		[/example]
1171 		Oops! I've used some variables without actually explaining them, hehe... please forgive me and read on.
1172 		This example is again really simple, but you might have more complex function-aliases.
1173 		The function-aliases are also normal aliases... you can use it as a command:
1174 		[example]
1175 			/sum3 1 2 3
1176 		[/example]
1177 		Is a perfectly valid call... it's just that it will have no visible results
1178 		(just because a command call implies ignoring the return value.
1179 		In fact there is no difference al all between function-aliases and normal-aliases:
1180 		the caller makes the difference: by calling an alias as a command the return value
1181 		just disappears in hyperspace, by calling an alias as a function, the return value
1182 		is propagated (and in fact [i]used[/i]).
1183 		(There are some [i]nice[/i] exceptions to this rule... but you don't need to care about it, for now).
1184 		If return is not called inside an alias body, the return value will be just a null value.
1185 		[br]
1186 		Aliases can accept switches just like any other command. The [fnc]$sw[/fnc] is there
1187 		exactly for that purpose. Check it out.
1188 		[br]
1189 */
1190 
1191 /*
1192 	@doc: kvs_addons
1193 	@type:
1194 		language
1195 	@keyterms:
1196 		addons, addon
1197 	@title:
1198 		The KVIrc addon system
1199 	@short:
1200 		Writing KVIrc addons
1201 	@body:
1202 		[big]Introduction[/big]
1203 		[br]
1204 		An addon is basically a set of KVS scripts, multimedia, documentation
1205 		and accessory files that implement a KVIrc feature.
1206 		It might be a simple automatic-away subsystem, a GUI newsticker or a complex
1207 		file sharing service (commonly called [i]fserve[/i]). Addons are sometimes called [i]scripts[/i].
1208 		In fact a KVIrc addon is usually made of more than one KVS script.[br][br]
1209 		KVIrc has a builtin addon management system that allows the users to create,
1210 		install, configure and uninstall features with a nice graphical interface.
1211 		The management system allows the addons to have documentation integrated in
1212 		the KVIrc help and to be translated in several languages.
1213 		[big]Addon installation[/big]
1214 		The addons are usually shipped in compressed archives (.kva). KVIrc will look
1215 		for the installer file called [i]install.kvs[/i] and executes it when the user will
1216 		ask for your addon to be installed. The install.kvs contains the code for the
1217 		[b]registration[/b] of your addon and will [cmd]include[/cmd] all the other
1218 		necessary source files.
1219 		[big]The minimal addon[/big]
1220 		[br]
1221 		The smallest addon that you can write is the one that does nothing.
1222 		[example]
1223 			[cmd]addon.register[/cmd]("MyAddon", \
1224 							"1.0.0", \
1225 							"My First Addon", \
1226 							"An addon that is really cool but does
1227 							simply nothing", \
1228 							"4.0.0", \
1229 							"MyAddon_32.png")
1230 			{
1231 			}
1232 		[/example]
1233 		The code above does nothing but registers the [i]MyAddon[/i] addon.
1234 		[br]
1235 		The first parameter is the internal addon ID which can be used to identify
1236 		your addon inside KVIrc. The ID must be unique: two addons that share the same
1237 		name cannot be installed. The second parameter is the addon version. It should
1238 		be expressed in the classic format [major].[minor].[pathlevel] or something
1239 		really similar (in fact KVIrc just expects the version to be a string composed
1240 		of numbers separated by dots).[br][br]
1241 		The version is compared when an addon is installed and KVIrc complains if the user
1242 		tries to downgrade an addon (that is to install a less recent version over a more recent one).[br]
1243 		The third parameter is the visible name of your addon: it will be displayed to the user in the
1244 		addon management dialog. It can contain the [fnc]$tr[/fnc] function so you
1245 		can have it translated to several languages. The fourth parameter
1246 		is a short description of the feature that the addon implements; it can
1247 		contain the $tr() function too. The fifth parameter is the minimal KVIrc
1248 		version required to run the addon. The sixth parameter is the icon to show in
1249 		the manager: it has to be 32x32 pixel big. There are also some switches that
1250 		can be used to fiddle a little bit more :)
1251 		[br]
1252 		The callback instruction that follows the registration command is the
1253 		uninstallation code. KVIrc will invoke it when the user will ask for your
1254 		addon to be uninstalled. Don't assume that your addon will be never
1255 		uninstalled: sooner or later it will be. For example, when upgrading an addon
1256 		KVIrc will first uninstall the existing version and after that install the new
1257 		one. The uninstallation process is a very important requisite for any program
1258 		(in any programming language). In the example above there is nothing to
1259 		uninstall (yet) so the callback code is empty, but if you continue reading we
1260 		will soon fill it.
1261 		To uninstall all files which are not automatically spotted by the installation
1262 		process, you need to write an alias which handles them.
1263 		[example]
1264 			alias(MyAddon::uninstall::uninstall)
1265 			{
1266 				...
1267 			}
1268 		[/example]
1269 		[big]A typical addon layout[/big]
1270 		[br]
1271 		As stated above, the addons are usually shipped in a compressed archive.
1272 		Once uncompressed, the installer will check the directory tree containing the
1273 		addon code and all the related files.
1274 		In order to have uniformity the installer complains if the structure is not
1275 		respected.
1276 		[br]
1277 		[pre]
1278 			[b]name-version[/b]
1279 			 +- init.kvs
1280 			 +- [b]src[/b]
1281 			 |	+- source1.kvs
1282 			 |	+- source2.kvs
1283 			 |	\- ...
1284 			 +- [b]locale[/b]
1285 			 |	+- name_it.mo
1286 			 |	+- name_de.mo
1287 			 |	\- ...
1288 			 +- [b]config[/b]
1289 			 |	+- config1.kvc
1290 			 |	+- config2.kvc
1291 			 |	\- ...
1292 			 +- [b]sound[/b]
1293 			 |	+- audio1.wav
1294 			 |	+- audio2.wav
1295 			 |	\- ...
1296 			 +- [b]pics[/b]
1297 			 |	+- pic1.png
1298 			 |	+- pic2.png
1299 			 |	\- ...
1300 			 +- [b]help[/b]
1301 			  	+- [b]en[/b]
1302 			  	|   +- index.html
1303 			  	|   +- hints.html
1304 			  	|   \- ...
1305 			  	+- [b]it[/b]
1306 			  	    +- index.html
1307 			  	    +- hints.html
1308 			  	    \- ...
1309 		[/pre]
1310 		The entries in [b]bold[/b] are directories while the other are files.
1311 		Please note that you need all of these directories or the routine that
1312 		automagically creates the installer will fail.
1313 		[br]
1314 		The toplevel directory should be named with your addon name and version.
1315 		Use no spaces in the directory entries (this will make the things simpler for
1316 		people that want to use your addon).
1317 		[br]
1318 		Hint: Remember that your addon is going to be installed on different platforms
1319 		(at least Linux, macOS and Windows based).
1320 		The poor windows' notepad has serious problems with reading text
1321 		files that contain only linefeeds as line separators. Keep it in mind...
1322 		[br]
1323 		The [b]initialization script[/b] has to be named init.kvs and must contain all the
1324 		routines to register your addon.
1325 		[example]
1326 			[comment]# Register classes[/comment]
1327 			MyAddon::classes::register
1328 
1329 			[comment]# Initialize events[/comment]
1330 			MyAddon::events::init
1331 
1332 			[comment]# Load configuration[/comment]
1333 			MyAddon::config::load
1334 
1335 			[comment]# Setup popups[/comment]
1336 			defpopup("MyAddon")
1337 			{
1338 				item($tr("Something","MyAddon"),110)
1339 				{
1340 					...
1341 				}
1342 			}
1343 
1344 			[comment]# Set options[/comment]
1345 			option boolAutoAcceptDccSend 1
1346 			option boolShowMinimizedDebugWindow 1
1347 		[/example]
1348 		[/p]
1349 		[p]
1350 		The main [b]source directory[/b] for your addon have to be named [i]src[/i] and must
1351 		contain the implementation of the feature(s) you're going to provide.
1352 		File names should contain the namespace of the addon, the optional subnamespace
1353 		and the name of the feature like $addonNS_$subNS_[$subNS_[...]]$name.kvs
1354 		[example]
1355 			[comment]# A class which handles a database[/comment]
1356 			MyAddon_classes_database.kvs
1357 
1358 			[comment]# A class which handles the options of our addon in a GUI[/comment]
1359 			MyAddon_classes_gui_options.kvs
1360 
1361 			[comment]# A script containing some logging functions[/comment]
1362 			MyAddon_functions_logging.kvs
1363 		[/example]
1364 		[br]
1365 		The [b]locale[/b] directory should contain the *.mo files for your translations.
1366 		The localization process of a script is explained in [doc:localization]this document[/doc].
1367 		Your *.mo filenames should be prefixed by your addon name.
1368 		[br]
1369 		The [b]configuration directory[/b] [i]config[/i] should contains only the files
1370 		which store the configuration of your addon and must end with the .kvc
1371 		extension.
1372 		[br]
1373 		The [b]pics[/b] and [b]sound[/b] (if relevant) directories should contain
1374 		your multimedia files. I's a good idea to have your pics file in PNG format
1375 		and sound files in WAV format.
1376 		[br]
1377 		The [b]help[/b] directory should contain subdirectories for each language
1378 		your help files are written in. The languages dirs should be named
1379 		with the language code also used for the translation files (like [i]en[/i], [i]it[/i]
1380 		etc...).
1381 		Please note that English is the default language and KVIrc will
1382 		fallback to the [i]en[/i] subdirectory when no other language is found around...
1383 		[big]Some examples[/big]
1384 		The code below is just an example of how to write a useful initialization of
1385 		your own addon. The name of the classes refer to the ones described above.
1386 		[example]
1387 			[comment]# Register the classes[/comment]
1388 			alias(MyAddon::classes::register)
1389 			{
1390 				[comment]# Create an array with all the classes of our addon.[/comment]
1391 				[comment]# In this way it's easy to add or remove classes to registering routine[/comment]
1392 				%classes[] = [fnc]$array[/fnc]( \
1393 					MyAddon::classes::database, \
1394 					MyAddon::classes::gui::options, \
1395 					...
1396 					)
1397 
1398 				[comment]# Scan the array and register the classes[/comment]
1399 				for(%i=0; %i < [fnc]$length[/fnc](%classes[]); %i++)
1400 				{
1401 					if([fnc]$classDefined[/fnc]("%classes[%i]"))
1402 					{
1403 						[cmd]objects.killclass[/cmd] %classes[%i]
1404 					}
1405 					[cmd]eval[/cmd] %classes[%i]
1406 				}
1407 			}
1408 
1409 			[comment]# Initialize events[/comment]
1410 			alias(MyAddon::events::init)
1411 			{
1412 				event(OnKVIrcStartup,"MyAddon")
1413 				{
1414 					...
1415 					[comment]# Load the catalogue (translation) file [i]myaddon[/i] from the path provided[/comment]
1416 					[cmd]trload[/cmd] myaddon [fnc]$file.localdir[/fnc]("locale/MyAddon")
1417 					MyAddon::config::load
1418 					...
1419 				}
1420 				event(OnChannelMessage,"MyAddon_something")
1421 				{
1422 				...
1423 				}
1424 			}
1425 
1426 			[comment]# Load configuration[/comment]
1427 			alias(MyAddon::config::load)
1428 			{
1429 				[comment]# If the class ConfHandler is not defined, register all classes we have[/comment]
1430 				if(![fnc]$classDefined[/fnc](MyAddon::classes::ConfHandler))
1431 				{
1432 					MyAddon::classes::register
1433 				}
1434 
1435 				[comment]# Sets some variables[/comment]
1436 				%MyAddonConfig = [fnc]$new[/fnc](MyAddon::classes::ConfHandler)
1437 				%MyAddonConfigPath = [fnc]$file.localdir[/fnc](config/scripts/MyAddon)
1438 
1439 				[comment]# Open the configuration file and sets the section general[/comment]
1440 				%c = [fnc]$config.open[/fnc](%MyAddonConfigPath/MyAddon.kvc,"r")
1441 				[cmd]config.setsection[/cmd] %c general
1442 
1443 				[comment]# Store the value of the key "Key" in the global variable %Key[/comment]
1444 				%Key = [fnc]$config.read[/fnc](%c,"Key",2)
1445 				...
1446 			}
1447 		[/example]
1448 		[big]The help and configuration callbacks[/big]
1449 		[br]
1450 		Each addon can have a help and a configuration callback. These are set
1451 		respectively by [cmd]addon.sethelpcallback[/cmd] and [cmd]addon.setconfigurecallback[/cmd].
1452 		[br]
1453 		The help callback will be invoked by KVIrc when the user will ask help for your addon (mainly
1454 		from the addon management dialog, but not necessarily). It should call [cmd]help.open[/cmd]
1455 		with the name of your documentation index html file (it should be relative
1456 		to the help language directory: help.open myaddon/index.html will automatically
1457 		lookup the right language). If you provide no help callback, the buttons
1458 		for requesting help will be simply disabled. (A good an relatively complex addon
1459 		*should* have at least a minimal help file explaining the features).
1460 		[br]
1461 		The configuration callback will be invoked when the user will try to configure
1462 		your addon from the addon management dialog. This callback is useful
1463 		mainly for more complex graphical scripts that can show up a dialog
1464 		that allows configuring all of the addon features. To use this callback
1465 		you will probably need some object scripting.
1466 		[big]The real addon work[/big]
1467 		[br]
1468 		The real addon work is done by the scripts contained in the src directory.
1469 		They will likely add aliases (maybe in a nice namespace named against your addon),
1470 		register event handlers, create actions, timers, toolbars and object classes.
1471 		You should install all of this stuff from your addon source files.
1472 		Remember that your source files will [b]not[/b] be parsed every time KVIrc starts up:
1473 		your stuff must be registered in KVIrc and be able to startup itself, if needed.
1474 		Remember that you must clean up [b]everything[/b] in your uninstallation callback.
1475 		This means that you must remove the aliases, unregister the event handlers,
1476 		destroy the actions, kill the timers and the object classes you've created.
1477 		Be a clean coder :)
1478 		[big]Where to start[/big]
1479 		[br]
1480 		It is a good idea to start in the KVIrc scripts GitHub repository https://github.com/kvirc/kvirc-scripts. There are surely
1481 		several addons to look at. Pick one that seems simple and analyze its layout and code
1482 		(wow... amazing free software!). It will be easier to do than it was to explain it :D[br]
1483 		Have fun! :)
1484 		[br]
1485 */
1486 
1487 /*
1488 	@doc: kvs_codingtips
1489 	@type:
1490 		generic
1491 	@title:
1492 		Coding tips
1493 	@keyterms:
1494 		indentation,indent,readability
1495 	@short:
1496 		Generic coding tips for scripters (and not only)
1497 	@body:
1498 		Here comes a small list of [i]coding tips[/i].[br]
1499 		These apply to programming in general, not only to KVIrc scripting.[br]
1500 		[br]
1501 		1. [b]Comment your code[/b][br]
1502 		A well commented code is easy to maintain, and easy to read by others.[br]
1503 		[br]
1504 		2. [b]Indent your code[/b][br]
1505 		Indentation increases the code readability; this is again for you and
1506 		other developers that will be going to read your code.[br]
1507 		[br]
1508 		3. [b]Use TABS to indent your code[/b][br]
1509 		...and use [b]only tabs[/b] to indent.[br]
1510 		Tabs are better than space since most code editors allow you
1511 		to set the tab since and thus to have the indentation steps smaller or bigger.[br]
1512 		This is really important since the indentation size is really a matter of personal taste.[br]
1513 		Mixing spaces and tabs is Evil (tm), since it makes the code look really
1514 		ugly in editors that have the tab size different than yours; in some cases the
1515 		code gets really unreadable.[br]
1516 		[br]
1517 		4. [b]Use descriptive variable names[/b][br]
1518 		Using 'foo' as variable name implies tracing its semantic the next
1519 		time that you're going to read the code that uses it.[br]
1520 		This is really annoying and time-consuming, especially if the project
1521 		is getting large.[br]
1522 		Obviously using [i]thisIsACounterVariable[/i] as name for a simple counter
1523 		is also a suicide.[br]
1524 		A good convention on variable names can speed up writing, debugging and maintaining code.[br]
1525 		Encoding the type of the variable in the variable name might be also a good idea,
1526 		but this is a matter of taste; personally I feel really well with that.[br]
1527 		Just as example, here go my fundamental convention rules for C++:[br]
1528 		[br]
1529 			- The type of the variable is encoded at the beginning of the variable name:[br]
1530 		[br]
1531 			- b prefix for the boolean variables[br]
1532 			- i prefix for signed integers[br]
1533 			- u prefix for unsigned integers[br]
1534 			- f and d prefixes for floating point stuff[br]
1535 			- sz prefix for strings (this is rather for string classes)[br]
1536 			- ...[br]
1537 		[br]
1538 			- Pointers have a [b]p[/b] prefix prepended[br]
1539 			- Global variables start with a [b]g_[/b] prefix[br]
1540 			- Member variables start with a [b]m_[/b] prefix[br]
1541 			- Exception comes for local variables with obvious semantics[br]
1542 		[br]
1543 			- i,j,k,l for local loop counters[br]
1544 			- [i]aux[/i] and [i]tmp[/i] for local obvious short-term temporary variables[br]
1545 		[br]
1546 		So actually by [b]only[/b] reading [i]g_pszQuitMessage[/i] I know that this is a global pointer to a string variable
1547 		containing a quit message. :)[br]
1548 		[/p]
1549 */
1550 
1551 // FIXME: #warning "FINISH THE SYNTACTIC RULES DOC"
1552 
1553 /*
1554 	@doc: syntactic_rules
1555 	@type:
1556 		language
1557 	@keyterms:
1558 		productions
1559 	@title:
1560 		Syntactic rules
1561 	@short:
1562 		Syntactic rules of the KVIrc scripting language
1563 	@body:
1564 		In the following table you can find a good part of the
1565 		KVIrc scripting language syntactic rules.[br]
1566 		[br]
1567 		<entity> indicates an [b]entity that can appear exactly one time[/b].[br]
1568 		[<entity>] indicates an [b]optional entity[/b].[br]
1569 		{<entity>} indicates an [b]entity that can appear one or more times[/b].[br]
1570 		'entity' indicates a [b]literal entity[/b]: written exactly as it is.[br]
1571 		<entity1>|<entity2> indicates mutually exclusive choices.[br]
1572 		The mutually exclusive choices are often separated in two or more
1573 		rules (productions), to improve readability.
1574 		[table]
1575 		[tr]
1576 		[td]<command buffer>[/td]
1577 		[td][<whitespace>][<command block>]{<command buffer>}[/td]
1578 		[/tr]
1579 		[tr]
1580 		[td]<command buffer>[/td]
1581 		[td][<whitespace>][<single command>]{<command buffer>}[/td]
1582 		[/tr]
1583 		[tr]
1584 		[td]<whitespace>[/td]
1585 		[td]{<space>|<tab>|<newline>}['\'<newline>][<whitespace>][/td]
1586 		[/tr]
1587 		[tr]
1588 		[td]<space>[/td]
1589 		[td]' '['\'<newline>][<space>] (ASCII space character)[/td]
1590 		[/tr]
1591 		[tr]
1592 		[td]<tab>[/td]
1593 		[td]'\t' (ASCII horizontal tabulation character)[/td]
1594 		[/tr]
1595 		[tr]
1596 		[td]<newline>[/td]
1597 		[td]'\n' (ASCII line feed (LF) character)[/td]
1598 		[/tr]
1599 		[tr]
1600 		[td]<command block>[/td]
1601 		[td]'{' <command buffer>[<whitespace>] '}'[/td]
1602 		[/tr]
1603 		[tr]
1604 		[td]<single command>[/td]
1605 		[td]<comment>[/td]
1606 		[/tr]
1607 		[tr]
1608 		[td]<single command>[/td]
1609 		[td]<lvalue command> <command terminator>[/td]
1610 		[/tr]
1611 		[tr]
1612 		[td]<single command>[/td]
1613 		[td]<rvalue command> <command terminator>[/td]
1614 		[/tr]
1615 		[tr]
1616 		[td]<comment>[/td]
1617 		[td]'#' {<non comment terminator>} <comment terminator>[/td]
1618 		[/tr]
1619 		[tr]
1620 		[td]<comment terminator>[/td]
1621 		[td]<newline> | <end of string>[/td]
1622 		[/tr]
1623 		[tr]
1624 		[td]<end of string>[/td]
1625 		[td]No character (internally ASCII character 0)[/td]
1626 		[/tr]
1627 		[tr]
1628 		[td]<command terminator>[/td]
1629 		[td]<newline> | <end of string> | ';'[/td]
1630 		[/tr]
1631 		[tr]
1632 		[td]<non comment-terminator>[/td]
1633 		[td]Any ASCII character except <newline> and <end of string>[/td]
1634 		[/tr]
1635 		[tr]
1636 		[td]<simple command>[/td]
1637 		[td][<module name>'.']<command name>[<switch list>]{<space>}<command dependent part>[/td]
1638 		[/tr]
1639 		[tr]
1640 		[td]<lvalue command>[/td]
1641 		[td]<variable>[<space>]<operation>[/td]
1642 		[/tr]
1643 		[tr]
1644 		[td]<lvalue command>[/td]
1645 		[td]<variable>'->'<object command>[/td]
1646 		[/tr]
1647 		[tr]
1648 		[td]<lvalue command>[/td]
1649 		[td]<identifier>'->'<object command>[/td]
1650 		[/tr]
1651 		[tr]
1652 		[td]<operation>[/td]
1653 		[td]<one op operator>[/td]
1654 		[/tr]
1655 		[tr]
1656 		[td]<operation>[/td]
1657 		[td]<two op operator>[<space>]<param string>[/td]
1658 		[/tr]
1659 		[tr]
1660 		[td]<switch list>[/td]
1661 		[td]{<space>}'-'<alpha char>[{<space>}'='<single parameter>][<switch list>][/td]
1662 		[/tr]
1663 		[tr]
1664 		[td]<command name>[/td]
1665 		[td]<alphanumeric char>{<alphanumeric char>}[/td]
1666 		[/tr]
1667 		[tr]
1668 		[td]<module name>[/td]
1669 		[td]<alphanumeric char>{<alphanumeric char>}[/td]
1670 		[/tr]
1671 		[tr]
1672 		[td]<alphanumeric char>[/td]
1673 		[td]Ascii characters 'A' to 'Z', 'a' to 'z', '0' to '9' and '_'[/td]
1674 		[/tr]
1675 		[tr]
1676 		[td]<variable>[/td]
1677 		[td]<global variable> | <local variable>[/td]
1678 		[/tr]
1679 		[tr]
1680 		[td]<global variable>[/td]
1681 		[td]'%' <uppercase letter> [<alphanumeric char>]['['<param string>']'][/td]
1682 		[/tr]
1683 		[tr]
1684 		[td]<local variable>[/td]
1685 		[td]'%' <lowercase letter> [<alphanumeric char>]['['<param string>']'][/td]
1686 		[/tr]
1687 		[tr]
1688 		[td]<param string>[/td]
1689 		[td][<single parameter>][<space>[<param string>]][/td]
1690 		[/tr]
1691 		[tr]
1692 		[td]<single parameter>[/td]
1693 		[td]<variable> | <identifier> | <nonterminator token> | <string>[/td]
1694 		[/tr]
1695 		[tr]
1696 		[td]<nonterminator token>[/td]
1697 		[td]<nonterminator char>['\'<newline><nonterminator char>][/td]
1698 		[/tr]
1699 		[tr]
1700 		[td]<nonterminator char>[/td]
1701 		[td]Any ascii character except <space> and <command terminator>[/td]
1702 		[/tr]
1703 		[tr]
1704 		[td]<command dependent part>[/td]
1705 		[td]Production in each command help page[/td]
1706 		[/tr]
1707 		[/table]
1708 		To be continued...
1709 */
1710 
1711 /*
1712 	@doc: kvs_datatypes
1713 	@type:
1714 		language
1715 	@keyterms:
1716 		global variable, global variables, local variable, local variables,
1717 		variables, variable, array, hash, dictionary, global variables, local variables, variable evaluation,
1718 		associative arrays, scalars, data types, percent sign and extended scope
1719 	@title:
1720 		Variables and Data types
1721 	@short:
1722 		All about the KVS variable and datatype management
1723 	@body:
1724 		[title]Basic syntax[/title]
1725 		[br]
1726 		A variable identifier is composed by a '%' (percent) sign followed
1727 		by a sequence of letters, digits or underscores.
1728 		Examples of valid variable names are:
1729 		[example]
1730 			%i
1731 			%variable
1732 			%MyVar
1733 			%1
1734 			%thisisavar
1735 			%2ndName
1736 			%_hidden
1737 		[/example]
1738 		[br]
1739 		Variables are created when you assign something to them: there is no need
1740 		for a declaration (unlike other languages such as C/C++, Java or VB).
1741 		[example]
1742 			[comment]# create a variable named %X by assigning the value 10 to it[/comment]
1743 			%X = 10
1744 			[comment]# use the variable[/comment]
1745 			echo "The value of X is" %X
1746 		[/example]
1747 		[title]Local and global variables[/title]
1748 		[br]
1749 		Variables can be local or global.
1750 		Local variables preserve their contents only inside the [b]scope[/b] of a single script.
1751 		Global variables are shared between all the scripts and preserve their contents
1752 		until they are explicitly unset or until KVIrc quits.
1753 		[br]
1754 		Local variables start with a [b]lowercase letter[/b] while the global ones with an [b]uppercase letter[/b].
1755 		[example]
1756 			%var = 10; [comment]# this is a local variable[/comment]
1757 			%Var = 10; [comment]# this is a global variable[/comment]
1758 		[/example]
1759 		[br]
1760 		You can also force a variable that start with a lowercase letter to be global
1761 		by pre-declaring it with the [cmd]global[/cmd] keyword.
1762 		[example]
1763 			[comment]# copy this script to a file and run /[cmd]parse[/cmd] <filename>[/comment]
1764 			global %a
1765 			%a = "The contents of the variable a"
1766 			%b = "The contents of the variable b"
1767 			[comment]# %a is a global variable now : all the other scripts can see its value[/comment]
1768 			[comment]# %b is a local variable and no other scripts can see its value[/comment]
1769 		[/example]
1770 		[br]
1771 		If you have executed the example above from a file (by the means of [cmd]parse[/cmd])
1772 		then now you can type
1773 		[example]
1774 			[cmd]echo[/cmd] %a
1775 		[/example]
1776 		[br]
1777 		in the commandline to see the contents of the variable %a.
1778 		If you also try
1779 		[example]
1780 			[cmd]echo[/cmd] %b
1781 		[/example]
1782 		[br]
1783 		you will see nothing printed since %b was local to the parsed script.
1784 		[title]Data types[/title]
1785 		[br]
1786 		KVS has three main categories of data types: scalars, arrays and associative
1787 		arrays (also known as dictionaries or hashes).
1788 		[subtitle]Scalars[/subtitle]
1789 		[br]
1790 		The scalars are simple variables containing a single value (a string or an integer).
1791 		[example]
1792 			[comment]# %a is a scalar variable[/comment]
1793 			%a = "This is a string"
1794 			[cmd]echo[/cmd] %a
1795 			%a = 24.5
1796 			[cmd]echo[/cmd] %a
1797 		[/example]
1798 		[subtitle]Arrays[/subtitle]
1799 		[br]
1800 		Arrays are collections of items indexed by integers. The array items
1801 		are selected by placing the index in square brackets just after the array name.
1802 		[example]
1803 			%arrayName[index]
1804 		[/example]
1805 		[br]
1806 		An easy way to create an array is to use the [fnc]$array[/fnc] function.
1807 		[example]
1808 			%a = $array("element1","element2","element3"); [comment]# Create an array with 3 items[/comment]
1809 			[cmd]for[/cmd](%i=0;%i<3;%i++)
1810 			{
1811 				echo %a[%i]; [comment]# Accessing the %i'th element of the array[/comment]
1812 			}
1813 		[/example]
1814 		[br]
1815 		Note that in the example above %a refers to the whole array while %a[%i] refers
1816 		to one of its elements, in particular the one with index %i.
1817 		You also create an array by explicitly assigning to one of its elements:
1818 		[example]
1819 			%a[9] = "This is an array element";
1820 		[/example]
1821 		[br]
1822 		Array indexes are zero-based so in the example above you have created an array
1823 		with 10 items. You can find out an array's length with the [fnc]$length[/fnc]() function.
1824 		[example]
1825 			%a[9] = "This is an array element";
1826 			echo $length(%a)
1827 		[/example]
1828 		[br]
1829 		Be aware that by making such an assignment you implicitly consume some memory for
1830 		all the preceding array items (even if they are unset). This means that
1831 		a simple instruction like the following may eat a huge amount of memory at once:
1832 		[example]
1833 			%a[1000000] = "An array element faaaaaar away...";
1834 			echo $length(%a)
1835 		[/example]
1836 		[note]
1837 		[big]Food for thought:[/big]
1838 		KVIrc allocates a pointer for each item in the array. The pointer is
1839 		empty when the item is unset and points to an additional block
1840 		of memory when the item is set. The size of a pointer is platform
1841 		dependent: on the platforms supported by KVIrc it's either 32 or 64-bit.
1842 		The size of the additional block depends both on the platform
1843 		and on the contents of the item... it's average value may
1844 		be around 16 bytes. The array size is determined by the last SET element index.
1845 		All this this means that in the worst case (64 bit assumption) an array in
1846 		that the highest indexed item set is N eats up at least N*8+16 bytes of memory.
1847 		[/note]
1848 		Besides the traditional indexed looping method you
1849 		can also use the [cmd]foreach[/cmd] command to iterate the items of an array.
1850 		Be aware that [cmd]foreach[/cmd] will [b]not[/b] iterate over unset items in the
1851 		array unless you use the -a switch.
1852 		[example]
1853 			%Array[0]=Pippo
1854 			%Array[1]=Pluto
1855 			%Array[2]=Paperino
1856 			%Array[5]=Prova
1857 			[cmd]foreach[/cmd](%item,%Array)[cmd]echo[/cmd] Got Item: %item
1858 		[/example]
1859 		[br]
1860 		Note that the items 3 and 4 are simply skipped.
1861 		[subtitle]Hashes[/subtitle]
1862 		[br]
1863 		The hashes are collections of items indexed by strings: the word [i]hash[/i]
1864 		is in fact a shortcut for [i]hashtable[/i]. In literature hashes are also called
1865 		[i]associative arrays[/i], [i]dictionaries[/i] or [i]key-value pair sets[i].
1866 		The hash items are selected by placing the key in curly brackets
1867 		just after the hash name.
1868 		[example]
1869 			%hashName{key}
1870 		[/example]
1871 		[br]
1872 		An easy way to create a hash is to use the [fnc]$hash[/fnc] function.
1873 		[/p]
1874 		[example]
1875 			%a = $hash("key1","value1","key2","value2","key3","value3")
1876 			[cmd]foreach[/cmd](%key,[fnc]$keys[/fnc](%a))
1877 			{
1878 				echo "KEY:" %key "VALUE:" %a{%key};
1879 			}
1880 		[/example]
1881 		[br]
1882 		Note that in the example above %a refers to the whole hash while %a{%i} refers
1883 		to one of its elements, in particular the one with the key %key.
1884 		You also create a hash by explicitly assigning to one of its elements:
1885 		[example]
1886 			%a{"MyKey"} = "MyValue"
1887 		[/example]
1888 		[br]
1889 		You may have already noticed that the [fnc]$keys[/fnc]() function returns
1890 		the array of the hash keys: it is useful to iterate over the hash items.
1891 		[title]Mutability of variables[/title]
1892 		[br]
1893 		KVS is not strictly typed: any variable can assume different type identities at different times,
1894 		even in the same script.
1895 		[example]
1896 			[comment]# %a is a scalar[/comment]
1897 			%a = "This is a string"
1898 			[comment]# %a becomes an array with 3 elements[/comment]
1899 			%a = $array("element1","element2","element3");
1900 			[comment]# %a becomes a hash with two values[/comment]
1901 			%a = $hash("key1","value1","key2","value2");
1902 		[/example]
1903 		[br]
1904 		In literature this kind of variable is called [b]variant[/b] and this is the
1905 		term that you will find all around the documentation when an explicit
1906 		data type is not requested.
1907 		[br]
1908 		Note that array and hash items are variants too. This means that you can have arrays
1909 		of arrays, hashes of arrays of hashes and any other multidimensional combination you like.
1910 		However remember that hash keys are strings and not variants so you can't use an array as hash key.
1911 		[example]
1912 			[comment]# here we eat 256 locations of memory at once :)[/comment]
1913 			%a[16][16] = 10
1914 			[comment]# a hash of hashes: here we eat just two memory locations[/comment]
1915 			%a{"16"}{"16"} = 10
1916 		[/example]
1917 		[br]
1918 		In most cases the KVS engine manages automatically the conversion between data types.
1919 		For example, when you put an array in a place where a scalar is requested, KVIrc
1920 		automatically transforms it to a scalar string by joining all the items with a comma.
1921 		[example]
1922 			%a = $array("element1","element2","element3");
1923 			echo %a; [comment]# echo expects its arguments to be scalar[/comment]
1924 		[/example]
1925 		[br]
1926 		Conversely, when you put a scalar in place of an array, KVIrc automatically
1927 		transforms it to an array with a single item. In this way a function like
1928 		[fnc]$sort[/fnc] works also with a scalar.
1929 		[br]
1930 		In literature the conversions between data types are called [b]casts[/b]. When
1931 		the conversion is automatic the cast is said to be [b]implicit[/b].
1932 		[br]
1933 		KVS handles also the other possible implicit casts: scalar->hash,hash->scalar,array->hash,hash->array.
1934 		Experiment with it.
1935 		[title]More about scalars[/title]
1936 		[br]
1937 		Internally KVS is implicitly typed: the [i]scalar[/i] data type is in fact
1938 		a set of types that KVIrc manages silently. The types are: integer, string, real, boolean and hobject.
1939 		[br]
1940 		Integers are non-floating point numbers. Their allowable range depends on the underlying
1941 		platform integer size: usually 32 or 64 bit.
1942 		[br]
1943 		Reals are floating point numbers. Their allowable range and precision depends on the underlying
1944 		platform.
1945 		[br]
1946 		Booleans are either true or false values. For boolean constants, use [fnc]$true[/fnc] or [fnc]$false[/fnc].
1947 		Don't use [i]true[/i] or [i]false[/i], because the engine sees them as non-empty strings, which always evaluate as true.
1948 		[br]
1949 		hobject stands for Handle to Object and it is a sort of a C++ pointer.
1950 		Detailed description of objects is in [doc:objects]this document[/doc].
1951 		[br]
1952 		Basically anything else fails in the [i]string[/i] category.
1953 		[br]
1954 		In most cases KVS manages all the conversions between data types automatically.
1955 		For example an integer becomes a true boolean when it's non zero and a false boolean
1956 		otherwise, a real becomes an integer by truncating it's fractional part...
1957 		[br]
1958 		You can find out the type of a specified variable by using the [fnc]$typeof[/fnc]() function.
1959 		[example]
1960 			%a = 1
1961 			echo $typeof(%a)
1962 			%a = 1.1
1963 			echo $typeof(%a)
1964 			%a = $true
1965 			echo $typeof(%a)
1966 			%a = "test"
1967 			echo $typeof(%a)
1968 		[/example]
1969 		[br]
1970 		There is also another subtle type of scalar called [i]nothing[/i]. It stands for an empty (unset) variable.
1971 		[example]
1972 			%a = $nothing
1973 			echo $typeof(%a)
1974 		[/example]
1975 		[br]
1976 		Nothing is something in between a data type and a special value for all the other data types:
1977 		it represents absence of information.
1978 		This may look a bit confusing but realize that all the unreferenced KVS variable are in fact of type [i]nothing[/i]:
1979 		they just don't exist. This means that you can use [fnc]$nothing[/fnc]() to effectively
1980 		unset a variable.
1981 		[br]
1982 		Again, when possible, the conversion between nothing and the other data types is
1983 		performed automatically. Nothing becomes an empty string, a null object handle or an empty array.
1984 		[title]Explicit casts[/title]
1985 		[br]
1986 		You can make explicit conversions between some data types by using the casting functions.
1987 		[fnc]$integer[/fnc]() will attempt to convert the variant parameter to an integer, [fnc]$real[/fnc]()
1988 		will cast to a floating point value, [fnc]$boolean[/fnc]() will convert to a
1989 		true/false value, [fnc]$string[/fnc]() will explicitly convert to a string,
1990 		[fnc]$array[/fnc]() will convert to an array and [fnc]$hash[/fnc] will return
1991 		a dictionary. By assigning the special [fnc]$nothing[/fnc]() value you will
1992 		convert to the nothing data type (or simply unset the variable).
1993 		The only explicit conversion that is not possible is to hobject.
1994 		[br]
1995 		As stated several times in this document, KVS tries to manage the casts automatically
1996 		so you usually don't need to care about it. The explicit casts are provided for
1997 		the very few cases where an automatic conversion would lead to an unexpected value (for your script)
1998 		and for writer's clarity.
1999 		[title]More about variables life-cycle[/title]
2000 		[br]
2001 		As stated above variables start their existence when you assign something to them.
2002 		After a variable has been created it persists until it goes out of his scope (remember
2003 		about local and global variables?) or you explicitly destroy it. You will usually
2004 		not care about it and just leave the KVS engine to do his cleaning job but it's still worth
2005 		knowing that you actually can force KVIrc to free the memory used by a variable.
2006 		[br]
2007 		The first method to explicitly destroy a variable is to call [cmd]unset[/cmd] on it.
2008 		[cmd]unset[/cmd] in fact accepts a list of variables so you can destroy more variables at once.
2009 		[example]
2010 			%a = [fnc]$array[/fnc]("data","for","a","really","huge","array","of","items")
2011 			%b = 10
2012 			%c = "just a string that eats memory"
2013 			[cmd]unset[/cmd] %a,%b,%c
2014 		[/example]
2015 		[br]
2016 		The KVS engine treats unset variables just like empty strings. The opposite is also valid: empty
2017 		strings behave like empty (unset) variables. This means that you can assign an empty string
2018 		to a variable to unset it.
2019 		[example]
2020 			%a = "test"; [comment]# %a starts his existence[/comment]
2021 			%b = "test2";
2022 			%a = ""; [comment]# %a is in fact unset[/comment]
2023 			%b = ; [comment]# syntactically this is just the same as above[/comment]
2024 		[/example]
2025 		[br]
2026 		Note that because of mutability of variables (explained above) you can use the empty string
2027 		assignment also to free arrays and hashes.
2028 		[title]Extended scope variables[/title]
2029 		[br]
2030 		Beside local and global variables there is a third family of them.
2031 		Variables that have a ':' character just after the leading '%' are [b]extended scope[/b] variables.
2032 		[i]%:index[/i], [i]%:Hello[/i], [i]%:something.else[/i] are all valid special scope variable names.
2033 		They're actually used in popups and in timers (but later I might find other usages as well :).
2034 		"Extended scope" means that these variables are somewhere in the middle between
2035 		global and local variables. They normally act as local, but in some cases their [b]lifetime[/b] and [b]visibility[/b]
2036 		may be extended.
2037 		[br]
2038 		For example, in the popups, all the special scope variables
2039 		are visible during all the "lifetime" of a popup (so from the prologue code call to
2040 		the moment when the user selects an item and the corresponding code is executed).
2041 		This allows you to pre-calculate some data or conditions in the popup prologue
2042 		and use this data in the popup item conditions and item handlers.
2043 		[title]Variable evaluation[/title]
2044 		[br]
2045 		A variable can appear in every place where a parameter
2046 		is expected: so after the command name, after a switch or inside
2047 		an identifier parameters. The KVS parser will try to extract the longest possible variable
2048 		name after a literal percent '%' sign everywhere in the parameter string. So the command sequence
2049 		[example]
2050 			%number = 1st; echo this is my %number variable test
2051 		[/example]
2052 		[br]
2053 		will first assign [i]1st[/i] to the variable [i]%number[/i] and then execute
2054 		"echo this is my 1st variable test". The following example will [b]not[/b] work as expected.
2055 		[example]
2056 			%number = 1; echo this is my %numberst variable test
2057 		[/example]
2058 		[br]
2059 		KVS will assign [b]1[/b] to %number in this case but the next variable
2060 		name extracted will be [i]%numberst[/i] that is actually empty; so finally
2061 		"echo this is my variable test" will be executed.
2062 		To avoid this problem you can use the backslash escape character:
2063 		[example]
2064 			%number = 1; echo this is my %number\st variable test
2065 		[/example]
2066 		[title]Putting it all together[/title]
2067 		[br]
2068 		Variables can be either local, global or have an extended scope. Their start to exist
2069 		when you first assign something to them and they disappear when they go out of their
2070 		scope or you explicitly destroy them.
2071 		[br]
2072 		KVS has 8 builtin data types: string, integer, real, boolean, hobject, nothing, array and hash.
2073 		The first 6 are scalar data types while the last two are not.
2074 		[br]
2075 		When possible, KVS manages all the conversions between data types silently.
2076 		In the few cases in that an implicit conversion is not possible you have to manage the conversion
2077 		manually otherwise KVS will complain.
2078 		[br]
2079 */
2080 
skipSpaces()2081 void KviKvsParser::skipSpaces()
2082 {
2083 	while((KVSP_curCharUnicode == ' ') || (KVSP_curCharUnicode == '\t'))
2084 	{
2085 		KVSP_skipChar;
2086 	}
2087 
2088 	if(KVSP_curCharUnicode == '\\')
2089 	{
2090 		KVSP_skipChar;
2091 		if(KVSP_curCharUnicode == '\n')
2092 		{
2093 			KVSP_skipChar;
2094 			skipSpaces();
2095 			return;
2096 		}
2097 		else if(KVSP_curCharUnicode == '\r')
2098 		{
2099 			KVSP_skipChar;
2100 			if(KVSP_curCharUnicode == '\n')
2101 			{
2102 				KVSP_skipChar;
2103 				skipSpaces();
2104 				return;
2105 			}
2106 			else
2107 			{
2108 				KVSP_backChar;
2109 				KVSP_backChar;
2110 			}
2111 		}
2112 		else
2113 		{
2114 			KVSP_backChar;
2115 		}
2116 	}
2117 }
2118 
skipSpacesAndNewlines()2119 bool KviKvsParser::skipSpacesAndNewlines()
2120 {
2121 	while((KVSP_curCharUnicode == ' ') || (KVSP_curCharUnicode == '\t') || (KVSP_curCharUnicode == '\n') || (KVSP_curCharUnicode == '\r'))
2122 	{
2123 		KVSP_skipChar;
2124 	}
2125 
2126 	switch(KVSP_curCharUnicode)
2127 	{
2128 		case '\\':
2129 			KVSP_skipChar;
2130 			if(KVSP_curCharUnicode == '\n')
2131 			{
2132 				KVSP_skipChar;
2133 				return skipSpacesAndNewlines();
2134 			}
2135 			else if(KVSP_curCharUnicode == '\r')
2136 			{
2137 				KVSP_skipChar;
2138 				if(KVSP_curCharUnicode == '\n')
2139 				{
2140 					KVSP_skipChar;
2141 					return skipSpacesAndNewlines();
2142 				}
2143 				else
2144 				{
2145 					KVSP_backChar;
2146 					KVSP_backChar;
2147 				}
2148 			}
2149 			else
2150 			{
2151 				KVSP_backChar;
2152 			}
2153 			break;
2154 		case '#':
2155 		case '/':
2156 			// we allow comments too!
2157 			(void)parseComment(); // this will return 0 anyway (and never trigger an error here)
2158 			if(error())
2159 				return false;
2160 			return skipSpacesAndNewlines();
2161 			break;
2162 	}
2163 	return true;
2164 }
2165 
skipToNextLine()2166 void KviKvsParser::skipToNextLine()
2167 {
2168 	while((KVSP_curCharUnicode != 0) && (KVSP_curCharUnicode != '\n'))
2169 		KVSP_skipChar;
2170 
2171 	if(KVSP_curCharUnicode == '\n')
2172 		KVSP_skipChar;
2173 }
2174 
parseInstructionList()2175 KviKvsTreeNodeInstruction * KviKvsParser::parseInstructionList()
2176 {
2177 	KviKvsTreeNodeInstructionBlock * l = new KviKvsTreeNodeInstructionBlock(KVSP_curCharPointer);
2178 
2179 	for(;;)
2180 	{
2181 		if(!skipSpacesAndNewlines())
2182 		{
2183 			delete l;
2184 			return nullptr;
2185 		}
2186 
2187 		if(KVSP_curCharUnicode != 0)
2188 		{
2189 			// instruction
2190 			KviKvsTreeNodeInstruction * i = parseInstruction();
2191 			if(i)
2192 				l->addInstruction(i);
2193 			else
2194 			{
2195 				if(error())
2196 				{
2197 					// ops...
2198 					delete l;
2199 					return nullptr;
2200 				} // else empty instruction
2201 			}
2202 		}
2203 		else
2204 		{
2205 			if(l->instructionCount() == 1)
2206 			{
2207 				// return the single instruction instead
2208 				KviKvsTreeNodeInstruction * i = l->releaseFirst();
2209 				delete l;
2210 				return i;
2211 			}
2212 			// end of buffer
2213 			return l;
2214 		}
2215 	}
2216 
2217 	// never here
2218 	KVSP_ASSERT(false);
2219 	return nullptr;
2220 }
2221 
parseParameterPercentOrDollar()2222 KviKvsTreeNodeData * KviKvsParser::parseParameterPercentOrDollar()
2223 {
2224 	KVSP_ASSERT((KVSP_curCharUnicode == '%') || (KVSP_curCharUnicode == '$') || (KVSP_curCharUnicode == '@'));
2225 
2226 	if(KVSP_curCharUnicode == '%')
2227 	{
2228 		KVSP_skipChar;
2229 		if(!KVSP_curCharIsLetter && (KVSP_curCharUnicode != ':'))
2230 		{
2231 			// be flexible : allow an "alone" '%' char
2232 			return new KviKvsTreeNodeConstantData(KVSP_curCharPointer - 1, new KviKvsVariant(QString("%")));
2233 		}
2234 		// this is surely a variable or function
2235 		KVSP_backChar;
2236 	}
2237 	else if(KVSP_curCharUnicode == '$')
2238 	{
2239 		KVSP_skipChar;
2240 		if(!KVSP_curCharIsFunctionStart)
2241 		{
2242 			// be flexible : allow an "alone" '$' char
2243 			return new KviKvsTreeNodeConstantData(KVSP_curCharPointer - 1, new KviKvsVariant(QString("$")));
2244 		}
2245 		// this is surely a variable or function
2246 		KVSP_backChar;
2247 	}
2248 
2249 	return parsePercentOrDollar();
2250 }
2251 
parsePercentOrDollar(bool bInObjScope)2252 KviKvsTreeNodeData * KviKvsParser::parsePercentOrDollar(bool bInObjScope)
2253 {
2254 	KVSP_ASSERT((KVSP_curCharUnicode == '%') || (KVSP_curCharUnicode == '$') || (KVSP_curCharUnicode == '@'));
2255 
2256 	KviKvsTreeNodeData * r;
2257 	const QChar * pBegin;
2258 
2259 	if(KVSP_curCharUnicode == '%')
2260 	{
2261 		r = parsePercent(bInObjScope);
2262 		if(!r)
2263 			return nullptr;
2264 	}
2265 	else if(KVSP_curCharUnicode == '$')
2266 	{
2267 		r = parseDollar(bInObjScope);
2268 		if(!r)
2269 			return nullptr;
2270 	}
2271 	else
2272 	{
2273 		// this is @
2274 
2275 		static QString szStrayAtRoutineName("@");
2276 		static QString szMightBeStrayAtOrThisRoutineName("@?");
2277 
2278 		pBegin = KVSP_curCharPointer;
2279 
2280 		KVSP_skipChar;
2281 
2282 		if(bInObjScope || ((KVSP_curCharUnicode != '$') && (KVSP_curCharUnicode != '%')))
2283 		{
2284 			// we're sure this is just a stray @
2285 			// we use a trick here: when @ is not supposed to be an object scope call
2286 			// then we create a function that will return the @ itself as a string
2287 			KviKvsCoreFunctionExecRoutine * pRoutine = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szStrayAtRoutineName);
2288 			r = new KviKvsTreeNodeCoreFunctionCall(KVSP_curCharPointer, szStrayAtRoutineName, pRoutine, new KviKvsTreeNodeDataList(KVSP_curCharPointer));
2289 			//KVSP_skipChar;
2290 			return r;
2291 		}
2292 		// we're not in object scope and cur char is either $ or %
2293 		// check for the common syntax $0!$1@$2 seen in hostmasks
2294 		// @$<digit> is non valid anyway
2295 		if(KVSP_curCharUnicode == '$')
2296 		{
2297 			KVSP_skipChar;
2298 			if(KVSP_curCharIsNumber)
2299 			{
2300 				// again a stray @
2301 				KVSP_backChar;
2302 				KviKvsCoreFunctionExecRoutine * pRoutine = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szStrayAtRoutineName);
2303 				r = new KviKvsTreeNodeCoreFunctionCall(KVSP_curCharPointer, szStrayAtRoutineName, pRoutine, new KviKvsTreeNodeDataList(KVSP_curCharPointer));
2304 				return r;
2305 			}
2306 			KVSP_backChar;
2307 		}
2308 
2309 		// now we're unsure: we will be able to decide only at runtime if it is a stray @ or the shortcut for $this
2310 		// this design was a bit ugly.. I must admit it... but it is really useful when writing object classes...
2311 		KviKvsCoreFunctionExecRoutine * pRoutine = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szMightBeStrayAtOrThisRoutineName);
2312 		// MUST BE THERE!
2313 		// core function call
2314 		r = new KviKvsTreeNodeCoreFunctionCall(pBegin, szMightBeStrayAtOrThisRoutineName, pRoutine, new KviKvsTreeNodeDataList(pBegin));
2315 
2316 		skipSpaces();
2317 
2318 		pBegin = KVSP_curCharPointer;
2319 
2320 		goto handle_scope_operator;
2321 	}
2322 
2323 	pBegin = KVSP_curCharPointer;
2324 
2325 	while((KVSP_curCharUnicode == '[') || (KVSP_curCharUnicode == '{'))
2326 	{
2327 		if(KVSP_curCharUnicode == '[')
2328 		{
2329 			// array index
2330 			KVSP_skipChar;
2331 			skipSpaces();
2332 			if(KVSP_curCharUnicode == ']')
2333 			{
2334 				KVSP_skipChar;
2335 				if(KVSP_curCharUnicode == '#')
2336 				{
2337 					// count
2338 					KVSP_skipChar;
2339 					return new KviKvsTreeNodeArrayCount(pBegin, r);
2340 				}
2341 				else
2342 				{
2343 					// a hash reference assert
2344 					return new KviKvsTreeNodeArrayReferenceAssert(pBegin, r);
2345 				}
2346 			}
2347 
2348 			KviKvsTreeNodeExpression * e = parseExpression(']');
2349 			if(!e)
2350 			{
2351 				delete r;
2352 				return nullptr;
2353 			}
2354 
2355 			r = new KviKvsTreeNodeArrayElement(pBegin, r, e);
2356 		}
2357 		else
2358 		{
2359 			// hash key
2360 			KVSP_skipChar;
2361 			skipSpaces();
2362 
2363 			if(KVSP_curCharUnicode == '}')
2364 			{
2365 				// entire hash ?
2366 				KVSP_skipChar;
2367 				if(KVSP_curCharUnicode == '#')
2368 				{
2369 					KVSP_skipChar;
2370 					return new KviKvsTreeNodeHashCount(pBegin, r);
2371 				}
2372 				return new KviKvsTreeNodeHashReferenceAssert(pBegin, r);
2373 			}
2374 
2375 			KviKvsTreeNodeData * i = parseHashKey();
2376 			if(!i)
2377 			{
2378 				// error
2379 				delete r;
2380 				return nullptr;
2381 			}
2382 
2383 			KVSP_ASSERT(KVSP_curCharUnicode == '}');
2384 
2385 			KVSP_skipChar;
2386 
2387 			r = new KviKvsTreeNodeHashElement(pBegin, r, i);
2388 		}
2389 	}
2390 
2391 	if(KVSP_curCharUnicode != '-')
2392 	{
2393 		return r;
2394 	}
2395 
2396 	if(!r->canEvaluateToObjectReference())
2397 		return r; // FIXME: maybe print a warning ?
2398 
2399 	// might be a scope operator
2400 
2401 	KVSP_skipChar;
2402 	if(KVSP_curCharUnicode != '>')
2403 	{
2404 		KVSP_backChar;
2405 		return r;
2406 	}
2407 
2408 	KVSP_skipChar;
2409 	skipSpaces();
2410 
2411 	if((KVSP_curCharUnicode != '$') && (KVSP_curCharUnicode != '%'))
2412 	{
2413 		KVSP_setCurCharPointer(pBegin);
2414 		return r;
2415 	}
2416 
2417 handle_scope_operator:
2418 
2419 	// hmmm... there really seems to be a scope operator there...
2420 	if(KVSP_curCharUnicode == '%')
2421 	{
2422 		KVSP_skipChar;
2423 		if(!KVSP_curCharIsLetter)
2424 		{
2425 			// be flexible : allow an "alone" '%' char
2426 			KVSP_setCurCharPointer(pBegin);
2427 			return r;
2428 		}
2429 	}
2430 	else
2431 	{
2432 		KVSP_skipChar;
2433 		if(!KVSP_curCharIsFunctionStart)
2434 		{
2435 			// be flexible : allow an "alone" '$' char
2436 			KVSP_setCurCharPointer(pBegin);
2437 			return r;
2438 		}
2439 	}
2440 
2441 	// ok : try the scope operator
2442 	KVSP_backChar;
2443 
2444 	pBegin = KVSP_curCharPointer;
2445 
2446 	KviKvsTreeNodeData * r2 = parsePercentOrDollar(true);
2447 
2448 	if(!r2)
2449 	{
2450 		// must be an error
2451 		delete r;
2452 		return nullptr;
2453 	}
2454 
2455 	if(!r2->canEvaluateInObjectScope())
2456 	{
2457 		// ops... it really wasn't
2458 		delete r2;
2459 		KVSP_setCurCharPointer(pBegin);
2460 		return r;
2461 	}
2462 
2463 	return new KviKvsTreeNodeScopeOperator(pBegin, r, r2);
2464 }
2465 
parsePercent(bool bInObjScope)2466 KviKvsTreeNodeVariable * KviKvsParser::parsePercent(bool bInObjScope)
2467 {
2468 	KVSP_ASSERT(KVSP_curCharUnicode == '%');
2469 
2470 	const QChar * pBegin = KVSP_curCharPointer;
2471 
2472 	KVSP_skipChar;
2473 
2474 	bool bExtScope;
2475 
2476 	if(KVSP_curCharUnicode == ':')
2477 	{
2478 		bExtScope = true;
2479 		KVSP_skipChar;
2480 	}
2481 	else
2482 	{
2483 		bExtScope = false;
2484 	}
2485 
2486 	if(!((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_')))
2487 	{
2488 		error(KVSP_curCharPointer, __tr2qs_ctx("Syntax error after '%' variable prefix. If you want to use a plain '%' in the code you need to escape it", "kvs"));
2489 		return nullptr;
2490 	}
2491 
2492 	const QChar * pIdBegin = KVSP_curCharPointer;
2493 
2494 	while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_'))
2495 		KVSP_skipChar;
2496 
2497 	QString szIdentifier(pIdBegin, KVSP_curCharPointer - pIdBegin);
2498 
2499 	//#warning "ADD A KviKvsTreeNodeBuiltinCleanupVariablesCommand on this KviKvsParser object"
2500 	//#warning "KviKvsParser will append it to the script"
2501 
2502 	if(bExtScope)
2503 	{
2504 		if(bInObjScope)
2505 		{
2506 			error(KVSP_curCharPointer, __tr2qs_ctx("Objects have no extended scope variables", "kvs"));
2507 			return nullptr;
2508 		}
2509 		return new KviKvsTreeNodeExtendedScopeVariable(pBegin, szIdentifier);
2510 	}
2511 
2512 	if(bInObjScope)
2513 		return new KviKvsTreeNodeObjectField(pBegin, szIdentifier);
2514 
2515 	// Check if explicitly declared as global
2516 	if(m_pGlobals)
2517 	{
2518 		if(m_pGlobals->find(szIdentifier))
2519 			return new KviKvsTreeNodeGlobalVariable(pBegin, szIdentifier);
2520 	}
2521 
2522 	if(m_iFlags & AssumeLocals)
2523 		return new KviKvsTreeNodeLocalVariable(pBegin, szIdentifier);
2524 
2525 	if(pIdBegin->category() == QChar::Letter_Uppercase)
2526 	{
2527 		//qDebug("Variable %s is global",szIdentifier.toUtf8().data());
2528 		//if(m_iFlags & Pedantic)
2529 		//	warning(pIdBegin,__tr2qs_ctx("Declaring global variables with an uppercase letter is deprecated. Global variables should be declared with 'global'","kvs"));
2530 		return new KviKvsTreeNodeGlobalVariable(pBegin, szIdentifier);
2531 	}
2532 
2533 	return new KviKvsTreeNodeLocalVariable(pBegin, szIdentifier);
2534 }
2535 
parseInstruction()2536 KviKvsTreeNodeInstruction * KviKvsParser::parseInstruction()
2537 {
2538 	switch(KVSP_curCharUnicode)
2539 	{
2540 		case '#':
2541 		case '/':
2542 			(void)parseComment(); // this will return 0 anyway
2543 			return nullptr;
2544 			break;
2545 		case 0: // empty instruction
2546 			return nullptr;
2547 			break;
2548 		case '\n':
2549 		case '\r':
2550 		case ';': // empty instruction
2551 			KVSP_skipChar;
2552 			return nullptr;
2553 			break;
2554 		case '{': // command block
2555 			return parseInstructionBlock();
2556 			break;
2557 		case '$':
2558 		case '%':
2559 		case '@':
2560 			return parseVoidFunctionCallOrOperation();
2561 			break;
2562 		default:
2563 			if(KVSP_curCharIsLetter || (KVSP_curCharUnicode == '_'))
2564 			{
2565 				// must be a command
2566 				return parseCommand();
2567 			}
2568 			else
2569 			{
2570 				// what the heck is this ?
2571 				error(KVSP_curCharPointer, __tr2qs_ctx("Found character '%q' (Unicode %x) where an instruction was expected", "kvs"), KVSP_curCharPointer, KVSP_curCharUnicode);
2572 				return nullptr;
2573 			}
2574 			break;
2575 	}
2576 	// never here
2577 	KVSP_ASSERT(false);
2578 	return nullptr;
2579 }
2580 
parseInstructionBlock()2581 KviKvsTreeNodeInstruction * KviKvsParser::parseInstructionBlock()
2582 {
2583 	KVSP_ASSERT(KVSP_curCharUnicode == '{');
2584 
2585 	KVSP_skipChar;
2586 
2587 	const QChar * pBegin = KVSP_curCharPointer;
2588 
2589 	KviKvsTreeNodeInstructionBlock * b = new KviKvsTreeNodeInstructionBlock(pBegin - 1);
2590 
2591 	for(;;)
2592 	{
2593 		if(!skipSpacesAndNewlines())
2594 		{
2595 			delete b;
2596 			return nullptr;
2597 		}
2598 
2599 		switch(KVSP_curCharUnicode)
2600 		{
2601 			case 0:
2602 				delete b;
2603 				warning(pBegin, __tr2qs_ctx("Unterminated instruction block", "kvs"));
2604 				error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of script in instruction block (missing closing brace)", "kvs"));
2605 				return nullptr;
2606 				break;
2607 			case '}':
2608 				KVSP_skipChar;
2609 				if(b->instructionCount() <= 1)
2610 				{
2611 					if(b->instructionCount() < 1)
2612 					{
2613 						delete b;
2614 						return nullptr; // just an empty block
2615 					}
2616 					// a single instruction
2617 					KviKvsTreeNodeInstruction * i = b->releaseFirst();
2618 					delete b;
2619 					return i;
2620 				}
2621 				return b;
2622 				break;
2623 			default:
2624 				// instruction
2625 				KviKvsTreeNodeInstruction * i = parseInstruction();
2626 				if(i)
2627 					b->addInstruction(i);
2628 				else
2629 				{
2630 					if(error())
2631 					{
2632 						// ops...
2633 						delete b;
2634 						return nullptr;
2635 					} // else empty instruction
2636 				}
2637 				break;
2638 		}
2639 	}
2640 	// never reached
2641 	return nullptr;
2642 }
2643 
parseCommandSwitchList()2644 KviKvsTreeNodeSwitchList * KviKvsParser::parseCommandSwitchList()
2645 {
2646 	KVSP_ASSERT(KVSP_curCharUnicode == '-');
2647 
2648 	KviKvsTreeNodeSwitchList * sw = new KviKvsTreeNodeSwitchList(KVSP_curCharPointer);
2649 
2650 	while(KVSP_curCharUnicode == '-')
2651 	{
2652 		const QChar * pBegin = KVSP_curCharPointer;
2653 		KVSP_skipChar;
2654 
2655 		bool bLong = false;
2656 
2657 		if(KVSP_curCharUnicode == '-')
2658 		{
2659 			// long switch
2660 			pBegin = KVSP_curCharPointer;
2661 			KVSP_skipChar;
2662 			bLong = true;
2663 		}
2664 
2665 		skipSpaces();
2666 		if(!KVSP_curCharIsLetter)
2667 		{
2668 			if(KVSP_curCharIsNumber || KVSP_curCharIsEndOfCommand)
2669 			{
2670 				// a -digit : this is probably a negative number instead
2671 				// or just a single dash (or couple of dashes)
2672 				// go back to the initial dash and treat it as text...and return the current switch list
2673 				KVSP_setCurCharPointer(pBegin);
2674 				if(sw->isEmpty())
2675 				{
2676 					// not an error!
2677 					delete sw;
2678 					return nullptr;
2679 				}
2680 				return sw;
2681 			}
2682 			else
2683 			{
2684 				delete sw;
2685 				warning(pBegin, __tr2qs_ctx("The dash after a command should be followed by a letter (switch), by a digit (negative number) or be escaped", "kvs"));
2686 
2687 				if(KVSP_curCharUnicode == 0)
2688 				{
2689 					error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected character '%q' (Unicode %x) after a switch dash", "kvs"), KVSP_curCharPointer, KVSP_curCharUnicode);
2690 				}
2691 				else
2692 				{
2693 					error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of script after a switch dash", "kvs"));
2694 				}
2695 				return nullptr;
2696 			}
2697 		}
2698 
2699 		const QChar * pSw = KVSP_curCharPointer;
2700 
2701 		KVSP_skipChar;
2702 		while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '-'))
2703 			KVSP_skipChar;
2704 
2705 		const QChar * pSwEnd = KVSP_curCharPointer;
2706 
2707 		skipSpaces();
2708 
2709 		if(KVSP_curCharUnicode == '=')
2710 		{
2711 			KVSP_skipChar;
2712 			skipSpaces();
2713 			KviKvsTreeNodeData * p = parseCommandParameter();
2714 			if(!p)
2715 			{
2716 				// must be an error :(
2717 				if(error())
2718 				{
2719 					error(pBegin, __tr2qs_ctx("The above problem might be related to the switch dash and the following equal sign", "kvs"));
2720 					delete sw;
2721 					return nullptr;
2722 				}
2723 				else
2724 				{
2725 					// assume empty string
2726 					p = new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant(QString("")));
2727 				}
2728 			}
2729 
2730 			skipSpaces();
2731 
2732 			if(bLong)
2733 				sw->addLong(QString(pSw, pSwEnd - pSw), p);
2734 			else
2735 				sw->addShort(pSw->toLower().unicode(), p);
2736 		}
2737 		else
2738 		{
2739 			if(bLong)
2740 				sw->addLong(QString(pSw, pSwEnd - pSw), new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant(true))); // empty param
2741 			else
2742 				sw->addShort(pSw->toLower().unicode(), new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant(true))); // empty param
2743 		}
2744 	}
2745 
2746 	return sw;
2747 }
2748 
parseCommandParameterList()2749 KviKvsTreeNodeDataList * KviKvsParser::parseCommandParameterList()
2750 {
2751 	KviKvsTreeNodeDataList * l = new KviKvsTreeNodeDataList(KVSP_curCharPointer);
2752 
2753 	for(;;)
2754 	{
2755 		skipSpaces();
2756 		switch(KVSP_curCharUnicode)
2757 		{
2758 			case 0:
2759 				return l;
2760 				break;
2761 			case '\r':
2762 			case '\n':
2763 			case ';':
2764 				KVSP_skipChar;
2765 				return l;
2766 				break;
2767 			default:
2768 				// anything else is a parameter
2769 				KviKvsTreeNodeData * p = parseCommandParameter();
2770 				if(!p)
2771 				{
2772 					// this is an error
2773 					delete l;
2774 					return nullptr;
2775 				}
2776 				l->addItem(p);
2777 				break;
2778 		}
2779 	}
2780 
2781 	// never here
2782 	KVSP_ASSERT(false);
2783 	return nullptr;
2784 }
2785 
parseCommaSeparatedParameterListNoTree()2786 KviPointerList<QString> * KviKvsParser::parseCommaSeparatedParameterListNoTree()
2787 {
2788 	KviPointerList<QString> * l = new KviPointerList<QString>;
2789 	l->setAutoDelete(true);
2790 
2791 	KVSP_skipChar;
2792 
2793 	for(;;)
2794 	{
2795 		skipSpaces();
2796 		switch(KVSP_curCharUnicode)
2797 		{
2798 			case 0:
2799 				error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of script in parameter list", "kvs"));
2800 				delete l;
2801 				return nullptr;
2802 				break;
2803 			case '\r':
2804 			case '\n':
2805 				error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of line in parameter list", "kvs"));
2806 				delete l;
2807 				return nullptr;
2808 				break;
2809 			/*
2810 			case ',':
2811 				KVSP_skipChar;
2812 			break;
2813 			case ')':
2814 				KVSP_skipChar;
2815 				return l;
2816 			break;
2817 			*/
2818 			default:
2819 			{
2820 				// anything else is a parameter
2821 				const QChar * pBegin = KVSP_curCharPointer;
2822 				KviKvsTreeNodeData * p = parseCommaSeparatedParameter();
2823 				if(!p)
2824 				{
2825 					// this is an error
2826 					delete l;
2827 					return nullptr;
2828 				}
2829 				delete p;
2830 				QString * s = new QString(QString(pBegin, KVSP_curCharPointer - pBegin).trimmed());
2831 				l->append(s);
2832 
2833 				switch(KVSP_curCharUnicode)
2834 				{
2835 					case ',':
2836 						KVSP_skipChar;
2837 						break;
2838 					case ')':
2839 						KVSP_skipChar;
2840 						return l;
2841 						break;
2842 				}
2843 			}
2844 			break;
2845 		}
2846 	}
2847 
2848 	// never here
2849 	KVSP_ASSERT(false);
2850 	return nullptr;
2851 }
2852 
parseCommaSeparatedParameterList()2853 KviKvsTreeNodeDataList * KviKvsParser::parseCommaSeparatedParameterList()
2854 {
2855 	KviKvsTreeNodeDataList * l = new KviKvsTreeNodeDataList(KVSP_curCharPointer);
2856 
2857 	KVSP_skipChar;
2858 
2859 	for(;;)
2860 	{
2861 		skipSpaces();
2862 		switch(KVSP_curCharUnicode)
2863 		{
2864 			case 0:
2865 				error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of script in parameter list", "kvs"));
2866 				delete l;
2867 				return nullptr;
2868 				break;
2869 			case '\r':
2870 			case '\n':
2871 				error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of line in parameter list", "kvs"));
2872 				delete l;
2873 				return nullptr;
2874 				break;
2875 			/*
2876 			case ',':
2877 				KVSP_skipChar;
2878 			break;
2879 			case ')':
2880 				KVSP_skipChar;
2881 				return l;
2882 			break;
2883 			*/
2884 			default:
2885 				// anything else is a parameter
2886 				KviKvsTreeNodeData * p = parseCommaSeparatedParameter();
2887 				if(!p)
2888 				{
2889 					// this is an error
2890 					delete l;
2891 					return nullptr;
2892 				}
2893 				l->addItem(p);
2894 
2895 				switch(KVSP_curCharUnicode)
2896 				{
2897 					case ',':
2898 						KVSP_skipChar;
2899 						break;
2900 					case ')':
2901 						KVSP_skipChar;
2902 						return l;
2903 						break;
2904 				}
2905 				break;
2906 		}
2907 	}
2908 
2909 	// never here
2910 	KVSP_ASSERT(false);
2911 	return nullptr;
2912 }
2913 
2914 #define LITERAL_PARAM_PARSING_FUNCTION_BEGIN(__funcname)    \
2915 	KviKvsTreeNodeConstantData * KviKvsParser::__funcname() \
2916 	{                                                       \
2917 		QString szValue;                                    \
2918                                                             \
2919 		[[maybe_unused]] const QChar * pStart = KVSP_curCharPointer;         \
2920 		const QChar * pBegin = KVSP_curCharPointer;         \
2921 		int iLen = 0;                                       \
2922 		[[maybe_unused]] int iNestedTerminators = 0;                         \
2923                                                             \
2924 		for(;;)                                             \
2925 		{                                                   \
2926 			switch(KVSP_curCharUnicode)                     \
2927 			{
2928 
2929 #define LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR                                                                                                                                                      \
2930 	if(!_OUTPUT_MUTE)                                                                                                                                                                                              \
2931 		warning(KVSP_curCharPointer, __tr2qs_ctx("Nested character %q corresponding to expected terminator, this might confuse me a bit: it is a good idea to enclose it in quotes", "kvs"), KVSP_curCharPointer); \
2932 	KVSP_skipChar;                                                                                                                                                                                                 \
2933 	iNestedTerminators++;                                                                                                                                                                                          \
2934 	iLen++;                                                                                                                                                                                                        \
2935 	break;
2936 
2937 #define LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR                                                           \
2938 	if(iNestedTerminators > 0)                                                                                                \
2939 	{                                                                                                                         \
2940 		if(!_OUTPUT_MUTE)                                                                                                     \
2941 			warning(KVSP_curCharPointer, __tr2qs_ctx("Skipping nested terminator character %q", "kvs"), KVSP_curCharPointer); \
2942 		KVSP_skipChar;                                                                                                        \
2943 		iNestedTerminators--;                                                                                                 \
2944 		iLen++;                                                                                                               \
2945 	}                                                                                                                         \
2946 	else                                                                                                                      \
2947 	{                                                                                                                         \
2948 		if(iLen > 0)                                                                                                          \
2949 			szValue.append(QString(pBegin, iLen));                                                                            \
2950 		{                                                                                                                     \
2951 			bool bOk;                                                                                                         \
2952 			kvs_int_t iVal = szValue.toLong(&bOk);                                                                            \
2953 			if(bOk)                                                                                                           \
2954 				return new KviKvsTreeNodeConstantData(pBegin, new KviKvsVariant(iVal));                                       \
2955 			kvs_real_t dVal = szValue.toDouble(&bOk);                                                                         \
2956 			if(bOk)                                                                                                           \
2957 				return new KviKvsTreeNodeConstantData(pBegin, new KviKvsVariant(dVal));                                       \
2958 		}                                                                                                                     \
2959 		return new KviKvsTreeNodeConstantData(pBegin, new KviKvsVariant(szValue));                                            \
2960 	}                                                                                                                         \
2961 	break;
2962 
2963 #define LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END                                                                \
2964 	if(iLen > 0)                                                                                                  \
2965 		szValue.append(QString(pBegin, iLen));                                                                    \
2966 	return new KviKvsTreeNodeConstantData(pBegin, new KviKvsVariant(szValue));                                    \
2967 	break;                                                                                                        \
2968 	case '\\':                                                                                                    \
2969 		if(iLen > 0)                                                                                              \
2970 			szValue.append(QString(pBegin, iLen));                                                                \
2971 		KVSP_skipChar;                                                                                            \
2972 		switch(KVSP_curCharUnicode)                                                                               \
2973 		{                                                                                                         \
2974 			case 0:                                                                                               \
2975 				warning(KVSP_curCharPointer - 1, __tr2qs_ctx("Stray backslash at the end of the script", "kvs")); \
2976 				iLen = 0;                                                                                         \
2977 				break;                                                                                            \
2978 			case '\r':                                                                                            \
2979 			case '\n':                                                                                            \
2980 				KVSP_skipChar;                                                                                    \
2981 				pBegin = KVSP_curCharPointer;                                                                     \
2982 				iLen = 0;                                                                                         \
2983 				break;                                                                                            \
2984 			case 'r':                                                                                             \
2985 				KVSP_skipChar;                                                                                    \
2986 				pBegin = KVSP_curCharPointer;                                                                     \
2987 				szValue.append(QChar('\r'));                                                                      \
2988 				iLen = 0;                                                                                         \
2989 				break;                                                                                            \
2990 			case 'n':                                                                                             \
2991 				KVSP_skipChar;                                                                                    \
2992 				pBegin = KVSP_curCharPointer;                                                                     \
2993 				szValue.append(QChar('\n'));                                                                      \
2994 				iLen = 0;                                                                                         \
2995 				break;                                                                                            \
2996 			case 't':                                                                                             \
2997 				KVSP_skipChar;                                                                                    \
2998 				pBegin = KVSP_curCharPointer;                                                                     \
2999 				szValue.append(QChar('\t'));                                                                      \
3000 				iLen = 0;                                                                                         \
3001 				break;                                                                                            \
3002 			default:                                                                                              \
3003 				pBegin = KVSP_curCharPointer;                                                                     \
3004 				KVSP_skipChar;                                                                                    \
3005 				iLen = 1;                                                                                         \
3006 				break;                                                                                            \
3007 		}                                                                                                         \
3008 		break;                                                                                                    \
3009 	default:                                                                                                      \
3010 		KVSP_skipChar;                                                                                            \
3011 		iLen++;                                                                                                   \
3012 		break;                                                                                                    \
3013 		}                                                                                                         \
3014 		}                                                                                                         \
3015 		KVSP_ASSERT(false);                                                                                       \
3016 		return nullptr;                                                                                           \
3017 		}
3018 
3019 LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseCommandLiteralParameter)
3020 
3021 case 0:
3022 case '$':
3023 case '%':
3024 case '@':
3025 case '\r':
3026 case '\n':
3027 case '"':
3028 case ';':
3029 case ' ':
3030 case '\t':
3031 	LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END
3032 
3033 	LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseStringLiteralParameter)
3034 
3035 case 0:
3036 case '$':
3037 case '%':
3038 case '@':
3039 case '\r':
3040 case '\n':
3041 case '"':
3042 	LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END
3043 
3044 	/*
3045 LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseArrayIndexLiteralParameter)
3046 			case '\t':
3047 			case ' ':
3048 			case ']':
3049 LITERAL_PARAM_PARSING_FUNCTION_END
3050 */
3051 
3052 	LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseHashKeyLiteralParameter)
3053 
3054 case '{':
3055 	LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR
3056 case '}':
3057 	LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR
3058 case 0:
3059 case '$':
3060 case '%':
3061 case '@':
3062 case '\r':
3063 case '\n':
3064 case '"':
3065 case '\t':
3066 case ' ':
3067 	LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END
3068 
3069 	LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseCommaSeparatedLiteralParameter)
3070 
3071 case '(':
3072 	LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR
3073 case ')':
3074 	LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR
3075 case 0:
3076 case '$':
3077 case '%':
3078 case '@':
3079 case '\r':
3080 case '\n':
3081 case '"':
3082 case ',':
3083 case ' ':
3084 case '\t':
3085 	LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END
3086 
3087 	LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseSingleLiteralParameterInParenthesis)
3088 
3089 case '(':
3090 	LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR
3091 case ')':
3092 	LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR
3093 case 0:
3094 case '$':
3095 case '%':
3096 case '@':
3097 case '\r':
3098 case '\n':
3099 case '"':
3100 case ' ':
3101 case '\t':
3102 	LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END
3103 
3104 	LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseBindingOperationLiteralParameter)
3105 
3106 case 0:
3107 case '$':
3108 case '%':
3109 case '@':
3110 case '\r':
3111 case '\n':
3112 case '"':
3113 case '/':
3114 	LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END
3115 
3116 	/*
3117 KviKvsTreeNodeData * KviKvsParser::parseArrayIndex()
3118 {
3119 	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
3120 	l->setAutoDelete(true);
3121 
3122 	const QChar * pBegin = KVSP_curCharPointer;
3123 
3124 	//KVSP_skipChar;
3125 
3126 	for(;;)
3127 	{
3128 		switch(KVSP_curCharUnicode)
3129 		{
3130 			case 0:
3131 				delete l;
3132 				warning(pBegin,__tr2qs_ctx("Unterminated array index","kvs"));
3133 				error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected end of script in array index (missing ']' character?)","kvs"));
3134 				return nullptr;
3135 			break;
3136 			case '\n':
3137 				delete l;
3138 				warning(pBegin,__tr2qs_ctx("Unterminated array index","kvs"));
3139 				error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected end of line in array index (missing ']' character or unescaped newline)","kvs"));
3140 				return nullptr;
3141 			break;
3142 			case ' ':
3143 			case '\t':
3144 				skipSpaces();
3145 				if(KVSP_curCharUnicode != ']')
3146 				{
3147 					delete l;
3148 					warning(pBegin,__tr2qs_ctx("Unterminated array index","kvs"));
3149 					switch(KVSP_curCharUnicode)
3150 					{
3151 						case 0:
3152 							error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected end of script in array index (missing ']' character?)","kvs"));
3153 						break;
3154 						case '\n':
3155 							error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected end of line in array index (missing ']' character or unescaped newline)","kvs"));
3156 						break;
3157 						default:
3158 							error(KVSP_curCharPointer,__tr2qs_ctx("Unexpected character '%q' (Unicode %x) in array index: it should be already terminated","kvs"),KVSP_curCharPointer,KVSP_curCharUnicode);
3159 						break;
3160 					}
3161 					return nullptr;
3162 				}
3163 				goto end_of_the_array_index;
3164 			break;
3165 			case '$':
3166 			case '%':
3167 			{
3168 				// this may be a data reference
3169 				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
3170 				if(!p)
3171 				{
3172 					// this is an error
3173 					delete l;
3174 					return nullptr;
3175 				}
3176 				l->append(p);
3177 			}
3178 			break;
3179 			case ']':
3180 			{
3181 				// end of the array index
3182 				goto end_of_the_array_index;
3183 			}
3184 			break;
3185 			case '"':
3186 			{
3187 				// string (should we parse strings in array indexes anyway ?).. well "1"$count might be a valid one in the end
3188 				KviKvsTreeNodeData * p = parseStringParameter();
3189 				if(!p)
3190 				{
3191 					// error
3192 					delete l;
3193 					return nullptr;
3194 				}
3195 				l->append(p);
3196 			}
3197 			break;
3198 			default:
3199 			{
3200 				// anything else is a literal
3201 				l->append(parseArrayIndexLiteralParameter());
3202 			}
3203 			break;
3204 		}
3205 	}
3206 end_of_the_array_index:
3207 	if(l->count() > 1)
3208 	{
3209 		// complex parameter needed
3210 		return new KviKvsTreeNodeCompositeData(l);
3211 	} else {
3212 		// a single parameter in the list
3213 		l->setAutoDelete(false);
3214 		KviKvsTreeNodeData * p = l->first();
3215 		delete l;
3216 		return p;
3217 	}
3218 
3219 }
3220 */
3221 
parseHashKey()3222 	KviKvsTreeNodeData * KviKvsParser::parseHashKey()
3223 	{
3224 		KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
3225 		l->setAutoDelete(true);
3226 
3227 		const QChar * pBegin = KVSP_curCharPointer;
3228 
3229 		//KVSP_skipChar;
3230 
3231 		for(;;)
3232 		{
3233 			switch(KVSP_curCharUnicode)
3234 			{
3235 				case 0:
3236 					delete l;
3237 					warning(pBegin, __tr2qs_ctx("Unterminated hash key", "kvs"));
3238 					error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of script in hash key (missing '}' character?)", "kvs"));
3239 					return nullptr;
3240 					break;
3241 				case '\r':
3242 				case '\n':
3243 					delete l;
3244 					warning(pBegin, __tr2qs_ctx("Unterminated hash key", "kvs"));
3245 					error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of line in hash key (missing '}' character or unescaped newline)", "kvs"));
3246 					return nullptr;
3247 					break;
3248 				case ' ':
3249 				case '\t':
3250 					skipSpaces();
3251 					if(KVSP_curCharUnicode != '}')
3252 					{
3253 						// separate by single spaces
3254 						l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant(QString(" "))));
3255 					}
3256 					else
3257 					{
3258 						goto end_of_the_hash_key;
3259 					}
3260 					break;
3261 				case '$':
3262 				case '%':
3263 				case '@':
3264 				{
3265 					// this may be a data reference
3266 					KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
3267 					if(!p)
3268 					{
3269 						// this is an error
3270 						delete l;
3271 						return nullptr;
3272 					}
3273 					l->append(p);
3274 				}
3275 				break;
3276 				case '}':
3277 				{
3278 					// end of the array index
3279 					goto end_of_the_hash_key;
3280 				}
3281 				break;
3282 				case '"':
3283 				{
3284 					// string
3285 					KviKvsTreeNodeData * p = parseStringParameter();
3286 					if(!p)
3287 					{
3288 						// error
3289 						delete l;
3290 						return nullptr;
3291 					}
3292 					l->append(p);
3293 				}
3294 				break;
3295 				default:
3296 				{
3297 					// anything else is a literal
3298 					l->append(parseHashKeyLiteralParameter());
3299 				}
3300 				break;
3301 			}
3302 		}
3303 	end_of_the_hash_key:
3304 		if(l->count() > 1)
3305 		{
3306 			// complex parameter needed
3307 			return new KviKvsTreeNodeCompositeData(pBegin, l);
3308 		}
3309 		else
3310 		{
3311 			// a single parameter in the list
3312 			l->setAutoDelete(false);
3313 			KviKvsTreeNodeData * p = l->first();
3314 			delete l;
3315 			return p;
3316 		}
3317 		// never reached
3318 		return nullptr;
3319 	}
3320 
3321 	/*
3322 PARENTHESIS_PARAMETER_PARSING_FUNCTION_BEGIN(parseCommaSeparatedParameter)
3323 	case 0:
3324 	case ',':
3325 	case ')':
3326 	case '\n':
3327 PARENTHESIS_PARAMETER_PARSING_FUNCTION_END()
3328 
3329 #define PARENTHESIS_PARAMETER_PARSING_FUNCTION_BEGIN(_name) \
3330 */
3331 
parseCommaSeparatedParameter()3332 	KviKvsTreeNodeData * KviKvsParser::parseCommaSeparatedParameter()
3333 	{
3334 		KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
3335 		l->setAutoDelete(true);
3336 
3337 		const QChar * pBegin = KVSP_curCharPointer;
3338 
3339 		for(;;)
3340 		{
3341 			switch(KVSP_curCharUnicode)
3342 			{
3343 				case 0:
3344 				case ',':
3345 				case ')':
3346 				case '\r':
3347 				case '\n':
3348 					// not a part of a parameter
3349 					goto end_of_function_parameter;
3350 					break;
3351 				case '$':
3352 				case '%':
3353 				case '@':
3354 				{
3355 					// this may be a data reference
3356 					KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
3357 					if(!p)
3358 					{
3359 						// this is an error
3360 						delete l;
3361 						return nullptr;
3362 					}
3363 					l->append(p);
3364 				}
3365 				break;
3366 				case ' ':
3367 				case '\t':
3368 					skipSpaces();
3369 					if((KVSP_curCharUnicode != ')') && (KVSP_curCharUnicode != ','))
3370 					{
3371 						// separate by single spaces
3372 						l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant(QString(" "))));
3373 					}
3374 					else
3375 					{
3376 						goto end_of_function_parameter;
3377 					}
3378 					break;
3379 				case '"':
3380 				{
3381 					// this is a string
3382 					KviKvsTreeNodeData * p = parseStringParameter();
3383 					if(!p)
3384 					{
3385 						// this is an error
3386 						delete l;
3387 						return nullptr;
3388 					}
3389 					l->append(p);
3390 				}
3391 				break;
3392 				default:
3393 				{
3394 					// anything else is a literal
3395 					l->append(parseCommaSeparatedLiteralParameter());
3396 				}
3397 				break;
3398 			}
3399 		}
3400 	end_of_function_parameter:
3401 		if(l->count() > 1)
3402 		{
3403 			// complex parameter needed
3404 			KviKvsTreeNodeData * p = new KviKvsTreeNodeCompositeData(pBegin, l);
3405 			p->setEndingLocation(KVSP_curCharPointer);
3406 			return p;
3407 		}
3408 		else
3409 		{
3410 			// a single parameter in the list, or no params at all
3411 			l->setAutoDelete(false);
3412 			KviKvsTreeNodeData * p = l->first();
3413 			delete l;
3414 			if(!p)
3415 				p = new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant());
3416 			p->setEndingLocation(KVSP_curCharPointer);
3417 			return p;
3418 		}
3419 		// never reached
3420 		return nullptr;
3421 	}
3422 
parseSingleParameterInParenthesis()3423 	KviKvsTreeNodeData * KviKvsParser::parseSingleParameterInParenthesis()
3424 	{
3425 		KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
3426 		l->setAutoDelete(true);
3427 
3428 		const QChar * pBegin = KVSP_curCharPointer;
3429 
3430 		for(;;)
3431 		{
3432 			switch(KVSP_curCharUnicode)
3433 			{
3434 				case ')':
3435 					// not a part of a parameter
3436 					KVSP_skipChar;
3437 					goto end_of_function_parameter;
3438 					break;
3439 				case 0:
3440 				case '\r':
3441 				case '\n':
3442 					// not a part of a parameter
3443 					goto end_of_function_parameter;
3444 					break;
3445 				case '$':
3446 				case '%':
3447 				case '@':
3448 				{
3449 					// this may be a data reference
3450 					KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
3451 					if(!p)
3452 					{
3453 						// this is an error
3454 						delete l;
3455 						return nullptr;
3456 					}
3457 					l->append(p);
3458 				}
3459 				break;
3460 				case ' ':
3461 				case '\t':
3462 					skipSpaces();
3463 					if((KVSP_curCharUnicode != ')') && (KVSP_curCharUnicode != ','))
3464 					{
3465 						// separate by single spaces
3466 						l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer, new KviKvsVariant(QString(" "))));
3467 					}
3468 					else
3469 					{
3470 						goto end_of_function_parameter;
3471 					}
3472 					break;
3473 				case '"':
3474 				{
3475 					// this is a string
3476 					KviKvsTreeNodeData * p = parseStringParameter();
3477 					if(!p)
3478 					{
3479 						// this is an error
3480 						delete l;
3481 						return nullptr;
3482 					}
3483 					l->append(p);
3484 				}
3485 				break;
3486 				default:
3487 				{
3488 					// anything else is a literal
3489 					l->append(parseSingleLiteralParameterInParenthesis());
3490 				}
3491 				break;
3492 			}
3493 		}
3494 	end_of_function_parameter:
3495 		if(l->count() > 1)
3496 		{
3497 			// complex parameter needed
3498 			KviKvsTreeNodeData * p = new KviKvsTreeNodeCompositeData(pBegin, l);
3499 			p->setEndingLocation(KVSP_curCharPointer);
3500 			return p;
3501 		}
3502 		else
3503 		{
3504 			// a single parameter in the list or list empty at all
3505 			l->setAutoDelete(false);
3506 			KviKvsTreeNodeData * p = l->first();
3507 			if(p)
3508 				p->setEndingLocation(KVSP_curCharPointer);
3509 			delete l;
3510 			return p;
3511 		}
3512 		// never reached
3513 		return nullptr;
3514 	}
3515 
parseStringParameter()3516 	KviKvsTreeNodeData * KviKvsParser::parseStringParameter()
3517 	{
3518 		KVSP_ASSERT(KVSP_curCharUnicode == '"');
3519 
3520 		KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
3521 		l->setAutoDelete(true);
3522 
3523 		const QChar * pBegin = KVSP_curCharPointer;
3524 
3525 		KVSP_skipChar;
3526 
3527 		for(;;)
3528 		{
3529 			switch(KVSP_curCharUnicode)
3530 			{
3531 				case 0:
3532 					delete l;
3533 					warning(pBegin, __tr2qs_ctx("Unterminated string constant", "kvs"));
3534 					error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of script in string constant (missing \" character?)", "kvs"));
3535 					return nullptr;
3536 					break;
3537 				case '\r':
3538 				case '\n':
3539 					delete l;
3540 					warning(pBegin, __tr2qs_ctx("Unterminated string constant", "kvs"));
3541 					error(KVSP_curCharPointer, __tr2qs_ctx("Unexpected end of line in string constant (missing \" character or unescaped newline)", "kvs"));
3542 					return nullptr;
3543 					break;
3544 				case '$':
3545 				case '%':
3546 				case '@':
3547 				{
3548 					// this may be a data reference
3549 					KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
3550 					if(!p)
3551 					{
3552 						// this is an error
3553 						delete l;
3554 						return nullptr;
3555 					}
3556 					l->append(p);
3557 				}
3558 				break;
3559 				case '"':
3560 				{
3561 					// end of the string
3562 					KVSP_skipChar;
3563 					goto end_of_the_string;
3564 				}
3565 				break;
3566 				default:
3567 				{
3568 					// anything else is a literal
3569 					l->append(parseStringLiteralParameter());
3570 				}
3571 				break;
3572 			}
3573 		}
3574 	end_of_the_string:
3575 		if(l->count() > 1)
3576 		{
3577 			// complex parameter needed
3578 			// it is also an implicit string cast
3579 			return new KviKvsTreeNodeCompositeData(pBegin, l);
3580 		}
3581 		else
3582 		{
3583 			if(l->count() > 0)
3584 			{
3585 				// a single parameter in the list
3586 				// we need an explicit string cast here (it is the most common cast)
3587 				l->setAutoDelete(false);
3588 				KviKvsTreeNodeData * p = l->first();
3589 				delete l;
3590 				return new KviKvsTreeNodeStringCast(pBegin, p);
3591 			}
3592 			else
3593 			{
3594 				// no parameters at all.. return straight empty string (no need to cast)
3595 				delete l;
3596 				return new KviKvsTreeNodeConstantData(pBegin, new KviKvsVariant(new QString()));
3597 			}
3598 		}
3599 		// never reached
3600 		return nullptr;
3601 	}
3602 
parseCommandParameter(bool bPreferNumeric)3603 	KviKvsTreeNodeData * KviKvsParser::parseCommandParameter(bool bPreferNumeric)
3604 	{
3605 		KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
3606 		l->setAutoDelete(true);
3607 
3608 		bool bGotLiteral = false;
3609 
3610 		const QChar * pBegin = KVSP_curCharPointer;
3611 
3612 		for(;;)
3613 		{
3614 			switch(KVSP_curCharUnicode)
3615 			{
3616 				case 0:
3617 				case ' ':
3618 				case '\t':
3619 				case '\r':
3620 				case '\n':
3621 				case ';':
3622 					// not a part of a parameter
3623 					goto jumpout;
3624 					break;
3625 				case '$':
3626 				case '%':
3627 				case '@':
3628 				{
3629 					// this may be a data reference
3630 					KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
3631 					if(!p)
3632 					{
3633 						// this is an error
3634 						delete l;
3635 						return nullptr;
3636 					}
3637 					l->append(p);
3638 				}
3639 				break;
3640 				case '"':
3641 				{
3642 					// this is a string
3643 					KviKvsTreeNodeData * p = parseStringParameter();
3644 					if(!p)
3645 					{
3646 						// this is an error
3647 						delete l;
3648 						return nullptr;
3649 					}
3650 					l->append(p);
3651 				}
3652 				break;
3653 				default:
3654 				{
3655 					bGotLiteral = true;
3656 					// anything else is a literal
3657 					l->append(parseCommandLiteralParameter());
3658 				}
3659 				break;
3660 			}
3661 		}
3662 	jumpout:
3663 		if(l->count() > 1)
3664 		{
3665 			// complex parameter needed
3666 			KviKvsTreeNodeData * p = new KviKvsTreeNodeCompositeData(pBegin, l);
3667 			p->setEndingLocation(KVSP_curCharPointer);
3668 			return p;
3669 		}
3670 		else
3671 		{
3672 			// a single parameter in the list or empty list at all
3673 			l->setAutoDelete(false);
3674 			KviKvsTreeNodeData * p = l->first();
3675 			delete l;
3676 			if(p)
3677 			{
3678 				if(bGotLiteral)
3679 				{
3680 					// a single literal parameter
3681 					if(bPreferNumeric)
3682 					{
3683 						// attempt to convert to a numeric format if this is a constant data item
3684 						p->convertStringConstantToNumeric();
3685 					}
3686 				}
3687 				p->setEndingLocation(KVSP_curCharPointer);
3688 			}
3689 			return p;
3690 		}
3691 		// never reached
3692 		return nullptr;
3693 	}
3694