summaryrefslogtreecommitdiffstats
path: root/src/kvirc/kvs/kvi_kvs_parser.cpp
blob: 24f3ac9a5691004aee250ec4bb3c617574f734c1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
2600
2601
2602
2603
2604
2605
2606
2607
2608
2609
2610
2611
2612
2613
2614
2615
2616
2617
2618
2619
2620
2621
2622
2623
2624
2625
2626
2627
2628
2629
2630
2631
2632
2633
2634
2635
2636
2637
2638
2639
2640
2641
2642
2643
2644
2645
2646
2647
2648
2649
2650
2651
2652
2653
2654
2655
2656
2657
2658
2659
2660
2661
2662
2663
2664
2665
2666
2667
2668
2669
2670
2671
2672
2673
2674
2675
2676
2677
2678
2679
2680
2681
2682
2683
2684
2685
2686
2687
2688
2689
2690
2691
2692
2693
2694
2695
2696
2697
2698
2699
2700
2701
2702
2703
2704
2705
2706
2707
2708
2709
2710
2711
2712
2713
2714
2715
2716
2717
2718
2719
2720
2721
2722
2723
2724
2725
2726
2727
2728
2729
2730
2731
2732
2733
2734
2735
2736
2737
2738
2739
2740
2741
2742
2743
2744
2745
2746
2747
2748
2749
2750
2751
2752
2753
2754
2755
2756
2757
2758
2759
2760
2761
2762
2763
2764
2765
2766
2767
2768
2769
2770
2771
2772
2773
2774
2775
2776
2777
2778
2779
2780
2781
2782
2783
2784
2785
2786
2787
2788
2789
2790
2791
2792
2793
2794
2795
2796
2797
2798
2799
2800
2801
2802
2803
2804
2805
2806
2807
2808
2809
2810
2811
2812
2813
2814
2815
2816
2817
2818
2819
2820
2821
2822
2823
2824
2825
2826
2827
2828
2829
2830
2831
2832
2833
2834
2835
2836
2837
2838
2839
2840
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
2857
2858
2859
2860
2861
2862
2863
2864
2865
2866
2867
2868
2869
2870
2871
2872
2873
2874
2875
2876
2877
2878
2879
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
2895
2896
2897
2898
2899
2900
2901
2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916
2917
2918
2919
2920
2921
2922
2923
2924
2925
2926
2927
2928
2929
2930
2931
2932
2933
2934
2935
2936
2937
2938
2939
2940
2941
2942
2943
2944
2945
2946
2947
2948
2949
2950
2951
2952
2953
2954
2955
2956
2957
2958
2959
2960
2961
2962
2963
2964
2965
2966
2967
2968
2969
2970
2971
2972
2973
2974
2975
2976
2977
2978
2979
2980
2981
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004
3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
3043
3044
3045
3046
3047
3048
3049
3050
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171
3172
3173
3174
3175
3176
3177
3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196
3197
3198
3199
3200
3201
3202
3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276
3277
3278
3279
3280
3281
3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399
3400
3401
3402
3403
3404
3405
3406
3407
3408
3409
3410
3411
3412
3413
3414
3415
3416
3417
3418
3419
3420
3421
3422
3423
3424
3425
3426
3427
3428
3429
3430
3431
3432
3433
3434
3435
3436
3437
3438
3439
3440
3441
3442
3443
3444
3445
3446
3447
3448
3449
3450
3451
3452
3453
3454
3455
3456
3457
3458
3459
3460
3461
3462
3463
3464
3465
3466
3467
3468
3469
3470
3471
3472
3473
3474
3475
3476
3477
3478
3479
3480
3481
3482
3483
3484
3485
3486
3487
3488
3489
3490
3491
3492
3493
3494
3495
3496
3497
3498
3499
3500
3501
3502
3503
3504
3505
3506
3507
3508
3509
3510
3511
3512
3513
3514
3515
3516
3517
3518
3519
3520
3521
3522
3523
3524
3525
3526
3527
3528
3529
3530
3531
3532
3533
3534
3535
3536
3537
3538
3539
3540
3541
3542
3543
3544
3545
3546
3547
3548
3549
3550
3551
3552
3553
3554
3555
3556
3557
3558
3559
3560
3561
3562
3563
3564
3565
3566
3567
3568
3569
3570
3571
3572
3573
3574
3575
3576
3577
3578
3579
3580
3581
3582
3583
3584
3585
3586
3587
3588
3589
3590
3591
3592
3593
3594
3595
3596
3597
3598
3599
3600
3601
3602
3603
3604
3605
3606
3607
3608
3609
3610
3611
3612
3613
3614
3615
3616
3617
3618
3619
3620
3621
3622
3623
3624
3625
3626
3627
3628
3629
3630
3631
3632
3633
3634
3635
3636
3637
3638
3639
3640
3641
3642
3643
3644
3645
3646
3647
3648
3649
3650
3651
3652
3653
3654
3655
3656
3657
3658
3659
3660
3661
3662
3663
3664
3665
3666
3667
3668
3669
3670
3671
3672
3673
3674
3675
3676
3677
3678
3679
3680
3681
3682
3683
3684
3685
3686
3687
3688
3689
3690
3691
3692
3693
3694
3695
3696
3697
3698
3699
3700
3701
3702
3703
3704
3705
3706
3707
3708
3709
3710
3711
3712
3713
3714
3715
3716
3717
3718
3719
3720
3721
3722
3723
3724
3725
3726
3727
3728
3729
3730
3731
3732
3733
3734
3735
3736
3737
3738
3739
3740
3741
3742
3743
3744
3745
3746
3747
3748
3749
3750
3751
3752
3753
3754
3755
3756
3757
3758
3759
3760
3761
3762
3763
3764
3765
3766
3767
3768
3769
3770
3771
3772
3773
3774
3775
3776
3777
3778
3779
3780
3781
3782
3783
3784
3785
3786
3787
3788
3789
3790
3791
3792
3793
3794
3795
3796
3797
3798
3799
3800
3801
3802
3803
3804
3805
3806
3807
3808
3809
3810
3811
3812
3813
3814
3815
3816
3817
3818
3819
3820
3821
3822
3823
3824
3825
3826
3827
//=============================================================================
//
//   File : kvi_kvs_parser.cpp
//   Creation date : Thu 25 Sep 2003 05.12 CEST by Szymon Stefanek
//
//   This file is part of the KVirc irc client distribution
//   Copyright (C) 2003 Szymon Stefanek (pragma at kvirc dot net)
//
//   This program is FREE software. You can redistribute it and/or
//   modify it under the terms of the GNU General Public License
//   as published by the Free Software Foundation; either version 2
//   of the License, or (at your opinion) any later version.
//
//   This program is distributed in the HOPE that it will be USEFUL,
//   but WITHOUT ANY WARRANTY; without even the implied warranty of
//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
//   See the GNU General Public License for more details.
//
//   You should have received a copy of the GNU General Public License
//   along with this program. If not, write to the Free Software Foundation,
//   Inc. ,51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
//
//=============================================================================

#define __KVIRC__


#include "kvi_kvs_parser.h"

#include "kvi_kvs_treenode.h"

#include "kvi_kvs_report.h"
#include "kvi_kvs_kernel.h"

#include "kvi_kvs_script.h"

#include "kvi_kvs_parser_macros.h"

#include "kvi_locale.h"

#include "kvi_options.h"

//FIXME: @ == $$-> == $this->

KviKvsParser::KviKvsParser(KviKvsScript * pScript,KviWindow * pOutputWindow)
{
	// no need to initialize m_pBuffer
	// no need to initialize m_ptr
	// no need to initialize m_bError
	m_pGlobals = 0;
	m_pScript = pScript;
	m_pWindow = pOutputWindow;
}

KviKvsParser::~KviKvsParser()
{
	if(m_pGlobals)delete m_pGlobals;
}




void KviKvsParser::init()
{
	KviKvsKernel * pKern = KviKvsKernel::instance();

#define _REG_CNTRL_CMD(__cntrlCmdName,__parsingRoutine) \
	{ \
		KviKvsSpecialCommandParsingRoutine * r = new KviKvsSpecialCommandParsingRoutine; \
		r->proc = KVI_PTR2MEMBER(KviKvsParser::__parsingRoutine); \
		pKern->registerSpecialCommandParsingRoutine(TQString(__cntrlCmdName),r); \
	}

	_REG_CNTRL_CMD("if",parseSpecialCommandIf);
	_REG_CNTRL_CMD("global",parseSpecialCommandGlobal);
	_REG_CNTRL_CMD("while",parseSpecialCommandWhile);
	_REG_CNTRL_CMD("break",parseSpecialCommandBreak);
	_REG_CNTRL_CMD("do",parseSpecialCommandDo);
	_REG_CNTRL_CMD("for",parseSpecialCommandFor);
	_REG_CNTRL_CMD("foreach",parseSpecialCommandForeach);
	_REG_CNTRL_CMD("switch",parseSpecialCommandSwitch);
	_REG_CNTRL_CMD("defpopup",parseSpecialCommandDefpopup);
	_REG_CNTRL_CMD("unset",parseSpecialCommandUnset);
	_REG_CNTRL_CMD("class",parseSpecialCommandClass);
	_REG_CNTRL_CMD("help",parseSpecialCommandHelp);

#undef _REG_CNTRL_CMD
}

void KviKvsParser::report(bool bError,const TQChar * pLocation,const TQString &szMsgFmt,kvi_va_list va)
{
	TQString szMsg;
	KviTQString::vsprintf(szMsg,szMsgFmt,va);

	KviPointerList<TQString> * pCodeListing = 0;
	TQString szLocation;

	if(pLocation)
	{
		pCodeListing = new KviPointerList<TQString>;
		pCodeListing->setAutoDelete(true);

		int iLine,iCol;

		KviKvsReport::findLineColAndListing(m_pBuffer,pLocation,iLine,iCol,pCodeListing);
		
		KviTQString::sprintf(szLocation,__tr2qs("line %d, near character %d"),iLine,iCol);
	} else {
		szLocation = __tr2qs("beginning of input");
	}

	KviKvsReport rep(bError ? KviKvsReport::ParserError : KviKvsReport::ParserWarning,m_pScript->name(),szMsg,szLocation,m_pWindow);
	if(pCodeListing)rep.setCodeListing(pCodeListing);

	KviKvsReport::report(&rep,m_pWindow);
}

void KviKvsParser::errorBadChar(const TQChar * pLocation,char cExpected,const char * szCommandName)
{
	if(pLocation->tqunicode())
		error(pLocation,__tr2qs("Found character '%q' (tqunicode 0x%x) where '%c' was expected: see \"/help %s\" for the command syntax"),
			pLocation,pLocation->tqunicode(),cExpected,szCommandName);
	else
		error(pLocation,__tr2qs("Found end of input where character '%c' was expected: see \"/help %s\" for the command syntax"),
			cExpected,szCommandName);
}

void KviKvsParser::error(const TQChar * pLocation,const TQString &szMsgFmt,...)
{
	m_bError = true;

	kvi_va_list va;
	kvi_va_start_by_reference(va,szMsgFmt);
	report(true,pLocation,szMsgFmt,va);
	kvi_va_end(va);
}

void KviKvsParser::warning(const TQChar * pLocation,const TQString &szMsgFmt,...)
{
	kvi_va_list va;
	kvi_va_start_by_reference(va,szMsgFmt);
	report(false,pLocation,szMsgFmt,va);
	kvi_va_end(va);
}

KviKvsTreeNodeInstruction * KviKvsParser::parse(const TQChar * pBuffer,int iFlags)
{
	m_iFlags = iFlags;

	m_bError = false;
	if(m_pGlobals)m_pGlobals->clear(); // this shouldn't be needed since this is a one time parser

	m_pBuffer = pBuffer;
	m_ptr = pBuffer;

	if(!pBuffer)
	{
		error(0,__tr2qs("Empty script"));
		return 0;
	}
	return parseInstructionList();
}

KviKvsTreeNodeInstruction * KviKvsParser::parseAsExpression(const TQChar * pBuffer,int iFlags)
{
	m_iFlags = iFlags;

	m_bError = false;
	if(m_pGlobals)m_pGlobals->clear(); // this shouldn't be needed since this is a one time parser

	m_pBuffer = pBuffer;
	m_ptr = pBuffer;

	if(!pBuffer)
	{
		error(0,__tr2qs("Empty script"));
		return 0;
	}

	KviKvsTreeNodeExpression * expr = parseExpression(0);
	if(!expr)return 0;
	return new KviKvsTreeNodeExpressionReturn(pBuffer,expr);
}

KviKvsTreeNodeInstruction * KviKvsParser::parseAsParameter(const TQChar * pBuffer,int iFlags)
{
	m_iFlags = iFlags;

	m_bError = false;
	if(m_pGlobals)m_pGlobals->clear(); // this shouldn't be needed since this is a one time parser

	m_pBuffer = pBuffer;
	m_ptr = pBuffer;

	if(!pBuffer)
	{
		error(0,__tr2qs("Empty script"));
		return 0;
	}

	KviKvsTreeNodeDataList * l = parseCommandParameterList();
	if(!l)return 0;

	return new KviKvsTreeNodeParameterReturn(pBuffer,l);
}



///////////////////////////////////////////////////////////////////////////////////////////////////
// THE REAL KVS
//
// <script> ::= <instruction list> '\0'
//
// <instruction list> ::= <instruction> [ <instruction list> ]
// <instruction> ::= <instruction block> | <command> | <operation> | <comment>
// <instruction block> ::= '{' <instruction list> '}'
//
// <comment> ::= <bash style line comment> | <c++ style comment> | <c style comment>
// <bash style comment> ::='#' <any char not including newline or null> <newline or null>
// <c++ style comment> ::= '//' <any char not including newline or null> <newline or null>
// <c style comment> ::= '/*' <any char not including null or the sequence */> '*/'
//
// <command> ::= <simple command> | <callback command> | <control command>
// <simple command> ::= <core command> | <module command> | <alias command>
// <core command> ::= <command identifier> <switch list> <command parameter list> <command terminator>
// <switch list> ::= '-'<switch body> [<switch list>]
// <command parameter list> ::= <command parameter>[<space><command parameter>]
// <command parameter> ::= <command parameter part>[<command parameter>]
// <command parameter part> ::= <command literal parameter> | <string parameter> | <data evaluation>
// <command literal parameter> ::= <anything except space , null , newline , ; , " , $ or %>
// <string parameter> ::= '"'<string parameter body>'"'
// <string parameter body> ::= <anything except '"' or null>...
// <command terminator> ::= ';' | '\n' | '\0'

// <data> ::= 
// <data_reference> ::= <function_call> | <structured_data>
// <structured_data> ::= <data_structure> | <variable> | <pointer_data>
// <data_structure> ::= <array> | <hash>
// <array> ::= '%'<identifier>'[]'
// <hash> ::= '%'<identifier>'{}'
// <variable> ::= '%'<identifier> | <array_element> | <hash_element>
// <array_element> ::= '%'<identifier>'['<expression>']'
// <hash_element> ::= '%'<identifier>'{'<key>'}'
// <function_call> ::= <simple_function_call> | <pointer_function_call>
// <simple_function_call> ::= '$'<identifier>'('<function_parameter_list>')'
// <pointer_function_call> ::= <variable>'->'<function_call> | <simple_function_call>'->'<function_call>
// <pointer_data> ::= <variable>'->'<data>' | <simple_function_call>'->'<data>


//
// This must evaluate SCOPE OBJECT operators!
// thus...first evaluate the <data> or <simple_function_call>
// If it was <simple_function_call> or <data> evaluation results in returning a <variable>
// then check if there is a scope operator
// if there is then take it as the top of the tree, the <variable> or <simple_function_call>
// go at the left param of the scope operator and re-evaluate the right side <data> or <simple_function_call>
//







/*
	@doc: kvs_introduction
	@type:
		language
	@keyterms:
		kvs, compilation
	@title:
		KVIrc scripting language introduction
	@short:
		KVIrc scripting language introduction
	@body:
		[p]
		[b]KVS[/b] is the [b]KV[/b]irc [b]S[/b]cripting language.
		It was inspired by C++,sh,perl,php and mIrc scripting language implementations.
		It is a compromise between flexibility and speed, a 'workaround' for many intrinsic
		problems of an IRC-oriented scripting language.
		[/p]
		[p]
		KVS is semi-interpreted: the execution is done in two main stages.
		The first stage is the compilation where a syntactic tree is built.
		The second stage is the real execution and is performed by visiting the tree
		in the proper order. The syntactic trees are cached in memory so
		the next executions can jump directly into the second stage.
		This two-stage approach has been introduced in version 3.0.0, the previous
		versions of the language used a single-stage on-the-fly interpreter.
		[/p]
		[p]
		KVS allows you to:[br]
		[ul]
		[li]Implement automated reactions to the events generated by an IRC network[/li]
		[li]Add new complex commands[/li]
		[li]Add interface elements like popups, toolbars, buttons...[/li]
		[li]Add advanced interface elements like complete dialogs or even widgets integrated in KVIrc[/li]
		[/ul]
		[/p]
		[p]
		KVS contains all the common constructs of structured programming.
		You will find almost all the C control commands, sh/perl-like variables, arrays and and functions.
		There are also some object-oriented characteristics: you will find C++ like
		objects with constructors, destructors and class inheritance.
		There are also more exotic concepts like the signal-slots interobject-communication.
		Obviously you will also find most of the RFC1459 IRC commands and
		other tools to "play" with an IRC connection.
		[/p]
		[p]
		I'll try to explain the language by using examples
		instead of strict syntactic rules. (Actually I have even
		tried to write the rules...take a look [doc:syntactic_rules]here[/doc][br][br]
		And please...forgive me for my "fantastic" english :)
		[/p]
		Szymon Stefanek
*/

/*
	@doc: kvs_basicconcepts
	@type:
		language
	@keyterms:
		script
	@title:
		KVS basic concepts
	@short:
		KVS basic concepts
	@body:
		[big]Scripts[/big]
		[p]
		You use KVS to implement [b]scripts[/b].
		A script is basically a finite list of KVS instructions.
		When you type a command in the KVIrc input window you in fact
		execute a small one-line script. You can store
		longer scripts in KVIrc memory and execute them at later time.
		Scripts can be also read from external files by the means of the
		[cmd]parse[/cmd] command.
		[/p]
		[p]
		There is an issue with the word [i]script[/i] that is worth clearing here.
		It is common usage to call [i]script[/i] a thing that is something more
		that a finite list of (some scripting language) instructions.
		In fact a set of scripts, documentation files, graphics or other multimedia
		files and sometimes executable binaries is still called a [i]script[/i]...just like
		the "PrincoScript" or "dynamirc" (tough this last one should be categorized as "malware" instead).
		In KVIrc such a collection of items is called [i]addon[/i], but be prepared
		for both usages of the word in this documentation and around the web.
		[/p]
		[p]
		More about addons in this [doc:addons]document[/doc]
		[/p]

		[big]Hello world![/big]
		[p]
		This documentation contains a lot of script examples.
		They will appear like the following block of code:
		[example]
			[cmd]echo[/cmd] Hello world!
		[/example]
		The best way to experiment is to execute the scripts from an external file.
		Try to copy & paste the example above to a file and save it in
		a known place. Then in the command input window type
		[example]
			[b]/[/b][cmd]parse[/cmd] <filename>
		[/example]
		where <filename> stands for the name of the file you just have saved.
		Some simple examples (like the one above) can be also typed
		directly in the command input window.
		You must remember that the command input window needs
		a leading slash ('/') character to recognize a script.
		The command input window can also be put in multiline mode by clicking
		on the button on the right.
		Another alternative for testing scripts is the code tester window.
		You can access it by selecting "New code tester" from the Scripting menu
		at the top of the KVIrc window. You will soon have the opportunity to
		experiment with all the methods. Read on.
		[/p]

		[big]Basic syntax[/big]
		[p]
		A script contains a list of instructions separated by newlines or ';' characters.
		Placing an instruction per line does not require a terminating character,
		placing more instructions in a single line require them to be separated by ';'.
		The most common instructions in KVS are [b]commands[/b]. A command is basically
		a keyword followed by a list of space separater parameters.
		The simplest (and the most useful) command in KVS is [cmd]echo[/cmd]; it prints
		all its parameters to a KVIrc window.[br]
		The following is an example of a valid script that uses only [cmd]echo[/cmd] commands.
		[example]
			echo "This is the first line"
			ECHO This is the second line;
			echo "This is the third line"; echo This is still on the third line;
			eChO "This is the fourth line"; Echo "This is still on the fourth line"
		[/example]
		You have probably noticed that the terminating ';' character is optional
		when the command is the last in a line.
		The commands are [b]case insensitive[/b]; 'echo' is equivalent to 'Echo',
		to 'ECHO' and to 'eChO'. In fact, most of KVS is case insensitive.
		(There are obvious unavoidable exceptions for this rule; for example,
		on UNIX systems file names are case sensitive and this must be
		also reflected in KVS).
		Another interesting thing is that when you execute the script you
		don't see the enclosing quotes around the printed text: more about this
		in the following sections.[br]
		[note]
		Cryptic note (you may skip it for now):[br]
		Yes, the command terminator is a problem for those that want to use ';)' at the end
		of IRC commands like [cmd]msg[/cmd]. It is almost unavoidable (read: the cost for
		avoiding it is too high). Note that using '|' or any other character as command terminator
		will NOT solve the problem: if the terminator is too difficult to type it will annoy the
		scripters (and me), if it is too easy then there will be always someone that wants to use it 
		at the end (or in the middle) of a command with the original meaning.
		The solution is to escape the ';' character:
		[example]
			[cmd]echo[/cmd] You can do it now \;)
		[/example]
		[/note]
		[/p]

		[big]Parameter processing[/big]
		[p]
		Most of the commands accept (and sometimes require) a list of parameters.
		For example, the [cmd]join[/cmd] command (that is used to join an IRC channel)
		accepts two parameters: the first one is the channel to join and the second is
		the password. The simplified syntax for join is:
		[example]
			[cmd]join[/cmd] <channel> [password]
		[/example]
		The line above is an example of syntax specification. All the commands
		are described by such syntax lines. [cmd]join[/cmd] is the command and it stands exactly
		for the literal string "join" typed in a script. <channel> is in angular parenthesis
		and rappresents a mandatory parameter: you must substitute a real channel name in its place
		otherwise the command will fail and KVIrc will probably complain too.
		[password] is still a parameter but the square parentheses indicate that it is
		optional: if you specify it, then it will be interpreted as the channel password,
		if you don't then no password will be used.
		[note]
		The syntax is written in a simplified BNF. I say simplified because it is not
		totally strict around the KVIrc documentation. I just prefer the syntax to be
		clear and easy to read instead of being formally perfect.
		[/note]
		You can finally join a channel by writing:
		[example]
			[cmd]join[/cmd] #kvirc kvircrocks
		[/example]
		or , since #kvirc usually has no password , by writing:
		[example]
			[cmd]join[/cmd] #kvirc
		[/example]
		In the example above the optional parameter [password] is omitted.
		[note]
		In fact it is not really omitted: KVIrc interprets it as an empty string that later
		means "do not send the password to the server".
		Empty strings are equivalent to omitted ones.
		[/note]
		[/p]

		[big]Parameters, spaces and quotes[/big]
		[p]
		From the examples above is obvious that KVS command parameters are separated by spaces.
		What is not totally obvious is that multiple spaces are allowed but KVIrc
		will automatically reduce them to exactly one (just like HTML parsers or the shell
		interpreters do). This is an useful behaviour in an IRC client since spaces usually
		carry no information and in text oriented protocols make the parsing really harder (:D).
		[/p]
		[p]
		The spaces are simplified in normal processing but there are ways to force KVIrc
		to interpret the spaces just as they are.
		The first method are the quotation marks: all the spaces enclosed in quotation marks
		will be preserved.
		[example]
			[cmd]echo[/cmd] This &nbsp; &nbsp; text &nbsp; &nbsp; will &nbsp; &nbsp; have &nbsp; &nbsp; spaces &nbsp; &nbsp; simplified
			[cmd]echo[/cmd] But &nbsp; &nbsp; "this &nbsp; &nbsp; &nbsp; one &nbsp; &nbsp; not"
		[/example]
		The first example will print out with spaces simplified but the second not.
		The quotes are also a nice trick to embed spaces into a single parameter that
		would be obviously splitted in two or more.
		[example]
			[cmd]echo[/cmd] Parameter1 Parameter2 "Parameter  3 ( with spaces )" Parameter4
		[/example]
		By running the examples above you may have noticed that the spaces are preserved but the
		quotes are then stripped! Yes, this is another tricky behaviour. But don't be afraid:
		it is really easier to use than to explain.
		There is obviously a method to preserve the quotes too and it is also another
		method to preserve the spaces but that leads us to the next paragraph.
		[/p]

		[big]Escape character[/big]
		[p]
		You may have already noticed that KVS treats some characters in a special way.
		For example the double-quote characters can be used to enclose strings
		and are stripped by the parser.
		Another example of a special character is the command terminator (';'):
		it has the "special" meaning of terminating a command.
		If you want to enclose a literal quote in your text, you need to [b]escape[/b] it.
		Like in most other programming languages, the escaping character is the backslash ('\').
		[example]
			[cmd]echo[/cmd] You can smile this way too! \;)
		[/example]
		The above example will treat the ';' as a part of the parameters and print it.[br]
		In some languages the action of "escaping" a character is called "quoting".
		Altough there is some confusion in this term, the meaning is to either use quotes
		or to use the escape character to remove special meaning from some characters.
		By quoting the spaces you can include them in a parameter, by escaping the quotes
		you can include them in a command.
		[example]
			[cmd]echo[/cmd] "And he said \"Hello world!\""
		[/example]
		The example above will have the internal quotes preserved.
		You can use the escape backslash to escape a newline:
		[example]
			[cmd]echo[/cmd] This text will be \
			&nbsp; &nbsp; printed on a single line!
		[/example]
		After an escaped newline all the leading space and tab characters are skipped,
		so you must include the needed spaces [b]before[/b] the escape character.
		The previous example will be printed as:[br][br]
		[i]This text will be printed on a single line[/i][br]
		Another example:[br]
		[example]
			[cmd]echo[/cmd] "The new kvirc &nbsp; &nbsp; &nbsp \
            &nbsp; &nbsp; IS OUT!"
			[cmd]echo[/cmd] Check it out at http://www.kvi\
            &nbsp; &nbsp; rc.net!
		[/example]
		This will be printed as:[br][br]
		[i]
		The new kvirc &nbsp; &nbsp; &nbsp; IS OUT![br]
		Check it out at http://www.kvirc.net!
		[/i][br]
		Finally, you can escape an escape character to include it literally in a parameter (and
		this is really the end of these tricks :)
		Later we will discover other common usages of the backslash escape, such
		as preventing KVIrc from interpreting a literal percent character as a variable
		or separating variable names from the text.
		[/p]

		[big]Command switches[/big]
		[p]
		Many commands accept switch parameters.
		[b]A switch modifies the behaviour of a command.[/b]
		Any switch can optionally accept a parameter, that must
		be specified after an equal ('=') sign.
		[example]
			[cmd]echo[/cmd] [b]-i = 2[/b] This text uses a specific color scheme
		[/example]
		The -i switch (just for example) changes the attributes
		and the icon of the printed text.
		[b]The switch must be specified immediately after the command keyword.[/b]
		[example]
			[cmd]echo[/cmd] This -i = 2 will obviously not work...
		[/example]
		If you want to start the first parameter of a command (that is not a switch)
		with a literal '-' you must again escape it:
		[example]
			[cmd]echo[/cmd] \--- This text has three minus signs on the left
		[/example]
		or use the quotes:
		[example]
			[cmd]echo[/cmd] "--- This text has three minus signs on the left"
		[/example]
		[/p]

		[big]Command blocks[/big]
		[p]
		Commands can be 'grouped' in blocks by using the classic C++ braces.
		Here is a single line example:[br]
		[example]
			{ [cmd]echo[/cmd] First command; [cmd]echo[/cmd] Second command; } [cmd]echo[/cmd] Third command
		[/example]
		Multi line example:[br]
		[example]
			{
			    [cmd]echo[/cmd] First command
				[cmd]echo[/cmd] Second command
			}
			[cmd]echo[/cmd] Third command
		[/example]
		[note]
		Reminder : copy the example above to a text file
		and then use /[cmd]parse[/cmd] &lt;filename&gt;
		[/note]
		In this case the command block has no special meaning
		other than making the code more readable , but command blocks
		will be useful later (see [cmd]if[/cmd],[cmd]while[/cmd]...).[br]
		[note]
		Unlike in C or C++, the braces do NOT automatically define a variable scope
		(with few exceptions to this rule ... just to complicate the things a bit more).
		You will recall this last assertion later, when reading about [doc:data_structures]data structures[/doc].
		[/note]
		[/p]

		[big]Comments[/big]
		[p]
		KVIrc supports comments in command sequences.[br]
		A comment starts with the character '#' and terminates with a newline.
		You can start a comment anywhere a command can start.[br]
		[example]
			# This is a comment , it occupies the whole line
			[cmd]echo[/cmd] After the comment!; # This is an end-line comment
		[/example]
		You can't escape newline characters in this case.
		(or better: escape characters have no meaning in comments...
		maybe one day I'll implement it).[br]
		Starting from version 3.0.0 kvirc supports also C++ single line and C multiline comments.[br]
		A C++ comment starts with two slashes '//' and terminates with a newline.
		A multiline C comment starts with '/*' and ends at the first '* /' encountered.
		Since KVIrc has no pre-processor, the C/C++ comments usually can't be placed in the middle of a command:
		they must start where a command would start and end before the begin of another command.[br]
		[/p]

		[big]Indentation[/big]
		[p]
		You [b]should[/b] use spaces or [b]tabs[/b] to [b]indent[/b] your code. Note that the [b]should[/b]
		word is written in bold characters: I mean that you really should indent your code.
		Indenting helps both you (the script writer) and the reader (any other user that will
		read your script). A good indenting practice is the first step to become a great programmer :)
		[note]
		Please note that the command parameters should be separated by
		space characters (ascii 32). Tabs are not granted to work as parameter separators.[br]
		[/note]
		[example]
		{
		&lt;tab&gt;[cmd]echo[/cmd] Indented command
		&lt;tab&gt;{
		&lt;tab&gt;&lt;tab&gt;# Comment
		&lt;tab&gt;&lt;tab&gt;[cmd]echo[/cmd] Really Really long indented \
		&lt;tab&gt;&lt;tab&gt;&lt;tab&gt;command
		&lt;tab&gt;}
		}
		[/example]
		Tabs behave better than spaces as indentation characters since other users can
		adjust the tab size to match their taste. I personally prefer 4 character tabs
		while most text/code editors usually come with 8 characters as default.
		[/p]
		
		[big]And now ?[/big]
		[p]
		You're now ready to really start experimenting with KVS. You can take
		a look at the [doc:commands]command index[/doc] and start trying to use them
		while keeping in mind the rules described in this document.
		The next suggested lecture is the documentation about [doc:kvs_aliasesandfunctions]the aliases and the functions[/doc].
		Have fun :)
		[/p]
*/

/*
	@doc: kvs_aliasesandfunctions
	@type:
		language
	@keyterms:
		aliases, functions
	@title:
		KVS Functions and aliases
	@short:
		KVS Functions and aliases
	@body:
		[big]Introduction[/big]
		[p]
		Since you're here, you should already have readed about the [doc:kvs_basicconcepts]KVS basic concepts[/doc]
		and have visited the [doc:commands]command index[/doc]. If you feel ready to take the next step
		then read on.
		[/p]

		[big]Functions[/big][br]
		[p]
		KVS has many internal [doc]functions[/doc] that can be used as command parameters.[br]
		[b]All the function names start with a literal '$' character.[/b][br]
		[example]
			[cmd]echo[/cmd] This window caption is [fnc]$window.caption[/fnc]
		[/example]
		The [fnc]$window.caption[/fnc] [doc:functions]function[/doc]
		is evaluated before the command executes,
		and it is changed into the current window caption text.[br]
		The [doc]functions[/doc] can be used also as switch parameters.[br]
		[example]
			[cmd]echo[/cmd] -w = [fnc]$window[/fnc] This text will be surely \
			&nbsp; &nbsp; printed in the current window
		[/example]
		The -w switch allows to redirect the echo text to a specified window --- in this
		case the one that you are typing in.[br]
		[i](Surprise: in this case the -w switch is useless ,
		since echo prints text to the current window by default...
		but it will work correctly. :)[/i]
		[/p]
		[p]
		Normal function names can be made of "anycase" letters, digits and underscores,
		with the restriction that the first character is not a digit.[br]
		Some kind of functions can contain a dot '.' character inside the name
		and these are assumed to be module references (see [doc:modules]the modules documentation[/doc]).[br]
		[/p]
		[p]
		By now we have seen only simple functions, but there's more...[br]
		The functions can accept parameters; the general syntax for a function call is:[br]
		[b]$<function name>['('<parameter_list>')'][/b][br]
		where <parameter_list> is a list of comma separated parameters,
		eventually empty.
		[example]
			[cmd]echo[/cmd] The word 'neural' is [fnc]$str.len[/fnc](neural) characters long
		[/example]
		The function [fnc]$str.len[/fnc] accepts a single parameter and returns the
		length in characters of the parameter string. The returned value is always
		a string: in this case it can be also interpreted as a number.[br]
		When passing an empty list you can avoid the parenthesis.
		(And you have found the "simple" functions shown above).
		So the followind two calls are equal:[br]
		[example]
			[cmd]echo[/cmd] [fnc]$window.caption[/fnc]
			[cmd]echo[/cmd] [fnc]$window.caption()[/fnc]
		[/example]
		If you want to pass an "empty" string as the first parameter you have to use
		the following syntax:[br]
		[example]
			[cmd]echo[/cmd] [fnc]$str.len[/fnc]("")
		[/example]
		Obviously a function is valid as a function parameter.[br]
		[example]
			[cmd]echo[/cmd] [fnc]$str.len[/fnc]([fnc]$window.caption[/fnc])
		[/example]
		If you want to place a literal '(' or ')' in the function parameters
		you must escape it.
		A special case for when you want to use 'matching' parentheses:
		an opened '(' corresponds to a closed ')'.
		In this case you can omit the 'escape' character.[br]
		[example]
			[cmd]echo[/cmd] The length of '(a+b)' is : [fnc]$str.len[/fnc]( (a+b) )
		[/example]
		This is useful for algebraic and boolean expressions , like the ones
		accepted by the special function $() (see next paragraphs).[br]
		[/p]


		[big]Aliases[/big][br]
		An alias is an user defined command.  It can be used to rename the builtin kvirc commands or functions,
		to automatize complex tasks or as structured programming mean.
		Aliases can be created or destroyed by using the scriptcenter (graphic interface)
		or from the commandline (or script) by using the [cmd]alias[/cmd] command.
		Once created, an alias remains stored permanently in the KVIrc configuration files
		until it is explicitly deleted.
		A couple of examples will make the things clear.
		join is a really commonly used command. It might be a good idea to rename it to
		simply "j" .. just to type it faster.
		Nothing easier in KVirc: just try this commandline:
		[example]
			[cmd]alias[/cmd](j){ [cmd]join[/cmd] $0-; };
		[/example]

		This will create the alias "j". From this moment you can use /j as it was a normal command.
		[example]
		j #kvirc
		[/example]
		You may have notices the strange $0- function in the alias body: it stands for
		"all parameters passed to the alias". This means that when you call
		[example]
			j #kvirc testpassword
		[/example]
		then both the parameters (#kvirc and testpassword) are passed to the join command.
		The $N functions are special functions that return the positional parameters passed
		to the current script context. In an alias the script context is the script body and
		it is the alias caller that generates the parameters.
		$N (where N is a digit) returns the (N-1)-th positional parameter passed by the caller.
		It returns the parameter numbered N-1 and not N since the parameters are indexed starting
		from zero ($0 is the first parameter!).
		$N-M returns the parameters from (N-1)-th to the (M-1)-th (a parameter range) and $N- returns
		all the parameters from (N-1)-th to the last one. In the example above $0- stands for
		all the parameters starting from the first one.
		[/p]
		[p]
		To remove an alias use again the alias command with an empty body:
		[example]
			[cmd]alias[/cmd](j){}
		[/example]
		This will remove the alias "j" defined above.
		[/p]
		[p]
		A common task in channel management is the kick & ban action.
		You first ban an user from the channel and then eventually kick him
		(obviously assuming that he is actually on the channel).
		This involves using two commands: ban and then kick.
		It could be a nice idea to have a single "kb" command to perform this action.
		Well...easy:
		[example]
			[cmd]alias[/cmd](kb){ [cmd]ban[/cmd] $0; [cmd]kick[/cmd] $0-; };
		[/example]
		This adds the "kb" alias: it can be called as a normal command:
		[example]
			kb spammer You're not welcome here!
		[/example]
		This will first execute "ban spammer" and then "kick spammer You're not welcome here".
		Our kb is a really simple example... it doesn't check for the validity of the parameters:
		the server will warn us if the parameters passed to kb were empty.
		[/p]
		[p]
		The alias can be modified at any time by re-using the alias command.
		Let's make our "kb" a bit more intelligent and add a check for the parameters.
		TIP: It is a good idea to write the following examples in a text file and then use /parse <filename> to execute it.
		[example]
			[cmd]alias[/cmd](kb)
			{
				[cmd]if[/cmd]("$0" == "")
				{
					[cmd]echo[/cmd] "Usage: /kb <nickname> <kick reason>"
					[cmd]return[/cmd]
				}
				[cmd]ban[/cmd] $0
				%reason = $1-
				[cmd]if[/cmd]("%reason" == "")%reason = "You're not welcome here!"
				[cmd]kick[/cmd] $0 %reason
			}
		[/example]
		The example above will first check the validity of the <nickname> passed to kb: 
		if no nickname was passed , it will warn the user and stop.
		The next step will be the "ban <nickname>" call. Another enchancement is the "default reason":
		we first assign the remaining parameters ($1- means "from $1 to the end") to a temporary variable,
		if the variable is empty , a default kick reason is assigned.
		Finally the "kick <nickname> <reason>" will be executed.
		Get used to looking at the single command documentation pages, they will give
		you the hints necessary to fully understand the above piece of code.
		[/p]
		[p]
		Aliases can be used as a mean for structured programming.
		In large scripts you will SURELY have "common tasks" to perform (like having specially
		colored output or calculating a value from a set of other values)...
		Aliases are the way of writing the common tasks: they are equivalent to the "procedures"
		or "functions" in many high-level programming languages.
		The alias as a procedure (subroutine or sub-task) has been shown in the "kb" example above:
		it might be commonly called from complexier scripts or other aliases in case that a
		kick & ban action is needed.
		[/p]
		[p]
		The aliases can be used also as functions.
		Assume that you need really often to calculate the sum of three numbers: a function-alias is the way.
		[example]
			[cmd]alias[/cmd](sum3){ [cmd]return[/cmd] $($0 + $1 + $2); };
		[/example]
		This will add the alias "sum3" and make it available both as a command and a function.
		The "return" command sets the return value of a sequence of commands
		(an alias is a sequence of commands...remember ?) and terminates the execution (by returning
		the control to the caller).
		So return $($0 + $1 + $2); will set the return value of the alias to the value
		computed by $($0 + $1 + $2) that actually is the sum of the first three parameters passed.
		You will then use it in the following way:
		[example]
			...
			%myfirstsum = $sum3(%somevalue,%someothervalue,4)
			%anothersum = $sum3(12,%somevalue,%anothervalue)
			...
		[/example]
		Ops.. I've used some variables without actually explaining them... hehe.. please forgive me and read on.
		This example is again really simple , but you might have complexier function-aliases.
		The function-aliases are also normal aliases.... you can use it as a command:
		[example]
			/sum3 1 2 3
		[/example]
		Is a perfectly valid call.... it's just that it will have no visible results
		(just because a command call implies ignoring the return value.
		In fact there is no difference al all between function-aliases and normal-aliases: 
		the caller makes the difference: by calling an alias as a command the return value 
		just disappears in hyperspace, by calling an alias as a function , the return value
		is propagated (and in fact "used").
		(There are some "nice" exceptions to this rule...but you don't need to care about it, for now).
		If return is not called inside an alias body , the return value will be just a null value.
		[/p]
		[p]
		Aliases can accept switches just like any other command. The [fnc]$sw[/fnc] is there
		exactly for that purpose. Check it out.
		[/p]

		[big]Special functions[/big]
		[p]
		We have already seen the positional parameter functions.
		The functions of type [b]$N[-[M]][/b] (where N and M are positive
		numbers starting from 0 and N < M) evaluate to the sequence of
		[b]positional parameters[/b] from Nth to Mth."[br]
		If M is omitted , the function evaluate to the sequence of [b]positional
		parameters[/b] from Nth to the last one. If the whole -M block is omitted
		the function evaluate to the Nth positional parameter.
		We will discover more on the [b]positional parameters[/b] when talking
		of aliases and events.[br]
		[example]
			$0 evaluates to the 1st positional parameter
			$0-4 evaluates to the parameters from first to 5th
			$41- evaluates to the parameters from 41st to the last avaiable
		[/example]
		The function [b]$#[/b] evaluates to the number of positional parameters available.
		The [b]positional parameter[/b] functions do not accept parameters.[br]
		The special function [b]$(<expression>)[/b] returns the result
		of the evaluation of the <expression>. In previous versions of KVIrc this
		function was called [fnc]$calc[/fnc].[br]
		[example]
			[cmd]echo[/cmd] $(2 + (3 ^ 7) <= 1 * (3 && 2))
		[/example]
		The special function [b]${<command sequence>}[/b] evaluates to the
		return value of the <command sequence>.[br]
		The special function [b]$$[/b] evaluates to the current object id,
		but it is too early to explain it here...[br]
*/

/*
	@doc: command_rebinding
	@type:
		language
	@keyterms:
		Rebinding commands to another window
	@title:
		Standard rebinding switch
	@short:
		Standard rebinding switch
	@syntax:
		<command> -r=<window_id> <parameters>
	@body:
		The -r switch is standardized along all the commands. It rebinds a command
		to the windows specified by <window_id>. It is useful to launch commands
		in windows that are not the current one. For example, you might want to
		say something in a specific channel while processing an event bound to
		a console, or say something in all the channels bound to the current irc context.
		The examples below will make everything clear.
	@examples:
		[example]
		[comment]# Run a command in the console of the current IRC context[/comment]
		[cmd]echo[/cmd] -r=$console This command is executed in the console ($window.caption)
		[comment]# Say something to all the channels of the current IRC context[/comment]
		[cmd]foreach[/cmd](%w,[fnc]$window.list[/fnc](channel))[cmd]say[/cmd] -r=%w Hi ppl on [fnc]$chan.name[/fnc]
		[/example]
*/

	/*
		@doc: window_naming_conventions
		@type:
			language
		@title:
			Window naming conventions
		@keyterms:
			IRC context,window ID,frame window,connection ID
		@short:
			KVIrc window structure and the window naming conventions
		@body:
			[big]Introduction[/big][br]
			Starting from the release 3.0.0 KVIrc window structure has
			grown in complexity. Older releases allowed one connetion
			per "frame window" and thus had a dedicated command parser
			for each connection. Finding a window in that scenario
			was quite easy: it was enough to designate it by "name"
			(that was exactly the text displayed in the window caption).
			It was sufficient to have an "unique" name for ever window;
			condition that was granted by the underlying IRC protocol
			and by the KVIrc core design.[br]
			In this version, the unique window names are impossible to be granted.[br]
			[big]Scenario[/big][br]
			The command parser is now "global" to the application.
			There can be two or more consoles in each frame and the user
			is able to join the same channel with two different nicknames
			using two separate connections.
			[ul]
			[li]
			Application (Unique command parser)
				[ul]
				[li]
				Frame X
					[ul]
					[li]
					Console M (IRC context)
						[ul]
						[li]Channel windows[/li]
						[li]Query windows[/li]
						[li]Other connection related windows[/li]
						[/ul]
					[/li]
					[li]
					Console N (IRC context)
						[ul]
						[li]Channel windows[/li]
						[li]Query windows[/li]
						[li]Other connection related windows[/li]
						[/ul]
					[/li]
					[li]
					Other windows
					[/li]
					[li]
					...
					[/li]
					[/ul]
				[/li]
				[li]
				Frame Y
					[ul]
					[li]
					Console O (IRC context)
						[ul]
						[li]Channel windows[/li]
						[li]Query windows[/li]
						[li]Other connection related windows[/li]
						[/ul]
					[/li]
					[li]
					Console P (IRC context)
						[ul]
						[li]Channel windows[/li]
						[li]Query windows[/li]
						[li]Other connection related windows[/li]
						[/ul]
					[/li]
					[li]
					Other windows
					[/li]
					[li]
					...
					[/li]
					[/ul]
				[/li]
				[li]
				...
				[/li]
				[/ul]
			[/li]
			[/ul]
			[br]
			A naming convention has becomed necessary to resolve ambiguities.[br]
			[big]Basic assumptions[/big]
			Every KVIrc window has four main properties:[br]
			-[b]an unique numeric identifier[/b][br]
			-[b]the logical name[/b][br]
			-[b]the type identifier[/b][br]
			-[b]the caption text[/b][br]
			The [b]numeric identifier[/b] is unique to the whole application,
			and is the one returned by the [fnc]$window[/fnc] function.[br]
			The identifier is assigned by KVIrc when the window is created
			and is not changed until the window is destroyed.
			This identifier will be referred as [b]window ID[/b].[br]
			The [b]logical name[/b] is a property of some kind of windows.
			It usually corresponds to the first part of the window caption.
			For example, for channel windows it is the channel name, for
			queries it is the list of the targets. For some other windows 
			the logical name corresponds to the caption text. This will be discussed later.[br]
			The [b]type identifier[/b] describes the properties of a certain window.
			For channel windows the type identifier is "channel" , for query windows is "query" ,
			for console windows it is "console", etc..[br]

			[big]Irc contexts[/big][br]
			The KVIrc frame windows are numbered starting from 0 and named
			"frame_<number>". Each frame can contain an unlimited number of consoles.[br]
			Each console is bound to an [b]IRC context[/b]. (The part "is bound to" could
			be substituted by "defines" or "is contained in").[br]
			[i]An [b]IRC context[/b] is a set of resources that can deal with a single
			IRC connection.[/i][br]
			The association between an [b]IRC context[/b]
			and a console is bijective: each [b]IRC context[/b] is associated
			to a single console window.[br]
			An [b]IRC context[/b] can be in connected or not-connected state.
			When in connected state, it contains a set of windows beside the console:
			mainly channels and query windows.
			The channels and query windows can exist ONLY if the associated
			[b]IRC context[/b] exists.[br]
			Channels and queries have unique names inside a connection so
			there is no way to confuse it. (Theoretically there can
			be more than one query window with the same name, but in fact
			all the windows refer to the same target so they are instances
			of the same resource).
			All this creates a sort of namespace: the channels and queries can be identified
			as "bound" to a specific [b]IRC context[/b].[br]
			An [b]IRC context[/b] can "contain" other windows, such as the "sockets"
			window or the "list" window. KVIrc takes care of making them
			unique inside the [b]IRC context[/b] namespace.[br]
			Each [b]IRC context[/b] has its own unique [b]IRC context ID[/b] (see [fnc]$context[/fnc]).[br]
			Since to a single [b]IRC context[/b] may correspond only a single irc connection,
			when in connected state, the [b]IRC context[/b] may be referred also as [b]connection[/b]
			or [b]connection context[/b], and the associated [b]IRC context Id[/b] can be
			referred as [b]connection ID[/b] or [b]connection context ID[/b].[br]
			There are classes of windows that are not bound to any [b]IRC context[/b]:
			this includes user created windows, DCC windows, browsers etc.[br]
			KVIrc will try to keep that windows with unique logical names.[br]
			[big]How to identify a window[/big][br]
			So what we have until now is:[br]
			[ul]
			[li]Each window has its own unique [b]window ID[/b]: we
			will refer windows always using this identifier.[/li]
			[li]Each window has a set of properties including:
			window type, logical name.[/li]
			[li]Subsets of windows are bound to a single [b]IRC context[/b][/li]
			[/ul]
			The simplest (but also the less significant) method of looking for
			a window is to finding it by caption.[br]
			The [fnc]$window[/fnc] function finds the first KVIrc window matching
			the "caption text" and returns its [b]window ID[/b].[br]
			This method will likely fail when there are more windows with the same
			caption text; for this reason several specific functions
			have been added to allow finding the correct window.[br]
			The [fnc]$console[/fnc] finds a console window bound to a specified
			[b]IRC context[/b].[br]
			The [fnc]$channel[/fnc] finds a channel window matching the specified
			name and bound to a specified [b]IRC context[/b].[br]
			The [fnc]$query[/fnc] finds a query window that has a specified target
			and is bound to a specified [b]IRC context[/b].[br]
	*/


	/*
		@doc: connection_dependant_commands
		@type:
			language
		@title:
			Connection dependant commands
		@keyterms:
			IRC context, connection dependant commands
		@body:
			Many KVIrc commands are connection dependant:
			you need an IRC connection to succesfully execute them;
			usually because some data needs to be sent to the server.
			This includes commands like [cmd]whois[/cmd],[cmd]raw[/cmd],[cmd]query[/cmd],
			[cmd]msg[/cmd],[cmd]notice[/cmd],[cmd]op[/cmd],[cmd]ctcp[/cmd]...[br]
			These commands must be executed in a window that is bound to a
			[b]connected [doc:window_naming_conventions]IRC context[/doc][/b].
			You will obviously get an error message if you try to use them in a window
			that has no associated IRC connection.[br]
			For instance: [cmd]whois[/cmd] will work only if you execute it
			in a console , channel or query window.[br]
			If you want to use these commands in a window that is not associated to
			any IRC context you may use the [doc:command_rebinding]standard -r switch[/doc].
			You can use the same switch to execute a command in an [b]IRC context[/b] that is
			not the current one.
	*/


/*
	@doc: aliases
	@type:
		language
	@keyterms:
		aliases
	@title:
		Aliases
	@short:
		Aliases : user definable command sequences
	@body:
		An alias is an user defined command.  It can be used to rename the builtin kvirc commands or functions,
		to automatize complex tasks or as structured programming mean.
		Aliases can be created or destroyed by using the scriptcenter (graphic interface)
		or from the commandline (or script) by using the [cmd]alias[/cmd] command.
		Once created, an alias remains stored permanently in the KVIrc configuration files
		until it is explicitly deleted.
		A couple of examples will make the things clear.
		join is a really commonly used command. It might be a good idea to rename it to
		simply "j" .. just to type it faster.
		Nothing easier in KVirc: just try this commandline:
		[example]
			[cmd]alias[/cmd](j){ [cmd]join[/cmd] $0-; };
		[/example]

		This will create the alias "j". From this moment you can use /j as it was a normal command.
		[example]
		j #kvirc
		[/example]
		You may have notices the strange $0- function in the alias body: it stands for
		"all parameters passed to the alias". This means that when you call
		[example]
			j #kvirc testpassword
		[/example]
		then both the parameters (#kvirc and testpassword) are passed to the join command.
		The $N functions are special functions that return the positional parameters passed
		to the current script context. In an alias the script context is the script body and
		it is the alias caller that generates the parameters.
		$N (where N is a digit) returns the (N-1)-th positional parameter passed by the caller.
		It returns the parameter numbered N-1 and not N since the parameters are indexed starting
		from zero ($0 is the first parameter!).
		$N-M returns the parameters from (N-1)-th to the (M-1)-th (a parameter range) and $N- returns
		all the parameters from (N-1)-th to the last one. In the example above $0- stands for
		all the parameters starting from the first one.
		[/p]
		[p]
		To remove an alias use again the alias command with an empty body:
		[example]
			[cmd]alias[/cmd](j){}
		[/example]
		This will remove the alias "j" defined above.
		[/p]
		[p]
		A common task in channel management is the kick & ban action.
		You first ban an user from the channel and then eventually kick him
		(obviously assuming that he is actually on the channel).
		This involves using two commands: ban and then kick.
		It could be a nice idea to have a single "kb" command to perform this action.
		Well...easy:
		[example]
			[cmd]alias[/cmd](kb){ [cmd]ban[/cmd] $0; [cmd]kick[/cmd] $0-; };
		[/example]
		This adds the "kb" alias: it can be called as a normal command:
		[example]
			kb spammer You're not welcome here!
		[/example]
		This will first execute "ban spammer" and then "kick spammer You're not welcome here".
		Our kb is a really simple example... it doesn't check for the validity of the parameters:
		the server will warn us if the parameters passed to kb were empty.
		[/p]
		[p]
		The alias can be modified at any time by re-using the alias command.
		Let's make our "kb" a bit more intelligent and add a check for the parameters.
		TIP: It is a good idea to write the following examples in a text file and then use /parse <filename> to execute it.
		[example]
			[cmd]alias[/cmd](kb)
			{
				[cmd]if[/cmd]("$0" == "")
				{
					[cmd]echo[/cmd] "Usage: /kb <nickname> <kick reason>"
					[cmd]return[/cmd]
				}
				[cmd]ban[/cmd] $0
				%reason = $1-
				[cmd]if[/cmd]("%reason" == "")%reason = "You're not welcome here!"
				[cmd]kick[/cmd] $0 %reason
			}
		[/example]
		The example above will first check the validity of the <nickname> passed to kb: 
		if no nickname was passed , it will warn the user and stop.
		The next step will be the "ban <nickname>" call. Another enchancement is the "default reason":
		we first assign the remaining parameters ($1- means "from $1 to the end") to a temporary variable,
		if the variable is empty , a default kick reason is assigned.
		Finally the "kick <nickname> <reason>" will be executed.
		Get used to looking at the single command documentation pages, they will give
		you the hints necessary to fully understand the above piece of code.
		[/p]
		[p]
		Aliases can be used as a mean for structured programming.
		In large scripts you will SURELY have "common tasks" to perform (like having specially
		colored output or calculating a value from a set of other values)...
		Aliases are the way of writing the common tasks: they are equivalent to the "procedures"
		or "functions" in many high-level programming languages.
		The alias as a procedure (subroutine or sub-task) has been shown in the "kb" example above:
		it might be commonly called from complexier scripts or other aliases in case that a
		kick & ban action is needed.
		[/p]
		[p]
		The aliases can be used also as functions.
		Assume that you need really often to calculate the sum of three numbers: a function-alias is the way.
		[example]
			[cmd]alias[/cmd](sum3){ [cmd]return[/cmd] $($0 + $1 + $2); };
		[/example]
		This will add the alias "sum3" and make it available both as a command and a function.
		The "return" command sets the return value of a sequence of commands
		(an alias is a sequence of commands...remember ?) and terminates the execution (by returning
		the control to the caller).
		So return $($0 + $1 + $2); will set the return value of the alias to the value
		computed by $($0 + $1 + $2) that actually is the sum of the first three parameters passed.
		You will then use it in the following way:
		[example]
			...
			%myfirstsum = $sum3(%somevalue,%someothervalue,4)
			%anothersum = $sum3(12,%somevalue,%anothervalue)
			...
		[/example]
		Ops.. I've used some variables without actually explaining them... hehe.. please forgive me and read on.
		This example is again really simple , but you might have complexier function-aliases.
		The function-aliases are also normal aliases.... you can use it as a command:
		[example]
			/sum3 1 2 3
		[/example]
		Is a perfectly valid call.... it's just that it will have no visible results
		(just because a command call implies ignoring the return value.
		In fact there is no difference al all between function-aliases and normal-aliases: 
		the caller makes the difference: by calling an alias as a command the return value 
		just disappears in hyperspace, by calling an alias as a function , the return value
		is propagated (and in fact "used").
		(There are some "nice" exceptions to this rule...but you don't need to care about it, for now).
		If return is not called inside an alias body , the return value will be just a null value.
		[/p]
		[p]
		Aliases can accept switches just like any other command. The [fnc]$sw[/fnc] is there
		exactly for that purpose. Check it out.
		[/p]
*/


/*
	@doc: kvs_addons
	@type:
		language
	@keyterms:
		addons, addon
	@title:
		The KVIrc addon system
	@short:
		Writing KVIrc addons
	@body:
		[big]Introduction[/big]
		[p]
		An addon is basically a set of KVS scripts, multimedia, documentation
		and accessory files that implement a KVIrc feature.
		It might be a simple automatic-away subsystem, a GUI newsticker or a complex file sharing
		service (commonly called "fserve"). Addons are sometimes called "scripts".
		In fact a KVIrc addon is usually made of more than one KVS script.
		[/p]
		[p]
		KVIrc has a builtin addon management system that allows the users
		to install, configure and uninstall features with a nice graphical interface.
		The management system allows the addons to have documentation integrated in the
		KVIrc help and to be translated in several languages.
		[/p]

		[big]Addon installation[/big]
		[p]
		The addons are usually shipped in compressed archives (such as tar.gz "tarballs" or
		zip files). Once uncompressed they should contain a KVS script file called "install.kvs".
		KVIrc will look for and execute this file when the user will ask for your addon to
		be installed. The install.kvs will usually contain the code for the [b]registration[/b]
		of your addon and will [cmd]include[/cmd] all the other necessary source files.
		[/p]

		[big]The minimal addon[/big]
		[p]
		The smallest addon that you can write is the one that does nothing.
		It just need to be writte in a file named install.kvs and contain code
		similar to the following:
		[example]
			[cmd]addon.register[/cmd]("myaddon", \
								"1.0.0", \
								"My First Addon", \
								"An addon that is really cool but does simply nothing", \
								"3.2.0.99.20051230")
			{
			}
		[/example]
		The code above does nothing but registers the "myaddon" addon.
		[/p]
		[p]
		The first parameter is the internal addon id which can be used to identify
		your addon inside KVIrc. The id must be unique: two addons that share the same
		name cannot be installed. The second parameter is the addon version. It should
		be expressed in the classic format [major].[minor].[pathlevel] or something
		really similar (in fact KVIrc just expects the version to be a string composed
		of numbers separated by dots). The version is compared when an addon is installed
		and KVIrc complains if the user tries to downgrade an addon (that is to install
		a less recent version over a more recent one). The third parameter
		is the visible name of your addon: it will be displayed to the user in the
		addon management dialog. It can contain the [fnc]$tr[/fnc] function so you
		can have it translated to several languages. The fourth parameter
		is a short description of the feature that the addon implements; it can contain
		the $tr() function too. The fifth parameter is the minimal KVIrc version
		required to run the addon. There is also a sixth parameter (the icon) and
		some switches that can be used to fiddle a little bit more :)
		[/p]
		[p]
		The callback instruction that follows the registration command is the
		uninstallation code. KVIrc will invoke it when the user will ask for
		your addon to be uninstalled. Don't assume that your addon will be never uninstalled:
		sooner or later it will be. For example, when upgrading an addon KVIrc
		will first uninstall the existing version and after that install the new one.
		The uninstallation process is a very important requisite for any program (in any
		programming language). In the example above there is nothing to uninstall (yet)
		so the callback code is empty, but if you continue reading we will soon fill it.
		[/p]

		[big]A typical addon tqlayout[/big]
		[p]
		As stated above, the addons are usually shipped in a compressed archive.
		Once uncompressed, the archive will expand into a small directory tree
		containing the addon code and all the related files.
		In order to have uniformity I encourage you to use the following directory structure.
		[/p]
		[p]
		[pre]
		&nbsp; &nbsp; [b]addonId-version/[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; install.kvs
		&nbsp; &nbsp; &nbsp; &nbsp; INSTALL
		&nbsp; &nbsp; &nbsp; &nbsp; [b]src[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source1.kvs
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source2.kvs
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; source3.kvs
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; [b]pics[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_pic1.png
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_pic2.png
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_pic3.png
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; [b]audio[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_audio1.png
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_audio2.png
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_audio3.png
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; [b]help[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; en
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.html
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hints.html
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; it
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; index.html
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; hints.html
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; [b]locale[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_it.mo
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_ru.mo
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; addonId_de.mo
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; [b]...[/b]
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ...
		[/pre]
		[/p]
		[p]
		The entries in [b]bold[/b] are directories while the other are files.
		Please note that this is a general tqlayout for a huge and rather complex
		addon: you might not need all of these directories. Remember: the minimal
		addon has only an install.kvs file. Anyway, a really cool addon
		will probably have all of them and maybe some more.
		[/p]
		[p]
		The toplevel directory should be named with your addonId and version.
		Try to use no spaces in the directory entries (this will make the things
		simplier for people that want to use your addon). The toplevel
		directory should contain your install.kvs script and a file with
		a small description and the basic installation instructions.
		This file can be named INSTALL or README.
		[/p]
		[p]
		Hint: Remember that your addon is going to be installed on different platforms
		(at least linux, macosx and windows based).
		The poor windows notepad has serious problems with reading text
		files that contain only linefeeds as line separators. Keep it in mind...
		[/p]
		[p]
		The main source directory for your addon should be named "src" and
		should contain the implementation of the feature(s) you're going to provide.
		These files should be executed by the means of the [cmd]parse[/cmd]
		command (or [cmd]include[/cmd] if you like the C/C++ style) from install.kvs.
		[/p]
		[p]
		The "pics" and "audio" (if relevant) directories should contain your
		multimedia files. It is a good idea to prefix the filenames with your addon id
		in order to avoid collisions with other addons. The install.kvs script
		should copy these files to the appropriate locations under the KVIrc local
		directory returned by [fnc]$file.localdir[/fnc]().
		[/p]
		[p]
		The "help" directory should contain subdirectories for each language that
		your help files are written in. The languages dirs should be named
		with the language code also used for the translation files (like "en","it" etc...).
		Please note that english is the default language and KVIrc will
		fallback to the "en" subdirectory when no other language is found around...
		The help files (and subdirectories) should be copied to the "help" subdirectory of the KVIrc local
		directory returned by [fnc]$file.localdir[/fnc]().
		Since there will be many help files inside the language dirs, it is a good idea
		to either prefix your help files with your addon id or (better) to create
		a subdirectory named agains your addon inside the help language directory.
		For an english file this would lead to something like...
		[example]
			file.copy index.html $file.localdir("help/en/myaddon")
		[/example]
		[/p]
		[p]
		The "locale" directory should contain the *.mo files for your tranlations.
		The localization process of a script is explained in [doc:localization]this document[/doc].
		The *.mo files should be copied to the "locale" subdirectory of the KVIrc local
		directory returned by [fnc]$file.localdir[/fnc]().
		Your *.mo filenames should be prefixed by your addon id (again to avoid collisions).
		[/p]

		[big]The help and configuration callbacks[/big]
		[p]
		Each addon can have a help and a configuration callback. These are set
		respectively by [cmd]addon.sethelpcallback[/cmd] and [cmd]addon.setconfigurecallback[/cmd].
		[/p]
		[p]
		The help callback will be invoked by KVIrc when the user will ask help for your addon (mainly
		from the addon management dialog, but not necessairly). It should call [cmd]help.open[/cmd]
		with the name of your documentation index html file (it should be relative
		to the help language directory: help.open myaddon/index.html will automatically
		lookup the right language). If you provide no help callback, the buttons
		for requesting help will be simply disabled. (A good an relatively complex addon
		*should* have at least a minimal help file explaining the features).
		[/p]
		[p]
		The configuration callback will be invoked when the user will try to configure
		your addon from the addon management dialog. This callback is useful
		mainly for complexier graphical scripts that can show up a dialog
		that allows configuring all of the addon features. To use this callback
		you will probably need some object scripting.
		[/p]

		[big]The real addon work[/big]
		[p]
		The real addon work is done by the scripts contained in the src directory.
		They will likely add aliases (maybe in a nice namespace named agains your addon),
		register event handlers, create actions, timers, toolbars and object classes.
		You should install all of this stuff from your addon source files.
		Remember that your source files will NOT be parsed every time KVIrc starts up:
		your stuff must be registered in KVIrc and be able to startup itself, if needed.
		Remember that you must clean up [b]everything[/b] in your uninstallation callback.
		This means that you must remove the aliases, unregister the event handlers,
		destroy the actions, kill the timers and the object classes you've created.
		Be a clean coder :)
		[/p]

		[big]Where to start[/big]
		[p]
		It is a good idea to start on the KVIrc web site. There are surely
		several addons to look at. Pick one that seems simple and analyze its
		tqlayout and code (wow... the free software!). It will be easier to do than it was to explain it :D
		[/p]
		[p]
		Have fun! :)
		[/p]
*/


/*
	@doc: kvs_codingtips
	@type:
		generic
	@title:
		Coding tips
	@keyterms:
		indentation,indent,readability
	@short:
		Generic coding tips for scripters (and not only)
	@body:
		Here comes a small list of "coding tips".[br]
		These apply to programming in general , not only to KVIrc scripting.[br]
		[br]
		1. [b]Comment your code[/b][br]
		A well commented code is easy to mantain, and easy to read by others.[br]
		[br]
		2. [b]Indent your code[/b][br]
		Indentation increases the code readability; this is again for you and
		other developers that will be going to read your code.[br]
		[br]
		3. [b]Use TABS to indent your code[/b][br]
		...and use ONLY TABS to indent.[br]
		Tabs are better than space since most code editors allow you
		to set the tab sice and thus to have the indentation steps smaller or bigger.[br]
		This is really important since the indentation size is really a matter of personal taste.[br]
		Mixing spaces and tabs is Evil (tm), since it makes the code look really
		ugly in editors that have the tab size different than yours; in some cases the
		code gets really unreadable.[br]
		[br]
		4. [b]Use descriptive variable names[/b][br]
		Using 'foo' as variable name implies tracing its semantic the next
		time that you're going to read the code that uses it.[br]
		This is really annoying and time-consuming, especially if the project
		is getting large.[br]
		Obviously using "thisIsACounterVariable" as name for a simple counter
		is also a suicide.[br]
		A good convention on variable names can speed up writing , debugging and mantaining code.[br]
		Encoding the type of the variable in the variable name might be also a good idea,
		but this is a matter of taste; personally I feel really well with that.[br]
		Just as example, here go my fundamental convention rules for C++:[br]
		[br]
		- The type of the variable is encoded at the beginning of the variable name:[br]
		[br]
			- b prefix for the boolean varables[br]
			- i prefix for signed integers[br]
			- u prefix for unsigned integers[br]
			- f and d prefixes for floating point stuff[br]
			- sz prefix for strings (this is rather for string classes)[br]
			- ...[br]
		[br]
		- Pointers have a "p" prefix prepended[br]
		- Global variables start with a "g_" prefix[br]
		- Member variables start with a "m_" prefix[br]
		- Exception comes for local variables with obvious semantics[br]
		[br]
			- i,j,k,l for local loop counters[br]
			- "aux" and "tmp" for local obvious short-term temporary variables[br]
		[br]
		So actually by ONLY reading "g_pszQuitMessage" I know that this is a global pointer to a string variable
		containing a quit message. :)[br]
		[/p]
*/

// FIXME: #warning "FINISH THE SYNTACTIC RULES DOC"

/*
	@doc: syntactic_rules
	@type:
		language
	@keyterms:
		productions
	@title:
		Syntactic rules
	@short:
		Syntactic rules of the KVIrc scripting language
	@body:

		In the following table you can find a good part of the
		KVIrc scripting language syntactic rules.[br]
		[br]
		<entity> indicates a ENTITY THAT CAN APPEAR EXACTLY ONE TIME.[br]
		[<entity>] indicates an OPTIONAL ENTITY.[br]
		{<entity>} indicates an ENTITY THAT CAN APPEAR ONE OR MORE TIMES.[br] 
		'entity' indicates a LITERAL ENTITY: written exactly as it is.[br]
		<entity1>|<entity2> indicates mutually exclusive choices.[br]
		The mutually exclusive choices are often separated in two or more
		rules (productions), to improve readability.[br]
		[table]
		[tr]
		[td]<command buffer>[/td]
		[td][<whitespace>][<command block>]{<command buffer>}[/td]
		[/tr]
		[tr]
		[td]<command buffer>[/td]
		[td][<whitespace>][<single command>]{<command buffer>}[/td]
		[/tr]
		[tr]
		[td]<whitespace>[/td]
	    [td]{<space>|<tab>|<newline>}['\'<newline>][<whitespace>][/td]
		[/tr]
		[tr]
		[td]<space>[/td]
		[td]' '['\'<newline>][<space>] (Ascii space character)[/td]
		[/tr]
		[tr]
		[td]<tab>[/td]
		[td]'\t' (Ascii horizontal tabulation character)[/td]
		[/tr]
		[tr]
		[td]<newline>[/td]
		[td]'\n' (Ascii line feed (LF) character)[/td]
		[/tr]
		[tr]
		[td]<command block>[/td]
		[td]'{' <command buffer>[<whitespace>] '}'[/td]
		[/tr]
		[tr]
		[td]<single command>[/td]
		[td]<comment>[/td]
		[/tr]
		[tr]
		[td]<single command>[/td]
		[td]<lvalue command> <command terminator>[/td]
		[/tr]
		[tr]
		[td]<single command>[/td]
		[td]<rvalue command> <command terminator>[/td]
		[/tr]
		[tr]
		[td]<comment>[/td]
		[td]'#' {<non comment terminator>} <comment terminator>[/td]
		[/tr]
		[tr]
		[td]<comment terminator>[/td]
		[td]<newline> | <end of string>[/td]
		[/tr]
		[tr]
		[td]<end of string>[/td]
		[td]No character (internally Ascii character 0)[/td]
		[/tr]
		[tr]
		[td]<command terminator>[/td]
		[td]<newline> | <end of string> | ';'[/td]
		[/tr]
		[tr]
		[td]<non comment-terminator>[/td]
		[td]Any Ascii character except <newline> and <end of string>[/td]
		[/tr]
		[tr]
		[td]<simple command>[/td]
		[td][<module name>'.']<command name>[<switch list>]{<space>}<command dependant part>[/td]
		[/tr]	
		[tr]
		[td]<lvalue command>[/td]
		[td]<variable>[<space>]<operation>[/td]
		[/tr]
		[tr]
		[td]<lvalue command>[/td]
		[td]<variable>'->'<object command>[/td]
		[/tr]
		[tr]
		[td]<lvalue command>[/td]
		[td]<identifier>'->'<object command>[/td]
		[/tr]
		[tr]
		[td]<operation>[/td]
		[td]<one op operator>[/td]
		[/tr]
	    [tr]
		[td]<operation>[/td]
		[td]<two op operator>[<space>]<param string>[/td]
		[/tr]
		[tr]
		[td]<switch list>[/td]
		[td]{<space>}'-'<alpha char>[{<space>}'='<single parameter>][<switch list>][/td]
		[/tr]
		[tr]
		[td]<command name>[/td]
		[td]<alphanumeric char>{<alphanumeric char>}[/td]
		[/tr]
		[tr]
		[td]<module name>[/td]
		[td]<alphanumeric char>{<alphanumeric char>}[/td]
		[/tr]
		[tr]
		[td]<alphanumeric char>[/td]
		[td]Ascii characters 'A' to 'Z' , 'a' to 'z' , '0' to '9' and '_'[/td]
		[/tr]
		[tr]
		[td]<variable>[/td]
		[td]<global variable> | <local variable>[/td]
		[/tr]
		[tr]
		[td]<global variable>[/td]
		[td]'%' <uppercase letter> [<alphanumeric char>]['['<param string>']'][/td]
		[/tr]
		[tr]
		[td]<local variable>[/td]
		[td]'%' <lowercase letter> [<alphanumeric char>]['['<param string>']'][/td]
		[/tr]
		[tr]
		[td]<param string>[/td]
		[td][<single parameter>][<space>[<param string>]][/td]
		[/tr]
		[tr]
		[td]<single parameter>[/td]
		[td]<variable> | <identifier> | <nonterminator token> | <string>[/td]
		[/tr]
		[tr]
		[td]<nonterminator token>[/td]
		[td]<nonterminator char>['\'<newline><nonterminator char>][/td]
		[/tr]
		[tr]
		[td]<nonterminator char>[/td]
		[td]Any ascii character except <space> and <command terminator>[/td]
		[/tr]
		[tr]
		[td]<command dependant part>[/td]
		[td][b]Production in each command help page[/b][/td]
		[/tr]
		[/table]
		To be continued...
*/

/*
	@doc: command_rebinding
	@type:
		language
	@keyterms:
		Not supported
	@title:
		Standard -r switch no longer supported
	@short:
		Standard -r switch no longer supported
	@body:
		Starting from version 3.0.0 the standard -r switch to commands is no longer supported.
		You should rebind your command sequences with [cmd]rebind[/cmd]
*/

/*
	@doc: kvs_datatypes
	@type:
		language
	@keyterms:
		global variable, global variables, local variable, local variables, 
		variables, variable, array, hash, dictionary, global variables, local variables,variable evaluation,
		associative arrays, scalars, data types, percent sign, extended scope
	@title:
		Variables and Data types
	@short:
		All about the KVS variable and datatype management
	@body:
		[title]Basic syntax[/title]

		[p]
		A variable identifier is composed by a '%' (percent) sign followed
		by a sequence of letters, digits or underscores.
		Examples of valid variable names are:
		[/p]

		[example]
			%i
			%variable
			%MyVar
			%1
			%thisisavar
			%2ndName
			%_hidden
		[/example]

		[p]
		Variables are created when you assign something to them: there is no need
		for a declaration (unlike other languages such as C/C++, Java or VB).
		[/p]

		[example]
			[comment]# create a variable named %X by assigning the value 10 to it[/comment]
			%X = 10
			[comment]# use the variable[/comment]
			echo "The value of X is" %X
		[/example]

		[title]Local and global variables[/title]

		[p]
		Variables can be local or global.
		Local variables preserve their contents only inside the [b]scope[/b] of a single script.
		Global variables are shared between all the scripts and preserve their contents
		until they are explicitly unset or until KVIrc quits.
		[/p]

		[p]
		Local variables start with a [b]lowercase letter[/b] while the global ones with an [b]uppercase letter[/b].
		[/p]

		[example]
			%var = 10; [comment]# this is a local variable[/comment]
			%Var = 10; [comment]# this is a global variable[/comment]
		[/example]

		[p]
		You can also force a variable that start with a lowercase letter to be global
		by predeclaring it with the [cmd]global[/cmd] keyword.[br]
		[/p]

		[example]
			[comment]# copy this script to a file and run /[cmd]parse[/cmd] <filename>[/comment]
			global %a
			%a = "The contents of the variable a"
			%b = "The contents of the variable b"
			[comment]# %a is a global variable now : all the other scripts can see its value[/comment]
			[comment]# %b is a local variable and no other scripts can see its value[/comment]
		[/example]

		[p]
		If you have executed the example above from a file (by the means of [cmd]parse[/cmd])
		then now you can type
		[/p]

		[example]
			[cmd]echo[/cmd] %a
		[/example]

		[p]
		in the commandline to see the contents of the variable %a.
		If you also try
		[/p]

		[example]
			[cmd]echo[/cmd] %b
		[/example]

		[p]
		you will see nothing printed since %b was local to the parsed script.
		[/p]

		[title]Data types[/title]

		[p]
		KVS has three main categories of data types: scalars, arrays and associative
		arrays (also known as dictionaries or hashes).
		[/p]

		[subtitle]Scalars[/subtitle]

		[p]
		The scalars are simple variables containing a single value (a string or an integer).
		[/p]
		
		[example]
			[comment]# %a is a scalar variable[/comment]
			%a = "This is a string"
			[cmd]echo[/cmd] %a
			%a = 24.5
			[cmd]echo[/cmd] %a
		[/example]

		[subtitle]Arrays[/subtitle]
		
		[p]
		Arrays are collections of items indexed by integers. The array items
		are selected by placing the index in square brackets just after the array name.
		[/p]

		[example]
			%arrayName[index]
		[/example]
		
		[p]
		An easy way to create an array is to use the [fnc]$array[/fnc] function.
		[/p]

		[example]
			%a = $array("element1","element2","element3"); [comment]# Create an array with 3 items[/comment]
			[cmd]for[/cmd](%i=0;%i<3;%i++)
			{
				echo %a[%i]; [comment]# Accessing the %i'th element of the array[/comment]
			}
		[/example]

		[p]
		Note that in the example above %a refers to the whole array while %a[%i] refers
		to one of its elements, in particular the one with index %i.
		You also create an array by explicitly assigning to one of its elements:
		[/p]

		[example]
			%a[9] = "This is an array element";
		[/example]

		[p]
		Array indexes are zero-based so in the example above you have created an array
		with 10 items. You can find out an array's length with the [fnc]$length[/fnc]() function.
		[/p]

		[example]
			%a[9] = "This is an array element";
			echo $length(%a)
		[/example]

		[p]
		Be aware that by making such an assignment you implicitly consume some memory for
		all the preceeding array items (even if they are unset). This means that
		a simple instruction like the following may eat a huge amount of memory at once:
		[/p]

		[example]
			%a[1000000] = "An array element faaaaaar away...";
			echo $length(%a)
		[/example]

		[note]
		[p]
		Food for thoughts:
		[/p]
		[p]
		KVIrc allocates a pointer for each item in the array. The pointer is
		empty when the item is unset and points to an additional block
		of memory when the item is set. The size of a pointer is platform
		dependant: on the platforms supported by KVIrc it's either 32 or 64 bit.
		The size of the additional block depends both on the platform
		and on the contents of the item... it's average value may
		be around 16 bytes. The array size is determined by the last SET element index.
		All this this means that in the worst case (64 bit assumption) an array in
		that the highest indexed item set is N eats up at least N*8+16 bytes of memory.
		[/p]
		[/note]

		[p]
		Besides the traditional indexed looping method you
		can also use the [cmd]foreach[/cmd] command to iterate the items of an array.
		Be aware that [cmd]foreach[/cmd] will NOT iterate over unset items in the
		array unless you use the -a switch.
		[/p]
		
		[example]
			%Array[0]=Pippo
			%Array[1]=Pluto
			%Array[2]=Paperino
			%Array[5]=Prova
			[cmd]foreach[/cmd](%item,%Array)[cmd]echo[/cmd] Got Item: %item
		[/example]
		
		[p]
		Note that the items 3 and 4 are simply skipped.
		[/p]

		[subtitle]Hashes[/subtitle]

		[p]
		The hashes are collections of items indexed by strings: the word "hash"
		is in fact a shortcut for "hashtable". In literature hashes are also called
		"associative arrays", "dictionaries" or "key-value pair sets".
		The hash items are selected by placing the key in curly brackets
		just after the hash name.
		[/p]

		[example]
			%hashName{key}
		[/example]

		[p]
		An easy way to create a hash is to use the [fnc]$hash[/fnc] function.
		[/p]
		[example]
			%a = $hash("key1","value1","key2","value2","key3","value3")
			[cmd]foreach[/cmd](%key,[fnc]$keys[/fnc](%a))
			{
				echo "KEY:" %key "VALUE:" %a{%key};
			}
		[/example]
		
		[p]
		Note that in the example above %a refers to the whole hash while %a{%i} refers
		to one of its elements, in particular the one with the key %key.
		You also create a hash by explicitly assigning to one of its elements:
		[/p]
		
		[example]
			%a{"MyKey"} = "MyValue"
		[/example]

		[p]
		You may have already noticed that the [fnc]$key[/fnc]() function returns
		the array of the hash keys: it is useful to iterate over the hash items.
		[/p]

		[title]Mutability of variables[/title]

		[p]
		KVS is not strictly typed: any variable can assume different type identities at different times,
		even in the same script.
		[/p]
		
		[example]
			[comment]# %a is a scalar[/comment]
			%a = "This is a string"
			[comment]# %a becomes an array with 3 elements[/comment]
			%a = $array("element1","element2","element3");
			[comment]# %a becomes a hash with two values[/comment]
			%a = $hash("key1","value1","key2","value2");
		[/example]
		
		[p]
		In literature this kind of variable is called [b]variant[/b] and this is the
		term that you will find all around the documentation when an explicit
		data type is not requested.
		[/p]

		[p]
		Note that array and hash items are variants too. This means that you can have arrays
		of arrays, hashes of arrays of hashes and any other multidimensional combination you like.
		However remember that hash keys are strings and not variants so you can't use an array as hash key.
		[/p]
		
		[example]
			[comment]# here we eat 256 locations of memory at once :)[/comment]
			%a[16][16] = 10
			[comment]# a hash of hashes: here we eat just two memory locations[/comment]
			%a{"16"}{"16"} = 10
		[/example]


		[p]
		In most cases the KVS engine manages automatically the conversion between data types.
		For example, when you put an array in a place where a scalar is requested, KVIrc
		automatically transforms it to a scalar string by joining all the items with a comma.
		[/p]
		
		[example]
			%a = $array("element1","element2","element3");
			echo %a; [comment]# echo expects its arguments to be scalar[/comment]
		[/example]
		
		[p]
		Conversely, when you put a scalar in place of an array, KVIrc automatically
		transforms it to an array with a single item. In this way a function like
		[fnc]$sort[/fnc] works also with a scalar.
		[/p]
		
		[p]
		In literature the conversions between data types are called [b]casts[/b]. When
		the conversion is automatic the cast is said to be [b]implicit[/b].
		[/p]
		
		[p]
		KVS handles also the other possible implicit casts: scalar->hash,hash->scalar,array->hash,hash->array.
		Experiment with it.
		[/p]

		[title]More about scalars[/title]

		[p]
		Internally KVS is implicitly typed: the "scalar" data type is in fact
		a set of types that KVIrc manages silently. The types are: integer, string, real, boolean and hobject.
		[/p]
		
		[p]
		Integers are non-floating point numbers. Their allowable range depends on the underlying
		platform integer size: usually 32 or 64 bit.
		[/p]
		
		[p]
		Reals are floating point numbers. Their allowable range and precision depends on the underlying
		platform.
		[/p]
		
		[p]
		Booleans are either true or false values.
		[/p]
		
		[p]
		Hobject stands for Handle to Object and it is a sort of a C++ pointer.
		Detailed description of objects is in [doc:objects]this document[/doc].
		[/p]
		
		[p]
		Basically anything else fails in the "string" category.
		[/p]
		
		[p]
		In most cases KVS manages all the conversions between data types automatically.
		For example an integer becomes a true boolean when it's non zero and a false boolean
		otherwise, a real becomes an integer by truncating it's fractional part...
		[/p]
		
		[p]
		You can find out the type of a specified variable by using the [fnc]$typeof[/fnc]() function.
		[/p]
		
		[example]
			%a = 1
			echo $typeof(%a)
			%a = 1.1
			echo $typeof(%a)
			%a = $true
			echo $typeof(%a)
			%a = "test"
			echo $typeof(%a)
		[/example]
		
		[p]
		There is also another subtle type of scalar called "nothing". It stands for an 
		empty (unset) variable.
		[/p]
		
		[example]
			%a = $nothing
			echo $typeof(%a)
		[/example]
		
		[p]
		Nothing is something in between a data type and a special value for all the other data types:
		it rappresents absence of information. 
		This may look a bit confusing but realize that all the unreferenced KVS variable are in fact of type "nothing":
		they just don't exist. This means that you can use [fnc]$nothing[/fnc]() to effectively
		unset a variable.
		[p]
		
		[p]
		Again, when possible, the conversion between nothing and the other data types is
		performed automatically. Nothing becomes an empty string, a null object handle or an empty array.
		[/p]


		[title]Explicit casts[/title]
		
		[p]
		You can make explicit conversions between some data types by using the casting functions.
		[fnc]$integer[/fnc]() will attempt to convert the variant parameter to an integer, [fnc]$real[/fnc]()
		will cast to a floating point value, [fnc]$boolean[/fnc]() will convert to a
		true/false value, [fnc]$string[/fnc]() will explicitly convert to a string, 
		[fnc]$array[/fnc]() will convert to an array and [fnc]$hash[/fnc] will return
		a dictionary. By assigning the special [fnc]$nothing[/fnc]() value you will
		convert to the nothing data type (or simply unset the variable).
		The only explicit conversion that is not possible is to hobject.
		[/p]
		
		[p]
		As stated several times in this document, KVS tries to manage the casts automatically
		so you usually don't need to care about it. The explicit casts are provided for
		the very few cases where an automatic conversion would lead to an unexpected value (for your script)
		and for writer's clarity.
		[/p]

		[title]More about variables lifecycle[/title]

		[p]
		As stated above variables start their existence when you assign something to them.
		After a variable has been created it persists until it goes out of his scope (remember
		about local and global variables ?) or you explicitly destroy it. You will usually
		not care about it and just leave the KVS engine to do his cleaning job but it's still worth
		knowing that you actually can force KVIrc to free the memory used by a variable.
		[/p]
		
		[p]
		The first method to explicitly destroy a variable is to call [cmd]unset[/cmd] on it.
		[cmd]unset[/cmd] in fact accepts a list of variables so you can destroy more variables at once.
		[/p]
		
		[example]
			%a = [fnc]$array[/fnc]("data","for","a","really","huge","array","of","items")
			%b = 10
			%c = "just a string that eats memory"
			[cmd]unset[/cmd] %a,%b,%c
		[/example]

		[p]
		The KVS engine treats unset variables just like empty strings. The opposite is also valid: empty
		strings behave like empty (unset) variables. This means that you can assign an empty string
		to a variable to unset it.
		[/p]

		[example]
			%a = "test"; [comment]# %a starts his existence[/comment]
			%b = "test2";
			%a = ""; [comment]# %a is in fact unset[/comment]
			%b = ; [comment]# syntactically this is just the same as above[/comment]
		[/example]
		
		[p]
		Note that because of mutability of variables (explained above) you can use the empty string
		assignment also to free arrays and hashes.
		[/p]

		[title]Extended scope variables[/title]

		[p]
		Beside local and global variables there is a third family of them.
		Variables that have a ':' character just after the leading '%' are [b]extended scope[/b] variables.
		"%:index" , "%:Hello" , "%:something.else" are all valid special scope variable names.
		They're actually used in popups and in timers (but later I might find other usages as well :).
		"Extended scope" means that these variables are somewhere in the middle between
		global and local variables. They normally act as local , but in some cases their [b]lifetime[/b] and [b]visibility[/b]
		may be extended.
		[/p]

		[p]
		For example , in the popups , all the special scope variables
		are visible during all the "lifetime" of a popup (so from the prologue code call to
		the moment when the user selects an item and the corresponding code is executed).
		This allows you to pre-calculate some data or conditions in the popup prologue
		and use this data in the popup item conditions and item handlers.
		[/p]

		[title]Variable evaluation[/title]
		
		[p]
		A variable can appear in every place where a parameter
		is expected: so after the command name, after a switch or inside
		an identifier parameters. The KVS parser will try to extract the longest possible variable
		name after a literal percent '%' sign everywhere in the parameter string. So the command sequence
		[/p]
		[example]
			%number = 1st; echo this is my %number variable test
		[/example]
		[p]
		will first assign "1st" to the variable "%number" and then execute
		"echo this is my 1st variable test". The following example will NOT work as expected.
		[/p]
		[example]
			%number = 1; echo this is my %numberst variable test
		[/example]
		[p]
		KVS will assign "1" to %number in this case but the next variable
		name extracted will be "%numberst" that is actually empty; so finally
		"echo this is my variable test" will be executed.
		To avoid this problem you can use the backslash escape character:
		[/p]
		[example]
			%number = 1; echo this is my %number\st variable test
		[/example]

		[title]Putting it all together[/title]

		[p]
		Variables can be either local, global or have an extended scope. Their start to exist
		when you first assign something to them and they disappear when they go out of their
		scope or you explicitly destroy them.
		[/p]

		[p]
		KVS has 8 builtin data types: string, integer, real, boolean, hobject, nothing, array and hash.
		The first 6 are scalar data types while the last two are not.
		[/p]

		[p]
		When possible, KVS manages all the conversions between data types silently.
		In the few cases in that an implicit conversion is not possible you have to manage the conversion
		manually otherwise KVS will complain.
		[/p]
*/



void KviKvsParser::skipSpaces()
{
	while((KVSP_curCharUnicode == ' ') || (KVSP_curCharUnicode == '\t'))
	{
		KVSP_skipChar;
	}

	if(KVSP_curCharUnicode == '\\')
	{
		KVSP_skipChar;
		if(KVSP_curCharUnicode == '\n')
		{
			KVSP_skipChar;
			skipSpaces();
			return;
		} else if(KVSP_curCharUnicode == '\r')
		{
			KVSP_skipChar;
			if(KVSP_curCharUnicode == '\n')
			{
				KVSP_skipChar;
				skipSpaces();
				return;
			} else {
				KVSP_backChar;
				KVSP_backChar;
			}
		} else {
			KVSP_backChar;
		}
	}
}



bool KviKvsParser::skipSpacesAndNewlines()
{
	while((KVSP_curCharUnicode == ' ') || (KVSP_curCharUnicode == '\t') || (KVSP_curCharUnicode == '\n') || (KVSP_curCharUnicode == '\r'))
	{
		KVSP_skipChar;
	}
	
	switch(KVSP_curCharUnicode)
	{
		case '\\':
			KVSP_skipChar;
			if(KVSP_curCharUnicode == '\n')
			{
				KVSP_skipChar;
				return skipSpacesAndNewlines();
			} else if(KVSP_curCharUnicode == '\r')
			{
				KVSP_skipChar;
				if(KVSP_curCharUnicode == '\n')
				{
					KVSP_skipChar;
					return skipSpacesAndNewlines();
				} else {
					KVSP_backChar;
					KVSP_backChar;
				}
			} else {
				KVSP_backChar;
			}
		break;
		case '#': 
		case '/':
			// we allow comments too!
			(void)parseComment(); // this will return 0 anyway (and never trigger an error here)
			if(error())return false;
			return skipSpacesAndNewlines();
		break;
	}
	return true;
}

void KviKvsParser::skipToNextLine()
{
	while((KVSP_curCharUnicode != 0) && (KVSP_curCharUnicode != '\n'))
		KVSP_skipChar;

	if(KVSP_curCharUnicode == '\n')KVSP_skipChar;
}


KviKvsTreeNodeInstruction * KviKvsParser::parseInstructionList()
{
	KviKvsTreeNodeInstructionBlock * l = new KviKvsTreeNodeInstructionBlock(KVSP_curCharPointer);


	for(;;)
	{
		if(!skipSpacesAndNewlines())
		{
			delete l;
			return 0;
		}

		if(KVSP_curCharUnicode != 0)
		{
			// instruction
			KviKvsTreeNodeInstruction * i = parseInstruction();
			if(i)l->addInstruction(i);
			else {
				if(error())
				{
					// ops...
					delete l;
					return 0;
				} // else empty instruction
			}
		} else {
			if(l->instructionCount() == 1)
			{
				// return the single instruction instead
				KviKvsTreeNodeInstruction * i = l->releaseFirst();
				delete l;
				return i;
			}
			// end of buffer
			return l;
		}
	}

	// never here
	KVSP_ASSERT(false);
	return 0;
}




KviKvsTreeNodeData * KviKvsParser::parseParameterPercentOrDollar()
{
	KVSP_ASSERT((KVSP_curCharUnicode == '%') || (KVSP_curCharUnicode == '$') || (KVSP_curCharUnicode == '@'));

	if(KVSP_curCharUnicode == '%')
	{
		KVSP_skipChar;
		if(!KVSP_curCharIsLetter && (KVSP_curCharUnicode != ':'))
		{
			// be flexible : allow an "alone" '%' char
			return new KviKvsTreeNodeConstantData(KVSP_curCharPointer - 1,new KviKvsVariant(TQString("%")));
		}
		// this is surely a variable or function
		KVSP_backChar;
	} else if(KVSP_curCharUnicode == '$')
	{
		KVSP_skipChar;
		if(!KVSP_curCharIsFunctionStart)
		{
			// be flexible : allow an "alone" '$' char
			return new KviKvsTreeNodeConstantData(KVSP_curCharPointer - 1,new KviKvsVariant(TQString("$")));
		}
		// this is surely a variable or function
		KVSP_backChar;
	}

	return parsePercentOrDollar();
}



KviKvsTreeNodeData * KviKvsParser::parsePercentOrDollar(bool bInObjScope)
{
	KVSP_ASSERT((KVSP_curCharUnicode == '%') || (KVSP_curCharUnicode == '$') || (KVSP_curCharUnicode == '@'));

	KviKvsTreeNodeData * r;
	const TQChar * pBegin;

	if(KVSP_curCharUnicode == '%')
	{
		r = parsePercent(bInObjScope);
		if(!r)return 0;
	} else if(KVSP_curCharUnicode == '$')
	{
		r = parseDollar(bInObjScope);
		if(!r)return 0;
	} else {
		// this is @
		static TQString szStrayAtRoutineName("@");
		static TQString szMightBeStrayAtOrThisRoutineName("@?");
		
		pBegin = KVSP_curCharPointer;
		
		KVSP_skipChar;
		
		if(bInObjScope || ((KVSP_curCharUnicode != '$') && (KVSP_curCharUnicode != '%')))
		{
			// we're sure this is just a stray @
			// we use a trick here: when @ is not supposed to be an object scope call
			// then we create a function that will return the @ itself as a string
			KviKvsCoreFunctionExecRoutine * pRoutine = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szStrayAtRoutineName);
			r = new KviKvsTreeNodeCoreFunctionCall(KVSP_curCharPointer,szStrayAtRoutineName,pRoutine,new KviKvsTreeNodeDataList(KVSP_curCharPointer));
			//KVSP_skipChar;
			return r;
		}
		// we're not in object scope and cur char is either $ or %
		// check for the common syntax $0!$1@$2 seen in hostmasks
		// @$<digit> is non valid anyway
		if(KVSP_curCharUnicode == '$')
		{
			KVSP_skipChar;
			if(KVSP_curCharIsNumber)
			{
				// again a stray @
				KVSP_backChar;
				KviKvsCoreFunctionExecRoutine * pRoutine = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szStrayAtRoutineName);
				r = new KviKvsTreeNodeCoreFunctionCall(KVSP_curCharPointer,szStrayAtRoutineName,pRoutine,new KviKvsTreeNodeDataList(KVSP_curCharPointer));
				return r;
			}
			KVSP_backChar;
		}

		// now we're unsure: we will be able to decide only at runtime if it is a stray @ or the shortcut for $this
		// this design was a bit ugly.. I must admit it... but it is really useful when writing object classes...
		KviKvsCoreFunctionExecRoutine * pRoutine = KviKvsKernel::instance()->findCoreFunctionExecRoutine(szMightBeStrayAtOrThisRoutineName);
		// MUST BE THERE!
		// core function call
		r = new KviKvsTreeNodeCoreFunctionCall(pBegin,szMightBeStrayAtOrThisRoutineName,pRoutine,new KviKvsTreeNodeDataList(pBegin));

		skipSpaces();

		goto handle_scope_operator;
	}

	pBegin = KVSP_curCharPointer;

	while((KVSP_curCharUnicode == '[') || (KVSP_curCharUnicode == '{'))
	{
		if(KVSP_curCharUnicode == '[')
		{
			// array index
			KVSP_skipChar;
			skipSpaces();
			if(KVSP_curCharUnicode == ']')
			{
				KVSP_skipChar;
				if(KVSP_curCharUnicode == '#')
				{
					// count
					KVSP_skipChar;
					return new KviKvsTreeNodeArrayCount(pBegin,r);
				} else {
					// a hash reference assert
					return new KviKvsTreeNodeArrayReferenceAssert(pBegin,r);
				}
			}
	
			KviKvsTreeNodeExpression * e = parseExpression(']');
			if(!e)
			{
				delete r;
				return 0;
			}
			
			r = new KviKvsTreeNodeArrayElement(pBegin,r,e);
		} else {
			// hash key
			KVSP_skipChar;
			skipSpaces();
	
			if(KVSP_curCharUnicode == '}')
			{
				// entire hash ?
				KVSP_skipChar;
				if(KVSP_curCharUnicode == '#')
				{
					KVSP_skipChar;
					return new KviKvsTreeNodeHashCount(pBegin,r);
				}
				return new KviKvsTreeNodeHashReferenceAssert(pBegin,r);
			}
	
			KviKvsTreeNodeData * i = parseHashKey();
			if(!i)
			{
				// error
				delete r;
				return 0;
			}
	
			KVSP_ASSERT(KVSP_curCharUnicode == '}');
	
			KVSP_skipChar;
	
			r = new KviKvsTreeNodeHashElement(pBegin,r,i);
		}
	}

	if(KVSP_curCharUnicode != '-')
	{
		return r;
	}

	if(!r->canEvaluateToObjectReference())return r; // FIXME: maybe print a warning ?

	// might be a scope operator

	KVSP_skipChar;
	if(KVSP_curCharUnicode != '>')
	{
		KVSP_backChar;
		return r;
	}


	KVSP_skipChar;
	skipSpaces();

	if((KVSP_curCharUnicode != '$') && (KVSP_curCharUnicode != '%'))
	{
		KVSP_setCurCharPointer(pBegin);
		return r;
	}

handle_scope_operator:

	// hmmm... there really seems to be a scope operator there...
	if(KVSP_curCharUnicode == '%')
	{
		KVSP_skipChar;
		if(!KVSP_curCharIsLetter)
		{
			// be flexible : allow an "alone" '%' char
			KVSP_setCurCharPointer(pBegin);
			return r;
		}
	} else {
		KVSP_skipChar;
		if(!KVSP_curCharIsFunctionStart)
		{
			// be flexible : allow an "alone" '$' char
			KVSP_setCurCharPointer(pBegin);
			return r;
		}
	}

	// ok : try the scope operator
	KVSP_backChar;

	pBegin = KVSP_curCharPointer;

	KviKvsTreeNodeData * r2 = parsePercentOrDollar(true);

	if(!r2)
	{
		// must be an error
		delete r;
		return 0;
	}
	
	if(!r2->canEvaluateInObjectScope())
	{
		// ops... it really wasn't
		delete r2;
		KVSP_setCurCharPointer(pBegin);
		return r;
	}

	return new KviKvsTreeNodeScopeOperator(pBegin,r,r2);
}





KviKvsTreeNodeVariable * KviKvsParser::parsePercent(bool bInObjScope)
{
	KVSP_ASSERT(KVSP_curCharUnicode == '%');

	const TQChar * pBegin = KVSP_curCharPointer;

	KVSP_skipChar;

	bool bExtScope;

	if(KVSP_curCharUnicode == ':')
	{
		bExtScope = true;
		KVSP_skipChar;
	} else {
		bExtScope = false;
	}

	if(!((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_')))
	{
		error(KVSP_curCharPointer,__tr2qs("Syntax error after '%' variable prefix. If you want to use a plain '%' in the code you need to escape it"));
		return 0;
	}

	const TQChar * pIdBegin = KVSP_curCharPointer;

	while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '_') || (KVSP_curCharUnicode == '.'))KVSP_skipChar;

	TQString szIdentifier(pIdBegin,KVSP_curCharPointer - pIdBegin);

//#warning "ADD A KviKvsTreeNodeBuiltinCleanupVariablesCommand on this KviKvsParser object"
//#warning "KviKvsParser will append it to the script"

	if(bExtScope)
	{
		if(bInObjScope)
		{
			error(KVSP_curCharPointer,__tr2qs("Objects have no extended scope variables"));
			return 0;
		}
		return new KviKvsTreeNodeExtendedScopeVariable(pBegin,szIdentifier);
	}
	
	if(bInObjScope)
		return new KviKvsTreeNodeObjectField(pBegin,szIdentifier);
	
	if(m_pGlobals)
	{
		if(m_pGlobals->tqfind(szIdentifier))return new KviKvsTreeNodeGlobalVariable(pBegin,szIdentifier);
	}

	if(m_iFlags & AssumeLocals)
		return new KviKvsTreeNodeLocalVariable(pBegin,szIdentifier);

	if(pIdBegin->category() & TQChar::Letter_Uppercase)
	{
		//if(m_iFlags & Pedantic)
		//	warning(pIdBegin,__tr2qs("Declaring global variables with an uppercase letter is deprecated. Global variables should be declared with 'global'"));
		return new KviKvsTreeNodeGlobalVariable(pBegin,szIdentifier);
	}

	return new KviKvsTreeNodeLocalVariable(pBegin,szIdentifier);
}

KviKvsTreeNodeInstruction * KviKvsParser::parseInstruction()
{
	switch(KVSP_curCharUnicode)
	{
		case '#': 
		case '/':
			(void)parseComment(); // this will return 0 anyway
			return 0;
		break;
		case 0: // empty instruction
			return 0;
		break;
		case '\n':
		case '\r':
		case ';': // empty instruction
			KVSP_skipChar;
			return 0;
		break;
		case '{': // command block
			return parseInstructionBlock();
		break;
		case '$':
		case '%':
		case '@':
			return parseVoidFunctionCallOrOperation();
		break;
		default:
			if(KVSP_curCharIsLetter || (KVSP_curCharUnicode == '_'))
			{
				// must be a command
				return parseCommand();
			} else {
				// what the heck is this ?
				error(KVSP_curCharPointer,__tr2qs("Found character '%q' (tqunicode %x) where an instruction was expected"),KVSP_curCharPointer,KVSP_curCharUnicode);
				return 0;
			}
		break;
	}

	// never here
	KVSP_ASSERT(false);
	return 0;
}

KviKvsTreeNodeInstruction * KviKvsParser::parseInstructionBlock()
{
	KVSP_ASSERT(KVSP_curCharUnicode == '{');

	KVSP_skipChar;

	const TQChar * pBegin = KVSP_curCharPointer;

	KviKvsTreeNodeInstructionBlock * b = new KviKvsTreeNodeInstructionBlock(pBegin - 1);

	for(;;)
	{
		if(!skipSpacesAndNewlines())
		{
			delete b;
			return 0;
		}

		switch(KVSP_curCharUnicode)
		{
			case 0:
				delete b;
				warning(pBegin,__tr2qs("Unterminated instruction block"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in instruction block (missing closing brace)"));
				return 0;
			break;
			case '}':
				KVSP_skipChar;
				if(b->instructionCount() <= 1)
				{
					if(b->instructionCount() < 1)
					{
						delete b;
						return 0; // just an empty block
					}
					// a single instruction
					KviKvsTreeNodeInstruction * i = b->releaseFirst();
					delete b;
					return i;
				}
				return b;
			break;
			default:
				// instruction
				KviKvsTreeNodeInstruction * i = parseInstruction();
				if(i)b->addInstruction(i);
				else {
					if(error())
					{
						// ops...
						delete b;
						return 0;
					} // else empty instruction
				}
			break;
		}
	}
	// never reached
	return 0;
}

KviKvsTreeNodeSwitchList * KviKvsParser::parseCommandSwitchList()
{
	KVSP_ASSERT(KVSP_curCharUnicode == '-');

	KviKvsTreeNodeSwitchList * sw = new KviKvsTreeNodeSwitchList(KVSP_curCharPointer);

	while(KVSP_curCharUnicode == '-')
	{
		const TQChar * pBegin = KVSP_curCharPointer;
		KVSP_skipChar;
		
		bool bLong = false;
		
		if(KVSP_curCharUnicode == '-')
		{
			// long switch
			pBegin = KVSP_curCharPointer;
			KVSP_skipChar;
			bLong = true;
		}

		skipSpaces();
		if(!KVSP_curCharIsLetter)
		{
			if(KVSP_curCharIsNumber || KVSP_curCharIsEndOfCommand)
			{
				// a -digit : this is probably a negative number instead
				// or just a single dash (or couple of dashes)
				// go back to the initial dash and treat it as text...and return the current switch list
				KVSP_setCurCharPointer(pBegin);
				if(sw->isEmpty())
				{
					// not an error!
					delete sw;
					return 0;
				}
				return sw;
			} else {
				delete sw;
				warning(pBegin,__tr2qs("The dash after a command should be followed by a letter (switch), by a digit (negative number) or be escaped"));
	
				if(KVSP_curCharUnicode == 0)
				{
					error(KVSP_curCharPointer,__tr2qs("Unexpected character '%q' (tqunicode %x) after a switch dash"),KVSP_curCharPointer,KVSP_curCharUnicode);
				} else {
					error(KVSP_curCharPointer,__tr2qs("Unexpected end of script after a switch dash"));
				}
				return 0;
			}
		}

		const TQChar * pSw = KVSP_curCharPointer;

		KVSP_skipChar;
		while((KVSP_curCharIsLetterOrNumber) || (KVSP_curCharUnicode == '-'))KVSP_skipChar;

		const TQChar * pSwEnd = KVSP_curCharPointer;

		skipSpaces();

		if(KVSP_curCharUnicode == '=')
		{
			KVSP_skipChar;
			skipSpaces();
			KviKvsTreeNodeData * p = parseCommandParameter();
			if(!p)
			{
				// must be an error :(
				if(error())
				{
					error(pBegin,__tr2qs("The above problem might be related to the switch dash and the following equal sign"));
					delete sw;
					return 0;
				} else {
					// assume empty string
					p = new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString("")));
				}
			}

			skipSpaces();

			if(bLong)
				sw->addLong(TQString(pSw,pSwEnd - pSw),p);
			else
				sw->addShort(pSw->lower().tqunicode(),p);
		} else {
			if(bLong)
				sw->addLong(TQString(pSw,pSwEnd - pSw),new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(true))); // empty param
			else
				sw->addShort(pSw->lower().tqunicode(),new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(true))); // empty param
		}
	}

	return sw;
}



KviKvsTreeNodeDataList * KviKvsParser::parseCommandParameterList()
{
	KviKvsTreeNodeDataList * l = new KviKvsTreeNodeDataList(KVSP_curCharPointer);

	for(;;)
	{
		skipSpaces();
		switch(KVSP_curCharUnicode)
		{
			case 0:
				return l;
			break;
			case '\r':
			case '\n':
			case ';':
				KVSP_skipChar;
				return l;
			break;
			default:
				// anything else is a parameter
				KviKvsTreeNodeData * p = parseCommandParameter();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->addItem(p);
			break;
		}
	}

	// never here
	KVSP_ASSERT(false);
	return 0;
}


KviPointerList<TQString> * KviKvsParser::parseCommaSeparatedParameterListNoTree()
{
	KviPointerList<TQString> * l = new KviPointerList<TQString>;
	l->setAutoDelete(true);

	KVSP_skipChar;

	for(;;)
	{
		skipSpaces();
		switch(KVSP_curCharUnicode)
		{
			case 0:
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in parameter list"));
				delete l;
				return 0;
			break;
			case '\r':
			case '\n':
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of line in parameter list"));
				delete l;
				return 0;
			break;
			/*
			case ',':
				KVSP_skipChar;
			break;
			case ')':
				KVSP_skipChar;
				return l;
			break;
			*/
			default:
			{
				// anything else is a parameter
				const TQChar *pBegin = KVSP_curCharPointer;
				KviKvsTreeNodeData * p = parseCommaSeparatedParameter();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				delete p;
				TQString * s = new TQString(pBegin,KVSP_curCharPointer - pBegin);
				s->stripWhiteSpace();
				l->append(s);
				
				switch(KVSP_curCharUnicode)
				{
					case ',':
					KVSP_skipChar;
					break;
					case ')':
					KVSP_skipChar;
					return l;
					break;
				}
			}
			break;
		}
	}

	// never here
	KVSP_ASSERT(false);
	return 0;
}


KviKvsTreeNodeDataList * KviKvsParser::parseCommaSeparatedParameterList()
{
	KviKvsTreeNodeDataList * l = new KviKvsTreeNodeDataList(KVSP_curCharPointer);

	KVSP_skipChar;

	for(;;)
	{
		skipSpaces();
		switch(KVSP_curCharUnicode)
		{
			case 0:
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in parameter list"));
				delete l;
				return 0;
			break;
			case '\r':
			case '\n':
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of line in parameter list"));
				delete l;
				return 0;
			break;
			/*
			case ',':
				KVSP_skipChar;
			break;
			case ')':
				KVSP_skipChar;
				return l;
			break;
			*/
			default:
				// anything else is a parameter
				KviKvsTreeNodeData * p = parseCommaSeparatedParameter();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->addItem(p);
				
				switch(KVSP_curCharUnicode)
				{
					case ',':
						KVSP_skipChar;
					break;
					case ')':
						KVSP_skipChar;
						return l;
					break;
				}
			break;
		}
	}

	// never here
	KVSP_ASSERT(false);
	return 0;
}


#define LITERAL_PARAM_PARSING_FUNCTION_BEGIN(__funcname) \
KviKvsTreeNodeConstantData * KviKvsParser::__funcname() \
{ \
	TQString szValue; \
\
 	const TQChar * pStart = KVSP_curCharPointer; \
	const TQChar * pBegin = KVSP_curCharPointer; \
	int iLen = 0; \
	int iNestedTerminators = 0; \
 \
	for(;;) \
	{ \
		switch(KVSP_curCharUnicode) \
		{

#define LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR \
				if(!_OUTPUT_MUTE) \
					warning(KVSP_curCharPointer,__tr2qs("Nested character %q corresponding to expected terminator, this might confuse me a bit: it is a good idea to enclose it in quotes"),KVSP_curCharPointer); \
				KVSP_skipChar; \
				iNestedTerminators++; \
				iLen++; \
			break;

#define LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR \
				if(iNestedTerminators > 0) \
				{ \
					if(!_OUTPUT_MUTE) \
						warning(KVSP_curCharPointer,__tr2qs("Skipping nested terminator character %q"),KVSP_curCharPointer); \
					KVSP_skipChar; \
					iNestedTerminators--; \
					iLen++; \
				} else { \
					if(iLen > 0)szValue.append(TQString(pBegin,iLen)); \
					{ \
						bool bOk; \
						kvs_int_t iVal = szValue.toLong(&bOk); \
						if(bOk)return new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(iVal)); \
						kvs_real_t dVal = szValue.toDouble(&bOk); \
						if(bOk)return new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(dVal)); \
					} \
					return new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(szValue)); \
				} \
			break;

#define LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END \
				if(iLen > 0) szValue.append(TQString(pBegin,iLen)); \
				return new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(szValue)); \
			break; \
			case '\\': \
				if(iLen > 0)szValue.append(TQString(pBegin,iLen)); \
				KVSP_skipChar; \
				switch(KVSP_curCharUnicode) \
				{ \
					case 0: \
						warning(KVSP_curCharPointer - 1,__tr2qs("Stray backslash at the end of the script")); \
						iLen = 0; \
					break; \
					case '\r': \
					case '\n': \
						KVSP_skipChar; \
						pBegin = KVSP_curCharPointer; \
						iLen = 0; \
					break; \
					case 'r': \
						KVSP_skipChar; \
						pBegin = KVSP_curCharPointer; \
						szValue.append(TQChar('\r')); \
						iLen = 0; \
					break; \
					case 'n': \
						KVSP_skipChar; \
						pBegin = KVSP_curCharPointer; \
						szValue.append(TQChar('\n')); \
						iLen = 0; \
					break; \
					case 't': \
						KVSP_skipChar; \
						pBegin = KVSP_curCharPointer; \
						szValue.append(TQChar('\t')); \
						iLen = 0; \
					break; \
					default: \
						pBegin = KVSP_curCharPointer; \
						KVSP_skipChar; \
						iLen = 1; \
					break; \
				} \
			break; \
			default: \
				KVSP_skipChar; \
				iLen++; \
			break; \
		} \
	} \
	KVSP_ASSERT(false); \
	return 0; \
}


LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseCommandLiteralParameter)
			case 0:
			case '$':
			case '%':
			case '@':
			case '\r':
			case '\n':
			case '"':
			case ';':
			case ' ':
			case '\t':
LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END


LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseStringLiteralParameter)
			case 0:
			case '$':
			case '%':
			case '@':
			case '\r':
			case '\n':
			case '"':
LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END

/*
LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseArrayIndexLiteralParameter)
			case '\t':
			case ' ':
			case ']':
LITERAL_PARAM_PARSING_FUNCTION_END
*/


LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseHashKeyLiteralParameter)
			case '{':
LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR
			case '}':
LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR
			case 0:
			case '$':
			case '%':
			case '@':
			case '\r':
			case '\n':
			case '"':
			case '\t':
			case ' ':
LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END


LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseCommaSeparatedLiteralParameter)
			case '(':
LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR
			case ')':
LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR
			case 0:
			case '$':
			case '%':
			case '@':
			case '\r':
			case '\n':
			case '"':
			case ',':
			case ' ':
			case '\t':
LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END


LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseSingleLiteralParameterInParenthesis)
			case '(':
LITERAL_PARAM_PARSING_FUNCTION_WARN_NESTED_TERMINATOR
			case ')':
LITERAL_PARAM_PARSING_FUNCTION_END_WITH_EXPECTED_TERMINATOR
			case 0:
			case '$':
			case '%':
			case '@':
			case '\r':
			case '\n':
			case '"':
			case ' ':
			case '\t':
LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END

LITERAL_PARAM_PARSING_FUNCTION_BEGIN(parseBindingOperationLiteralParameter)
			case 0:
			case '$':
			case '%':
			case '@':
			case '\r':
			case '\n':
			case '"':
			case '/':
LITERAL_PARAM_PARSING_FUNCTION_GENERIC_END


/*
KviKvsTreeNodeData * KviKvsParser::parseArrayIndex()
{
	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
	l->setAutoDelete(true);

	const TQChar * pBegin = KVSP_curCharPointer;

	//KVSP_skipChar;

	for(;;)
	{
		switch(KVSP_curCharUnicode)
		{
			case 0:
				delete l;
				warning(pBegin,__tr2qs("Unterminated array index"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in array index (missing ']' character ?)"));
				return 0;
			break;
			case '\n':
				delete l;
				warning(pBegin,__tr2qs("Unterminated array index"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of line in array index (missing ']' character or unescaped newline)"));
				return 0;
			break;
			case ' ':
			case '\t':
				skipSpaces();
				if(KVSP_curCharUnicode != ']')
				{
					delete l;
					warning(pBegin,__tr2qs("Unterminated array index"));
					switch(KVSP_curCharUnicode)
					{
						case 0:
							error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in array index (missing ']' character ?)"));
						break;
						case '\n':
							error(KVSP_curCharPointer,__tr2qs("Unexpected end of line in array index (missing ']' character or unescaped newline)"));
						break;
						default:
							error(KVSP_curCharPointer,__tr2qs("Unexpected character '%q' (tqunicode %x) in array index: it should be already terminated"),KVSP_curCharPointer,KVSP_curCharUnicode);
						break;
					}
					return 0;
				}
				goto end_of_the_array_index;
			break;
			case '$':
			case '%':
			{
				// this may be a data reference
				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			case ']':
			{
				// end of the array index
				goto end_of_the_array_index;
			}
			break;
			case '"':
			{
				// string (should we parse strings in array indexes anyway ?).. well "1"$count might be a valid one in the end
				KviKvsTreeNodeData * p = parseStringParameter();
				if(!p)
				{
					// error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			default:
			{
				// anything else is a literal
				l->append(parseArrayIndexLiteralParameter());
			}
			break;
		}
	}
end_of_the_array_index:
	if(l->count() > 1)
	{
		// complex parameter needed
		return new KviKvsTreeNodeCompositeData(l);
	} else {
		// a single parameter in the list
		l->setAutoDelete(false);
		KviKvsTreeNodeData * p = l->first();
		delete l;
		return p;
	}

}
*/





KviKvsTreeNodeData * KviKvsParser::parseHashKey()
{
	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
	l->setAutoDelete(true);

	const TQChar * pBegin = KVSP_curCharPointer;

	//KVSP_skipChar;

	for(;;)
	{
		switch(KVSP_curCharUnicode)
		{
			case 0:
				delete l;
				warning(pBegin,__tr2qs("Unterminated hash key"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in hash key (missing '}' character ?)"));
				return 0;
			break;
			case '\r':
			case '\n':
				delete l;
				warning(pBegin,__tr2qs("Unterminated hash key"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of line in hash key (missing '}' character or unescaped newline)"));
				return 0;
			break;
			case ' ':
			case '\t':
				skipSpaces();
				if(KVSP_curCharUnicode != '}')
				{
					// separate by single spaces
					l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString(" "))));
				} else {
					goto end_of_the_hash_key;
				}
			break;
			case '$':
			case '%':
			case '@':
			{
				// this may be a data reference
				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			case '}':
			{
				// end of the array index
				goto end_of_the_hash_key;
			}
			break;
			case '"':
			{
				// string 
				KviKvsTreeNodeData * p = parseStringParameter();
				if(!p)
				{
					// error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			default:
			{
				// anything else is a literal
				l->append(parseHashKeyLiteralParameter());
			}
			break;
		}
	}
end_of_the_hash_key:
	if(l->count() > 1)
	{
		// complex parameter needed
		return new KviKvsTreeNodeCompositeData(pBegin,l);
	} else {
		// a single parameter in the list
		l->setAutoDelete(false);
		KviKvsTreeNodeData * p = l->first();
		delete l;
		return p;
	}
	// never reached
	return 0;
}

/*
PARENTHESIS_PARAMETER_PARSING_FUNCTION_BEGIN(parseCommaSeparatedParameter)
	case 0:
	case ',':
	case ')':
	case '\n':
PARENTHESIS_PARAMETER_PARSING_FUNCTION_END()

#define PARENTHESIS_PARAMETER_PARSING_FUNCTION_BEGIN(_name) \
*/



KviKvsTreeNodeData * KviKvsParser::parseCommaSeparatedParameter()
{
	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
	l->setAutoDelete(true);

	const TQChar * pBegin = KVSP_curCharPointer;

	for(;;)
	{
		switch(KVSP_curCharUnicode)
		{
			case 0:
			case ',':
			case ')':
			case '\r':
			case '\n':
				// not a part of a parameter
				goto end_of_function_parameter;
			break;
			case '$':
			case '%':
			case '@':
			{
				// this may be a data reference
				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			case ' ':
			case '\t':
				skipSpaces();
				if((KVSP_curCharUnicode != ')') && (KVSP_curCharUnicode != ','))
				{
					// separate by single spaces
					l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString(" "))));
				} else {
					goto end_of_function_parameter;
				}
			break;
			case '"':
			{
				// this is a string
				KviKvsTreeNodeData * p = parseStringParameter();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			default:
			{
				// anything else is a literal
				l->append(parseCommaSeparatedLiteralParameter());
			}
			break;
		}
	}
end_of_function_parameter:
	if(l->count() > 1)
	{
		// complex parameter needed
		KviKvsTreeNodeData * p = new KviKvsTreeNodeCompositeData(pBegin,l);
		p->setEndingLocation(KVSP_curCharPointer);
		return p;
	} else {
		// a single parameter in the list, or no params at all
		l->setAutoDelete(false);
		KviKvsTreeNodeData * p = l->first();
		delete l;
		if(!p)p = new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant());
		p->setEndingLocation(KVSP_curCharPointer);
		return p;
	}
	// never reached
	return 0;
}


KviKvsTreeNodeData * KviKvsParser::parseSingleParameterInParenthesis()
{
	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
	l->setAutoDelete(true);

	const TQChar * pBegin = KVSP_curCharPointer;

	for(;;)
	{
		switch(KVSP_curCharUnicode)
		{
			case ')':
				// not a part of a parameter
				KVSP_skipChar;
				goto end_of_function_parameter;
			break;
			case 0:
			case '\r':
			case '\n':
				// not a part of a parameter
				goto end_of_function_parameter;
			break;
			case '$':
			case '%':
			case '@':
			{
				// this may be a data reference
				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			case ' ':
			case '\t':
				skipSpaces();
				if((KVSP_curCharUnicode != ')') && (KVSP_curCharUnicode != ','))
				{
					// separate by single spaces
					l->append(new KviKvsTreeNodeConstantData(KVSP_curCharPointer,new KviKvsVariant(TQString(" "))));
				} else {
					goto end_of_function_parameter;
				}
			break;
			case '"':
			{
				// this is a string
				KviKvsTreeNodeData * p = parseStringParameter();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			default:
			{
				// anything else is a literal
				l->append(parseSingleLiteralParameterInParenthesis());
			}
			break;
		}
	}
end_of_function_parameter:
	if(l->count() > 1)
	{
		// complex parameter needed
		KviKvsTreeNodeData * p = new KviKvsTreeNodeCompositeData(pBegin,l);
		p->setEndingLocation(KVSP_curCharPointer);
		return p;
	} else {
		// a single parameter in the list or list empty at all
		l->setAutoDelete(false);
		KviKvsTreeNodeData * p = l->first();
		if(p)p->setEndingLocation(KVSP_curCharPointer);
		delete l;
		return p;
	}
	// never reached
	return 0;
}


KviKvsTreeNodeData * KviKvsParser::parseStringParameter()
{
	KVSP_ASSERT(KVSP_curCharUnicode == '"');

	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>();
	l->setAutoDelete(true);

	const TQChar * pBegin = KVSP_curCharPointer;

	KVSP_skipChar;

	for(;;)
	{
		switch(KVSP_curCharUnicode)
		{
			case 0:
				delete l;
				warning(pBegin,__tr2qs("Unterminated string constant"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of script in string constant (missing \" character ?)"));
				return 0;
			break;
			case '\r':
			case '\n':
				delete l;
				warning(pBegin,__tr2qs("Unterminated string constant"));
				error(KVSP_curCharPointer,__tr2qs("Unexpected end of line in string constant (missing \" character or unescaped newline)"));
				return 0;
			break;
			case '$':
			case '%':
			case '@':
			{
				// this may be a data reference
				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			case '"':
			{
				// end of the string
				KVSP_skipChar;
				goto end_of_the_string;
			}
			break;
			default:
			{
				// anything else is a literal
				l->append(parseStringLiteralParameter());
			}
			break;
		}
	}
end_of_the_string:
	if(l->count() > 1)
	{
		// complex parameter needed
		// it is also an implicit string cast
		return new KviKvsTreeNodeCompositeData(pBegin,l);
	} else {
		if(l->count() > 0)
		{
			// a single parameter in the list
			// we need an explicit string cast here (it is the most common cast)
			l->setAutoDelete(false);
			KviKvsTreeNodeData * p = l->first();
			delete l;
			return new KviKvsTreeNodeStringCast(pBegin,p);
		} else {
			// no parameters at all.. return straight empty string (no need to cast)
			delete l;
			return new KviKvsTreeNodeConstantData(pBegin,new KviKvsVariant(new TQString()));
		}
	}
	// never reached
	return 0;
}

KviKvsTreeNodeData * KviKvsParser::parseCommandParameter(bool bPreferNumeric)
{
	KviPointerList<KviKvsTreeNodeData> * l = new KviPointerList<KviKvsTreeNodeData>;
	l->setAutoDelete(true);

	bool bGotLiteral = false;

	const TQChar * pBegin = KVSP_curCharPointer;

	for(;;)
	{
		switch(KVSP_curCharUnicode)
		{
			case 0:
			case ' ':
			case '\t':
			case '\r':
			case '\n':
			case ';':
				// not a part of a parameter
				goto jumpout;
			break;
			case '$':
			case '%':
			case '@':
			{
				// this may be a data reference
				KviKvsTreeNodeData * p = parseParameterPercentOrDollar();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			case '"':
			{
				// this is a string
				KviKvsTreeNodeData * p = parseStringParameter();
				if(!p)
				{
					// this is an error
					delete l;
					return 0;
				}
				l->append(p);
			}
			break;
			default:
			{
				bGotLiteral = true;
				// anything else is a literal
				l->append(parseCommandLiteralParameter());
			}
			break;
		}
	}
jumpout:
	if(l->count() > 1)
	{
		// complex parameter needed
		KviKvsTreeNodeData * p = new KviKvsTreeNodeCompositeData(pBegin,l);
		p->setEndingLocation(KVSP_curCharPointer);
		return p;
	} else {
		// a single parameter in the list or empty list at all
		l->setAutoDelete(false);
		KviKvsTreeNodeData * p = l->first();
		delete l;
		if(p)
		{
			if(bGotLiteral)
			{
				// a single literal parameter
				if(bPreferNumeric)
				{
					// attempt to convert to a numeric format if this is a constant data item
					p->convertStringConstantToNumeric();
				}
			} 
			p->setEndingLocation(KVSP_curCharPointer);
		}
		return p;
	}
	// never reached
	return 0;
}