db2b5d208c3766f3b082673e689c23e015ba0812
[sdk] / ecere / src / com / instance.ec
1 #define _Noreturn
2
3 namespace com;
4
5 // #define DISABLE_MEMMGR
6
7 import "BinaryTree"
8 import "OldList"
9 import "String"
10 import "dataTypes"
11
12 //#define JUST_CHECK_LEAKS
13 //#define JUST_CHECK_BOUNDARIES
14
15
16 #if defined(ECERE_BOOTSTRAP) || defined(ECERE_STATIC)
17 #define dllexport
18 #if !defined(ECERE_BOOTSTRAP)
19 #define stdcall
20 #endif
21 #endif
22
23 #undef __BLOCKS__
24
25 #if !defined(__EMSCRIPTEN__)
26 #if !defined(ECERE_BOOTSTRAP)
27 import "Mutex"
28 #endif
29 #endif
30
31 #if defined(__EMSCRIPTEN__)
32 #define GetCurrentThreadID()  0
33 #endif
34
35 // #define MEMINFO
36 /*
37 #ifdef MEMINFO
38  #undef REDZONE
39  #define REDZONE   256
40 #endif
41 */
42
43 #if defined(JUST_CHECK_LEAKS) || !defined(REDZONE)
44 #undef REDZONE
45 #define REDZONE 0
46 #endif
47
48
49 #ifdef _DEBUG
50 // #define MEMTRACKING
51 #endif
52
53 #ifdef MEMINFO
54 #if !defined(__EMSCRIPTEN__)
55 import "Thread"
56 #endif
57 static define MAX_MEMORY_LOC = 40;
58 static define MAX_STACK_FRAMES = 1000;
59
60 static class MemStack : BTNode
61 {
62    const char * frames[MAX_STACK_FRAMES];
63    int pos;
64    bool recurse;
65 };
66
67 static BinaryTree memStacks { };
68 static uint memoryErrorsCount = 0;
69
70 #endif
71
72 default:
73 #define property _property
74
75 #if defined(DISABLE_MEMMGR)
76
77 #ifndef ECERE_BOOTSTRAP
78 # include <malloc.h>
79 #endif
80
81 #if defined(__WIN32__)
82 #ifdef ECERE_BOOTSTRAP
83 uintsize _msize(void * p);
84 #endif
85
86 #  define msize _msize
87 #else
88 #ifdef ECERE_BOOTSTRAP
89 uintsize malloc_usable_size(void * p);
90 #endif
91
92 #  define msize malloc_usable_size
93 #endif
94
95 #endif
96
97 #include <stdlib.h>
98 #include <stdio.h>
99
100 private:
101
102 #if defined(__ANDROID__)
103
104 default const char * AndroidInterface_GetLibLocation();
105
106 #include <android/log.h>
107 #include <android/native_activity.h>
108
109 #define printf(...)  ((void)__android_log_print(ANDROID_LOG_VERBOSE, "ecere-app", __VA_ARGS__))
110 #endif
111
112 #undef property
113
114 #undef CompareString
115
116 public define null = ((void *)0);
117
118 dllexport Class eSystem_FindClass(Module module, const char * name);
119 dllexport void * eSystem_Renew(void * memory, unsigned int size);
120 dllexport void * eSystem_Renew0(void * memory, unsigned int size);
121 dllexport void * eSystem_New(unsigned int size);
122 dllexport void * eSystem_New0(unsigned int size);
123 dllexport void eSystem_Delete(void * memory);
124 dllexport void * eInstance_New(Class _class);
125
126 default:
127 extern int __ecereVMethodID_class_OnGetDataFromString;
128
129 // IMPLEMENTATION FOR THESE IN _instance.c:
130 #if defined(__MINGW32__) && !defined(_W64) && __GNUC__ < 4
131 dllexport int isblank(int c);
132 #endif
133 bool Instance_LocateModule(const char * name, const char * fileName);
134 void Instance_COM_Initialize(int argc, char ** argv, char ** parsedCommand, int * argcPtr, const char *** argvPtr);
135 void System_SetArgs(int argc, char ** argv, int * argcPtr, const char *** argvPtr);
136 void * Instance_Module_Load(const char * libLocation, const char * name, void ** Load, void ** Unload);
137 void Instance_Module_Free(void * library);
138 #if defined(_DEBUG)
139 void InternalModuleLoadBreakpoint();
140 #endif
141
142 private:
143
144 public class Angle : double;
145
146 public class ::unichar : uint32
147 {
148
149    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
150    {
151       UTF32toUTF8Len(&this, 1, tempString, 5);
152       return tempString;
153    }
154
155    bool OnGetDataFromString(const char * string)
156    {
157       int nb;
158       this = UTF8GetChar(string, &nb);
159       return true;
160    }
161
162 };
163
164 // Forward declarations to hook on to libec:
165 class ::Type;
166 class ::Instantiation;
167 class ::ClassDefinition;
168
169 public class Property : struct
170 {
171 public:
172    class_fixed
173    class_no_expansion
174    Property prev, next;
175    const char * name;
176    bool isProperty;
177    AccessMode memberAccess;
178    int id;
179    Class _class;
180    const char * dataTypeString;
181    Class dataTypeClass;
182    Type dataType;
183
184    void (*Set)(void *, int);
185    int (*Get)(void *);
186    bool (*IsSet)(void *);
187    void * data;
188    void * symbol;
189    int vid;
190    bool conversion;
191    uint watcherOffset;
192    const char * category;
193    bool compiled;
194    bool selfWatchable, isWatchable;
195 };
196
197 dllexport void eInstance_FireWatchers(Instance instance, Property _property);
198
199 public dllexport void MemoryGuard_PushLoc(const char * loc)
200 {
201 #ifdef MEMINFO
202    MemStack stack;
203 #if !defined(__EMSCRIPTEN__)
204    memMutex.Wait();
205 #endif
206    stack = (MemStack)memStacks.Find(GetCurrentThreadID());
207    if(!stack)
208    {
209       stack = (MemStack)calloc(1, sizeof(class MemStack));
210       stack.key = GetCurrentThreadID();
211       memStacks.Add(stack);
212    }
213    if(stack.pos < MAX_STACK_FRAMES)
214       stack.frames[stack.pos++] = loc;
215 #if !defined(__EMSCRIPTEN__)
216    memMutex.Release();
217 #endif
218 #endif
219 }
220
221 public dllexport void MemoryGuard_PopLoc()
222 {
223 #ifdef MEMINFO
224    MemStack stack;
225 #if !defined(__EMSCRIPTEN__)
226    memMutex.Wait();
227 #endif
228    stack = (MemStack)memStacks.Find(GetCurrentThreadID());
229    if(stack && stack.pos > 0)
230    {
231       stack.pos--;
232    }
233 #if !defined(__EMSCRIPTEN__)
234    memMutex.Release();
235 #endif
236 #endif
237 }
238
239 #ifdef ECERE_STATIC
240
241 #ifdef ECERE_COM_ONLY
242
243 #define COM_LOAD_FUNCTION  __ecereDll_Load_ecereCOM
244 #define COM_UNLOAD_FUNCTION  __ecereDll_Unload_ecereCOM
245
246 #else
247
248 #define COM_LOAD_FUNCTION  __ecereDll_Load_ecere
249 #define COM_UNLOAD_FUNCTION  __ecereDll_Unload_ecere
250
251 #endif
252
253 #else
254
255 #define COM_LOAD_FUNCTION  __ecereDll_Load
256 #define COM_UNLOAD_FUNCTION  __ecereDll_Unload
257
258 #endif
259
260 default:
261
262 #if defined(ECERE_BOOTSTRAP)
263 extern bool COM_LOAD_FUNCTION(Module module);
264 extern bool COM_UNLOAD_FUNCTION(Module module);
265 #else
266 extern bool stdcall COM_LOAD_FUNCTION(Module module);
267 extern bool stdcall COM_UNLOAD_FUNCTION(Module module);
268 #endif
269
270 private:
271
272 public class BTNamedLink : struct
273 {
274    class_fixed
275 public:
276    const char * name;
277    BTNamedLink parent, left, right;
278    int depth;
279    void * data;
280 };
281
282 class SelfWatcher : struct
283 {
284    class_fixed
285    SelfWatcher prev, next;
286    void (*callback)(void *);
287    Property _property;
288 };
289
290 public enum AccessMode
291 {
292    defaultAccess,
293    publicAccess,
294    privateAccess,
295    staticAccess,
296    baseSystemAccess
297 };
298
299 public class SubModule : struct
300 {
301 public:
302    SubModule prev, next;
303    Module module;
304    AccessMode importMode;
305 };
306
307 public enum DataMemberType { normalMember, unionMember, structMember };
308
309 public enum ClassType
310 {
311    normalClass,
312    structClass,
313    bitClass,
314    unitClass,
315    enumClass,
316    noHeadClass,
317    unionClass, // Temporary only in firstPass
318    systemClass = 1000
319 };
320
321 public class Class : struct
322 {
323 public:
324    class_fixed
325    class_no_expansion
326    Class prev, next;
327    const char * name;
328    int offset, structSize;
329    void ** _vTbl;
330    int vTblSize;
331    bool (*Constructor)(void *);
332    void (*Destructor)(void *);
333
334    int offsetClass, sizeClass;
335    Class base;
336    BinaryTree methods;
337    BinaryTree members;
338    BinaryTree prop;
339    OldList membersAndProperties;
340    BinaryTree classProperties;
341    OldList derivatives;
342    int memberID, startMemberID;
343    ClassType type;
344    Module module;
345    NameSpace * nameSpace;
346    const char * dataTypeString;
347    Type dataType;
348    int typeSize;
349    int defaultAlignment;
350    void (*Initialize)();
351    int memberOffset;       // For structs, this includes all base classes structSize. Otherwise it restarts at for each class hierarchy level.
352    OldList selfWatchers;
353    const char * designerClass;
354    bool noExpansion;
355    const char * defaultProperty;
356    bool comRedefinition;
357
358    int count;     // DEBUGGING
359
360    int isRemote;  // TODO: Convert to an enum, can have values 0..3
361    bool internalDecl;
362    void * data;
363    bool computeSize;
364    short structAlignment; short pointerAlignment;
365    int destructionWatchOffset;
366    bool fixed;
367    OldList delayedCPValues;
368    AccessMode inheritanceAccess;
369    const char * fullName;
370    void * symbol;
371    OldList conversions;
372
373    OldList templateParams;
374    ClassTemplateArgument * templateArgs;
375    Class templateClass;
376    OldList templatized;
377    int numParams;       // TOTAL number of params including all base classes; use templateParams.count for this level
378    bool isInstanceClass;
379    bool byValueSystemClass;
380
381    property const char *
382    {
383       get { return name; }
384       set
385       {
386          Class theClass = eSystem_FindClass(__thisModule, value);
387          /*
388          if(!theClass)
389             theClass = eSystem_FindClass(__thisModule.application, value);
390          */
391          return theClass;
392       }
393    };
394
395    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
396    {
397       return name;
398    }
399
400    bool OnGetDataFromString(const char * string)
401    {
402       Class theClass;
403       theClass = eSystem_FindClass(__thisModule, string);
404       if(!theClass)
405          theClass = eSystem_FindClass(__thisModule.application, string);
406       this = (void *)theClass;
407       return theClass != null;
408    }
409
410    void OnSerialize(IOChannel channel)
411    {
412       channel.Serialize(fullName);
413    }
414
415    void OnFree()
416    {
417
418    }
419
420    void OnUnserialize(IOChannel channel)
421    {
422       Class theClass;
423       String string;
424       channel.Unserialize(string);
425       theClass = eSystem_FindClass(__thisModule, string);
426       if(!theClass)
427          theClass = eSystem_FindClass(__thisModule.application, string);
428       delete string;
429       this = (void *)theClass;
430    }
431 };
432
433
434 public enum TemplateParameterType { type, identifier, expression };
435 public enum TemplateMemberType { dataMember, method, prop };
436
437 public struct ClassTemplateArgument
438 {
439 public:
440    union
441    {
442       // For type
443       struct
444       {
445          const char * dataTypeString;
446          Class dataTypeClass;
447          // Type dataType;
448       };
449       // For expression
450       DataValue expression;
451
452       // For identifier
453       struct
454       {
455          const char * memberString;
456          union
457          {
458             DataMember member;
459             Property prop;
460             Method method;
461          };
462       };
463    };
464 };
465
466 public class ClassTemplateParameter : struct
467 {
468 class_fixed
469 public:
470    ClassTemplateParameter prev, next;
471    const char * name;
472    TemplateParameterType type;
473    union
474    {
475       // Class baseClass;                 // For type
476       const char * dataTypeString;           // For expression
477       TemplateMemberType memberType;   // For identifier
478    };
479    ClassTemplateArgument defaultArg;
480    void * param;  // To attach to Compiler TemplateParameter
481 }
482
483 /*    // Module inherits off the Instance class (_vTbl, _class, _refCount)
484 public class Module
485 {
486    class_no_expansion
487
488    Application app;
489
490    // So we can clean them up
491    OldList classes;
492    OldList defines;
493    OldList functions;
494    OldList modules;
495
496    Module prev, next;
497    const char * name;
498    void * library;
499    void (stdcall * Unload)(Module module);
500    ImportType importType;
501    // Added to solve stdcall issues with the bootstrap on Windows for Unload
502    ImportType origImportType;
503
504    NameSpace privateNameSpace;
505    NameSpace publicNameSpace;
506 };
507
508 public class Application : Module
509 {
510    int argc;
511    const char ** argv;
512    int exitCode;
513    bool isGUIApp;
514    OldList allModules;
515    const char * parsedCommand;
516    NameSpace systemNameSpace;
517 };
518 */
519 public enum MethodType { normalMethod, virtualMethod };
520
521 public class Method : struct
522 {
523 public:
524    class_fixed
525    const char * name;
526    Method parent, left, right;
527    int depth;
528    int (*function)();
529    int vid;              // For METHOD_VIRTUAL:  Index into the class virtual table
530    MethodType type;
531    Class _class;
532    void * symbol;
533    const char * dataTypeString;
534    Type dataType;
535    AccessMode memberAccess;
536 };
537
538 public enum ImportType
539 {
540    normalImport,
541    staticImport,
542    remoteImport,
543
544 // For internal usage in the compiler:
545    preDeclImport,
546    comCheckImport
547 };
548
549 public struct NameSpace
550 {
551    const char * name;
552    NameSpace * btParent, * left, * right;
553    int depth;
554
555    NameSpace * parent;
556    BinaryTree nameSpaces;
557    BinaryTree classes;
558    BinaryTree defines;
559    BinaryTree functions;
560 };
561
562 public union DataValue
563 {
564    char c;
565    unsigned char uc;
566    short s;
567    unsigned short us;
568    int i;
569    unsigned int ui;
570    void * p;
571    float f;
572    double d;
573    int64 i64;
574    uint64 ui64;
575 };
576
577 public class DataMember : struct
578 {
579 public:
580    class_fixed
581    DataMember prev, next;
582    const char * name;
583    bool isProperty;
584    AccessMode memberAccess;
585    int id;
586    Class _class;
587    const char * dataTypeString;
588    Class dataTypeClass;
589    Type dataType;
590
591    DataMemberType type;
592    int offset;
593    int memberID;
594    OldList members;
595    BinaryTree membersAlpha;
596    int memberOffset;
597    short structAlignment; short pointerAlignment;
598 };
599
600 public class BitMember : struct
601 {
602 public:
603    class_fixed
604    BitMember prev, next;
605    const char * name;
606    bool isProperty;
607    AccessMode memberAccess;
608    int id;
609    Class _class;
610    const char * dataTypeString;
611    Class dataTypeClass;
612    Type dataType;
613
614    DataMemberType type;
615    int size;
616    int pos;
617    uint64 mask;
618 };
619
620 public class ClassProperty : struct
621 {
622 public:
623    class_fixed
624    const char * name;
625    ClassProperty parent, left, right;
626    int depth;
627    void (*Set)(Class, int64);
628    int64 (*Get)(Class);
629    const char * dataTypeString;
630    Type dataType;
631    bool constant;
632 };
633
634 public class DefinedExpression : struct
635 {
636 public:
637    class_fixed
638    DefinedExpression prev, next;
639    const char * name;
640    const char * value;
641    NameSpace * nameSpace;
642 };
643
644 public class GlobalFunction : struct
645 {
646 public:
647    class_fixed
648    GlobalFunction prev, next;
649    const char * name;
650    int (*function)();
651    Module module;
652    NameSpace * nameSpace;
653    const char * dataTypeString;
654    Type dataType;
655    void * symbol;
656 };
657
658 public class EnumClassData : struct
659 {
660 public:
661    class_fixed
662    OldList values;
663    int64 largest;
664 };
665
666 class Watcher : struct
667 {
668    class_fixed
669    Watcher prev, next;
670    void (*callback)(void *, void *);
671    Instance object;
672 };
673
674 #ifdef MEMINFO
675 static class MemInfo : BTNode //struct
676 {
677    class_fixed
678
679    /*
680    byte * key;
681    MemInfo parent, left, right;
682    int depth;
683    */
684
685    byte * oldmem;
686    uint size;
687    bool freed;
688    const char * _class;
689    uint id;
690    char * allocLoc[MAX_MEMORY_LOC];
691    char * freeLoc[MAX_MEMORY_LOC];
692    bool internal;
693
694    void OutputStacks(bool showFree)
695    {
696       int c;
697
698       if(_class)
699          printf("Object of class %s\n", _class);
700       printf("   Allocation Stack:\n");
701       for(c = 0; c<MAX_MEMORY_LOC; c++)
702 #if (defined(__WORDSIZE) && __WORDSIZE == 8) || defined(__x86_64__)
703          if(allocLoc[c] && allocLoc[c] != (void *)0xabababababababab)
704 #else
705          if(allocLoc[c] && allocLoc[c] != (void *)0xabababab)
706 #endif
707             printf("      %s\n", allocLoc[c]);
708
709       if(showFree)
710       {
711          printf("   Free Location Stack:\n");
712          for(c = 0; c<MAX_MEMORY_LOC; c++)
713             if(freeLoc[c])
714                printf("      %s\n", freeLoc[c]);
715       }
716       //getch();
717    }
718 };
719
720 static BinaryTree memBlocks;
721
722 bool recurse = false;
723 static int blockID;
724 //Class allocateClass;
725 char * allocateClass;
726 bool allocateInternal;
727
728 #endif
729
730 static uint TOTAL_MEM = 0;
731 #if !defined(MEMINFO) && !defined(DISABLE_MEMMGR)
732 static uint OUTSIDE_MEM = 0;
733 #endif
734
735 #if !defined(__EMSCRIPTEN__)
736 #if !defined(ECERE_BOOTSTRAP)
737 static Mutex memMutex { };
738 #endif
739 #endif
740
741 private class MemBlock : struct
742 {
743    MemBlock prev, next;
744    MemPart part;
745    uint size;
746 #if !defined(MEMINFO) && defined(MEMTRACKING)
747    Class _class;
748 #endif
749 };
750
751 private class MemPart : struct
752 {
753    void * memory;
754    int blocksUsed;
755    int size;
756    BlockPool * pool;
757 };
758 /*
759 #define NUM_POOLS          29
760 #define NEXT_SIZE(s)       NextFibonacci(s)
761 #define SIZE_POSITION(s)   PosFibonacci(s)
762 #define NTH_SIZE(p)        NthFibonacci(p)
763
764 static uint initNumBlocks[NUM_POOLS] =
765 {
766    1024, // 1
767    1024, // 2
768    1024, // 3
769    1024, // 5
770    1024, // 8
771    1024, // 13
772    1024, // 21
773    1024, // 34
774    1024, // 55
775    1024, // 89
776    1024, // 144
777    512,  // 233
778    512,  // 377
779    256,  // 610
780    128,  // 987
781    128,  // 1597
782    64,   // 2584
783    32,   // 4181
784    32,   // 6765
785    16,   // 10946
786    16,   // 17711
787    8,    // 28657
788    4,    // 46368
789    2,    // 75025
790    1,    // 121393
791    1,    // 196418
792    1,    // 317811
793    1,    // 514229
794    1,    // 832040
795 };
796
797 */
798 /*
799 #define NUM_POOLS 20
800 #define NEXT_SIZE(s)       pow2i(s)
801 #define SIZE_POSITION(s)   log2i(s)
802 #define NTH_SIZE(p)        (1<<p)
803
804    1024,  // 1 byte
805    4000,  // 1024,    // 2 bytes
806    2500,  // 1024,    // 4 bytes
807    18000, //1024,    // 8 bytes
808    20000, //1024,    // 16 bytes
809    29000, //1024,    // 32 bytes
810    46000, //1024,    // 64 bytes
811    20000, //1024,    // 128 bytes
812    26000, //512,     // 256 bytes
813    1400,  //256,     // 512 bytes
814    160,   //128,     // 1 K
815    500,  //64,      // 2 K
816
817 static uint initNumBlocks[NUM_POOLS] =
818 {
819    1024,  // 1 byte
820    1024,    // 2 bytes
821    1024,    // 4 bytes
822    1024,    // 8 bytes
823    1024,    // 16 bytes
824    1024,    // 32 bytes
825    1024,    // 64 bytes
826    1024,    // 128 bytes
827    512,     // 256 bytes
828    256,     // 512 bytes
829    128,     // 1 K
830    64,      // 2 K
831    32,      // 4 K
832    16,      // 8 K
833    8,       // 16 K
834    4,       // 32 K
835    2,       // 64 K
836    1,       // 128 K
837    1,       // 256 K
838    1        // 512 K
839 };
840 */
841
842 #define NUM_POOLS 31
843 #define NEXT_SIZE(s)       pow1_5i(s)
844 #define SIZE_POSITION(s)   log1_5i(s)
845 #define NTH_SIZE(p)        pow1_5(p)
846
847 #if 0
848 static int power15[] =
849 {
850 /*
851 1
852 2
853 3
854 */
855 /*
856 4     // 4
857 6     // 8
858 9     // 12
859 13    // 16
860 19    // 24
861 28    // 32
862 42    // 48
863 63    // 64
864 94    // 96
865 141   // 144
866 211   // 224
867 316   // 320
868 474   // 480
869 711   // 720
870 1066  // 1072
871 1599  // 1600
872 2398  // 2400
873 3597  // 6900
874 5395  // 5408
875 8092  // 8096
876 12138 // 12144
877 18207 // 18208
878 27310 // 27312
879 40965 // 40976
880 61447 // 61456
881 92170 // 92176
882 138255   // 138256
883 207382   // 207392
884 311073   // 311088
885 466609   // 466624
886 699913   // 699920
887 */
888 4,
889 8,
890 12,
891 16,
892 24,
893 32,
894 48,
895 64,
896 96,
897 144,
898 224,
899 320,
900 480,
901 720,
902 1072,
903 1600,
904 2400,
905 6900,
906 5408,
907 8096,
908 12144,
909 18208,
910 27312,
911 40976,
912 61456,
913 92176,
914 138256,
915 207392,
916 311088,
917 466624,
918 699920
919 };
920 #endif
921
922 private struct BlockPool
923 {
924    MemBlock first, last;
925    MemBlock free;
926    uint blockSize;
927    uint blockSpace;
928    //MemPart * parts;
929    int numParts;
930    int numBlocks;
931    uint totalSize;
932    uint usedSpace;
933
934    bool Expand(uint numBlocks)
935    {
936       byte * memory = malloc(numBlocks * blockSpace);
937       // byte * memory = calloc(1, numBlocks * blockSpace);
938       TOTAL_MEM += numBlocks * blockSpace;
939 #ifdef _DEBUG
940       /*if(blockSize == 28)
941          printf("Expanding pool %x (%d)\n", this, blockSize);*/
942 #endif
943       if(memory)
944       {
945          int c;
946 #ifdef _DEBUG
947          /*uint totalAvailable = 0, totalAllocated = 0, totalBlocks = 0, totalUsed = 0;
948          uint totalParts = 0;*/
949 #endif
950          MemBlock block = (MemBlock)memory;
951          MemPart part = calloc(1, sizeof(class MemPart));
952          TOTAL_MEM += sizeof(class MemPart);
953          free = block;
954          for(c = 0; c<numBlocks - 1; c++)
955          {
956             // block.pool = this;
957             block.part = part;
958             /*if(part.size < 0)
959                printf("WARNING! part.size < 0\n");*/
960             block.prev = null;
961             block.next = (MemBlock)((byte *)block + blockSpace);
962             block = block.next;
963          }
964          part.blocksUsed = 0;
965          part.pool = this;
966          part.memory = memory;
967          part.size = numBlocks;
968
969          // block.pool = this;
970          block.part = part;
971          /*if(part.size < 0)
972             printf("/! part.size < 0\n");
973          if(part.pool == (void*) -1)
974             printf("WARNING! pool is -1\n");*/
975          block.prev = null;
976          block.next = null;
977
978          /*if(free && free.part && (free.part.size < 0 || free.part.pool == (void *)-1))
979             printf("WARNING! Bad next free block!\n");*/
980
981          //parts = realloc(parts, sizeof(MemPart) * (numParts + 1));
982
983          totalSize += numBlocks;
984
985 #ifdef _DEBUG
986          /*
987          {
988             for(c = 0; c<NUM_POOLS; c++)
989             {
990                BlockPool * pool = &pools[c];
991                printf("[%d %s (%d)]: available: %d, allocated: %d, free: %d, used: %d k, wasted: %d k, free: %d k\n", c, (&pools[c] == this) ? "*" : " ",
992                   pools[c].blockSize, pools[c].totalSize, pools[c].numBlocks,
993                   pools[c].totalSize - pools[c].numBlocks, pools[c].usedSpace / 1024, ((pools[c].numBlocks * pools[c].blockSize) - pools[c].usedSpace) / 1024,
994                   (pools[c].totalSize - pools[c].numBlocks) * pools[c].blockSize / 1024);
995                totalAvailable += pools[c].totalSize * pools[c].blockSize;
996                totalAllocated += pools[c].numBlocks * pools[c].blockSize;
997                totalUsed += pools[c].usedSpace;
998                totalBlocks += pools[c].totalSize;
999                totalParts += pools[c].numParts;
1000             }
1001             printf("Total Available %d k, Total Allocated: %d k, Total Free: %d k\n", totalAvailable / 1024, totalAllocated / 1024, (totalAvailable - totalAllocated) / 1024);
1002             printf("Total Number of Blocks %d, overhead of %d k\n", totalBlocks, totalBlocks * sizeof(class MemBlock) / 1024);
1003             printf("Total Used Space %d k, wasted from roundup: %d k\n", totalUsed / 1024, (totalAllocated - totalUsed) / 1024);
1004             printf("Total Memory Parts: %d\n", totalParts);
1005             printf("TOTAL_MEM: %d k, OUTSIDE_MEM: %d k, BLOCKS: %d k\n", TOTAL_MEM / 1024, OUTSIDE_MEM / 1024, (totalAvailable + totalBlocks * sizeof(class MemBlock)) / 1024);
1006             printf("\n");
1007          }
1008          */
1009 #endif
1010          //parts[] = part;
1011          numParts++;
1012          return true;
1013       }
1014       return false;
1015    }
1016
1017    MemBlock Add()
1018    {
1019       MemBlock block = null;
1020       /*if(blockSize == 28)
1021          printf("BlockPool::Add (%d)\n", blockSize);*/
1022       if(!free)
1023          Expand(Max(1, numBlocks / 2));
1024       if(free)
1025       {
1026          block = free;
1027          block.prev = last;
1028          if(block.prev)
1029             block.prev.next = block;
1030          if(!first)
1031             first = block;
1032          last = block;
1033          free = block.next;
1034          /*if(blockSize == 28)
1035             printf("Free: %x, free.part: %x, free.part.size: %d, free.part.pool: %x (this = %x), next = %x (part = %x)\n", free, free ? free.part : null,
1036                (free && free.part) ? free.part.size : 0, (free && free.part) ? free.part.pool : 0, this,
1037                (free ? free.next : 0), (free && free.next) ? free.next.part : 0);
1038          if(free && free.part && (free.part.size < 0 || free.part.pool == (void *)-1))
1039             printf("WARNING! Bad next free block!\n");*/
1040
1041          block.next = null;
1042          //if(block.part)
1043             block.part.blocksUsed++;
1044          /*else
1045          {
1046             printf("");
1047          }*/
1048          numBlocks++;
1049       }
1050       return block;
1051    }
1052
1053    void Remove(MemBlock block)
1054    {
1055       MemPart part = block.part;
1056       /*if(blockSize == 28)
1057          printf("BlockPool::Remove (%d)\n", blockSize);*/
1058       if(block.prev)
1059          block.prev.next = block.next;
1060       if(block.next)
1061          block.next.prev = block.prev;
1062
1063       if(first == block)
1064          first = block.next;
1065       if(last == block)
1066          last = block.prev;
1067
1068       // block.prev = null;
1069       block.next = free;
1070       free = block;
1071
1072       /*if(blockSize == 28)
1073       {
1074          printf("Setting new free block: part = %x\n", block.part);
1075       }*/
1076
1077       part.blocksUsed--;
1078       numBlocks--;
1079       part.pool->usedSpace -= block.size;
1080
1081       if(!part.blocksUsed && numBlocks && totalSize > numBlocks + numBlocks / 2)
1082       {
1083          MemBlock next = free, prev = null;
1084          free = null;
1085          totalSize -= part.size;
1086          /*if(blockSize == 28)
1087             printf("Freeing a part\n");*/
1088          while(next)
1089          {
1090             if(next.part != part)
1091             {
1092                if(prev)
1093                   prev.next = next;
1094                else
1095                   free = next;
1096                prev = next;
1097             }
1098             next = next.next;
1099          };
1100          if(prev)
1101             prev.next = null;
1102
1103          TOTAL_MEM -= part.size * blockSpace;
1104          TOTAL_MEM -= sizeof(class MemPart);
1105          numParts--;
1106
1107          ::free(part.memory);
1108          ::free(part);
1109       }
1110       /*if(free && free.part && (free.part.size < 0 || free.part.pool == (void *)-1))
1111          printf("WARNING! Bad next free block!\n");*/
1112    }
1113 };
1114
1115 #if !defined(MEMINFO) && !defined(DISABLE_MEMMGR)
1116 static BlockPool * pools; //[NUM_POOLS];
1117
1118 /*static uint PosFibonacci(uint number)
1119 {
1120    uint pos;
1121    uint last = 1, prev = 0;
1122    uint current = 1;
1123
1124    for(pos=0; ; pos++)
1125    {
1126       current += prev;
1127       prev = last;
1128       last = current;
1129       if(current >= number)
1130          break;
1131    }
1132    return pos;
1133 }
1134
1135 static uint NthFibonacci(uint number)
1136 {
1137    uint pos;
1138    uint last = 1, prev = 0;
1139    uint current = 1;
1140
1141    for(pos=0; pos <= number; pos++)
1142    {
1143       current += prev;
1144       prev = last;
1145       last = current;
1146    }
1147    return current;
1148 }
1149
1150 static uint NextFibonacci(uint number)
1151 {
1152    uint pos;
1153    uint last = 1, prev = 0;
1154    uint current = 1;
1155
1156    for(pos=0; ; pos++)
1157    {
1158       current += prev;
1159       prev = last;
1160       last = current;
1161       if(current >= number)
1162          return current;
1163    }
1164 }
1165 */
1166
1167 static uint log1_5i(uint number)
1168 {
1169    uint pos;
1170    uint64 current = sizeof(void *);
1171
1172    for(pos=0; pos < NUM_POOLS; pos++)
1173    {
1174       if(current >= number)
1175          break;
1176       current = current * 3 / 2;
1177       if(current == 1) current = 2;
1178       if(current & 7) current += 8 - (current & 7);
1179    }
1180    return pos;
1181 }
1182
1183 static uint pow1_5(uint number)
1184 {
1185    uint pos;
1186    uint64 current = sizeof(void *);
1187    for(pos=0; pos < number; pos++)
1188    {
1189       current = current * 3 / 2;
1190       if(current == 1) current = 2;
1191       if(current & 7) current += 8 - (current & 7);
1192    }
1193    return (uint)current;
1194 }
1195
1196 static uint pow1_5i(uint number)
1197 {
1198    uint pos;
1199    uint64 current = sizeof(void *);
1200
1201    for(pos=0; pos < NUM_POOLS; pos++)
1202    {
1203       if(current >= number)
1204          return (uint)current;
1205       current = current * 3 / 2;
1206       if(current == 1) current = 2;
1207       if(current & 7) current += 8 - (current & 7);
1208    }
1209    return (uint)current;
1210 }
1211 #endif
1212
1213 // -- Math Helpers ---
1214 public uint log2i(uint number)
1215 {
1216    uint power;
1217
1218    for(power=0; power<32; power++)
1219       if((1L<<power) >= number)
1220          break;
1221    return power;
1222 }
1223
1224 public uint pow2i(uint number)
1225 {
1226    return 1<<log2i(number);
1227 }
1228
1229 #if !defined(MEMINFO) && !defined(DISABLE_MEMMGR)
1230 static bool memoryInitialized = false;
1231 static void InitMemory()
1232 {
1233    int c;
1234    memoryInitialized = true;
1235    pools = calloc(1, sizeof(BlockPool) * NUM_POOLS);
1236    for(c = 0; c<NUM_POOLS; c++)
1237    {
1238       int expansion;
1239
1240       pools[c].blockSize = NTH_SIZE(c);
1241       if(pools[c].blockSize % sizeof(void *))
1242          pools[c].blockSize += sizeof(void *) - (pools[c].blockSize % sizeof(void *));
1243       pools[c].blockSpace = pools[c].blockSize;
1244       pools[c].blockSpace += sizeof(class MemBlock);
1245       // pools[c].Expand(initNumBlocks[c]);
1246
1247       expansion = (pools[c].blockSize < 128) ? 1024 : (131072 / pools[c].blockSize);
1248
1249       if(c < 12)
1250          pools[c].Expand(Max(1, expansion));
1251    }
1252 }
1253 #endif
1254
1255 #if !defined(MEMINFO) && !defined(DISABLE_MEMMGR)
1256 static void * _mymalloc(unsigned int size)
1257 {
1258    MemBlock block = null;
1259    if(size)
1260    {
1261       unsigned int p = SIZE_POSITION(size);
1262       if(!memoryInitialized) InitMemory();
1263       if(!poolingDisabled && p < NUM_POOLS)
1264       {
1265          block = pools[p].Add();
1266          if(block)
1267          {
1268 #if defined(MEMTRACKING)
1269             block._class = null;
1270 #endif
1271             block.size = size;
1272             pools[p].usedSpace += size;
1273          }
1274       }
1275       else
1276       {
1277          block = malloc(sizeof(class MemBlock) + size);
1278          if(block)
1279          {
1280             TOTAL_MEM += sizeof(class MemBlock) + size;
1281             OUTSIDE_MEM += sizeof(class MemBlock) + size;
1282             block.part = null;
1283 #if defined(MEMTRACKING)
1284             block._class = null;
1285 #endif
1286             block.size = size;
1287          }
1288       }
1289    }
1290    return block ? ((struct MemBlock *)block + 1) : null;
1291 }
1292
1293 static void * _mycalloc(int n, unsigned int size)
1294 {
1295    void * pointer = _mymalloc(n*size);
1296    if(pointer)
1297       memset(pointer, 0, n*size);
1298    return pointer;
1299 }
1300
1301
1302 static void _myfree(void * pointer)
1303 {
1304    if(pointer)
1305    {
1306       MemBlock block = (MemBlock)((byte *)pointer - sizeof(class MemBlock));
1307       MemPart part = block.part;
1308       BlockPool * pool = part ? part.pool : null; //block.pool;
1309       /*if(pool == (void*) -1)
1310          printf("WARNING! pool is -1\n");
1311       else   */
1312       if(pool)
1313       {
1314 #ifdef _DEBUG
1315          memset(pointer, 0xec, block.size);
1316 #endif
1317          pool->Remove(block);
1318       }
1319       else
1320       {
1321          TOTAL_MEM -= sizeof(class MemBlock) + block.size;
1322          OUTSIDE_MEM -= sizeof(class MemBlock) + block.size;
1323
1324 #ifdef _DEBUG
1325          memset(block, 0xec, sizeof(class MemBlock) + block.size);
1326 #endif
1327          free(block);
1328       }
1329    }
1330 }
1331
1332 static void * _myrealloc(void * pointer, unsigned int size)
1333 {
1334    MemBlock block = pointer ? ((MemBlock)((byte *)pointer - sizeof(class MemBlock))) : null;
1335    void * newPointer = null;
1336    MemPart part = block ? block.part : null;
1337    BlockPool * pool = part ? part.pool : null;
1338    if(block)
1339    {
1340       /*if(pool == (void*) -1)
1341          printf("WARNING! pool is -1\n");
1342       else*/
1343       if(pool)
1344       {
1345          // if((1 << pool) >= size && (pool - SIZE_POSITION(size)) <= 1)
1346          uint ns = NEXT_SIZE(size);
1347          uint mod = ns % sizeof(void *);
1348          if(mod) ns += sizeof(void *)-mod;
1349          if(ns == pool->blockSize)
1350          {
1351             newPointer = pointer;
1352             pool->usedSpace += size - block.size;
1353             block.size = size;
1354          }
1355       }
1356       else if(size)
1357       {
1358          MemBlock newBlock = realloc(block, sizeof(class MemBlock) + size);
1359          if(newBlock)
1360          {
1361             TOTAL_MEM += size - newBlock.size;
1362             OUTSIDE_MEM += size - newBlock.size;
1363             newPointer = ((struct MemBlock *)newBlock + 1);
1364             newBlock.size = size;
1365          }
1366       }
1367    }
1368    if(!newPointer)
1369    {
1370       newPointer = _mymalloc(size);
1371       if(pointer && newPointer)
1372       {
1373          memcpy(newPointer, pointer, Min(size, block.size));
1374          _myfree(pointer);
1375       }
1376    }
1377    return newPointer;
1378 }
1379
1380 static void * _mycrealloc(void * pointer, unsigned int size)
1381 {
1382    MemBlock block = pointer ? ((MemBlock)((byte *)pointer - sizeof(class MemBlock))) : null;
1383    void * newPointer = null;
1384    MemPart part = block ? block.part : null;
1385    BlockPool * pool = part ? part.pool : null;
1386    if(block)
1387    {
1388       /*if(pool == (void*) -1)
1389          printf("WARNING! pool is -1\n");
1390       else*/
1391
1392       if(pool)
1393       {
1394          // if((1 << pool) >= size && (pool - SIZE_POSITION(size)) <= 1)
1395          uint ns = NEXT_SIZE(size);
1396          uint mod = ns % sizeof(void *);
1397          if(mod) ns += sizeof(void *)-mod;
1398          if(ns == pool->blockSize)
1399          {
1400             int extra = size - block.size;
1401             newPointer = pointer;
1402             pool->usedSpace += extra;
1403             if(extra > 0)
1404                memset((byte *)pointer + block.size, 0, extra);
1405             block.size = size;
1406          }
1407       }
1408       else if(size)
1409       {
1410          MemBlock newBlock = realloc(block, sizeof(class MemBlock) + size);
1411          if(newBlock)
1412          {
1413             int extra = size - newBlock.size;
1414             TOTAL_MEM += extra;
1415             OUTSIDE_MEM += extra;
1416             newPointer = ((struct MemBlock *)newBlock + 1);
1417             if(extra > 0)
1418                memset((byte *)newPointer + newBlock.size, 0, extra);
1419             newBlock.size = size;
1420          }
1421       }
1422    }
1423    if(!newPointer)
1424    {
1425       newPointer = _mymalloc(size);
1426       if(newPointer)
1427       {
1428          if(pointer)
1429          {
1430             memcpy(newPointer, pointer, Min(size, block.size));
1431             if(size > block.size)
1432                memset((byte *)newPointer + block.size, 0, size - block.size);
1433             _myfree(pointer);
1434          }
1435          else
1436             memset((byte *)newPointer, 0, size);
1437       }
1438    }
1439    return newPointer;
1440 }
1441
1442 #undef realloc
1443 #undef crealloc
1444 #undef malloc
1445 #undef free
1446 #undef calloc
1447
1448 #define realloc _myrealloc
1449 #define crealloc _mycrealloc
1450 #define malloc _mymalloc
1451 #define free _myfree
1452 #define calloc _mycalloc
1453 #endif
1454
1455 static void * _malloc(unsigned int size)
1456 {
1457 #if defined(DISABLE_MEMMGR) && !defined(MEMINFO)
1458    return size ? malloc(size) : null;
1459 #else
1460    void * pointer;
1461
1462
1463 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1464    memMutex.Wait();
1465 #endif
1466
1467    pointer = size ? malloc(size + 2 * REDZONE) : null;
1468 #ifdef MEMINFO
1469    if(pointer)
1470    {
1471       MemInfo block;
1472       MemStack stack = (MemStack)memStacks.Find(GetCurrentThreadID());
1473       if(!stack)
1474       {
1475          stack = (MemStack)calloc(1, sizeof(class MemStack));
1476          stack.key = GetCurrentThreadID();
1477          memStacks.Add(stack);
1478       }
1479
1480       if(!pointer)
1481       {
1482          int c;
1483          printf("Memory allocation of %d bytes failed\n", size);
1484          printf("Current Stack:\n");
1485          for(c = 0; c<stack.pos; c++)
1486             if(stack.frames[c])
1487                printf("      %s\n", stack.frames[c]);
1488
1489          memoryErrorsCount++;
1490 #if !defined(__EMSCRIPTEN__)
1491          memMutex.Release();
1492 #endif
1493          return null;
1494       }
1495
1496       if(!recurse && !stack.recurse)
1497       {
1498          stack.recurse = true;
1499          block = MemInfo { size = size, key = (uintptr)((byte *)pointer + REDZONE), id = blockID++ };
1500          memcpy(block.allocLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1501          memBlocks.Add(block);
1502          stack.recurse = false;
1503       }
1504    }
1505 #endif
1506
1507 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1508    memMutex.Release();
1509 #endif
1510
1511 #if REDZONE
1512    if(pointer)
1513    {
1514       memset(pointer, 0xAB, REDZONE);
1515       memset((byte *)pointer + REDZONE + size, 0xAB, REDZONE);
1516       // ((byte *)pointer)[0] = 0x00;
1517    }
1518 #endif
1519    return pointer ? ((byte*)pointer + REDZONE) : null;
1520 #endif
1521 }
1522
1523 static void * _calloc(int n, unsigned int size)
1524 {
1525 #if defined(DISABLE_MEMMGR) && !defined(MEMINFO)
1526    return size ? calloc(n, size) : null;
1527 #else
1528    void * pointer;
1529
1530 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1531    memMutex.Wait();
1532 #endif
1533
1534    pointer = (n*size) ? calloc(1, n*size + 2 * REDZONE) : null;
1535 #ifdef MEMINFO
1536    if(pointer)
1537    {
1538       MemStack stack;
1539       stack = (MemStack)memStacks.Find(GetCurrentThreadID());
1540       if(!stack)
1541       {
1542          stack = (MemStack)calloc(1, sizeof(class MemStack));
1543          stack.key = GetCurrentThreadID();
1544          memStacks.Add(stack);
1545       }
1546       if(!pointer)
1547       {
1548          int c;
1549          printf("Memory allocation of %d bytes failed\n", size);
1550          printf("Current Stack:\n");
1551          for(c = 0; c<stack.pos; c++)
1552             if(stack.frames[c])
1553                printf("      %s\n", stack.frames[c]);
1554          memoryErrorsCount++;
1555 #if !defined(__EMSCRIPTEN__)
1556          memMutex.Release();
1557 #endif
1558          return null;
1559       }
1560
1561       if(!recurse && !stack.recurse)
1562       {
1563          MemInfo block;
1564
1565          stack.recurse = true;
1566          block = MemInfo { size = (unsigned int)n*size, key = (uintptr)((byte *)pointer + REDZONE), _class = allocateClass, internal = allocateInternal, id = blockID++ };
1567          memcpy(block.allocLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1568          memBlocks.Add(block);
1569          stack.recurse = false;
1570       }
1571    }
1572 #endif
1573
1574 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1575    memMutex.Release();
1576 #endif
1577
1578 #if REDZONE
1579    if(pointer)
1580    {
1581       memset(pointer, 0xAB, REDZONE);
1582       memset((byte *)pointer + REDZONE + (unsigned int)n*size, 0xAB, REDZONE);
1583    }
1584 #endif
1585    return pointer ? ((byte*)pointer + REDZONE) : null;
1586 #endif
1587 }
1588
1589 static void * _realloc(void * pointer, unsigned int size)
1590 {
1591 #if defined(DISABLE_MEMMGR) && !defined(MEMINFO)
1592    if(!size) { free(pointer); return null; }
1593    return realloc(pointer, size);
1594
1595 #else
1596    if(!size) { _free(pointer); return null; }
1597
1598 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1599    memMutex.Wait();
1600 #endif
1601
1602 #ifdef MEMINFO
1603 {
1604    MemInfo block = null;
1605    MemStack stack;
1606    stack = (MemStack)memStacks.Find(GetCurrentThreadID());
1607    if(!stack)
1608    {
1609       stack = (MemStack)calloc(1, sizeof(class MemStack));
1610       stack.key = GetCurrentThreadID();
1611       memStacks.Add(stack);
1612    }
1613
1614    if(!recurse && !stack.recurse && pointer)
1615    {
1616       block = (MemInfo)memBlocks.Find((uintptr)pointer);
1617       if(!block)
1618       {
1619          printf("Reallocating Bad Memory\n");
1620          memoryErrorsCount++;
1621       }
1622       else if(block.freed)
1623       {
1624          printf("Reallocating Freed Memory\n");
1625          memoryErrorsCount++;
1626          block.OutputStacks(true);
1627       }
1628    }
1629
1630    pointer = malloc(size + REDZONE * 2);
1631    if(!pointer)
1632    {
1633       int c;
1634       printf("Memory allocation of %d bytes failed\n", size);
1635       printf("Current Stack:\n");
1636       for(c = 0; c<stack.pos; c++)
1637          if(stack.frames[c])
1638             printf("      %s\n", stack.frames[c]);
1639       memoryErrorsCount++;
1640 #if !defined(__EMSCRIPTEN__)
1641       memMutex.Release();
1642 #endif
1643       return null;
1644    }
1645    memset(pointer, 0xAB, REDZONE);
1646    memset((byte *)pointer + REDZONE + size, 0xAB, REDZONE);
1647
1648    if(block)
1649    {
1650 #if defined(JUST_CHECK_LEAKS) || defined(JUST_CHECK_BOUNDARIES)
1651       memcpy((byte *)pointer + REDZONE, (byte *)block.key, Min(block.size, size));
1652       free((byte *)block.key - REDZONE);
1653       memBlocks.Remove(block);
1654       free(block);
1655 #else
1656       if(block.freed)
1657       {
1658          memcpy((byte *)pointer + REDZONE, block.oldmem, Min(block.size, size));
1659       }
1660       else
1661       {
1662          memcpy(block.freeLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1663          memcpy((byte *)pointer + REDZONE, (byte *)block.key, Min(block.size, size));
1664          block.oldmem = (byte *)malloc(block.size + REDZONE * 2);
1665          if(block.oldmem)
1666          {
1667             block.oldmem += REDZONE;
1668             memcpy(block.oldmem - REDZONE, (byte *)block.key - REDZONE, block.size + 2 * REDZONE);
1669          }
1670          memset((byte *)block.key - REDZONE, 0xEC, block.size + REDZONE * 2);
1671          block.freed = true;
1672       }
1673 #endif
1674    }
1675
1676    if(!recurse && !stack.recurse)
1677    {
1678       MemInfo block;
1679       stack.recurse = true;
1680       block = MemInfo { size = size, key = (uintptr)((byte *)pointer + REDZONE), id = blockID++ };
1681       memcpy(block.allocLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1682       memBlocks.Add(block);
1683       stack.recurse = false;
1684    }
1685 }
1686 #else
1687    pointer = realloc(pointer, size);
1688 #endif
1689
1690 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1691    memMutex.Release();
1692 #endif
1693    return pointer ? ((byte *)pointer + REDZONE) : null;
1694 #endif
1695 }
1696
1697 static void * _crealloc(void * pointer, unsigned int size)
1698 {
1699 #if defined(DISABLE_MEMMGR) && !defined(MEMINFO)
1700    uintsize s = pointer ? msize(pointer) : 0;
1701    void * p;
1702    if(!size) { free(pointer); return null; }
1703
1704    p = realloc(pointer, size);
1705    if(size > s)
1706       memset((byte *)p + s, 0, size - s);
1707    return p;
1708 #else
1709    if(!size) { _free(pointer); return null; }
1710
1711 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1712    memMutex.Wait();
1713 #endif
1714
1715 #ifdef MEMINFO
1716 {
1717    MemInfo block = null;
1718    MemStack stack;
1719    stack = (MemStack)memStacks.Find(GetCurrentThreadID());
1720    if(!stack)
1721    {
1722       stack = (MemStack)calloc(1, sizeof(class MemStack));
1723       stack.key = GetCurrentThreadID();
1724       memStacks.Add(stack);
1725    }
1726
1727    if(!recurse && !stack.recurse && pointer)
1728    {
1729       block = (MemInfo)memBlocks.Find((uintptr)pointer);
1730       if(!block)
1731       {
1732          printf("Reallocating Bad Memory\n");
1733          memoryErrorsCount++;
1734       }
1735       else if(block.freed)
1736       {
1737          printf("Reallocating Freed Memory\n");
1738          memoryErrorsCount++;
1739          block.OutputStacks(true);
1740       }
1741    }
1742
1743    pointer = calloc(1, size + REDZONE * 2);
1744    if(!pointer)
1745    {
1746       int c;
1747       printf("Memory allocation of %d bytes failed\n", size);
1748       printf("Current Stack:\n");
1749       for(c = 0; c<stack.pos; c++)
1750          if(stack.frames[c])
1751             printf("      %s\n", stack.frames[c]);
1752       memoryErrorsCount++;
1753 #if !defined(__EMSCRIPTEN__)
1754       memMutex.Release();
1755 #endif
1756       return null;
1757    }
1758    memset(pointer, 0xAB, REDZONE);
1759    memset((byte *)pointer + REDZONE + size, 0xAB, REDZONE);
1760
1761    if(block)
1762    {
1763 #if defined(JUST_CHECK_LEAKS) || defined(JUST_CHECK_BOUNDARIES)
1764       memcpy((byte *)pointer + REDZONE, (byte *)block.key, Min(block.size, size));
1765       free((byte *)block.key - REDZONE);
1766       memBlocks.Remove(block);
1767       free(block);
1768 #else
1769       if(block.freed)
1770       {
1771          memcpy((byte *)pointer + REDZONE, block.oldmem, Min(block.size, size));
1772       }
1773       else
1774       {
1775          memcpy(block.freeLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1776          memcpy((byte *)pointer + REDZONE, (byte *)block.key, Min(block.size, size));
1777          block.oldmem = (byte *)malloc(block.size + REDZONE * 2);
1778          if(block.oldmem)
1779          {
1780             block.oldmem += REDZONE;
1781             memcpy(block.oldmem - REDZONE, (byte *)block.key - REDZONE, block.size + 2 * REDZONE);
1782          }
1783          memset((byte *)block.key - REDZONE, 0xEC, block.size + REDZONE * 2);
1784          block.freed = true;
1785       }
1786 #endif
1787    }
1788
1789    if(!recurse && !stack.recurse)
1790    {
1791       MemInfo block;
1792       stack.recurse = true;
1793       block = MemInfo { size = size, key = (uintptr)((byte *)pointer + REDZONE), id = blockID++ };
1794       memcpy(block.allocLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1795       memBlocks.Add(block);
1796       stack.recurse = false;
1797    }
1798 }
1799 #else
1800    pointer = crealloc(pointer, size);
1801 #endif
1802
1803 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1804    memMutex.Release();
1805 #endif
1806    return pointer ? ((byte *)pointer + REDZONE) : null;
1807 #endif
1808 }
1809
1810 static void _free(void * pointer)
1811 {
1812    if(pointer)
1813    {
1814 #if defined(DISABLE_MEMMGR) && !defined(MEMINFO)
1815       free(pointer);
1816 #else
1817 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1818       if(memMutex != pointer) memMutex.Wait();
1819 #endif
1820
1821 #ifdef MEMINFO
1822 {
1823       MemStack stack;
1824
1825       stack = (MemStack)memStacks.Find(GetCurrentThreadID());
1826       if(!stack)
1827       {
1828          stack = (MemStack)calloc(1, sizeof(class MemStack));
1829          stack.key = GetCurrentThreadID();
1830          memStacks.Add(stack);
1831       }
1832
1833       if(!recurse && !stack.recurse)
1834       {
1835          MemInfo block;
1836          stack.recurse = true;
1837          block = (MemInfo)memBlocks.Find((uintptr)pointer);
1838          if(!block)
1839          {
1840             int c;
1841             printf("Freeing Bad Memory\n");
1842             printf("Current Stack:\n");
1843             for(c = 0; c<stack.pos; c++)
1844                if(stack.frames[c])
1845                   printf("      %s\n", stack.frames[c]);
1846
1847             memoryErrorsCount++;
1848          }
1849          else if(block.freed)
1850          {
1851             int c;
1852             printf("Freeing Already Freed Memory\n");
1853             printf("Current Stack:\n");
1854             for(c = 0; c<stack.pos; c++)
1855                if(stack.frames[c])
1856                   printf("      %s\n", stack.frames[c]);
1857
1858             memoryErrorsCount++;
1859             block.OutputStacks(true);
1860          }
1861          else
1862          {
1863             /*int c;
1864             byte * address = (byte *)block.key;
1865             for(c = 0; c<REDZONE; c++)
1866             {
1867                if(address[-c-1] != 0xEC)
1868                {
1869                   printf("Buffer Underrun\n");
1870                   memoryErrorsCount++;
1871                   block.OutputStacks(block.freed);
1872                }
1873                if(address[c + block.size] != 0xEC)
1874                {
1875                   printf("Buffer Overrun\n");
1876                   memoryErrorsCount++;
1877                   block.OutputStacks(block.freed);
1878                }
1879             }*/
1880
1881             {
1882                byte * address;
1883                int c;
1884                int size = block.size;
1885                address = (byte *)block.key;
1886                for(c = 0; c<REDZONE; c++)
1887                {
1888                   if(address[-c-1] != 0xAB)
1889                   {
1890                      printf("Buffer Underrun (%d bytes before)\n", c+1);
1891                      memoryErrorsCount++;
1892                      block.OutputStacks(block.freed);
1893                   }
1894                   if(address[c + size] != 0xAB)
1895                   {
1896                      printf("Buffer Overrun (%d bytes past block)\n", c);
1897                      memoryErrorsCount++;
1898                      block.OutputStacks(block.freed);
1899                   }
1900                }
1901             }
1902
1903             block.freed = true;
1904 #if defined(JUST_CHECK_LEAKS) || defined(JUST_CHECK_BOUNDARIES)
1905             free((byte *)block.key - REDZONE);
1906             memBlocks.Remove(block);
1907             free(block);
1908 #else
1909             block.oldmem = (byte *)malloc(block.size + REDZONE * 2);
1910             if(block.oldmem)
1911             {
1912                block.oldmem += REDZONE;
1913                memcpy(block.oldmem - REDZONE, (byte *)block.key - REDZONE, block.size + REDZONE * 2);
1914             }
1915             memset((byte *)block.key - REDZONE, 0xEC, block.size + REDZONE * 2);
1916
1917             memcpy(block.freeLoc, stack.frames + stack.pos - Min(stack.pos, MAX_MEMORY_LOC), Min(stack.pos, MAX_MEMORY_LOC) * sizeof(char *));
1918 #endif
1919          }
1920          stack.recurse = false;
1921       }
1922 }
1923 #else
1924       free(pointer);
1925 #endif
1926
1927 #if !defined(ECERE_BOOTSTRAP) && !defined(__EMSCRIPTEN__)
1928       if(memMutex != pointer) memMutex.Release();
1929 #endif
1930
1931 #endif
1932    }
1933 }
1934
1935 public void memswap(byte * a, byte * b, uint size)
1936 {
1937    uint c;
1938    byte buffer[1024];
1939    for(c = 0; c<size;)
1940    {
1941       int s = sizeof(buffer);
1942       if(c + s > size) s = size - c;
1943       memcpy(buffer, a + c, s);
1944       memcpy(a + c, b + c, s);
1945       memcpy(b + c, buffer, s);
1946       c += s;
1947    }
1948 }
1949
1950 public void CheckConsistency()
1951 {
1952 #ifdef MEMINFO
1953    if(!memBlocks.Check())
1954       printf("Memory Blocks Tree Integrity Failed\n");
1955 #endif
1956 }
1957
1958 public void CheckMemory()
1959 {
1960 #ifdef MEMINFO
1961    MemInfo block;
1962    uint leaksCount = 0;
1963    uint leakedObjects = 0;
1964    uint leaksSize = 0;
1965    recurse = true;
1966    // Verify Tree Integrity
1967    if(!memBlocks.Check())
1968    {
1969       printf("Memory Blocks Tree Integrity Failed\n");
1970       memoryErrorsCount++;
1971    }
1972    printf("Starting Memory Check\n");
1973    for(block = (MemInfo)memBlocks.first; block; block = (MemInfo)block.next)
1974    {
1975       if(!block.freed && block._class)
1976          leakedObjects++;
1977    }
1978
1979    for(block = (MemInfo)memBlocks.root; block;)
1980    {
1981       if(block.freed)
1982          memswap((byte *)block.key - REDZONE, block.oldmem - REDZONE, block.size + REDZONE * 2);
1983       else
1984       {
1985          if(block._class)
1986          {
1987             // if(!block.internal)
1988             {
1989                // printf("Object of class %s\n", block._class);
1990                block.OutputStacks(false);
1991             }
1992          }
1993          else if(!leakedObjects)
1994          {
1995             printf("Memory Leak\n");
1996             block.OutputStacks(false);
1997          }
1998
1999          leaksCount ++;
2000          leaksSize += block.size;
2001       }
2002
2003       if(block.left)
2004          block = (MemInfo)block.left;
2005       else if(block.right)
2006          block = (MemInfo)block.right;
2007       else
2008       {
2009          while(block)
2010          {
2011             MemInfo parent = (MemInfo)block.parent;
2012             if(parent && block == (MemInfo)parent.left && parent.right)
2013             {
2014                block = (MemInfo)parent.right;
2015                break;
2016             }
2017             block = parent;
2018          }
2019       }
2020    }
2021
2022    while((block = (MemInfo)memBlocks.root))
2023    {
2024       byte * address;
2025       int c;
2026       int size = block.size;
2027       if(block.freed)
2028       {
2029          address = block.oldmem;
2030          for(c = -REDZONE; c<size + REDZONE; c++)
2031             if(address[c] != 0xEC)
2032             {
2033                break;
2034             }
2035          if(c < size + REDZONE)
2036          {
2037             printf("Freed Memory Write\n");
2038             memoryErrorsCount++;
2039             block.OutputStacks(true);
2040          }
2041       }
2042
2043       address = (byte *)block.key;
2044       for(c = 0; c<REDZONE; c++)
2045       {
2046          if(address[-c-1] != 0xAB)
2047          {
2048             printf("Buffer Underrun (%d bytes before)\n", c + 1);
2049             memoryErrorsCount++;
2050             block.OutputStacks(block.freed);
2051          }
2052          if(address[c + size] != 0xAB)
2053          {
2054             printf("Buffer Overrun (%d bytes past)\n", c);
2055             memoryErrorsCount++;
2056             block.OutputStacks(block.freed);
2057          }
2058       }
2059
2060       memBlocks.Delete(block);
2061    }
2062    if(leaksCount)
2063    {
2064       printf("%d Memory Leaks Detected (%d objects, %d bytes).\n", leaksCount, leakedObjects, leaksSize);
2065       memoryErrorsCount++;
2066    }
2067    printf("Memory Check Completed.\n");
2068 #if defined(__WIN32__) && !defined(ECERE_BOOTSTRAP)
2069    if(memoryErrorsCount)
2070       system("pause");
2071 #endif
2072 #endif
2073 }
2074
2075 static void FixDerivativesBase(Class base, Class mod)
2076 {
2077    OldLink derivative;
2078
2079    ComputeClassParameters(base, strchr(base.name, '<'), null);
2080
2081    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
2082    {
2083       Class _class = derivative.data;
2084       ClassType type = _class.type;
2085       ClassType oldType = type;
2086       int size = _class.structSize - _class.offset;
2087       int oldSizeClass = _class.sizeClass;
2088       int sizeClass = _class.sizeClass - _class.offsetClass;
2089       Class enumBase = null;
2090       const char * dataTypeString = null;
2091       // NOTE: baseClass is class(class)
2092       Class baseClass;
2093       uint offsetBefore = _class.offset;
2094
2095       int offsetClass, totalSizeClass;
2096
2097       for(baseClass = base; baseClass.base; baseClass = baseClass.base);
2098
2099       if(base && !base.internalDecl && (base.type == noHeadClass || base.type == structClass || base.type == normalClass))
2100       {
2101          // Normal classes inheriting off simple classes should become no head classes
2102          if(base.type == structClass && type == normalClass)
2103             type = noHeadClass;
2104          else
2105             type = base.type;
2106       }
2107       if(base && (_class.type == normalClass || _class.type == noHeadClass || _class.type == structClass) &&
2108          (base.type == unitClass || base.type == bitClass || base.type == enumClass))
2109       {
2110          type = base.type;
2111       }
2112
2113       if(type == enumClass)
2114       {
2115          if(base.type != enumClass)
2116          {
2117             enumBase = base;
2118             base = eSystem_FindClass(_class.module, "enum");
2119          }
2120       }
2121
2122       dataTypeString = enumBase ? enumBase.dataTypeString : base.dataTypeString;
2123
2124       /////////////////////
2125
2126       offsetClass = base ? (base.templateClass ? base.templateClass.sizeClass : base.sizeClass) : (type == noHeadClass ? 0 : 0 /*sizeof(class Class)*/);
2127       totalSizeClass = offsetClass + sizeClass;
2128
2129       // TESTING WITHOUT THIS... Seems to yield better results, as it otherwise prevents ComputeClassMembers from doing its job on derived classes
2130
2131       // _class.memberID = _class.startMemberID = (base && (type == normalClass || type == noHeadClass || type == structClass)) ? base.memberID : 0;
2132
2133       if(type == normalClass || type == noHeadClass)
2134       {
2135          // Use 'memberOffset' for nohead class as the members get added without padding
2136          _class.offset = (base && (base.templateClass ? (type == normalClass ? base.templateClass.structSize : base.templateClass.memberOffset) : (type == normalClass ? base.structSize : base.memberOffset)) && base.type != systemClass) ? (base.templateClass ? base.templateClass.structSize : base.structSize) : ((type == noHeadClass) ? 0 : sizeof(class Instance));
2137          if(_class.structAlignment && (_class.offset % _class.structAlignment))
2138             _class.offset += _class.structAlignment - _class.offset % _class.structAlignment;
2139       }
2140       else
2141          _class.offset = 0; // Force set to 0
2142
2143       if(type == structClass)
2144       {
2145          _class.memberOffset = (base && (base.templateClass ? base.templateClass.structSize : base.structSize) && base.type != systemClass) ? (base.templateClass ? base.templateClass.structSize : base.structSize) : 0;
2146          // THIS IS NEW...
2147          _class.typeSize = _class.structSize = _class.memberOffset + size;
2148       }
2149       else if(type == bitClass || type == enumClass || type == unitClass)
2150       {
2151          Class dataTypeClass = eSystem_FindClass(_class.module, dataTypeString);
2152          if(dataTypeClass)
2153             _class.typeSize = dataTypeClass.typeSize;
2154          _class.structSize = 0;
2155       }
2156       else if(type == normalClass || type == noHeadClass)
2157       {
2158          _class.structSize = _class.offset + size;
2159           _class.typeSize = sizeof(void *);
2160       }
2161
2162       /////////////////////
2163
2164       if(_class.type != systemClass)
2165          _class.type = type;
2166       delete (void *)_class.dataTypeString;
2167       _class.dataTypeString = CopyString(dataTypeString);
2168
2169       if(totalSizeClass != oldSizeClass)
2170       {
2171          _class.data = renew _class.data byte[totalSizeClass];
2172          /*
2173          memmove((byte *)_class.data + offsetClass, (byte *)_class.data + _class.offsetClass, _class.sizeClass - _class.offsetClass);
2174          if(base.type != systemClass && base.type != enumClass)
2175             memcpy((byte *)_class.data + _class.offsetClass, (byte *)base.data + _class.offsetClass, totalSizeClass - _class.sizeClass);
2176          else
2177             memset((byte *)_class.data + _class.offsetClass, 0, totalSizeClass - _class.sizeClass);
2178          */
2179          memmove((byte *)_class.data + mod.offsetClass, (byte *)_class.data, totalSizeClass - mod.sizeClass);
2180          if(base.type != systemClass && base.type != enumClass)
2181             memcpy((byte *)_class.data, (byte *)base.data, totalSizeClass - _class.sizeClass);
2182          else
2183             memset((byte *)_class.data, 0, totalSizeClass - _class.sizeClass);
2184       }
2185
2186       _class.offsetClass = offsetClass;
2187       _class.sizeClass = totalSizeClass;
2188
2189       {
2190          Method method, next;
2191          Class b;
2192          bool needUpdate = (mod != (base.templateClass ? base.templateClass : base) || _class.vTblSize != mod.vTblSize);
2193          int updateStart = -1, updateEnd = -1;
2194
2195          if(mod.base && mod.base.base && mod.base.vTblSize > baseClass.vTblSize && needUpdate)
2196          {
2197             _class.vTblSize += mod.base.vTblSize - baseClass.vTblSize;
2198             _class._vTbl = renew _class._vTbl void *[_class.vTblSize];
2199             // memmove(_class._vTbl + mod.base.vTblSize, _class._vTbl + baseClass.vTblSize, (mod.base.vTblSize - baseClass.vTblSize) * sizeof(void *));
2200             memmove(_class._vTbl + mod.base.vTblSize, _class._vTbl + baseClass.vTblSize, (_class.vTblSize - mod.vTblSize) * sizeof(void *));
2201             memcpy(_class._vTbl + baseClass.vTblSize, mod._vTbl + baseClass.vTblSize, (mod.base.vTblSize - baseClass.vTblSize) * sizeof(void *));
2202
2203             updateStart = baseClass.vTblSize;
2204             updateEnd = updateStart + mod.base.vTblSize - baseClass.vTblSize;
2205
2206             for(method = (Method)_class.methods.first; method; method = next)
2207             {
2208                next = (Method)((BTNode)method).next;
2209                if(method.type == virtualMethod)
2210                   method.vid += mod.base.vTblSize - baseClass.vTblSize;
2211             }
2212          }
2213
2214             for(b = mod.base; b && b != null; b = b.base)
2215             {
2216                Method vMethod;
2217                for(vMethod = (Method)b.methods.first; vMethod; vMethod = (Method)((BTNode)vMethod).next)
2218                {
2219                   if(vMethod.type == virtualMethod)
2220                   {
2221                      method = (Method)_class.methods.FindString(vMethod.name);
2222                      if(method)
2223                      {
2224                         if(method.function) _class._vTbl[vMethod.vid] = method.function;
2225                         if(!method.symbol)
2226                         {
2227                            delete (void *)method.name;
2228                            delete (void *)method.dataTypeString;
2229                            _class.methods.Delete((BTNode)method);
2230                         }
2231                         else
2232                         {
2233                            delete (void *)method.dataTypeString;
2234                            method.type = vMethod.type;
2235                            method.dataTypeString = CopyString(vMethod.dataTypeString);
2236                            method._class = vMethod._class;
2237                         }
2238                      }
2239                      else if((vMethod.vid >= updateStart && vMethod.vid < updateEnd ) || _class._vTbl[vMethod.vid] == b._vTbl[vMethod.vid])
2240                         _class._vTbl[vMethod.vid] = _class.base._vTbl[vMethod.vid];
2241                   }
2242                }
2243             }
2244          //}
2245
2246          // Trying to simply move out the above block of code outside the if to handle this
2247          /*
2248          // Also doing this now, otherwise overridden methods of base classes from intermediate classes will not be set in higher level class
2249          // (e.g. OnGetString overridden in Id , Location inheriting from Id, LocationAbbreviation created later inheriting from Location would not get Id's OnGetString)
2250          for(b = mod.base; b && b != null; b = b.base)
2251          {
2252             Method vMethod;
2253             for(vMethod = (Method)b.methods.first; vMethod; vMethod = (Method)((BTNode)vMethod).next)
2254             {
2255                if(vMethod.type == virtualMethod)
2256                {
2257                   if(_class._vTbl[vMethod.vid] == b._vTbl[vMethod.vid] && _class._vTbl[vMethod.vid] != _class.base._vTbl[vMethod.vid])
2258                      _class._vTbl[vMethod.vid] = _class.base._vTbl[vMethod.vid];
2259                }
2260             }
2261          }
2262          */
2263       }
2264
2265       // _class.defaultAlignment = base ? base.defaultAlignment : 0;
2266
2267       if(type == normalClass || type == noHeadClass || type == structClass)
2268       {
2269          Property prop;
2270          DataMember member;
2271          Class c;
2272          for(c = mod.base; c; c = c.base)
2273          {
2274             Property _property;
2275             for(_property = c.membersAndProperties.first; _property; _property = _property.next)
2276             {
2277                if(_property.isProperty)
2278                {
2279                   BTNamedLink link = (BTNamedLink)_class.prop.FindString(_property.name);
2280                   if(link)
2281                   {
2282                      prop = link.data;
2283                      if(!prop.Set && !prop.Get && prop.memberAccess == baseSystemAccess)
2284                      {
2285                         SelfWatcher watcher;
2286                         for(watcher = _class.selfWatchers.first; watcher; watcher = watcher.next)
2287                         {
2288                            if(watcher._property == prop)
2289                               watcher._property = _property;
2290                         }
2291                         _property.selfWatchable = true;
2292                         _class.prop.Delete((BTNode)link);
2293                         delete (void *)prop.name;
2294                         delete (void *)prop.dataTypeString;
2295                         _class.membersAndProperties.Delete(prop);    // Remove only was done before?
2296                      }
2297                   }
2298                }
2299             }
2300          }
2301          // if(mod.base.memberID)
2302          {
2303             DataMember next;
2304             for(member = _class.membersAndProperties.first; member; member = next)
2305             {
2306                int offsetDiff = _class.offset - offsetBefore;
2307                next = member.next;
2308                if(!member.isProperty)
2309                {
2310                   if(oldType == bitClass && type != bitClass)
2311                   {
2312                      DataMember prev = member.prev;
2313                      // Correcting a bitClass to be a non-bit class (This should really never be required)
2314                      _class.membersAndProperties.Remove(member);
2315                      member = (DataMember)renew0 member byte[sizeof (class DataMember)];
2316                      _class.membersAndProperties.Insert(prev, member);
2317                   }
2318
2319                   if(offsetDiff > 0)
2320                   {
2321                      member.offset += offsetDiff;
2322                      member.memberOffset += offsetDiff;
2323                   }
2324                }
2325                member.id += mod.base.memberID;
2326             }
2327
2328             _class.memberID += mod.base.memberID;
2329             _class.startMemberID += mod.base.memberID;
2330          }
2331       }
2332       // Moved this before to ensure CPValues have their data ready
2333       FixDerivativesBase(_class, mod);
2334       {
2335          Class c;
2336          for(c = mod.base; c; c = c.base)
2337          {
2338             ClassProperty _property;
2339             for(_property = (ClassProperty)c.classProperties.first; _property; _property = (ClassProperty)((BTNode)_property).next)
2340             {
2341                SetDelayedCPValues(_class, _property);
2342             }
2343          }
2344       }
2345    }
2346
2347    {
2348       OldLink templateLink;
2349       for(templateLink = base.templatized.first; templateLink; templateLink = templateLink.next)
2350       {
2351          Class template = templateLink.data;
2352          //const char * templateParams = strchr(template.name, '<');
2353          template.base = base.base;
2354          template._vTbl = base._vTbl;
2355          //ComputeClassParameters(template, templateParams, null);
2356
2357          template.data = base.data;
2358          template.offset = base.offset;
2359          template.offsetClass = base.offsetClass;
2360          template.sizeClass = base.sizeClass;
2361          template.structSize = base.structSize;
2362          template.vTblSize = base.vTblSize;
2363
2364          FixDerivativesBase(template, mod);
2365       }
2366    }
2367 }
2368
2369 public dllexport Class eSystem_RegisterClass(ClassType type, const char * name, const char * baseName, int size, int sizeClass,
2370                              bool (* Constructor)(void *), void (* Destructor)(void *),
2371                              Module module, AccessMode declMode, AccessMode inheritanceAccess)
2372 {
2373    int start = 0, c;
2374    NameSpace * nameSpace = null;
2375    bool force64Bits = (module.application.isGUIApp & 2) ? true : false;
2376    bool force32Bits = (module.application.isGUIApp & 4) ? true : false;
2377    bool inCompiler = (module.application.isGUIApp & 8) ? true : false;
2378    bool crossBits = force32Bits || force64Bits;
2379    bool fixed = false;
2380    if(inCompiler && crossBits)
2381    {
2382       Class c = eSystem_FindClass(__thisModule.application, name);
2383       if(c && c.fixed)
2384          fixed = true;
2385       else if(__thisModule.name && !strcmp(__thisModule.name, "ecereCOM"))
2386          fixed = true;
2387    }
2388
2389    {
2390       nameSpace = (declMode == publicAccess) ? &module.publicNameSpace : &module.privateNameSpace;
2391       if(declMode == baseSystemAccess) nameSpace = &module.application.systemNameSpace;
2392
2393       // if(declMode != staticAccess)
2394       {
2395          for(c = 0; name[c]; c++)
2396          {
2397             if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
2398             {
2399                NameSpace * newSpace;
2400
2401                char * spaceName = _malloc(c - start + 1);
2402                strncpy(spaceName, name + start, c - start);
2403                spaceName[c-start] = '\0';
2404
2405                newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
2406                if(!newSpace)
2407                {
2408                   newSpace = new0 NameSpace[1];
2409                   newSpace->classes.CompareKey = (void *)BinaryTree::CompareString;
2410                   newSpace->defines.CompareKey = (void *)BinaryTree::CompareString;
2411                   newSpace->functions.CompareKey = (void *)BinaryTree::CompareString;
2412                   newSpace->nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
2413                   newSpace->name = spaceName;
2414                   newSpace->parent = nameSpace;
2415                   nameSpace->nameSpaces.Add((BTNode)newSpace);
2416                }
2417                else
2418                   delete spaceName;
2419                nameSpace = newSpace;
2420                if(name[c] == ':') c++;
2421                start = c+1;
2422             }
2423          }
2424       }
2425       /*else
2426          c = strlen(name);*/
2427    }
2428
2429    if(c - start)
2430    {
2431       int offsetClass;
2432       int totalSizeClass;
2433       BTNamedLink classLink = null;
2434       Class _class = null;
2435       const char * dataTypeString = null;
2436       Class enumBase = null;
2437       Class base = (baseName && baseName[0]) ? eSystem_FindClass(module, baseName) : null;
2438       Class prevBase = null;
2439
2440       if(base && !base.internalDecl && (base.type == noHeadClass || base.type == structClass || base.type == normalClass))
2441       {
2442          // Normal classes inheriting off simple classes should become no head classes
2443          if(base.type == structClass && type == normalClass)
2444             type = noHeadClass;
2445          else
2446             type = base.type;
2447       }
2448       if(base && (type == normalClass || type == noHeadClass || type == structClass) &&
2449          (base.type == unitClass || base.type == bitClass || base.type == enumClass))
2450       {
2451          type = base.type;
2452       }
2453       if(!base || base.type == systemClass || base.isInstanceClass)
2454       {
2455          if(type == enumClass)
2456          {
2457             // TO IMPROVE:
2458             if(base || !baseName || !baseName[0] ||
2459                !strcmp(baseName, "unsigned int") ||
2460                !strcmp(baseName, "uint") ||
2461                !strcmp(baseName, "unsigned int64") ||
2462                !strcmp(baseName, "uint64") ||
2463                !strcmp(baseName, "int64") ||
2464                !strcmp(baseName, "unsigned short") ||
2465                !strcmp(baseName, "short") ||
2466                !strcmp(baseName, "unsigned char") ||
2467                !strcmp(baseName, "byte") ||
2468                !strcmp(baseName, "char") ||
2469                !strcmp(baseName, "uint32") ||
2470                !strcmp(baseName, "uint16"))
2471             {
2472                base = eSystem_FindClass(module, "enum");
2473                dataTypeString = (baseName && baseName[0]) ? baseName : "int"; //"unsigned int";
2474             }
2475             else
2476             {
2477                // Undefined base
2478                base = eSystem_RegisterClass(0, baseName, null, 0,0, null, null, module, declMode, publicAccess);
2479                base.internalDecl = true;
2480
2481                enumBase = base;
2482                base = eSystem_FindClass(module, "enum");
2483                //dataTypeString = (baseName && baseName[0]) ? baseName : "unsigned int";
2484             }
2485          }
2486          else if(type == structClass && (!baseName || !baseName[0]))
2487          {
2488             base = eSystem_FindClass(module, "struct");
2489             dataTypeString = name + start;
2490          }
2491          else
2492          {
2493             if(type == normalClass)
2494                // dataTypeString = "struct Instance";
2495                dataTypeString = "struct __ecereNameSpace__ecere__com__Instance";
2496             else if(type == noHeadClass)
2497                dataTypeString = "void *";
2498             else if(type == bitClass)
2499                dataTypeString = (baseName && baseName[0]) ? baseName : "unsigned int";
2500             else if(type == unitClass)
2501                dataTypeString = (baseName && baseName[0]) ? baseName : "int";
2502             else if(type == structClass)
2503                dataTypeString = name + start;
2504
2505             // TODO: base bit, unit or enum classes not defined yet
2506             if(base || (!baseName || !baseName[0]) || type == bitClass || type == unitClass)
2507             {
2508                // DANGEROUSLY TESTING THIS... PUT IT BACK
2509                //if(!base)
2510                if(base || !baseName || !baseName[0] ||
2511                   !strcmp(baseName, "unsigned int") ||
2512                   !strcmp(baseName, "uint") ||
2513                   !strcmp(baseName, "unsigned int64") ||
2514                   !strcmp(baseName, "uint64") ||
2515                   !strcmp(baseName, "int64") ||
2516                   !strcmp(baseName, "unsigned short") ||
2517                   !strcmp(baseName, "short") ||
2518                   !strcmp(baseName, "unsigned char") ||
2519                   !strcmp(baseName, "byte") ||
2520                   !strcmp(baseName, "char") ||
2521                   !strcmp(baseName, "uint32") ||
2522                   !strcmp(baseName, "uint16"))
2523                {
2524                   if(type == normalClass && strcmp(name, "ecere::com::Instance") && strcmp(name, "enum") && strcmp(name, "struct"))
2525                      base = eSystem_FindClass(module, "ecere::com::Instance");
2526                   else
2527                      base = eSystem_FindClass(module, "class");
2528                }
2529             }
2530             else
2531             {
2532                // Base class has not been defined yet!
2533             }
2534          }
2535       }
2536       else
2537       {
2538          if(type == enumClass)
2539          {
2540             if(base.type != enumClass)
2541             {
2542                enumBase = base;
2543                base = eSystem_FindClass(module, "enum");
2544             }
2545          }
2546          dataTypeString = enumBase ? enumBase.dataTypeString : base.dataTypeString;
2547       }
2548
2549       offsetClass = base ? base.sizeClass : (type == noHeadClass ? 0 : 0 /*sizeof(class Class)*/);
2550       totalSizeClass = offsetClass + sizeClass;
2551
2552       _class = eSystem_FindClass(module, name);
2553       if(!_class)
2554       {
2555          const char * colons = RSearchString(name, "::", strlen(name), true, false);
2556          if(colons && colons)
2557          {
2558             _class = eSystem_FindClass(module, colons + 2);
2559             if(_class)
2560             {
2561                if(_class.internalDecl)
2562                {
2563                   delete (void *)_class.fullName;
2564                   _class.fullName = CopyString(name);
2565                }
2566                else
2567                   _class = null;
2568             }
2569          }
2570       }
2571       if(_class)
2572       {
2573          if(!_class.internalDecl)
2574          {
2575             if(declMode != baseSystemAccess)
2576                // i18n in instance.ec is more trouble than it's worth.
2577                printf("error: Redefinition of class %s\n", name);
2578             else
2579             {
2580                _class.comRedefinition = true;
2581                return _class;
2582             }
2583             return null;
2584          }
2585
2586          FreeTemplatesDerivatives(_class);
2587
2588          classLink = (BTNamedLink)_class.nameSpace->classes.FindString(name + start);
2589          _class.nameSpace->classes.Delete((BTNode)classLink);
2590          {
2591             OldLink t;
2592             for(t = _class.templatized.first; t; t = t.next)
2593             {
2594                Class template = t.data;
2595                classLink = (BTNamedLink)_class.nameSpace->classes.FindString(template.name);
2596
2597                _class.nameSpace->classes.Delete((BTNode)classLink);
2598             }
2599          }
2600          {
2601             NameSpace * ns = _class.nameSpace;
2602             while(ns != nameSpace &&
2603                ns->parent &&
2604                !ns->classes.first &&
2605                !ns->functions.first &&
2606                !ns->defines.first &&
2607                !ns->nameSpaces.first)
2608             {
2609                NameSpace * parent = ns->parent;
2610                NameSpace_Free(ns);
2611                parent->nameSpaces.Delete((BTNode)ns);
2612                ns = parent;
2613             }
2614          }
2615       }
2616       else
2617       {
2618          classLink = SearchNameSpace(module.application.privateNameSpace, name, &((NameSpace *)0)->classes);
2619          if(!classLink)
2620             classLink = SearchNameSpace(module.application.publicNameSpace, name, &((NameSpace *)0)->classes);
2621
2622          if(!classLink)
2623             classLink = SearchNameSpace(module.application.privateNameSpace, name + start, &((NameSpace *)0)->classes);
2624          if(!classLink)
2625             classLink = SearchNameSpace(module.application.publicNameSpace, name + start, &((NameSpace *)0)->classes);
2626
2627          if(classLink)
2628             _class = classLink.data;
2629          if(_class && _class.internalDecl)
2630          {
2631             FreeTemplatesDerivatives(_class);
2632
2633             _class.nameSpace->classes.Delete((BTNode)classLink);
2634             {
2635                OldLink t;
2636                for(t = _class.templatized.first; t; t = t.next)
2637                {
2638                   Class template = t.data;
2639                   classLink = (BTNamedLink)_class.nameSpace->classes.FindString(template.name);
2640                   _class.nameSpace->classes.Delete((BTNode)classLink);
2641
2642                }
2643             }
2644
2645             delete (void *)_class.fullName;
2646             _class.fullName = CopyString(name);
2647          }
2648          else
2649          {
2650             _class = _calloc(1, sizeof(class Class));
2651             _class.methods.CompareKey = (void *)BinaryTree::CompareString;
2652             _class.members.CompareKey = (void *)BinaryTree::CompareString;
2653             _class.prop.CompareKey = (void *)BinaryTree::CompareString;
2654             _class.classProperties.CompareKey = (void *)BinaryTree::CompareString;
2655
2656             _class.name = CopyString(name + start);
2657             _class.fullName = CopyString(name);
2658          }
2659       }
2660       if(nameSpace)
2661       {
2662          nameSpace->classes.Add((BTNode)BTNamedLink { name = (char *)_class.name, data = _class });
2663          {
2664             OldLink t;
2665             for(t = _class.templatized.first; t; t = t.next)
2666             {
2667                Class template = t.data;
2668                nameSpace->classes.Add((BTNode)BTNamedLink { name = (char *)template.name, data = template });
2669             }
2670          }
2671
2672       }
2673
2674       if(_class)
2675       {
2676          if(!base && baseName && strcmp(baseName, name))
2677          {
2678             // Undefined base
2679             if(strchr(baseName, '<'))
2680             {
2681                char templateClassName[1024];
2682                Class templateBase;
2683                strcpy(templateClassName, baseName);
2684                *strchr(templateClassName, '<') = '\0';
2685                templateBase = eSystem_FindClass(module, templateClassName);
2686                if(!templateBase)
2687                {
2688                   templateBase = eSystem_RegisterClass(0, templateClassName, null, 0,0, null, null, module, declMode, publicAccess);
2689                   templateBase.internalDecl = true;
2690                }
2691                base = eSystem_FindClass(module, baseName);
2692             }
2693             else
2694             {
2695                base = eSystem_RegisterClass(0, baseName, null, 0,0, null, null, module, declMode, publicAccess);
2696                base.internalDecl = true;
2697             }
2698             /*
2699             base.size = 0;
2700             base.offset = 0;
2701             base.memberOffset = 0;
2702             */
2703          }
2704          else
2705             _class.internalDecl = false;
2706
2707          if(totalSizeClass)
2708          {
2709             _class.data = renew _class.data byte[totalSizeClass];
2710             // Class Data is often not inherited... e.g. Window::pureVtbl problem
2711             // memset(_class.data, 0, totalSizeClass);
2712             if(base && base.type != systemClass && base.type != enumClass)
2713                memcpy(_class.data, base.data, offsetClass);
2714             else
2715                memset(_class.data, 0, offsetClass);
2716             memset((byte *)_class.data + offsetClass, 0, sizeClass);
2717          }
2718
2719          delete (void *)_class.dataTypeString;
2720          _class.dataTypeString = CopyString(dataTypeString);
2721          _class.defaultAlignment = base ? base.defaultAlignment : 0;
2722
2723          // Dereference the class in previous module the classed belonged to
2724          if(_class.module)
2725          {
2726             _class.module.classes.Remove(_class);
2727          }
2728
2729          if(_class.base)
2730          {
2731             //Class base = _class.base.templateClass ? _class.base.templateClass : _class.base;
2732             Class base = _class.base;
2733             OldLink deriv = base.derivatives.FindLink(_class);
2734             base.derivatives.Delete(deriv);
2735          }
2736
2737          // Reference the class in the module
2738          if(module)
2739          {
2740             module.classes.Add(_class);
2741          }
2742
2743          _class.nameSpace = nameSpace;
2744          {
2745             OldLink t;
2746             for(t = _class.templatized.first; t; t = t.next)
2747             {
2748                Class template = t.data;
2749                template.nameSpace = nameSpace;
2750             }
2751          }
2752
2753          _class.module = module;
2754          prevBase = _class.base;
2755          _class.base = base;
2756          if(base)
2757          {
2758             int numParams = 0;
2759             Class sClass;
2760             for(sClass = base; sClass; sClass = sClass.base)
2761             {
2762                if(sClass.templateClass) sClass = sClass.templateClass;
2763                numParams += sClass.templateParams.count;
2764             }
2765             if(numParams)
2766             {
2767                if(_class.templateArgs)
2768                {
2769                   FreeTemplateArgs(_class);
2770                }
2771                delete _class.templateArgs;
2772                _class.templateArgs = new0 ClassTemplateArgument[numParams];
2773                _class.numParams = numParams;
2774
2775                for(sClass = _class; sClass; sClass = sClass.base)
2776                {
2777                   Class prevClass;
2778                   ClassTemplateParameter param;
2779                   int id = 0;
2780                   if(sClass.templateClass) sClass = sClass.templateClass;
2781                   for(prevClass = sClass.base; prevClass; prevClass = prevClass.base)
2782                   {
2783                      if(prevClass.templateClass) prevClass = prevClass.templateClass;
2784                      id += prevClass.templateParams.count;
2785                   }
2786
2787                   if(base.templateArgs)   // Add numParams test here?
2788                   {
2789                      for(param = sClass.templateParams.first; param; param = param.next)
2790                      {
2791                         _class.templateArgs[id] = base.templateArgs[id];
2792                         CopyTemplateArg(param, _class.templateArgs[id]);
2793                         id++;
2794                      }
2795                   }
2796                }
2797             }
2798          }
2799          _class.memberID = _class.startMemberID = (base && (type == normalClass || type == noHeadClass || type == structClass)) ? base.memberID : 0;
2800          if(type == normalClass || type == noHeadClass)
2801             _class.offset = (base && base.structSize && base.type != systemClass) ?
2802                // Use 'memberOffset' for nohead class as the members get added without padding
2803                (base.type == normalClass ? base.structSize : base.memberOffset) : ((type == noHeadClass) ? 0 : ((force64Bits && inCompiler && fixed) ? 24 : (force32Bits && inCompiler && fixed) ? 12 : sizeof(class Instance)));
2804          else
2805             _class.offset = 0;   // Force set to 0 for redefinitions
2806
2807          // For cross-bitness-compiling
2808          if(crossBits)
2809          {
2810             // The GNOSIS runtime will use 'offset' to point to the object during compile executation
2811             // Need to rethink through our cross-bitness compiling to have a distinct 'offset' (e.g. runtimeOffset)
2812             // used by the runtime library vs. 'offset' used by the compiler to hardcode compilation results (or avoid those altogether)
2813             if(!strcmp(name, "GNOSISSystem") ||
2814                !strcmp(name, "LineStyle") ||
2815                !strcmp(name, "FillStyle") ||
2816                !strcmp(name, "FontObject") ||
2817                !strcmp(name, "FontObject") ||
2818                !strcmp(name, "ecere::sys::Thread"))
2819             {
2820                _class.offset = force32Bits ? 24 : 12;
2821             }
2822             // Ideally, the running library should be aware of the struct size of both 32 and 64 bit, since the compiler has no knowledge whatsoever of private members
2823             else if(strstr(name, "ecere::sys::EARHeader") ||
2824                strstr(name, "AnchorValue") ||
2825                !strcmp(name, "ecere::com::CustomAVLTree") ||
2826                !strcmp(name, "ecere::com::Array") ||
2827                !strcmp(name, "ecere::gui::Window") ||
2828                !strcmp(name, "ecere::sys::Mutex"));   // Never recompute these, they're always problematic (errors, crashes)
2829             else
2830             {
2831                if(!strcmp(name, "ecere::sys::FileListing"))
2832                {
2833                   size = 3*(force32Bits ? 4 : 8);
2834                   _class.structAlignment = force32Bits ? 4 : 8;   // FileListing is problematic because it is a struct with private data that the user allocates
2835                   _class.pointerAlignment = 1;
2836                }
2837                // These we want to recompute inside the IDE to help the debugger
2838                else if(!strcmp(name, "ecere::com::Class"))           size = 0; // 616
2839                else if(!strcmp(name, "ecere::com::ClassProperty"))   size = 0; // 80
2840                else if(!strcmp(name, "ecere::com::NameSpace"))       size = 0; // 176
2841                else if(!strcmp(name, "ecere::sys::BufferedFile"))    size = 0;
2842                else if(!strcmp(name, "ecere::sys::BTNode"))          size = 0;
2843                else if(!strcmp(name, "ecere::sys::StringBTNode"))    size = 0;
2844                else if(!strcmp(name, "ecere::sys::OldList"))         size = 0; // 32
2845                else if(!strcmp(name, "ecere::sys::Item"))            size = 0;
2846                else if(!strcmp(name, "ecere::sys::NamedLink"))       size = 0;
2847                else if(!strcmp(name, "ecere::sys::NamedLink64"))     size = 0;
2848                else if(!strcmp(name, "ecere::sys::OldLink"))         size = 0;
2849                else if(!strcmp(name, "ecere::sys::NamedItem"))       size = 0;
2850                else if(!strcmp(name, "ecere::sys::NamedItem64"))     size = 0;
2851                else if(!strcmp(name, "ecere::sys::BinaryTree"))      size = 0;
2852                else if(module != module.application && inCompiler)
2853                {
2854                   // These we only want to recompute inside the compiler
2855                   if(fixed || type == structClass)
2856                      size = 0;
2857                }
2858             }
2859          }
2860          if(type == structClass)
2861          {
2862             _class.memberOffset = (base && base.structSize && base.type != systemClass) ? base.structSize : 0;
2863             // THIS IS NEW...
2864             _class.typeSize = _class.structSize = _class.memberOffset + size;
2865          }
2866          else if(type == bitClass || type == enumClass || type == unitClass)
2867          {
2868             Class dataTypeClass = eSystem_FindClass(_class.module, dataTypeString);
2869             if(dataTypeClass)
2870                _class.typeSize = dataTypeClass.typeSize;
2871             _class.structSize = 0;
2872          }
2873          else if(type == normalClass || type == noHeadClass)
2874          {
2875             _class.structSize = _class.offset + size;
2876             _class.typeSize = sizeof(void *);
2877          }
2878          _class.offsetClass = offsetClass;
2879          _class.sizeClass = totalSizeClass;
2880          _class.Constructor = Constructor;
2881          _class.Destructor = Destructor;
2882          if(_class.type != systemClass)
2883             _class.type = type;
2884          if(!size)
2885             _class.computeSize = true;
2886          else
2887             _class.computeSize = false;
2888          _class.inheritanceAccess = inheritanceAccess;
2889
2890          /*if(type == bitClass)
2891             _class.size = 0;*/
2892          if(type == enumClass)
2893          {
2894             if(enumBase)
2895                _class.base = base = enumBase;
2896             //else
2897             {
2898                EnumClassData data = (EnumClassData)_class.data;
2899                // TOCHECK: Trying this (if specifiers specified, no class found...)
2900                // What about bit classes, unit classes...
2901                if(base && base.type != enumClass)
2902                   data.largest = -1;//_class.base = null;
2903                else
2904                   data.largest = ((EnumClassData)(base.data)).largest;
2905             }
2906          }
2907          if(base)
2908          {
2909             int i;
2910             uint oldSize = _class.vTblSize;
2911             if(base.vTblSize && _class.vTblSize < base.vTblSize)
2912             {
2913                _class.vTblSize = base.vTblSize;
2914                // OK to scrap existing virtual table?
2915                //delete _class._vTbl;
2916                //_class._vTbl = _malloc(sizeof(int(*)()) * _class.vTblSize);
2917                // memcpy(_class._vTbl, base._vTbl, sizeof(int(*)()) * _class.vTblSize);
2918                _class._vTbl = _realloc(_class._vTbl, sizeof(int(*)()) * _class.vTblSize);
2919             }
2920             if(!prevBase)
2921             {
2922                if(_class.type == normalClass && strcmp(_class.name, "ecere::com::Instance") && strcmp(_class.name, "enum") && strcmp(_class.name, "struct"))
2923                   prevBase = eSystem_FindClass(module, "ecere::com::Instance");
2924                else
2925                   prevBase = eSystem_FindClass(module, "class");
2926             }
2927             for(i = 0; i < base.vTblSize; i++)
2928             {
2929                if(i >= oldSize || _class._vTbl[i] == prevBase._vTbl[i])
2930                   _class._vTbl[i] = base._vTbl[i];
2931             }
2932          }
2933
2934          if(_class.base)
2935          {
2936             OldLink link { data = _class };
2937             /*(_class.base.templateClass ? _class.base.templateClass : _class.base)*/_class.base.derivatives.Add(link);
2938          }
2939
2940          FixDerivativesBase(_class, _class);
2941
2942          return _class;
2943       }
2944    }
2945    return null;
2946 }
2947
2948 static void DataMember_Free(DataMember parentMember)
2949 {
2950    DataMember member;
2951    BTNamedLink namedLink;
2952    delete (void *)parentMember.name;
2953    delete (void *)parentMember.dataTypeString;
2954
2955    while((member = parentMember.members.first))
2956    {
2957       DataMember_Free(member);
2958       parentMember.members.Delete(member);
2959    }
2960
2961    while((namedLink = (BTNamedLink)parentMember.membersAlpha.first))
2962    {
2963       parentMember.membersAlpha.Delete((BTNode)namedLink);
2964    }
2965 }
2966
2967 static void FreeEnumValue(NamedLink64 value)
2968 {
2969    delete value.name;
2970 }
2971
2972 static void FreeTemplateArg(Class template, ClassTemplateParameter param, int id)
2973 {
2974    switch(param.type)
2975    {
2976       case type:
2977          delete (void *)template.templateArgs[id].dataTypeString;
2978          template.templateArgs[id].dataTypeClass = null;
2979          break;
2980       case identifier:
2981          delete (void *)template.templateArgs[id].memberString;
2982          break;
2983       case expression:
2984
2985          break;
2986    }
2987 }
2988
2989 static void FreeTemplateArgs(Class template)
2990 {
2991    if(template.templateArgs)
2992    {
2993       Class _class;
2994       for(_class = template; _class; _class = _class.base)
2995       {
2996          Class prevClass;
2997          ClassTemplateParameter param;
2998          int id = 0;
2999          if(_class.templateClass) _class = _class.templateClass;
3000          for(prevClass = _class.base; prevClass; prevClass = prevClass.base)
3001          {
3002             if(prevClass.templateClass) prevClass = prevClass.templateClass;
3003             id += prevClass.templateParams.count;
3004          }
3005          if(id < template.numParams)
3006          {
3007             for(param = _class.templateParams.first; param; param = param.next)
3008             {
3009                switch(param.type)
3010                {
3011                   case type:
3012                      delete (void *)template.templateArgs[id].dataTypeString;
3013                      template.templateArgs[id].dataTypeClass = null;
3014                      break;
3015                   case identifier:
3016                      delete (void *)template.templateArgs[id].memberString;
3017                      break;
3018                   case expression:
3019                      // delete template.templateArgs[id].dataTypeString;
3020                      break;
3021                }
3022                id++;
3023             }
3024          }
3025       }
3026    }
3027 }
3028
3029 static void FreeTemplate(Class template)
3030 {
3031    OldLink deriv;
3032
3033    if(template.nameSpace)
3034    {
3035       BTNamedLink link = (BTNamedLink)template.nameSpace->classes.FindString(template.name);
3036       if(link)
3037          template.nameSpace->classes.Delete((BTNode)link);
3038    }
3039
3040    FreeTemplatesDerivatives(template);
3041    FreeTemplateArgs(template);
3042
3043    while((deriv = template.derivatives.first))
3044    {
3045       ((Class)deriv.data).base = null;
3046       template.derivatives.Delete(deriv);
3047    }
3048
3049    delete (void *)template.fullName;
3050    delete (void *)template.name;
3051    delete template.templateArgs;
3052    delete (void *)template.dataTypeString;
3053
3054    if(template.module)
3055       template.module.classes.Delete(template);
3056    else
3057       _free(template);
3058 }
3059
3060 static void FreeTemplates(Class _class)
3061 {
3062    OldLink deriv, template;
3063
3064    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
3065    {
3066       FreeTemplates(deriv.data);
3067    }
3068
3069    FreeTemplateArgs(_class);
3070    delete _class.templateArgs;
3071    delete (void *)_class.dataTypeString;
3072
3073    while((template = _class.templatized.first))
3074    {
3075       FreeTemplates(template.data);
3076       FreeTemplate(template.data);
3077       _class.templatized.Delete(template);
3078    }
3079 }
3080
3081 public dllexport void eClass_Unregister(Class _class)
3082 {
3083    BTNamedLink namedLink;
3084    DataMember member;
3085    Method method;
3086    OldLink deriv, template;
3087    ClassProperty classProp;
3088    ClassTemplateParameter param;
3089
3090    if(_class.templateClass)
3091    {
3092       // Unregistering templates... Used in IDE to address crash on Ecere classes templatized with imported modules
3093       OldLink templateLink;
3094       for(templateLink = _class.templateClass.templatized.first; templateLink; templateLink = templateLink.next)
3095       {
3096          if(templateLink.data == _class)
3097          {
3098             _class.templateClass.templatized.Delete(templateLink);
3099             break;
3100          }
3101       }
3102       FreeTemplate(_class);
3103       return;
3104    }
3105
3106    delete _class._vTbl;
3107
3108    FreeTemplates(_class);
3109
3110    while((template = _class.templatized.first))
3111    {
3112       FreeTemplate(template.data);
3113       _class.templatized.Delete(template);
3114    }
3115
3116    while((member = _class.membersAndProperties.first))
3117    {
3118       if(!member.isProperty && (member.type == unionMember || member.type == structMember))
3119          DataMember_Free(member);
3120       delete (void *)member.name;
3121       delete (void *)member.dataTypeString;
3122       _class.membersAndProperties.Delete(member);
3123    }
3124
3125    while((member = _class.conversions.first))
3126    {
3127       delete (void *)member.name;
3128       delete (void *)member.dataTypeString;
3129       _class.conversions.Delete(member);
3130    }
3131
3132    while((namedLink = (BTNamedLink)_class.prop.first))
3133    {
3134       _class.prop.Delete((BTNode)namedLink);
3135    }
3136
3137    while((namedLink = (BTNamedLink)_class.members.first))
3138    {
3139       _class.members.Delete((BTNode)namedLink);
3140    }
3141
3142    while((classProp = (ClassProperty)_class.classProperties.first))
3143    {
3144       delete (void *)classProp.name;
3145       delete (void *)classProp.dataTypeString;
3146       _class.classProperties.Delete((BTNode)classProp);
3147    }
3148
3149    while((method = (Method)_class.methods.first))
3150    {
3151       delete (void *)method.name;
3152       delete (void *)method.dataTypeString;
3153       _class.methods.Delete((BTNode)method);
3154    }
3155
3156    if(_class.type == enumClass)
3157    {
3158       EnumClassData data = (EnumClassData)_class.data;
3159
3160       data.values.Free((void *)FreeEnumValue);
3161    }
3162    _class.delayedCPValues.Free(null);
3163
3164    _class.selfWatchers.Free(null);
3165
3166    if(_class.base)
3167    {
3168       // Class base = _class.base.templateClass ? _class.base.templateClass : _class.base;
3169       Class base = _class.base;
3170       for(deriv = base.derivatives.first; deriv; deriv = deriv.next)
3171       {
3172          if(deriv.data == _class)
3173             break;
3174       }
3175       if(deriv)
3176          base.derivatives.Delete(deriv);
3177    }
3178    while((deriv = _class.derivatives.first))
3179    {
3180       ((Class)deriv.data).base = null;
3181       _class.derivatives.Delete(deriv);
3182    }
3183
3184    if(_class.nameSpace)
3185    {
3186       BTNamedLink link = (BTNamedLink)_class.nameSpace->classes.FindString(_class.name);
3187       _class.nameSpace->classes.Delete((BTNode)link);
3188    }
3189
3190    delete (void *)_class.name;
3191    delete (void *)_class.fullName;
3192
3193    delete (void *)_class.dataTypeString;
3194
3195    delete _class.data;
3196
3197    while((param = _class.templateParams.first))
3198    {
3199       switch(param.type)
3200       {
3201          case type:
3202             delete (void *)param.defaultArg.dataTypeString;
3203             break;
3204          case identifier:
3205             delete (void *)param.defaultArg.memberString;
3206             break;
3207          case expression:
3208
3209             break;
3210       }
3211       if(param.type != identifier) delete (void *)param.dataTypeString;
3212       delete (void *)param.name;
3213
3214       _class.templateParams.Delete(param);
3215    }
3216
3217    //_class.nameSpace->classes.Delete(_class);
3218    _free(_class);
3219 }
3220
3221 static BTNamedLink ScanNameSpace(NameSpace nameSpace, const char * name, void * listOffset)
3222 {
3223    BinaryTree * tree = (BinaryTree *)((byte *)nameSpace + (uintptr)listOffset);
3224    BTNamedLink link = (BTNamedLink)tree->Find((uintptr)name);
3225    NameSpace * child;
3226    if(!link)
3227    {
3228       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
3229       {
3230          link = ScanNameSpace(child, name, listOffset);
3231          if(link)
3232             break;
3233       }
3234    }
3235    return link;
3236 }
3237
3238 static BTNamedLink SearchNameSpace(NameSpace nameSpace, const char * name, void * listOffset)
3239 {
3240    int start = 0, c;
3241    char ch;
3242    int level = 0;
3243    for(c = 0; (ch = name[c]); c++)
3244    {
3245       if(ch == '<') level++;
3246       if(ch == '>') level--;
3247       if(level == 0 && (ch == '.' || (ch == ':' && name[c+1] == ':')))
3248       {
3249          NameSpace * newSpace;
3250          char * spaceName = _malloc(c - start + 1);
3251          memcpy(spaceName, name + start, c - start);
3252          spaceName[c-start] = '\0';
3253          newSpace = (NameSpace *)nameSpace.nameSpaces.FindString(spaceName);
3254          _free(spaceName);
3255          if(!newSpace)
3256             return null;
3257          nameSpace = newSpace;
3258          if(level == 0 && ch == ':') c++;
3259          start = c+1;
3260       }
3261    }
3262    if(c - start)
3263    {
3264       return ScanNameSpace(nameSpace, name + start, listOffset);
3265    }
3266    return null;
3267 }
3268
3269 static BTNamedLink SearchModule(Module module, const char * name, void * listOffset, bool searchPrivate)
3270 {
3271    SubModule subModule;
3272    BTNamedLink link;
3273
3274    if(searchPrivate)
3275    {
3276       link = SearchNameSpace(&module.privateNameSpace, name, listOffset);
3277       if(link) return link;
3278    }
3279    link = SearchNameSpace(&module.publicNameSpace, name, listOffset);
3280    if(link) return link;
3281
3282    for(subModule = module.modules.first; subModule; subModule = subModule.next)
3283    {
3284       if(searchPrivate || subModule.importMode == publicAccess)
3285       {
3286          // TOCHECK: Reverting to false to test what we were trying to fix by passing searchPrivate
3287          // Passing searchPrivate finds ALL classes private or not and thus classes clash
3288          // SearchModule here is called mainly from eSystem_FindClass, and also for Functions and Defines
3289
3290          link = SearchModule(subModule.module, name, listOffset, false);
3291          //link = SearchModule(subModule.module, name, listOffset, searchPrivate /*false*/);
3292          if(link) return link;
3293       }
3294    }
3295    return null;
3296 }
3297
3298 public int64 _strtoi64(const char * string, const char ** endString, int base)
3299 {
3300    int64 value = 0;
3301    int sign = 1;
3302    int c;
3303    char ch;
3304    for(c = 0; (ch = string[c]) && isspace(ch); c++);
3305    if(ch =='+') c++;
3306    else if(ch == '-') { sign = -1; c++; };
3307    if(!base)
3308    {
3309       if(ch == '0' && string[c+1] == 'x')
3310       {
3311          base = 16;
3312          c+=2;
3313       }
3314       else if(ch == '0')
3315       {
3316          base = 8;
3317          c++;
3318       }
3319       else
3320          base = 10;
3321    }
3322    for( ;(ch = string[c]); c++)
3323    {
3324       if(ch >= '0' && ch <= '9')
3325          ch -= '0';
3326       else if(ch >= 'a' && ch <= 'z')
3327          ch -= ('a' - 10);
3328       else if(ch >= 'A' && ch <= 'Z')
3329          ch -= ('A'- 10);
3330       else
3331          // Invalid character
3332          break;
3333       if(ch < base)
3334       {
3335          value *= base;
3336          value += ch;
3337       }
3338       else
3339          // Invalid character
3340          break;
3341    }
3342    if(endString)
3343       *endString = string + c;
3344
3345    return sign*value;
3346 }
3347
3348 public uint64 _strtoui64(const char * string, const char ** endString, int base)
3349 {
3350    uint64 value = 0;
3351    int sign = 1;
3352    int c;
3353    char ch;
3354    for(c = 0; (ch = string[c]) && isspace(ch); c++);
3355    if(ch =='+') c++;
3356    else if(ch == '-') { sign = -1; c++; };
3357    if(!base)
3358    {
3359       if(ch == '0' && string[c+1] == 'x')
3360       {
3361          base = 16;
3362          c+=2;
3363       }
3364       else if(ch == '0')
3365       {
3366          base = 8;
3367          c++;
3368       }
3369       else
3370          base = 10;
3371    }
3372    for( ;(ch = string[c]); c++)
3373    {
3374       if(ch >= '0' && ch <= '9')
3375          ch -= '0';
3376       else if(ch >= 'a' && ch <= 'z')
3377          ch -= ('a' - 10);
3378       else if(ch >= 'A' && ch <= 'Z')
3379          ch -= ('A' - 10);
3380       else
3381          // Invalid character
3382          break;
3383       if(ch < base)
3384       {
3385          value *= base;
3386          value += ch;
3387       }
3388       else
3389          // Invalid character
3390          break;
3391    }
3392    if(endString)
3393       *endString = string + c;
3394    return sign*value;
3395 }
3396
3397 public dllexport Class eSystem_FindClass(Module module, const char * name)
3398 {
3399    if(name && module)
3400    {
3401       BTNamedLink link;
3402       if(!strncmp(name, "const ", 6)) name += 6;
3403       link = SearchNameSpace(&module.application.systemNameSpace, name, &((NameSpace *)0)->classes);
3404       if(link) return link.data;
3405
3406       link = SearchModule(module, name, &((NameSpace *)0)->classes, true);
3407       if(link) return link.data;
3408
3409       {
3410          char noTemplateName[1024];
3411          char * templateParams = strchr(name, '<');
3412
3413          if(templateParams)
3414          {
3415             strncpy(noTemplateName, name, templateParams - name);
3416             noTemplateName[templateParams - name] = '\0';
3417          }
3418          else
3419             strcpy(noTemplateName, name);
3420
3421          link = SearchNameSpace(&module.application.systemNameSpace, noTemplateName, &((NameSpace *)0)->classes);
3422          if(!link)
3423             link = SearchModule(module, noTemplateName, &((NameSpace *)0)->classes, true);
3424          if(link)
3425          {
3426             Class _class = link.data;
3427             Class templatedClass = null;
3428             char className[1024];
3429             strcpy(className, _class.fullName);
3430             strcat(className, templateParams);
3431
3432             link = SearchNameSpace(&module.application.systemNameSpace, className, &((NameSpace *)0)->classes);
3433             if(link)
3434                return link.data;
3435
3436             link = SearchModule(module, className, &((NameSpace *)0)->classes, true);
3437             if(link)
3438                return link.data;
3439
3440             if(_class && templateParams)
3441             {
3442                // if(!numParams) return null;
3443
3444                templatedClass = Class { };
3445                *templatedClass = *_class;
3446                templatedClass.templateClass = _class;
3447                //templatedClass.fullName = CopyString(name);
3448                templatedClass.fullName = CopyString(className);
3449                templatedClass.dataTypeString = CopyString(_class.dataTypeString);
3450                templatedClass.name = CopyString(templatedClass.fullName + strlen(_class.fullName) - strlen(_class.name));
3451                templatedClass.nameSpace->classes.Add((BTNode)BTNamedLink { name = (char *)templatedClass.name, data = templatedClass });
3452                templatedClass.templateArgs = null;
3453                templatedClass.numParams = 0;
3454                templatedClass.derivatives = { };
3455                templatedClass.templatized = { };
3456                templatedClass.module = module;
3457                templatedClass.count = 0; // TOCHECK: Keeping track of individual templatized classes?
3458                templatedClass.prev = null;
3459                templatedClass.next = null;
3460
3461                module.classes.Add(templatedClass);
3462
3463                ComputeClassParameters(templatedClass, templateParams, module);
3464
3465                _class.templatized.Add(OldLink { data = templatedClass });
3466             }
3467             return templatedClass;
3468          }
3469       }
3470    }
3471    return null;
3472 }
3473
3474 static void CopyTemplateArg(ClassTemplateParameter param, ClassTemplateArgument arg)
3475 {
3476    switch(param.type)
3477    {
3478       case type:
3479             arg.dataTypeString = CopyString(arg.dataTypeString);
3480          break;
3481       case expression:
3482
3483          break;
3484       case identifier:
3485          arg.memberString = CopyString(arg.memberString);
3486          break;
3487    }
3488 }
3489
3490 static void ComputeClassParameters(Class templatedClass, const char * templateParams, Module findModule)
3491 {
3492    char ch;
3493    const char * nextParamStart = templateParams ? (templateParams + 1) : null;
3494    ClassTemplateParameter curParam = null;
3495    Class lastClass = null, sClass;
3496    int curParamID = 0;
3497    int numParams = 0;
3498    Class _class = templatedClass.templateClass ? templatedClass.templateClass : templatedClass;
3499
3500    for(sClass = _class; sClass; sClass = sClass.base)
3501    {
3502       if(sClass.templateClass) sClass = sClass.templateClass;
3503       numParams += sClass.templateParams.count;
3504    }
3505
3506    if(templatedClass.templateArgs)
3507       FreeTemplateArgs(templatedClass);
3508    delete templatedClass.templateArgs;
3509    templatedClass.templateArgs = new0 ClassTemplateArgument[numParams];
3510    templatedClass.numParams = numParams;
3511
3512    if(_class != templatedClass)
3513    {
3514       /*int c;
3515       Class sClass;
3516       memcpy(templatedClass.templateArgs, _class.templateArgs, numParams * sizeof(ClassTemplateArgument));
3517       for(sClass = _class; sClass; sClass = sClass.base)
3518       {
3519          ClassTemplateParameter param;
3520          Class prevClass;
3521          int id = 0;
3522          if(sClass.templateClass) sClass = sClass.templateClass;
3523          for(prevClass = sClass.base; prevClass; prevClass = prevClass.base)
3524          {
3525             if(prevClass.templateClass) prevClass = prevClass.templateClass;
3526             id += prevClass.templateParams.count;
3527          }
3528          for(param = sClass.templateParams.first; param; param = param.next)
3529            CopyTemplateArg(param, templatedClass.templateArgs[id++]);
3530       }*/
3531    }
3532
3533    if(templatedClass.base && templatedClass.base.templateArgs && _class == templatedClass)
3534    {
3535       Class sClass;
3536       memcpy(templatedClass.templateArgs, templatedClass.base.templateArgs,
3537          sizeof(ClassTemplateArgument) * (numParams - templatedClass.templateParams.count));
3538       for(sClass = templatedClass.base; sClass; sClass = sClass.base)
3539       {
3540          ClassTemplateParameter param;
3541          Class prevClass;
3542          int id = 0;
3543          for(prevClass = sClass.base; prevClass; prevClass = prevClass.base)
3544          {
3545             if(prevClass.templateClass) prevClass = prevClass.templateClass;
3546             id += prevClass.templateParams.count;
3547          }
3548
3549          if(sClass.templateClass) sClass = sClass.templateClass;
3550          for(param = sClass.templateParams.first; param; param = param.next)
3551             CopyTemplateArg(param, templatedClass.templateArgs[id++]);
3552       }
3553    }
3554
3555    while(nextParamStart)
3556    {
3557       const char * paramStart = nextParamStart;
3558       const char * paramEnd;
3559       int level = 0;
3560       while(*paramStart == ' ') paramStart++;
3561       paramEnd = paramStart;
3562       while((ch = *paramEnd, ch && (level > 0 || (ch != '>' && ch != ','))))
3563       {
3564          if(ch == '<') level++;
3565          if(ch == '>') level--;
3566
3567          paramEnd++;
3568       }
3569       nextParamStart = (ch == ',') ? (paramEnd + 1) : null;
3570       while(*paramEnd == ' ') paramEnd--;
3571       if(paramEnd > paramStart)
3572       {
3573          const char * ptr, * equal = null;
3574          for(ptr = paramStart; ptr <= paramEnd; ptr++)
3575          {
3576             if(*ptr == '=')
3577             {
3578                equal = ptr;
3579                break;
3580             }
3581          }
3582          if(equal)
3583          {
3584             const char * end = equal - 1;
3585             char ident[1024];
3586
3587             while(*end == ' ') end--;
3588             strncpy(ident, paramStart, end + 1 - paramStart);
3589             ident[end + 1 - paramStart] = 0;
3590
3591             for(sClass = _class; sClass; sClass = sClass.base)
3592             {
3593                if(sClass.templateClass) sClass = sClass.templateClass;
3594                for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3595                {
3596                   if(!strcmp(curParam.name, ident))
3597                      break;
3598                }
3599                if(curParam)
3600                {
3601                   Class nextClass;
3602                   ClassTemplateParameter prevParam;
3603                   curParamID = 0;
3604                   for(prevParam = curParam.prev; prevParam; prevParam = prevParam.prev) curParamID++;
3605                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3606                   {
3607                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
3608                      curParamID += nextClass.templateParams.count;
3609                   }
3610                   break;
3611                }
3612             }
3613             lastClass = sClass;
3614          }
3615          else
3616          {
3617             if(curParam)
3618             {
3619                curParam = curParam.next;
3620                curParamID++;
3621             }
3622
3623             if(!curParam)
3624             {
3625                for(sClass = lastClass ? lastClass.base : _class; sClass; sClass = sClass.base)
3626                {
3627                   ClassTemplateParameter param;
3628                   curParamID = 0;
3629                   if(sClass.templateClass) sClass = sClass.templateClass;
3630                   for(param = sClass.templateParams.first; param; param = param.next, curParamID++)
3631                   {
3632                      curParam = param;
3633                      break;
3634                   }
3635                   if(curParam)
3636                   {
3637                      Class nextClass;
3638                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3639                      {
3640                         if(nextClass.templateClass) nextClass = nextClass.templateClass;
3641                         curParamID += nextClass.templateParams.count;
3642                      }
3643                      lastClass = sClass;
3644                      break;
3645                   }
3646                }
3647                /*
3648                for(sClass = _class; sClass; sClass = sClass.base)
3649                {
3650                   if(sClass.templateParams.first)
3651                   {
3652                      Class nextClass;
3653                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3654                         if(nextClass.templateParams.first)
3655                            break;
3656                      if(nextClass != lastClass) continue;
3657
3658                      curParam = sClass.templateParams.first;
3659                      lastClass = sClass;
3660
3661                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3662                         if(nextClass.templateParams.first)
3663                         {
3664                            curParamID += nextClass.templateParams.count;
3665                            break;
3666                         }
3667                      break;
3668                   }
3669                }
3670                */
3671             }
3672          }
3673
3674          if(curParam)
3675          {
3676             ClassTemplateArgument argument { };
3677             char value[1024];
3678             if(equal)
3679             {
3680                equal++;
3681                while(*equal == ' ') equal++;
3682                memcpy(value, equal, paramEnd - equal);
3683                value[paramEnd - equal] = 0;
3684             }
3685             else
3686             {
3687                memcpy(value, paramStart, paramEnd - paramStart);
3688                value[paramEnd - paramStart] = 0;
3689             }
3690             TrimRSpaces(value, value);
3691
3692             switch(curParam.type)
3693             {
3694                case type:
3695                   argument.dataTypeString = CopyString(value);
3696                   argument.dataTypeClass = eSystem_FindClass(findModule, value);
3697                   if(!argument.dataTypeClass)
3698                      argument.dataTypeClass = eSystem_FindClass(_class.module, value);
3699                   if(!argument.dataTypeClass)
3700                      argument.dataTypeClass = eSystem_FindClass(_class.module.application, value);
3701                   break;
3702                case expression:
3703                {
3704                   Class expClass = eSystem_FindClass(_class.module, curParam.dataTypeString);
3705                   if(!expClass) expClass = eSystem_FindClass(_class.module.application, curParam.dataTypeString);
3706                   if(expClass)
3707                   {
3708                      //if(expClass.type ==
3709                      ((bool (*)(void *, void *, const char *))(void *)expClass._vTbl[__ecereVMethodID_class_OnGetDataFromString])(expClass, &argument.expression, value);
3710                   }
3711                   // Expression should be pre simplified here
3712                   else if(value[0] == '\"')
3713                   {
3714                      char * endQuote = value + strlen(value) - 1;
3715                      if(*endQuote != '\"') endQuote++;
3716                      *endQuote = '\0';
3717                      argument.expression.p = CopyString(value + 1);
3718                   }
3719                   else if(value[0] == '\'')
3720                   {
3721                      int nb;
3722                      unichar ch = UTF8GetChar(value + 1, &nb);
3723                      argument.expression.ui = ch;
3724                   }
3725                   else if(!strcmp(curParam.dataTypeString, "uint"))
3726                   {
3727                      argument.expression.ui = (uint)strtoul(value, null, 0);
3728                   }
3729                   else if(!strcmp(curParam.dataTypeString, "char"))
3730                   {
3731                      argument.expression.c = (char)strtol(value, null, 0);
3732                   }
3733                   else if(!strcmp(curParam.dataTypeString, "byte"))
3734                   {
3735                      argument.expression.uc = (unsigned char)strtoul(value, null, 0);
3736                   }
3737                   else if(!strcmp(curParam.dataTypeString, "short"))
3738                   {
3739                      argument.expression.s = (short)strtol(value, null, 0);
3740                   }
3741                   else if(!strcmp(curParam.dataTypeString, "uint16"))
3742                   {
3743                      argument.expression.us = (unsigned short)strtoul(value, null, 0);
3744                   }
3745                   else if(!strcmp(curParam.dataTypeString, "int64"))
3746                   {
3747                      argument.expression.i64 = _strtoi64(value, null, 0);
3748                   }
3749                   else if(!strcmp(curParam.dataTypeString, "uint64"))
3750                   {
3751                      argument.expression.ui64 = _strtoui64(value, null, 0);
3752                   }
3753                   else if(!strcmp(curParam.dataTypeString, "float"))
3754                   {
3755                      argument.expression.f = (float)strtod(value, null);
3756                   }
3757                   else if(!strcmp(curParam.dataTypeString, "double"))
3758                   {
3759                      argument.expression.d = strtod(value, null);
3760                   }
3761                   else // if(!strcmp(curParam.dataTypeString, "int"))
3762                   {
3763                      argument.expression.i = (int)strtol(value, null, 0);
3764                   }
3765                   break;
3766                }
3767                case identifier:
3768                   argument.memberString = CopyString(value);
3769                   break;
3770             }
3771             FreeTemplateArg(templatedClass, curParam, curParamID);
3772             templatedClass.templateArgs[curParamID] = argument;
3773          }
3774       }
3775    }
3776
3777    // TESTING THIS BEFORE...
3778    if(templatedClass == _class)
3779    {
3780       Class sClass = _class;
3781       int curParamID = 0;
3782       Class nextClass;
3783       ClassTemplateParameter param;
3784       for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3785       {
3786          if(nextClass.templateClass) nextClass = nextClass.templateClass;
3787          curParamID += nextClass.templateParams.count;
3788       }
3789
3790       for(param = sClass.templateParams.first; param; param = param.next)
3791       {
3792          if(!templatedClass.templateArgs[curParamID].dataTypeString)
3793          {
3794             templatedClass.templateArgs[curParamID] = param.defaultArg;
3795             CopyTemplateArg(param, templatedClass.templateArgs[curParamID]);
3796             if(param.type == type && param.defaultArg.dataTypeString)
3797             {
3798                templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(findModule, param.defaultArg.dataTypeString);
3799                if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3800                   templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module, param.defaultArg.dataTypeString);
3801                if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3802                   templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module.application, param.defaultArg.dataTypeString);
3803             }
3804          }
3805          curParamID++;
3806       }
3807    }
3808
3809    if(templatedClass.base && templatedClass.base.templateArgs && numParams - _class.templateParams.count)
3810    {
3811       int c = numParams - _class.templateParams.count-1;
3812
3813       for(sClass = _class.base; sClass; sClass = sClass.base)
3814       {
3815          ClassTemplateParameter param;
3816          if(sClass.templateClass) sClass = sClass.templateClass;
3817          for(param = sClass.templateParams.last; param; param = param.prev)
3818          {
3819             ClassTemplateArgument * arg = &templatedClass.templateArgs[c];
3820             ClassTemplateArgument * baseArg = &templatedClass.base.templateArgs[c];
3821             if(!arg->dataTypeString)
3822             {
3823                *arg = templatedClass.base.templateArgs[c];
3824                CopyTemplateArg(param, arg);
3825                if(param.type == type)
3826                {
3827                   if(arg->dataTypeClass && strchr(arg->dataTypeString, '<') && arg->dataTypeClass.templateArgs)
3828                   {
3829                      Class expClass = arg->dataTypeClass;
3830                      Class cClass = null;
3831                      int paramCount = 0;
3832                      int lastParam = -1;
3833
3834                      char templateString[1024];
3835                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
3836                      for(cClass = expClass; cClass; cClass = cClass.base)
3837                      {
3838                         int p = 0;
3839                         ClassTemplateParameter param;
3840                         for(param = cClass.templateParams.first; param; param = param.next)
3841                         {
3842                            int id = p;
3843                            Class sClass;
3844                            // NOTE: This struct 'arg' here is only to build up templateString
3845                            ClassTemplateArgument arg;
3846                            for(sClass = expClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
3847                            arg = expClass.templateArgs[id];
3848
3849                            {
3850                               ClassTemplateParameter cParam;
3851                               int p = numParams - _class.templateParams.count;
3852                               for(cParam = _class.templateParams.first; cParam; cParam = cParam.next, p++)
3853                               {
3854                                  if(cParam.type == type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
3855                                  {
3856                                     arg = templatedClass.templateArgs[p];
3857                                     break;
3858                                  }
3859                               }
3860                            }
3861
3862                            {
3863                               char argument[256];
3864                               argument[0] = '\0';
3865                               switch(param.type)
3866                               {
3867                                  case expression:
3868                                  {
3869                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
3870                                     /*
3871                                     char expString[1024];
3872                                     OldList * specs = MkList();
3873                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
3874                                     Expression exp;
3875                                     char * string = PrintHexUInt64(arg.expression.ui64);
3876                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
3877
3878                                     ProcessExpressionType(exp);
3879                                     ComputeExpression(exp);
3880                                     expString[0] = '\0';
3881                                     PrintExpression(exp, expString);
3882                                     strcat(argument, expString);
3883                                     //delete exp;
3884                                     FreeExpression(exp);
3885                                     */
3886                                     break;
3887                                  }
3888                                  case identifier:
3889                                  {
3890                                     strcat(argument, arg.member.name);
3891                                     break;
3892                                  }
3893                                  case TemplateParameterType::type:
3894                                  {
3895                                     if(arg.dataTypeString)
3896                                        strcat(argument, arg.dataTypeString);
3897                                     break;
3898                                  }
3899                               }
3900                               if(argument[0])
3901                               {
3902                                  if(paramCount) strcat(templateString, ", ");
3903                                  if(lastParam != p - 1)
3904                                  {
3905                                     strcat(templateString, param.name);
3906                                     strcat(templateString, " = ");
3907                                  }
3908                                  strcat(templateString, argument);
3909                                  paramCount++;
3910                                  lastParam = p;
3911                               }
3912                            }
3913                            p++;
3914                         }
3915                      }
3916                      {
3917                         int len = (int)strlen(templateString);
3918                         if(templateString[len-1] == '>') templateString[len++] = ' ';
3919                         templateString[len++] = '>';
3920                         templateString[len++] = '\0';
3921                      }
3922
3923                      FreeTemplateArg(templatedClass, param, c);
3924
3925                      arg->dataTypeString = CopyString(templateString);
3926                      arg->dataTypeClass = eSystem_FindClass(findModule, templateString);
3927                      if(!arg->dataTypeClass)
3928                         arg->dataTypeClass = eSystem_FindClass(templatedClass.module, templateString);
3929                      if(!arg->dataTypeClass)
3930                         arg->dataTypeClass = eSystem_FindClass(templatedClass.module.application, templateString);
3931                   }
3932                   else
3933                   {
3934                      ClassTemplateParameter cParam;
3935                      int p = numParams - _class.templateParams.count;
3936                      for(cParam = _class.templateParams.first; cParam; cParam = cParam.next, p++)
3937                      {
3938                         // if(cParam.type == type && !strcmp(cParam.name, param.name))
3939                         if(cParam.type == type && baseArg->dataTypeString && !strcmp(cParam.name, baseArg->dataTypeString))
3940                         {
3941                            FreeTemplateArg(templatedClass, param, c);
3942
3943                            // TRICKY: This copies from equivalent parameters
3944                            arg->dataTypeString = templatedClass.templateArgs[p].dataTypeString;
3945                            arg->dataTypeClass = templatedClass.templateArgs[p].dataTypeClass;
3946                            CopyTemplateArg(cParam, arg);
3947                            break;
3948                         }
3949                      }
3950                   }
3951                }
3952             }
3953             c--;
3954          }
3955       }
3956    }
3957
3958    {
3959       Class sClass;
3960       for(sClass = _class; sClass; sClass = sClass.base)
3961       {
3962          int curParamID = 0;
3963          Class nextClass;
3964          ClassTemplateParameter param;
3965          if(sClass.templateClass) sClass = sClass.templateClass;
3966
3967          for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3968          {
3969             if(nextClass.templateClass) nextClass = nextClass.templateClass;
3970             curParamID += nextClass.templateParams.count;
3971          }
3972
3973          for(param = sClass.templateParams.first; param; param = param.next)
3974          {
3975             if(!templatedClass.templateArgs[curParamID].dataTypeString)
3976             {
3977                templatedClass.templateArgs[curParamID] = param.defaultArg;
3978                CopyTemplateArg(param, templatedClass.templateArgs[curParamID]);
3979                if(param.type == type && param.defaultArg.dataTypeString)
3980                {
3981                   templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(findModule, param.defaultArg.dataTypeString);
3982                   if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3983                      templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module, param.defaultArg.dataTypeString);
3984                   if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3985                      templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module.application, param.defaultArg.dataTypeString);
3986                }
3987             }
3988             curParamID++;
3989          }
3990       }
3991    }
3992
3993    {
3994       int c = numParams - 1;
3995       for(sClass = _class; sClass; sClass = sClass.base)
3996       {
3997          ClassTemplateParameter param;
3998          if(sClass.templateClass) sClass = sClass.templateClass;
3999          for(param = sClass.templateParams.last; param; param = param.prev)
4000          {
4001             if(param.type == type)
4002             {
4003                ClassTemplateArgument * arg = &templatedClass.templateArgs[c];
4004                ClassTemplateParameter cParam;
4005                Class dClass;
4006                int p = numParams - 1;
4007                for(dClass = _class; dClass; dClass = dClass.base)
4008                {
4009                   if(dClass.templateClass) dClass = dClass.templateClass;
4010                   for(cParam = dClass.templateParams.last; cParam; cParam = cParam.prev, p--)
4011                   {
4012                      if(cParam.type == type && arg->dataTypeString && !strcmp(cParam.name, arg->dataTypeString))
4013                      {
4014                         if(templatedClass.templateArgs[p].dataTypeString && c != p)
4015                         {
4016                            FreeTemplateArg(templatedClass, param, c);
4017
4018                            arg->dataTypeString = templatedClass.templateArgs[p].dataTypeString;
4019                            arg->dataTypeClass = templatedClass.templateArgs[p].dataTypeClass;
4020                            CopyTemplateArg(cParam, arg);
4021                         }
4022                      }
4023                   }
4024                }
4025             }
4026             c--;
4027          }
4028       }
4029    }
4030
4031    {
4032       Class tClass;
4033       int c = numParams - 1;
4034       for(tClass = _class; tClass; tClass = tClass.base)
4035       {
4036          ClassTemplateParameter param;
4037          if(tClass.templateClass) tClass = tClass.templateClass;
4038          for(param = tClass.templateParams.last; param; param = param.prev)
4039          {
4040             ClassTemplateArgument * arg = &templatedClass.templateArgs[c];
4041             if(param.type == identifier && arg->memberString)
4042             {
4043                Class memberClass = templatedClass;
4044                const char * memberString = arg->memberString;
4045                const char * colon = strstr(memberString, "::");
4046                const char * memberName = memberString;
4047                if(colon) memberName = colon + 2;
4048                if(!colon)
4049                {
4050                   memberString = param.defaultArg.memberString;
4051                   colon = memberString ? strstr(memberString, "::") : null;
4052                }
4053
4054                if(colon)
4055                {
4056                   char className[1024];
4057                   Class sClass;
4058
4059                   memcpy(className, memberString, colon - memberString);
4060                   className[colon - memberString] = '\0';
4061
4062                   for(sClass = _class; sClass; sClass = sClass.base)
4063                   {
4064                      ClassTemplateParameter cParam;
4065                      Class nextClass;
4066                      int id = 0;
4067
4068                      if(sClass.templateClass) sClass = sClass.templateClass;
4069                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
4070                      {
4071                         if(nextClass.templateClass) nextClass = nextClass.templateClass;
4072                         id += nextClass.templateParams.count;
4073                      }
4074                      for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next)
4075                      {
4076                         if(cParam.type == type && !strcmp(cParam.name, className) && templatedClass.templateArgs[id].dataTypeString)
4077                         {
4078                            strcpy(className, templatedClass.templateArgs[id].dataTypeString);
4079                         }
4080                         id++;
4081                      }
4082                   }
4083                   // TESTING: Added this here...
4084                   memberClass = eSystem_FindClass(findModule, className);
4085                   if(!memberClass)
4086                      memberClass = eSystem_FindClass(templatedClass.module, className);
4087                   if(!memberClass)
4088                      memberClass = eSystem_FindClass(templatedClass.module.application, className);
4089                }
4090
4091                if(memberClass)
4092                {
4093                   switch(param.memberType)
4094                   {
4095                      case dataMember:
4096                         arg->member = eClass_FindDataMember(memberClass, memberName, memberClass.module, null, null);
4097                         break;
4098                      case method:
4099                         arg->method = eClass_FindMethod(memberClass, memberName, memberClass.module);
4100                         break;
4101                      case prop:
4102                         arg->prop = eClass_FindProperty(memberClass, memberName, memberClass.module);
4103                         break;
4104                   }
4105                }
4106             }
4107             c--;
4108          }
4109       }
4110    }
4111 }
4112
4113 /*static */bool DefaultFunction()
4114 {
4115    return true;
4116 }
4117
4118 public dllexport bool eClass_IsDerived(Class _class, Class from)
4119 {
4120    if(!_class && !from)
4121       return true;
4122
4123    if(_class && from && (_class.templateClass || from.templateClass))
4124    {
4125       if(eClass_IsDerived(_class.templateClass ? _class.templateClass : _class, from.templateClass ? from.templateClass : from))
4126       {
4127          if(!from.templateClass)
4128             return true;
4129          else if(!_class.templateClass && _class == from.templateClass)
4130             return false;
4131          else
4132          {
4133             Class sClass;
4134             for(sClass = from; sClass; sClass = sClass.base)
4135             {
4136                if(sClass.templateParams.first)
4137                {
4138                   ClassTemplateParameter param;
4139                   Class nextClass;
4140                   int p = 0;
4141                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
4142                   for(param = sClass.templateParams.first; param; param = param.next, p++)
4143                   {
4144                      ClassTemplateArgument * arg = &_class.templateArgs[p];
4145                      ClassTemplateArgument * fArg = &from.templateArgs[p];
4146                      if(param.type == type)
4147                      {
4148                         if(arg->dataTypeString != fArg->dataTypeString && arg->dataTypeString && fArg->dataTypeString &&
4149                           strcmp(arg->dataTypeString, fArg->dataTypeString))
4150                            break;
4151                      }
4152                      else if(param.type == identifier)
4153                      {
4154                         if(arg->member != fArg->member)
4155                            break;
4156                      }
4157                      else if(param.type == expression)
4158                      {
4159                         if(arg->expression.ui64 != fArg->expression.ui64)
4160                            break;
4161                      }
4162                   }
4163                   if(param)
4164                      return false;
4165                }
4166             }
4167             return true;
4168          }
4169       }
4170    }
4171    else
4172    {
4173       for(; _class && from; _class = _class.base)
4174       {
4175          if(_class == from || _class.templateClass == from || ((_class.type == systemClass || (_class.type == normalClass && _class.isInstanceClass)) && from.name && !strcmp(_class.name, from.name)))
4176             return true;
4177       }
4178    }
4179    return false;
4180 }
4181
4182 static void FixDerivativeVirtualMethod(Class base, const char * name, int vid, void * origFunction, const char * type)
4183 {
4184    OldLink derivative;
4185    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
4186    {
4187       Class _class = derivative.data;
4188       Method method, next;
4189       void * function = origFunction;
4190
4191       _class.vTblSize++;
4192       _class._vTbl = renew _class._vTbl void *[_class.vTblSize];
4193       memmove(_class._vTbl + vid + 1, _class._vTbl + vid, (_class.vTblSize - vid - 1) * sizeof(void *));
4194
4195       method = (Method) _class.methods.FindString(name);
4196       if(method)
4197       {
4198          if(method.function) function = method.function;
4199
4200          if(!method.symbol)
4201          {
4202             delete (void *)method.name;
4203             delete (void *)method.dataTypeString;
4204             _class.methods.Delete((BTNode)method);
4205          }
4206          else
4207          {
4208             delete (void *)method.dataTypeString;
4209             method.type = virtualMethod;
4210             method.dataTypeString = CopyString(type);
4211             method._class = base;
4212          }
4213       }
4214       for(method = (Method)_class.methods.first; method; method = next)
4215       {
4216          next = (Method)((BTNode)method).next;
4217          if(method.type == virtualMethod)
4218             method.vid++;
4219       }
4220       _class._vTbl[vid] = function;
4221
4222       {
4223          OldLink templateLink;
4224          for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4225          {
4226             Class template = templateLink.data;
4227             template._vTbl = _class._vTbl;
4228          }
4229       }
4230       if(_class.derivatives.first || _class.templatized.first)
4231          FixDerivativeVirtualMethod(_class, name, vid, function, type);
4232    }
4233    {
4234       OldLink templateLink;
4235       for(templateLink = base.templatized.first; templateLink; templateLink = templateLink.next)
4236       {
4237          Class template = templateLink.data;
4238          template._vTbl = base._vTbl;
4239          FixDerivativeVirtualMethod(template, name, vid, origFunction, type);
4240       }
4241    }
4242 }
4243
4244 public dllexport Method eClass_AddMethod(Class _class, const char * name, const char * type, void * function, AccessMode declMode)
4245 {
4246    if(_class && !_class.comRedefinition && name)
4247    {
4248       Class base;
4249       for(base = _class; base; base = base.base)
4250       {
4251          Method method;
4252          if(base.templateClass) base = base.templateClass;
4253          method = (Method)base.methods.FindString(name);
4254          if(method)
4255          {
4256             // If this overrides a virtual method
4257             if(method.type == virtualMethod)
4258             {
4259                OldLink deriv;
4260                void * oldFunction = _class._vTbl[method.vid];
4261                if(method.vid >= _class.vTblSize)
4262                   printf("error: virtual methods overriding failure\n");
4263                else
4264                   _class._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
4265                for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
4266                {
4267                   Class derivClass = deriv.data;
4268                   if(derivClass._vTbl[method.vid] == oldFunction)
4269                      eClass_AddMethod(derivClass, name, type, function, declMode);
4270                }
4271                {
4272                   OldLink templateLink;
4273                   for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4274                   {
4275                      Class template = templateLink.data;
4276                      for(deriv = template.derivatives.first; deriv; deriv = deriv.next)
4277                      {
4278                         Class derivClass = deriv.data;
4279                         if(derivClass._vTbl[method.vid] == oldFunction)
4280                            eClass_AddMethod(derivClass, name, type, function, declMode);
4281                      }
4282                   }
4283                }
4284
4285             }
4286             else
4287             {
4288                if(base == _class)
4289                {
4290                   // printf("error: Redefinition of method %s in class %s\n", name, _class.name);
4291                   break;
4292                }
4293                base = null;
4294                break;
4295             }
4296             return method;
4297          }
4298       }
4299
4300       if(!base)
4301       {
4302          Method method
4303          {
4304             name = CopyString(name),
4305             function = function ? function : null; //DefaultFunction;
4306             _class = _class;
4307             dataTypeString = CopyString(type);
4308             memberAccess = declMode;
4309          };
4310          _class.methods.Add((BTNode)method);
4311          return method;
4312       }
4313    }
4314    return null;
4315 }
4316
4317 public dllexport Method eClass_AddVirtualMethod(Class _class, const char * name, const char * type, void * function, AccessMode declMode)
4318 {
4319    if(_class && !_class.comRedefinition && name)
4320    {
4321       Class base;
4322       for(base = _class; base; base = base.base)
4323       {
4324          Method method = (Method)base.methods.FindString(name);
4325          if(method)
4326          {
4327             // If this overides a virtual method
4328             if(method.type == virtualMethod)
4329             {
4330                if(method.vid >= _class.vTblSize)
4331                   printf("error: virtual methods overriding failure\n");
4332                else
4333                   _class._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
4334             }
4335             else
4336                base = null;
4337             return method;
4338          }
4339       }
4340
4341       if(!base)
4342       {
4343          Method method
4344          {
4345             name = CopyString(name);
4346             function = function ? function : null; //DefaultFunction;
4347             type = virtualMethod;
4348             _class = _class;
4349             vid = _class.vTblSize++;
4350             dataTypeString = CopyString(type);
4351             memberAccess = declMode;
4352          };
4353          _class.methods.Add((BTNode)method);
4354          _class._vTbl = renew _class._vTbl void *[_class.vTblSize];
4355          _class._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
4356
4357          // TODO: Fix derived classes
4358          if(_class.derivatives.first || _class.templatized.first)
4359             FixDerivativeVirtualMethod(_class, name, method.vid, function ? function : null /*(void *)DefaultFunction*/, type);
4360          return method;
4361       }
4362    }
4363    return null;
4364 }
4365
4366 static void FixDerivativeProperty(Class base, Property _property)
4367 {
4368    OldLink derivative;
4369    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
4370    {
4371       Class _class = derivative.data;
4372       Property prop;
4373       BTNamedLink link = (BTNamedLink)_class.prop.FindString(_property.name);
4374       if(link)
4375       {
4376          prop = link.data;
4377          if(!prop.Set && !prop.Get && prop.memberAccess == baseSystemAccess)
4378          {
4379             SelfWatcher watcher;
4380             for(watcher = _class.selfWatchers.first; watcher; watcher = watcher.next)
4381             {
4382                if(watcher._property == prop)
4383                   watcher._property = _property;
4384             }
4385             _property.selfWatchable = true;
4386
4387             delete (void *)prop.name;
4388             delete (void *)prop.dataTypeString;
4389             _class.membersAndProperties.Delete(prop);
4390             _class.prop.Delete((BTNode)link);
4391          }
4392       }
4393
4394       for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
4395          prop.id++;
4396       _class.memberID++;
4397       _class.startMemberID++;
4398
4399       FixDerivativeProperty(_class, _property);
4400    }
4401 }
4402
4403 public dllexport Property eClass_AddProperty(Class _class, const char * name, const char * dataType, void * setStmt, void * getStmt, AccessMode declMode)
4404 {
4405    Property _property = null;
4406    if(_class)
4407    {
4408       BTNamedLink link = (BTNamedLink)_class.prop.FindString(name ? name : dataType);
4409       bool isConversion = name ? false : true;
4410       if(!name && dataType && !strncmp(dataType, "const ", 6))
4411       {
4412          name = dataType + 6;
4413          isConversion = true;
4414       }
4415       if(link)
4416          _property = link.data;
4417       if(!_property)
4418       {
4419          _property =
4420          {
4421             isProperty = true;
4422             name = CopyString(name ? name : dataType);
4423             id = (name && (setStmt || getStmt || dataType)) ? _class.memberID++ : 0;
4424             Set = setStmt;
4425             Get = getStmt;
4426             dataTypeString = CopyString(dataType);
4427             _class = _class;
4428             compiled = true;
4429             conversion = isConversion;
4430             memberAccess = declMode;
4431          };
4432          if(!isConversion)
4433             _class.membersAndProperties.Add(_property);
4434          else
4435             _class.conversions.Add(_property);
4436          _class.prop.Add((BTNode)BTNamedLink { name = _property.name, data = _property });
4437
4438          if(!_property.conversion)
4439          {
4440             FixDerivativeProperty(_class, _property);
4441          }
4442       }
4443    }
4444    return _property;
4445 }
4446
4447 static void SetDelayedCPValues(Class _class, ClassProperty _property)
4448 {
4449    OldLink deriv;
4450    NamedLink64 value, next;
4451
4452    for(value = _class.delayedCPValues.first; value; value = next)
4453    {
4454       next = value.next;
4455       if(!strcmp(value.name, _property.name))
4456       {
4457          // eClass_SetProperty(_class, _property.name, value.data);
4458          _property.Set(_class, value.data);
4459          _class.delayedCPValues.Delete(value);
4460       }
4461    }
4462
4463    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
4464    {
4465       SetDelayedCPValues(deriv.data, _property);
4466    }
4467 }
4468
4469 public dllexport ClassProperty eClass_AddClassProperty(Class _class, const char * name, const char * dataType, void * setStmt, void * getStmt)
4470 {
4471    if(name && !_class.classProperties.FindString(name))
4472    {
4473       ClassProperty _property
4474       {
4475          name = CopyString(name);
4476          Set = setStmt;
4477          Get = getStmt;
4478          dataTypeString = CopyString(dataType);
4479       };
4480       _class.classProperties.Add((BTNode)_property);
4481       SetDelayedCPValues(_class, _property);
4482       return _property;
4483    }
4484    return null;
4485 }
4486
4487 /*import "Time"
4488
4489 Time classFindTotalTime;
4490
4491 public dllexport void ResetClassFindTime()
4492 {
4493    classFindTotalTime = 0;
4494 }
4495
4496 public dllexport Time GetClassFindTime()
4497 {
4498    return classFindTotalTime;
4499 }
4500 */
4501 public dllexport ClassProperty eClass_FindClassProperty(Class _class, const char * name)
4502 {
4503    //Time startTime = GetTime();
4504    ClassProperty _property = null;
4505    if(name && _class)
4506    {
4507       Class origClass = _class;
4508       for(; _class; _class = _class.base)
4509       {
4510          _property = (ClassProperty)_class.classProperties.FindString(name);
4511          if(_property)
4512             break;
4513       }
4514       // For enum class deriving off something else than enum to find enumSize...
4515       if(!_property && origClass.type == enumClass)
4516       {
4517          Class enumClass = eSystem_FindClass(origClass.module, "enum");
4518          _property = eClass_FindClassProperty(enumClass, name);
4519       }
4520    }
4521    /*if(!_property)
4522       eSystem_Logf("No such property (%s) for class %s\n", name, _class.name);*/
4523    //classFindTotalTime += GetTime() - startTime;
4524    return _property;
4525 }
4526
4527 public dllexport int64 eClass_GetProperty(Class _class, const char * name)
4528 {
4529    ClassProperty _property = eClass_FindClassProperty(_class, name);
4530    if(_property && _property.Get && _property.Get != (void *)1)
4531    {
4532       int64 result = _property.Get(_class);
4533       return result;
4534    }
4535    return 0;
4536 }
4537
4538 public dllexport void eClass_SetProperty(Class _class, const char * name, int64 value)
4539 {
4540    ClassProperty _property = eClass_FindClassProperty(_class, name);
4541    if(_property)
4542    {
4543       if(_property.Set)
4544          ((void(*)(void *, int64))_property.Set)(_class, value);
4545    }
4546    else
4547    {
4548       _class.delayedCPValues.Add(NamedLink64 { name = (char *)name, value });
4549    }
4550 }
4551
4552 public dllexport Method eClass_FindMethod(Class _class, const char * name, Module module)
4553 {
4554    //Time startTime = GetTime();
4555    if(_class && name)
4556    {
4557       for(; _class; _class = _class.base)
4558       {
4559          Method method;
4560          if(_class.templateClass) _class = _class.templateClass;
4561          method = (Method)_class.methods.FindString(name);
4562          if(method && (method.memberAccess == publicAccess || _class.module == module || !method.dataTypeString))
4563          {
4564             if(!method.dataTypeString)
4565             {
4566                if(_class.module != module)
4567                {
4568                   if(method.memberAccess == publicAccess)
4569                      module = _class.module;
4570                   else
4571                   {
4572                      //classFindTotalTime += GetTime() - startTime;
4573                      return null;
4574                   }
4575                }
4576             }
4577             else
4578             {
4579                //classFindTotalTime += GetTime() - startTime;
4580                return method;
4581             }
4582          }
4583          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
4584       }
4585    }
4586    //classFindTotalTime += GetTime() - startTime;
4587    return null;
4588 }
4589
4590 // Construct an instance
4591 static bool ConstructInstance(void * instance, Class _class, Class from)
4592 {
4593    if(_class.templateClass) _class = _class.templateClass;
4594    if(_class.base && from != _class.base)
4595    {
4596       if(!ConstructInstance(instance, _class.base, from))
4597          return false;
4598    }
4599    if(_class.Initialize)
4600    {
4601       void (* Initialize)(Module module) = (void *)_class.Initialize;
4602       _class.Initialize = null;
4603       Initialize(_class.module);
4604    }
4605    if(_class.Constructor)
4606    {
4607       if(!_class.Constructor(instance))
4608       {
4609          for(; _class; _class = _class.base)
4610          {
4611             if(_class.templateClass) _class = _class.templateClass;
4612             if(_class.Destructor)
4613                _class.Destructor(instance);
4614          }
4615          return false;
4616       }
4617    }
4618    (_class.templateClass ? _class.templateClass : _class).count++;
4619    return true;
4620 }
4621
4622 public dllexport void * eInstance_New(Class _class)
4623 {
4624    Instance instance = null;
4625    if(_class)
4626    {
4627       // instance = _malloc(_class.size);
4628 #ifdef MEMINFO
4629
4630 #undef malloc
4631 #if !defined(__EMSCRIPTEN__)
4632    memMutex.Wait();
4633 #endif
4634       //allocateClass = _class;
4635       allocateClass = malloc(strlen(_class.name)+1);
4636       allocateInternal = _class.module == __thisModule;
4637       strcpy(allocateClass, _class.name);
4638 #ifndef MEMINFO
4639 #define malloc _mymalloc
4640 #endif
4641
4642 #endif
4643       {
4644          int size = _class.structSize;
4645          int flags = _class.module.application.isGUIApp;
4646          bool inCompiler = (flags & 8) ? true : false;
4647          bool force32Bits = (flags & 4) ? true : false;
4648          if(force32Bits && inCompiler)
4649          {
4650             // Allocate 64 bit sizes for these when cross-compiling for 32 bit to allow loaded libraries to work properly
4651             if(!strcmp(_class.name, "Module"))
4652                size = 560;
4653             else if(_class.templateClass && !strcmp(_class.templateClass.name, "Map"))
4654                size = 40;
4655             else
4656                size *= 3;
4657          }
4658          instance = _calloc(1, size);
4659          if(!instance && size)
4660             printf("Failed to allocate memory instantiating %s object!\n", _class.name);
4661          else if(!size)
4662             printf("Warning: 0 size instantiating %s object!\n", _class.name);
4663       }
4664 #ifdef MEMINFO
4665       allocateClass = null;
4666 #if !defined(__EMSCRIPTEN__)
4667    memMutex.Release();
4668 #endif
4669 #endif
4670
4671 #if !defined(MEMINFO) && defined(MEMTRACKING)
4672       {
4673          MemBlock block = (MemBlock)((byte *)instance - sizeof(class MemBlock));
4674          block._class = _class;
4675       }
4676 #endif
4677
4678       if(instance && _class.type == normalClass)
4679       {
4680          instance._class = _class;
4681          // Copy the virtual table initially
4682          instance._vTbl = _class._vTbl;
4683       }
4684       if(instance && !ConstructInstance(instance, _class, null))
4685       {
4686          _free(instance);
4687          instance = null;
4688       }
4689       /*if(_class.type == normalClass && _class.count > 1000)
4690          printf("%s: %d instances\n", _class.name, _class.count);*/
4691    }
4692    return instance;
4693 }
4694
4695 public dllexport void eInstance_Evolve(Instance * instancePtr, Class _class)
4696 {
4697    if(_class && instancePtr && *instancePtr)
4698    {
4699       bool wasApp = false, wasGuiApp = false;
4700       Instance oldInstance = *instancePtr;
4701       Instance instance = (Instance)renew *instancePtr byte[_class.structSize];
4702       Class fromClass = instance._class;
4703       *instancePtr = instance;
4704       memset(((byte *)instance) + instance._class.structSize, 0, _class.structSize - instance._class.structSize);
4705       // Fix pointers to application
4706       if((wasApp = !strcmp(instance._class.name, "Application")) ||
4707          (wasGuiApp = !strcmp(instance._class.name, "GuiApplication")))
4708       {
4709          Module module;
4710          Application app = (Application) instance;
4711          BTNamedLink link;
4712          Class _class;
4713          NameSpace * nameSpace;
4714          for(module = app.allModules.first; module; module = module.next)
4715             module.application = app;
4716
4717          for(link = (BTNamedLink)app.privateNameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
4718          {
4719             OldLink t;
4720             ((Class)link.data).nameSpace = &app.privateNameSpace;
4721             for(t = ((Class)link.data).templatized.first; t; t = t.next) { Class template = t.data; template.nameSpace = ((Class)link.data).nameSpace; }
4722          }
4723          for(link = (BTNamedLink)app.publicNameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
4724          {
4725             OldLink t;
4726             ((Class)link.data).nameSpace = &app.publicNameSpace;
4727             for(t = ((Class)link.data).templatized.first; t; t = t.next) { Class template = t.data; template.nameSpace = ((Class)link.data).nameSpace; }
4728          }
4729
4730          for(link = (BTNamedLink)app.privateNameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next)
4731             ((DefinedExpression)link.data).nameSpace = &app.privateNameSpace;
4732          for(link = (BTNamedLink)app.publicNameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next)
4733             ((DefinedExpression)link.data).nameSpace = &app.publicNameSpace;
4734
4735          for(link = (BTNamedLink)app.privateNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4736             ((GlobalFunction)link.data).nameSpace = &app.privateNameSpace;
4737          for(link = (BTNamedLink)app.publicNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4738             ((GlobalFunction)link.data).nameSpace = &app.publicNameSpace;
4739
4740          for(nameSpace = (NameSpace *)app.privateNameSpace.nameSpaces.first; nameSpace; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
4741             nameSpace->parent = &app.privateNameSpace;
4742          for(nameSpace = (NameSpace *)app.publicNameSpace.nameSpaces.first; nameSpace; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
4743             nameSpace->parent = &app.publicNameSpace;
4744
4745          // --------------------------------------------------
4746          for(link = (BTNamedLink)app.systemNameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
4747          {
4748             OldLink t;
4749             ((Class)link.data).nameSpace = &app.systemNameSpace;
4750             for(t = ((Class)link.data).templatized.first; t; t = t.next) { Class template = t.data; template.nameSpace = ((Class)link.data).nameSpace; }
4751          }
4752          for(link = (BTNamedLink)app.systemNameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next)
4753             ((DefinedExpression)link.data).nameSpace = &app.systemNameSpace;
4754          for(link = (BTNamedLink)app.systemNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4755             ((GlobalFunction)link.data).nameSpace = &app.systemNameSpace;
4756          for(link = (BTNamedLink)app.systemNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4757             ((GlobalFunction)link.data).nameSpace = &app.systemNameSpace;
4758          for(nameSpace = (NameSpace *)app.systemNameSpace.nameSpaces.first; nameSpace; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
4759             nameSpace->parent = &app.systemNameSpace;
4760          // --------------------------------------------------
4761
4762          for(_class = app.classes.first; _class; _class = _class.next)
4763          {
4764             OldLink templateLink;
4765             _class.module = (Module) app;
4766             for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4767             {
4768                Class template = templateLink.data;
4769                if(template.module == oldInstance)
4770                   template.module = _class.module;
4771             }
4772          }
4773
4774          for(module = app.allModules.first; module; module = module.next)
4775          {
4776             for(_class = module.classes.first; _class; _class = _class.next)
4777             {
4778                OldLink templateLink;
4779                Module oldModule = _class.module;
4780                _class.module = module;
4781                for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4782                {
4783                   Class template = templateLink.data;
4784                   if(template.module == oldModule)
4785                      template.module = _class.module;
4786                }
4787             }
4788          }
4789
4790          app.application = app;
4791       }
4792
4793       {
4794          Class base;
4795          for(base = instance._class; base && base.type == normalClass && base.count; base = base.base)
4796             (base.templateClass ? base.templateClass : base).count--;
4797       }
4798
4799       instance._class = _class;
4800       // Copy the virtual table initially
4801       instance._vTbl = _class._vTbl;
4802
4803       // We don't want to reconstruct the portion already constructed...
4804       if(!ConstructInstance(instance, _class, fromClass))
4805       {
4806          _free(instance);
4807          *instancePtr = null;
4808       }
4809    }
4810 }
4811
4812 public dllexport void eInstance_Delete(Instance instance)
4813 {
4814 #ifdef MEMINFO
4815    bool checkMemory = false;
4816 #endif
4817    if(instance)
4818    {
4819       Class _class, base;
4820       bool ownVtbl;
4821
4822 #ifdef MEMINFO
4823 #if (defined(__WORDSIZE) && __WORDSIZE == 8) || defined(__x86_64__)
4824       if(instance._class == (void *)0xecececececececec)
4825 #else
4826       if(instance._class == (void *)0xecececec)
4827 #endif
4828          _free(instance);
4829 #endif
4830
4831       ownVtbl = instance._vTbl != instance._class._vTbl;
4832
4833       for(_class = instance._class; _class; _class = base)
4834       {
4835          if(_class.templateClass) _class = _class.templateClass;
4836          if(_class.destructionWatchOffset)
4837          {
4838             OldList * watchers = (OldList *)((byte *)instance + _class.destructionWatchOffset);
4839             Watcher watcher, next;
4840
4841             for(watcher = watchers->first; watcher; watcher = next)
4842             {
4843                next = watcher.next;
4844                watchers->Remove(watcher);
4845                watcher.callback(watcher.object, instance);
4846                watchers->Delete(watcher);
4847             }
4848          }
4849
4850          /*// Loop through properties to delete all watchers? Might slow down destruction...
4851          {
4852             Property _property;
4853             for(_property = _class.membersAndProperties.first; _property; _property = _property.next)
4854             {
4855                if(_property.isProperty && _property.isWatchable)
4856                {
4857                   OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
4858                   Watcher watcher, next;
4859                   for(watcher = watchers->first; watcher; watcher = next)
4860                   {
4861                      next = watcher.next;
4862                      watchers->Delete(watcher);
4863                   }
4864                }
4865             }
4866          }*/
4867
4868
4869          base = _class.base;
4870          if(base && (base.type == systemClass || base.isInstanceClass)) base = null;
4871          if(_class.Destructor)
4872             _class.Destructor(instance);
4873 #ifdef MEMINFO
4874          if(_class == class(Application))
4875             checkMemory = true;
4876 #endif
4877       }
4878
4879       for(_class = instance._class; _class; _class = base)
4880       {
4881          if(_class.templateClass) _class = _class.templateClass;
4882
4883          base = _class.base;
4884          (_class.templateClass ? _class.templateClass : _class).count--;
4885          if(_class.type == normalClass && !_class.count && !_class.module)
4886          {
4887 #ifdef MEMINFO
4888             // printf("Now Destructing class %s\n", _class.name);
4889 #endif
4890             eClass_Unregister(_class);
4891          }
4892       }
4893
4894       if(ownVtbl)
4895       {
4896          delete instance._vTbl;
4897       }
4898       //instance.prop.Free(null);
4899       _free(instance);
4900 #ifdef MEMINFO
4901       if(checkMemory) CheckMemory();
4902 #endif
4903    }
4904 }
4905
4906 public dllexport Property eClass_FindProperty(Class _class, const char * name, Module module)
4907 {
4908    //Time startTime = GetTime();
4909    if(_class && name)
4910    {
4911       if(!strncmp(name, "const ", 6))
4912          name += 6;
4913
4914       for(; _class; _class = _class.base)
4915       {
4916          BTNamedLink link;
4917          if(_class.templateClass) _class = _class.templateClass;
4918          link = (BTNamedLink)_class.prop.FindString(name);
4919          if(link)
4920          {
4921             Property _property = (Property)link.data;
4922             if(_property.memberAccess == publicAccess || _class.module == module || !_property.dataTypeString)
4923             {
4924                if(!_property.dataTypeString)
4925                {
4926                   if(_class.module != module)
4927                   {
4928                      if(_property.memberAccess == publicAccess)
4929                         module = _class.module;
4930                      else
4931                      {
4932                         //classFindTotalTime += GetTime() - startTime;
4933                         return null;
4934                      }
4935                   }
4936                }
4937                else
4938                {
4939                   //classFindTotalTime += GetTime() - startTime;
4940                   return _property;
4941                }
4942             }
4943          }
4944          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
4945       }
4946    }
4947    //classFindTotalTime += GetTime() - startTime;
4948    return null;
4949 }
4950
4951 static DataMember FindDataMember(OldList list, BinaryTree alist, const char * name, uint * offset, int * id, bool searchPrivate, DataMember * subMemberStack, int * subMemberStackPos)
4952 {
4953    BTNamedLink link;
4954    DataMember dataMember;
4955
4956    link = (BTNamedLink)alist.FindString(name);
4957    if(link)
4958    {
4959       dataMember = link.data;
4960       if(dataMember.type == normalMember && (dataMember.memberAccess == publicAccess || searchPrivate || !dataMember.dataTypeString))
4961       {
4962          if(offset)
4963             *offset += dataMember.offset;
4964          if(id) *id = dataMember.id;
4965          return dataMember;
4966       }
4967       return null;
4968    }
4969    for(dataMember = list.first; dataMember; dataMember = dataMember.next)
4970    {
4971       if(!dataMember.isProperty && (dataMember.memberAccess == publicAccess || searchPrivate) && !dataMember.name && (dataMember.type == unionMember || dataMember.type == structMember))
4972       {
4973          DataMember childMember;
4974          if(subMemberStackPos) subMemberStack[(*subMemberStackPos)++] = dataMember;
4975          childMember = FindDataMember(dataMember.members, dataMember.membersAlpha, name, offset, id, searchPrivate, subMemberStack, subMemberStackPos);
4976          if(childMember)
4977          {
4978             if(offset)
4979                *offset += dataMember.offset;
4980             if(id) *id += dataMember.id;
4981             return childMember;
4982          }
4983          if(subMemberStackPos) (*subMemberStackPos)--;
4984       }
4985    }
4986    return null;
4987 }
4988
4989 public dllexport DataMember eClass_FindDataMember(Class _class, const char * name, Module module, DataMember * subMemberStack, int * subMemberStackPos)
4990 {
4991    //Time startTime = GetTime();
4992    DataMember dataMember = null;
4993    if(subMemberStackPos) *subMemberStackPos = 0;
4994    if(_class && name)
4995    {
4996       for(; _class; _class = _class.base)
4997       {
4998          if(_class.templateClass) _class = _class.templateClass;
4999          dataMember = FindDataMember(_class.membersAndProperties, _class.members, name, null, null, _class.module == module, subMemberStack, subMemberStackPos);
5000          if(dataMember)
5001          {
5002             if(!dataMember.dataTypeString)
5003             {
5004                if(_class.module != module)
5005                {
5006                   if(dataMember.memberAccess == publicAccess)
5007                      module = _class.module;
5008                   else
5009                   {
5010                      //classFindTotalTime += GetTime() - startTime;
5011                      return null;
5012                   }
5013                }
5014                dataMember = null;
5015             }
5016             else
5017             {
5018                // HACK: Is this good enough? avoiding setting it when adding...
5019                dataMember._class = _class.templateClass ? _class.templateClass : _class;
5020                //classFindTotalTime += GetTime() - startTime;
5021                return dataMember;
5022             }
5023          }
5024          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
5025       }
5026    }
5027    //classFindTotalTime += GetTime() - startTime;
5028    return dataMember;
5029 }
5030
5031 public dllexport DataMember eClass_FindDataMemberAndOffset(Class _class, const char * name, uint * offset, Module module, DataMember * subMemberStack, int * subMemberStackPos)
5032 {
5033    //Time startTime = GetTime();
5034    DataMember dataMember = null;
5035    if(subMemberStackPos) *subMemberStackPos = 0;
5036    if(offset) *offset = 0;
5037    if(_class)
5038    {
5039       for(; _class; _class = _class.base)
5040       {
5041          if(_class.templateClass) _class = _class.templateClass;
5042          dataMember = FindDataMember(_class.membersAndProperties, _class.members, name, offset, null, _class.module == module, subMemberStack, subMemberStackPos);
5043          if(dataMember)
5044          {
5045             if(!dataMember.dataTypeString)
5046             {
5047                if(_class.module != module)
5048                {
5049                   if(dataMember.memberAccess == publicAccess)
5050                      module = _class.module;
5051                   else
5052                   {
5053                      //classFindTotalTime += GetTime() - startTime;
5054                      return null;
5055                   }
5056                }
5057                dataMember = null;
5058             }
5059             else
5060             {
5061                // HACK: Is this good enouh? avoiding setting it when adding...
5062                dataMember._class = _class;
5063                //classFindTotalTime += GetTime() - startTime;
5064                return dataMember;
5065             }
5066          }
5067          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
5068       }
5069    }
5070    //classFindTotalTime += GetTime() - startTime;
5071    return dataMember;
5072 }
5073
5074 public dllexport DataMember eClass_FindDataMemberAndId(Class _class, const char * name, int * id, Module module, DataMember * subMemberStack, int * subMemberStackPos)
5075 {
5076    //Time startTime = GetTime();
5077    DataMember dataMember = null;
5078    if(subMemberStackPos) *subMemberStackPos = 0;
5079    if(_class)
5080    {
5081       for(; _class; _class = _class.base)
5082       {
5083          if(_class.templateClass) _class = _class.templateClass;
5084          dataMember = FindDataMember(_class.membersAndProperties, _class.members, name, null, id, _class.module == module, subMemberStack, subMemberStackPos);  // TOCHECK: Why was this null? null, null);
5085          if(dataMember)
5086          {
5087             if(!dataMember.dataTypeString)
5088             {
5089                if(_class.module != module)
5090                {
5091                   if(dataMember.memberAccess == publicAccess)
5092                      module = _class.module;
5093                   else
5094                   {
5095                      //classFindTotalTime += GetTime() - startTime;
5096                      return null;
5097                   }
5098                }
5099                dataMember = null;
5100             }
5101             else
5102             {
5103                // HACK: Is this good enouh? avoiding setting it when adding...
5104                dataMember._class = _class;
5105                //classFindTotalTime += GetTime() - startTime;
5106                return dataMember;
5107             }
5108          }
5109          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
5110       }
5111    }
5112    //classFindTotalTime += GetTime() - startTime;
5113    return dataMember;
5114 }
5115
5116 public dllexport void eClass_FindNextMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
5117 {
5118    // THIS CODE WILL FIND NEXT MEMBER... (PUBLIC MEMBERS ONLY)
5119    if(*curMember)
5120    {
5121       *curMember = (*curMember).next;
5122
5123       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
5124       {
5125          *curMember = subMemberStack[--(*subMemberStackPos)];
5126          *curMember = (*curMember).next;
5127       }
5128
5129       if(subMemberStackPos && *subMemberStackPos > 0)
5130       {
5131          while(*curMember && ((*curMember).memberAccess == privateAccess))
5132             *curMember = (*curMember).next;
5133       }
5134       else
5135          while(*curMember && (*curMember).name)      // ADDED THIS HERE for eComPacket packet { Connect, 0, { ECOMMUNICATOR_PROTOCOL_VERSION } };
5136          {
5137             DataMember dataMember = eClass_FindDataMember(_class, curMember->name, null, null, null);
5138             if(!dataMember) dataMember = (DataMember)eClass_FindProperty(_class, curMember->name, null);
5139             if(dataMember && dataMember.memberAccess != privateAccess)
5140             {
5141                *curMember = dataMember;
5142                break;
5143             }
5144             else
5145                *curMember = (*curMember).next;
5146          }
5147
5148       if(subMemberStackPos)
5149       {
5150          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
5151          {
5152             subMemberStack[(*subMemberStackPos)++] = *curMember;
5153
5154             *curMember = (*curMember).members.first;
5155             while(*curMember && ((*curMember).memberAccess == privateAccess))
5156                *curMember = (*curMember).next;
5157          }
5158       }
5159    }
5160    while(!*curMember)
5161    {
5162       if(!*curMember)
5163       {
5164          if(subMemberStackPos && *subMemberStackPos)
5165          {
5166             *curMember = subMemberStack[--(*subMemberStackPos)];
5167             *curMember = (*curMember).next;
5168          }
5169          else
5170          {
5171             Class lastCurClass = *curClass;
5172
5173             if(*curClass == _class) break;     // REACHED THE END
5174
5175             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass && (*curClass).inheritanceAccess != privateAccess; *curClass = (*curClass).base);
5176             *curMember = (*curClass).membersAndProperties.first;
5177          }
5178
5179          if(subMemberStackPos && *subMemberStackPos > 0)
5180          {
5181             while(*curMember && ((*curMember).memberAccess == privateAccess))
5182                *curMember = (*curMember).next;
5183          }
5184          else
5185             while(*curMember && (*curMember).name)      // ADDED THIS HERE for eComPacket packet { Connect, 0, { ECOMMUNICATOR_PROTOCOL_VERSION } };
5186             {
5187                DataMember dataMember = null;
5188                if(((*curMember).memberAccess != privateAccess))
5189                {
5190                   dataMember = eClass_FindDataMember(_class, curMember->name, null, null, null);
5191                   if(!dataMember) dataMember = (DataMember)eClass_FindProperty(_class, curMember->name, null);
5192                }
5193                if(dataMember && dataMember.memberAccess != privateAccess && dataMember.id >= 0) // Skip _vTbl, _refCount and _class in Instance
5194                {
5195                   *curMember = dataMember;
5196                   break;
5197                }
5198                else
5199                   *curMember = (*curMember).next;
5200             }
5201
5202          if(subMemberStackPos)
5203          {
5204             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
5205             {
5206                subMemberStack[(*subMemberStackPos)++] = *curMember;
5207
5208                *curMember = (*curMember).members.first;
5209                while(*curMember && (*curMember).memberAccess == privateAccess)
5210                   *curMember = (*curMember).next;
5211             }
5212          }
5213       }
5214    }
5215 }
5216
5217 public dllexport void eInstance_SetMethod(Instance instance, const char * name, void * function)     // YET TO BE DECIDED:   , Module module)
5218 {
5219    if(instance && name)
5220    {
5221       Class _class;
5222       for(_class = instance._class; _class; _class = _class.base)
5223       {
5224          Method method = (Method)_class.methods.FindString(name);
5225          if(method && method.type == virtualMethod)
5226          {
5227             if(instance._vTbl == instance._class._vTbl)
5228             {
5229                instance._vTbl = _malloc(sizeof(void *) * instance._class.vTblSize);
5230                memcpy(instance._vTbl, instance._class._vTbl,
5231                   sizeof(int(*)()) * instance._class.vTblSize);
5232             }
5233             instance._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
5234          }
5235       }
5236    }
5237 }
5238
5239 public dllexport bool eInstance_IsDerived(Instance instance, Class from)
5240 {
5241    if(instance)
5242    {
5243       Class _class = instance._class;
5244       for(; _class; _class = _class.base)
5245       {
5246          if(_class == from)
5247             return true;
5248       }
5249    }
5250    return false;
5251 }
5252
5253 public dllexport void eInstance_IncRef(Instance instance)
5254 {
5255    if(instance)
5256       instance._refCount++;
5257 }
5258
5259 public dllexport void eInstance_DecRef(Instance instance)
5260 {
5261    if(instance)
5262    {
5263       instance._refCount--;
5264       //if(!instance._refCount)
5265       if(instance._refCount <= 0)
5266       {
5267          eInstance_Delete(instance);
5268       }
5269    }
5270 }
5271
5272 static void FixOffsets(Class _class)
5273 {
5274    OldLink deriv;
5275    _class.structSize += _class.base.structSize - _class.offset;
5276
5277    _class.offset = _class.base.structSize;
5278
5279    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
5280       FixOffsets(deriv.data);
5281 }
5282
5283 public dllexport void eClass_Resize(Class _class, int newSize)
5284 {
5285    OldLink deriv;
5286    _class.structSize = newSize;
5287    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
5288       FixOffsets(deriv.data);
5289 }
5290                                                                                                                         // F000F000 will mean a pointer size alignment
5291 public dllexport DataMember eClass_AddDataMember(Class _class, const char * name, const char * type, unsigned int size, unsigned int alignment, AccessMode declMode)
5292 {
5293    if(_class && name)
5294    {
5295       if(!_class.members.FindString(name))
5296       {
5297          DataMember dataMember;
5298
5299          if(alignment)
5300          {
5301             bool pointerAlignment = alignment == 0xF000F000;
5302             bool force64Bits = (_class.module.application.isGUIApp & 2) ? true : false;
5303             bool force32Bits = (_class.module.application.isGUIApp & 4) ? true : false;
5304             if((force32Bits || force64Bits) && !strcmp(_class.name, "AVLNode") && !strcmp(name, "__ecerePrivateData0"))
5305             {
5306                if(force64Bits)
5307                {
5308                   type = "byte[32]";
5309                   size = 32;
5310                }
5311                if(force32Bits)
5312                {
5313                   type = "byte[16]";
5314                   size = 16;
5315                }
5316             }
5317
5318             if(pointerAlignment) alignment = force64Bits ? 8 : force32Bits ? 4 : sizeof(void *);
5319
5320             if(pointerAlignment && _class.structAlignment <= 4)
5321                _class.pointerAlignment = 1;
5322             else if(!pointerAlignment && alignment >= 8)
5323                _class.pointerAlignment = 0;
5324
5325             _class.structAlignment = Max(_class.structAlignment, alignment);
5326
5327             if(_class.offset % alignment)
5328             {
5329                _class.structSize += alignment - (_class.offset % alignment);
5330                _class.offset += alignment - (_class.offset % alignment);
5331             }
5332             if(_class.memberOffset % alignment)
5333                _class.memberOffset += alignment - (_class.memberOffset % alignment);
5334          }
5335
5336          dataMember = DataMember {
5337             name = CopyString(name);
5338             dataTypeString = CopyString(type);
5339             id = _class.memberID++;
5340             _class = _class;
5341             offset = _class.memberOffset;
5342             memberOffset = size;
5343             memberAccess = declMode;
5344             membersAlpha.CompareKey = (void *)BinaryTree::CompareString;
5345          };
5346          _class.membersAndProperties.Add(dataMember);
5347          _class.memberOffset += size;
5348
5349          _class.members.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5350          return dataMember;
5351       }
5352    }
5353    return null;
5354 }
5355                                                                                                                               // F000F000 will mean a pointer size alignment
5356 public dllexport DataMember eMember_AddDataMember(DataMember member, const char * name, const char * type, unsigned int size, unsigned int alignment, AccessMode declMode)
5357 {
5358    if(name && !member.membersAlpha.FindString(name))
5359    {
5360       DataMember dataMember;
5361
5362       if(alignment)
5363       {
5364          bool pointerAlignment = alignment == 0xF000F000;
5365          bool force64Bits = false; //(member._class.module.application.isGUIApp & 2) ? true : false;
5366          bool force32Bits = false; //(member._class.module.application.isGUIApp & 4) ? true : false;
5367          if(pointerAlignment) alignment = force64Bits ? 8 : force32Bits ? 4 : sizeof(void *);
5368
5369          if(pointerAlignment && member.structAlignment <= 4)
5370             member.pointerAlignment = 1;
5371          else if(!pointerAlignment && alignment >= 8)
5372             member.pointerAlignment = 0;
5373
5374          member.structAlignment = Max(member.structAlignment, alignment);
5375
5376          if(member.memberOffset % alignment)
5377             member.memberOffset += alignment - (member.memberOffset % alignment);
5378       }
5379       dataMember = DataMember {
5380          name = CopyString(name);
5381          _class = member._class;
5382          dataTypeString = CopyString(type);
5383          id = member.memberID++;
5384          offset = (member.type == unionMember) ? 0 : member.memberOffset;
5385          memberAccess = declMode;
5386          membersAlpha.CompareKey = (void *)BinaryTree::CompareString;
5387       };
5388       member.members.Add(dataMember);
5389       if(member.type == unionMember)
5390       {
5391          if(size > member.memberOffset)
5392             member.memberOffset = size;
5393       }
5394       else
5395          member.memberOffset += size;
5396       member.membersAlpha.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5397       return dataMember;
5398    }
5399    return null;
5400 }
5401
5402 public dllexport DataMember eMember_New(DataMemberType type, AccessMode declMode)
5403 {
5404    return DataMember { type = type, memberAccess = declMode, membersAlpha.CompareKey = (void *)BinaryTree::CompareString };
5405 }
5406
5407 static void SetMemberClass(DataMember member, Class _class)
5408 {
5409    DataMember dataMember;
5410    member._class = _class;
5411    for(dataMember = member.members.first; dataMember; dataMember = dataMember.next)
5412       SetMemberClass(dataMember, _class);
5413 }
5414
5415 public dllexport bool eMember_AddMember(DataMember addTo, DataMember dataMember)
5416 {
5417    if(dataMember.name && addTo.membersAlpha.FindString(dataMember.name))
5418    {
5419       DataMember_Free(dataMember);
5420       delete dataMember;
5421       return false;
5422    }
5423    addTo.members.Add(dataMember);
5424
5425    if(dataMember.name)
5426       addTo.membersAlpha.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5427
5428    dataMember._class = addTo._class;
5429    // ? SetMemberClass(dataMember, addTo._class);
5430
5431    //dataMember.id = addTo.memberID++;
5432    dataMember.id = addTo.memberID;
5433    if(dataMember.type == unionMember)
5434       addTo.memberID += 1;
5435    else
5436       addTo.memberID += dataMember.memberID;
5437
5438    if(dataMember.pointerAlignment && dataMember.structAlignment <= 4)
5439       addTo.pointerAlignment = 1;
5440    else if(!dataMember.pointerAlignment && dataMember.structAlignment >= 8)
5441       addTo.pointerAlignment = 0;
5442
5443    addTo.structAlignment = Max(addTo.structAlignment, dataMember.structAlignment);
5444
5445    dataMember.offset = (addTo.type == unionMember) ? 0 : addTo.memberOffset;
5446
5447    if(dataMember.structAlignment)
5448    {
5449       if(addTo.memberOffset % dataMember.structAlignment)
5450          addTo.memberOffset += dataMember.structAlignment - (addTo.memberOffset % dataMember.structAlignment);
5451    }
5452
5453    if(addTo.type == unionMember)
5454    {
5455       if(dataMember.memberOffset > addTo.memberOffset)
5456          addTo.memberOffset = dataMember.memberOffset;
5457    }
5458    else
5459       addTo.memberOffset += dataMember.memberOffset;
5460    return true;
5461 }
5462
5463 public dllexport bool eClass_AddMember(Class _class, DataMember dataMember)
5464 {
5465    if(!_class || _class.comRedefinition || (dataMember.name && _class.members.FindString(dataMember.name)))
5466    {
5467       DataMember_Free(dataMember);
5468       delete dataMember;
5469       return false;
5470    }
5471    _class.membersAndProperties.Add(dataMember);
5472
5473    if(dataMember.name)
5474       _class.members.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5475
5476    //dataMember._class = _class;
5477    SetMemberClass(dataMember, _class);
5478
5479    //dataMember.id = _class.memberID++;
5480    dataMember.id = _class.memberID;
5481
5482    if(dataMember.pointerAlignment && dataMember.structAlignment <= 4)
5483       _class.pointerAlignment = 1;
5484    else if(!dataMember.pointerAlignment && dataMember.structAlignment >= 8)
5485       _class.pointerAlignment = 0;
5486
5487    _class.structAlignment = Max(_class.structAlignment, dataMember.structAlignment);
5488    if(dataMember.type == unionMember)
5489       _class.memberID += 1;
5490    else
5491       _class.memberID += dataMember.memberID;
5492
5493    if(dataMember.structAlignment)
5494    {
5495       if(_class.memberOffset % dataMember.structAlignment)
5496          _class.memberOffset += dataMember.structAlignment - (_class.memberOffset % dataMember.structAlignment);
5497    }
5498
5499    dataMember.offset = _class.memberOffset;
5500    _class.memberOffset += dataMember.memberOffset;
5501    return true;
5502 }
5503
5504 public dllexport BitMember eClass_AddBitMember(Class _class, const char * name, const char * type, int bitSize, int bitPos, AccessMode declMode)
5505 {
5506    if(_class && name && !_class.members.FindString(name))
5507    {
5508       uint64 mask = 0;
5509       int c;
5510       BitMember bitMember
5511       {
5512          name = CopyString(name);
5513          _class = _class;
5514          dataTypeString = CopyString(type);
5515          id = _class.memberID++;
5516          memberAccess = declMode;
5517       };
5518       _class.membersAndProperties.Add(bitMember);
5519       if(bitSize)
5520       {
5521          bitMember.pos = (bitPos == -1) ? _class.memberOffset : bitPos;
5522          bitMember.size = bitSize;
5523          _class.memberOffset = bitMember.pos + bitMember.size;
5524          for(c = 0; c<bitSize; c++)
5525          {
5526             if(c)
5527                mask <<= 1;
5528             mask |= 1;
5529          }
5530          bitMember.mask = mask << bitMember.pos;
5531       }
5532
5533      _class.members.Add((BTNode)BTNamedLink { name = bitMember.name, data = bitMember });
5534       return bitMember;
5535    }
5536    return null;
5537 }
5538
5539 static Module Module_Load(Module fromModule, const char * name, AccessMode importAccess, bool ensureCOM)
5540 {
5541    bool (stdcall * Load)(Module module) = null;
5542    bool (stdcall * Unload)(Module module) = null;
5543    Module module;
5544
5545    for(module = fromModule.application.allModules.first; module; module = module.next)
5546    {
5547       if(!strcmp(module.name, name))
5548          break;
5549    }
5550    if(ensureCOM && (!strcmp(name, "ecereCOM") || !strcmp(name, "ecere")))
5551    {
5552       for(module = fromModule.application.allModules.first; module; module = module.next)
5553       {
5554          if(!strcmp(module.name, "ecere") || !strcmp(module.name, "ecereCOM"))
5555             break;
5556       }
5557    }
5558    if(!module)
5559    {
5560       void * library = null;
5561
5562       if(ensureCOM && !strcmp(name, "ecereCOM"))
5563       {
5564          Load = COM_LOAD_FUNCTION;
5565          Unload = COM_UNLOAD_FUNCTION;
5566       }
5567       else
5568       {
5569          const char * libLocation = null;
5570 #if defined(__ANDROID__)
5571          libLocation = AndroidInterface_GetLibLocation();
5572 #endif
5573          library = Instance_Module_Load(libLocation, name, &Load, &Unload);
5574       }
5575       if(Load)
5576       {
5577          module = (Module)eInstance_New(eSystem_FindClass(fromModule, "Module"));
5578          module.application = fromModule.application;
5579          module.library = library;
5580          {
5581             char moduleName[MAX_FILENAME];
5582             char ext[MAX_EXTENSION];
5583             GetLastDirectory(name, moduleName);
5584             GetExtension(moduleName, ext);
5585             StripExtension(moduleName);
5586             if((!strcmpi(ext, "dylib") || !strcmpi(ext, "so")) && strstr(moduleName, "lib") == moduleName)
5587             {
5588                int len = (int)strlen(moduleName) - 3;
5589                memmove(moduleName, moduleName + 3, len);
5590                moduleName[len] = 0;
5591             }
5592             module.name = CopyString(moduleName);
5593          }
5594          module.Unload = Unload;
5595          module.origImportType = normalImport;
5596
5597          if(!Load(module))
5598          {
5599             eInstance_Delete((Instance)module);
5600             module = null;
5601          }
5602       }
5603       fromModule.application.allModules.Add(module);
5604    }
5605    if(ensureCOM && !strcmp(name, "ecere") && module)
5606    {
5607       name = !strcmp(module.name, "ecereCOM") ? "ecere" : "ecereCOM";
5608       if((!Load && !strcmp(module.name, "ecereCOM")) ||
5609          (Load && (!__thisModule || !__thisModule.name || !strcmp(__thisModule.name, "ecereCOM")) && Load != (void *)COM_LOAD_FUNCTION))
5610       {
5611          Module module;
5612          for(module = fromModule.application.allModules.first; module; module = module.next)
5613          {
5614             if(!strcmp(module.name, name))
5615                break;
5616          }
5617          if(!module)
5618          {
5619             Load = COM_LOAD_FUNCTION;
5620             Unload = COM_UNLOAD_FUNCTION;
5621
5622             module = (Module)eInstance_New(eSystem_FindClass(fromModule, "Module"));
5623             module.application = fromModule.application;
5624             module.library = null;
5625             module.name = CopyString(name);
5626             module.Unload = Unload;
5627
5628             if(!Load(module))
5629             {
5630                eInstance_Delete((Instance)module);
5631                module = null;
5632             }
5633
5634             fromModule.application.allModules.Add(module);
5635          }
5636          if(module)
5637          {
5638             if(fromModule)
5639             {
5640                fromModule.modules.Add(SubModule { module = module, importMode = importAccess });
5641             }
5642             incref module;
5643          }
5644       }
5645    }
5646    if(module)
5647    {
5648       if(fromModule)
5649       {
5650          fromModule.modules.Add(SubModule { module = module, importMode = importAccess });
5651       }
5652       incref module;
5653    }
5654 #if defined(_DEBUG)
5655    InternalModuleLoadBreakpoint();
5656 #endif
5657    return module;
5658 }
5659
5660 public dllexport Module eModule_Load(Module fromModule, const char * name, AccessMode importAccess)
5661 {
5662    return Module_Load(fromModule, name, importAccess, true);
5663 }
5664
5665 public dllexport Module eModule_LoadStrict(Module fromModule, const char * name, AccessMode importAccess)
5666 {
5667    return Module_Load(fromModule, name, importAccess, false);
5668 }
5669
5670 public dllexport Module eModule_LoadStatic(Module fromModule, const char * name, AccessMode importAccess, bool (* Load)(Module module), bool (* Unload)(Module module))
5671 {
5672    Module module;
5673    for(module = fromModule.application.allModules.first; module; module = module.next)
5674    {
5675       if(!strcmp(module.name, name))
5676          break;
5677    }
5678    if(!module)
5679    {
5680       if(Load)
5681       {
5682          module = (Module)eInstance_New(eSystem_FindClass(fromModule, "Module"));
5683          module.application = fromModule.application;
5684          module.name = CopyString(name);
5685          module.origImportType = staticImport;
5686          module.Unload = (void *)Unload;
5687          if(!Load(module))
5688          {
5689             eInstance_Delete((Instance)module);
5690             module = null;
5691          }
5692       }
5693       fromModule.application.allModules.Add(module);
5694    }
5695    if(module)
5696    {
5697       if(fromModule)
5698       {
5699          fromModule.modules.Add(SubModule { module = module, importMode = importAccess });
5700       }
5701       incref module;
5702    }
5703    return module;
5704 }
5705
5706 public dllexport void eModule_Unload(Module fromModule, Module module)
5707 {
5708    OldLink m;
5709    for(m = fromModule.modules.first; m; m = m.next)
5710    {
5711       if(m.data == module)
5712          break;
5713    }
5714    if(m)
5715    {
5716       fromModule.modules.Delete(m);
5717       delete module;
5718    }
5719 }
5720
5721 public dllexport void eEnum_AddFixedValue(Class _class, const char * string, int64 value)
5722 {
5723    if(_class && _class.type == enumClass)
5724    {
5725       EnumClassData data = (EnumClassData)_class.data;
5726       NamedLink64 item;
5727
5728       for(item = data.values.first; item; item = item.next)
5729          if(!strcmp(item.name, string))
5730             break;
5731       if(!item)
5732       {
5733          data.values.Add(NamedLink64 { data = value, name = CopyString(string) });
5734          if(value > data.largest)
5735             data.largest = value;
5736       }
5737    }
5738 }
5739
5740 public dllexport int64 eEnum_AddValue(Class _class, const char * string)
5741 {
5742    if(_class && _class.type == enumClass)
5743    {
5744       EnumClassData data = (EnumClassData)_class.data;
5745       int64 value = data.largest + 1;
5746       NamedLink64 item;
5747       for(item = data.values.first; item; item = item.next)
5748          if(!strcmp(item.name, string))
5749             break;
5750       if(!item)
5751       {
5752          data.values.Add(NamedLink64 { data = value, name = CopyString(string) });
5753          if(value > data.largest)
5754             data.largest = value;
5755          return value;
5756       }
5757    }
5758    return -1;
5759 }
5760
5761 static void NameSpace_Free(NameSpace parentNameSpace)
5762 {
5763    NameSpace * nameSpace;
5764    delete (void *)parentNameSpace.name;
5765
5766          /*   {
5767       BTNamedLink n, next;
5768       for(n = (BTNamedLink)parentNameSpace.classes.first; n; n = next)
5769       {
5770          Class c = n.data;
5771
5772          next = (BTNamedLink)((BTNode)n).next;
5773
5774          if(c.templateClass)
5775             eClass_Unregister(c);
5776       }
5777    }         */
5778
5779    while((nameSpace = (NameSpace *)parentNameSpace.nameSpaces.first))
5780    {
5781       NameSpace_Free(nameSpace);
5782       parentNameSpace.nameSpaces.Delete((BTNode)nameSpace);
5783    }
5784 }
5785
5786 static void Application_Destructor(Application app)
5787 {
5788    if(app.parsedCommand)
5789    {
5790       delete (void *)app.argv;
5791       delete app.parsedCommand;
5792    }
5793 }
5794
5795 static bool Module_Constructor(Module module)
5796 {
5797    module.privateNameSpace.classes.CompareKey = (void *)BinaryTree::CompareString;
5798    module.privateNameSpace.defines.CompareKey = (void *)BinaryTree::CompareString;
5799    module.privateNameSpace.functions.CompareKey = (void *)BinaryTree::CompareString;
5800    module.privateNameSpace.nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
5801
5802    module.publicNameSpace.classes.CompareKey = (void *)BinaryTree::CompareString;
5803    module.publicNameSpace.defines.CompareKey = (void *)BinaryTree::CompareString;
5804    module.publicNameSpace.functions.CompareKey = (void *)BinaryTree::CompareString;
5805    module.publicNameSpace.nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
5806    return true;
5807 }
5808
5809 static void Module_Destructor(Module module)
5810 {
5811    Class _class;
5812    DefinedExpression def;
5813    GlobalFunction function;
5814    Module m;
5815    SubModule handle;
5816
5817    // printf("Destructing module %s\n", module.name);
5818
5819    // Take out references from all modules
5820    for(m = module.application.allModules.first; m; m = m.next)
5821    {
5822       SubModule next;
5823       for(handle = m.modules.first; handle; handle = next)
5824       {
5825          next = handle.next;
5826          if(handle.module == module)
5827             m.modules.Delete(handle);
5828       }
5829    }
5830
5831    if(module.Unload)
5832    {
5833       if(module.origImportType == staticImport)
5834       {
5835          bool (* Unload)(Module module) = (void *)module.Unload;
5836          Unload(module);
5837       }
5838       else
5839       {
5840          bool (stdcall * Unload)(Module module) = (void *)module.Unload;
5841          Unload(module);
5842       }
5843    }
5844
5845    // Unload dependencies
5846    {
5847       Module ourWorld = class(Class).module;
5848       void * ourHandle = null;
5849       while((handle = module.modules.last))  // STARTING WITH LAST SO THAT ecereCOM IS UNLOADED LAST...
5850       {
5851          Module depModule = handle.module;
5852          if(depModule == ourWorld)
5853          {
5854             module.modules.Remove(handle);
5855             ourHandle = handle;
5856          }
5857          else
5858          {
5859             module.modules.Delete(handle);
5860             delete depModule;
5861          }
5862       }
5863       if(ourHandle)
5864       {
5865          delete ourHandle;
5866          delete ourWorld;
5867       }
5868    }
5869
5870    // Unload classes
5871    for(;(_class = module.classes.first);)
5872    {
5873       if(_class.nameSpace)
5874       {
5875          BTNamedLink classLink = (BTNamedLink)_class.nameSpace->classes.FindString(_class.name);
5876          if(classLink)
5877          {
5878             OldLink t;
5879             for(t = _class.templatized.first; t; t = t.next)
5880             {
5881                Class template = t.data;
5882                BTNamedLink link;
5883                link = (BTNamedLink)template.nameSpace->classes.FindString(template.name);
5884
5885                template.nameSpace->classes.Delete((BTNode)link);
5886                template.nameSpace = null;
5887             }
5888             _class.nameSpace->classes.Delete((BTNode)classLink);
5889          }
5890 #ifdef _DEBUG
5891          else
5892          {
5893             printf("Warning: Could not find %s in namespace classes while destructing module %s\n", _class.name, module.name);
5894          }
5895 #endif
5896          _class.nameSpace = null;
5897       }
5898       _class.module = null;
5899       module.classes.Remove(_class);
5900       if(_class.count <= 0 || _class.type != normalClass || _class.isInstanceClass)
5901          eClass_Unregister(_class);
5902       else
5903       {
5904 #ifdef MEMINFO
5905          // printf("Delayed destruction of class %s\n", _class.name);
5906 #endif
5907       }
5908    }
5909
5910    // Unload defines
5911    for(;(def = module.defines.first);)
5912    {
5913       if(def.nameSpace)
5914       {
5915          BTNamedLink defLink;
5916          for(defLink = (BTNamedLink)def.nameSpace->defines.first; defLink; defLink = (BTNamedLink)((BTNode)defLink).next)
5917             if(defLink.data == def)
5918             {
5919                def.nameSpace->defines.Delete((BTNode)defLink);
5920                break;
5921             }
5922       }
5923       delete (void *)def.name;
5924       delete (void *)def.value;
5925       module.defines.Delete(def);
5926    }
5927
5928    // Unload functions
5929    for(;(function = module.functions.first);)
5930    {
5931       if(function.nameSpace)
5932       {
5933          BTNamedLink functionLink;
5934          for(functionLink = (BTNamedLink)function.nameSpace->functions.first; functionLink; functionLink = (BTNamedLink)((BTNode)functionLink).next)
5935             if(functionLink.data == function)
5936             {
5937                function.nameSpace->functions.Delete((BTNode)functionLink);
5938                break;
5939             }
5940       }
5941       delete (void *)function.name;
5942       delete (void *)function.dataTypeString;
5943       module.functions.Delete(function);
5944    }
5945
5946    delete (void *)module.name;
5947
5948    NameSpace_Free(module.privateNameSpace);
5949    NameSpace_Free(module.publicNameSpace);
5950
5951    if(module != module.application)
5952       module.application.allModules.Remove(module);
5953    else
5954       NameSpace_Free(module.application.systemNameSpace);
5955
5956 #ifndef MEMINFO
5957    Instance_Module_Free(module.library);
5958 #endif
5959 }
5960
5961 static int64 GetEnumSize(Class _class)
5962 {
5963    EnumClassData data = (EnumClassData)_class.data;
5964    return data.largest+1;
5965 }
5966
5967 #if defined(__GNUC__)
5968 #define strcmpi strcasecmp
5969 #define strnicmp strncasecmp
5970 #endif
5971
5972 #if defined(ECERE_BOOTSTRAP) || (defined(__GNUC__) && !defined(__DJGPP__) && !defined(__WIN32__) && !defined(__EMSCRIPTEN__))
5973 #undef strlwr
5974 #undef strupr
5975 default dllexport char * strlwr(char *string)
5976 {
5977    int c;
5978    for(c=0; string[c]; c++)
5979       if(string[c]>='A' && string[c]<='Z')
5980          string[c]+='a'-'A';
5981    return string;
5982 }
5983 default dllexport char * strupr(char *string)
5984 {
5985    int c;
5986    for(c=0; string[c]; c++)
5987       if(string[c]>='a' && string[c]<='z')
5988          string[c]-='a'-'A';
5989    return string;
5990 }
5991 #endif
5992
5993 public dllexport DefinedExpression eSystem_RegisterDefine(const char * name, const char * value, Module module, AccessMode declMode)
5994 {
5995    NameSpace * nameSpace = null;
5996
5997    int start = 0, c;
5998
5999    nameSpace = (declMode == publicAccess) ? &module.publicNameSpace : &module.privateNameSpace;
6000    if(declMode == baseSystemAccess) nameSpace = &module.application.systemNameSpace;
6001
6002    if(declMode != staticAccess)
6003    {
6004       for(c = 0; name[c]; c++)
6005       {
6006          if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
6007          {
6008             NameSpace * newSpace;
6009
6010             char * spaceName = _malloc(c - start + 1);
6011             strncpy(spaceName, name + start, c - start);
6012             spaceName[c-start] = '\0';
6013
6014             newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
6015             if(!newSpace)
6016             {
6017                newSpace = new0 NameSpace[1];
6018                newSpace->classes.CompareKey = (void *)BinaryTree::CompareString;
6019                newSpace->defines.CompareKey = (void *)BinaryTree::CompareString;
6020                newSpace->functions.CompareKey = (void *)BinaryTree::CompareString;
6021                newSpace->nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
6022                newSpace->name = spaceName;
6023                newSpace->parent = nameSpace;
6024                nameSpace->nameSpaces.Add((BTNode)newSpace);
6025             }
6026             else
6027                delete spaceName;
6028             nameSpace = newSpace;
6029             if(name[c] == ':') c++;
6030             start = c+1;
6031          }
6032       }
6033    }
6034    else
6035       c = (int)strlen(name);
6036
6037    if(c - start && !nameSpace->defines.FindString(name + start))
6038    {
6039       DefinedExpression def
6040       {
6041          name = CopyString(name);
6042          nameSpace = nameSpace;
6043          value = CopyString(value);
6044       };
6045       nameSpace->defines.Add((BTNode)BTNamedLink { name = def.name + start, data = def });
6046       // Reference the definition in the module
6047       module.defines.Add(def);
6048       return def;
6049    }
6050    return null;
6051 }
6052
6053 public dllexport GlobalFunction eSystem_RegisterFunction(const char * name, const char * type, void * func, Module module, AccessMode declMode)
6054 {
6055    NameSpace * nameSpace = null;
6056    int start = 0, c;
6057
6058    nameSpace = (declMode == publicAccess) ? &module.publicNameSpace : &module.privateNameSpace;
6059    if(declMode == baseSystemAccess) nameSpace = &module.application.systemNameSpace;
6060
6061    if(declMode != staticAccess)
6062    {
6063       for(c = 0; name[c]; c++)
6064       {
6065          if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
6066          {
6067             NameSpace * newSpace;
6068
6069             char * spaceName = _malloc(c - start + 1);
6070             strncpy(spaceName, name + start, c - start);
6071             spaceName[c-start] = '\0';
6072
6073             newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
6074             if(!newSpace)
6075             {
6076                newSpace = new0 NameSpace[1];
6077                newSpace->classes.CompareKey = (void *)BinaryTree::CompareString;
6078                newSpace->defines.CompareKey = (void *)BinaryTree::CompareString;
6079                newSpace->functions.CompareKey = (void *)BinaryTree::CompareString;
6080                newSpace->nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
6081                newSpace->name = spaceName;
6082                newSpace->parent = nameSpace;
6083                nameSpace->nameSpaces.Add((BTNode)newSpace);
6084             }
6085             else
6086                delete spaceName;
6087             nameSpace = newSpace;
6088             if(name[c] == ':') c++;
6089             start = c+1;
6090          }
6091       }
6092    }
6093    else
6094       c = (int)strlen(name);
6095
6096    if(c - start && !nameSpace->functions.FindString(name + start))
6097    {
6098       GlobalFunction function
6099       {
6100          name = CopyString(name);
6101          nameSpace = nameSpace;
6102          dataTypeString = CopyString(type);
6103          function = func;
6104          module = module;
6105       };
6106       nameSpace->functions.Add((BTNode)BTNamedLink { name = function.name + start, data = function });
6107       // Reference the definition in the module
6108       module.functions.Add(function);
6109       return function;
6110    }
6111    return null;
6112 }
6113
6114 public dllexport DefinedExpression eSystem_FindDefine(Module module, const char * name)
6115 {
6116    if(name && module)
6117    {
6118       BTNamedLink link;
6119       link = SearchNameSpace(&module.application.systemNameSpace, name, &((NameSpace *)0)->defines);
6120       if(link) return link.data;
6121
6122       link = SearchModule(module, name, &((NameSpace *)0)->defines, true);
6123       if(link) return link.data;
6124    }
6125    return null;
6126 }
6127
6128 public dllexport GlobalFunction eSystem_FindFunction(Module module, const char * name)
6129 {
6130    if(name && module)
6131    {
6132       BTNamedLink link;
6133       link = SearchNameSpace(&module.application.systemNameSpace, name, &((NameSpace *)0)->functions);
6134       if(link) return link.data;
6135
6136       link = SearchModule(module, name, &((NameSpace *)0)->functions, true);
6137       if(link) return link.data;
6138    }
6139    return null;
6140 }
6141
6142 public dllexport void * eSystem_Renew(void * memory, unsigned int size)
6143 {
6144    return _realloc(memory, size);
6145 }
6146
6147 public dllexport void * eSystem_Renew0(void * memory, unsigned int size)
6148 {
6149    return _crealloc(memory, size);
6150 }
6151
6152 public dllexport void * eSystem_New(unsigned int size)
6153 {
6154 /*#ifdef _DEBUG
6155    void * pointer = _malloc(size);
6156    memset(pointer, 0xec, size);
6157    return pointer;
6158 #else*/
6159    return _malloc(size);
6160 //#endif
6161 }
6162
6163 public dllexport void * eSystem_New0(unsigned int size)
6164 {
6165    return _calloc(1,size);
6166 }
6167
6168 public dllexport void eSystem_Delete(void * memory)
6169 {
6170    if(memory)
6171       _free(memory);
6172 }
6173
6174 // Properties
6175 public dllexport void eInstance_FireSelfWatchers(Instance instance, Property _property)
6176 {
6177    if(instance && _property && _property.selfWatchable)
6178    {
6179       Class _class;
6180       for(_class = instance._class; _class; _class = _class.base)
6181       {
6182          SelfWatcher selfWatcher, next;
6183          for(selfWatcher = _class.selfWatchers.first; selfWatcher; selfWatcher = next)
6184          {
6185             next = selfWatcher.next;
6186             if(selfWatcher._property == _property)
6187                selfWatcher.callback(instance);
6188          }
6189       }
6190    }
6191 }
6192
6193 public dllexport void eInstance_FireWatchers(Instance instance, Property _property)
6194 {
6195    if(instance && _property && _property.isWatchable)
6196    {
6197       Module module = instance._class ? instance._class.module : null;
6198       Application application = module ? module.application : null;
6199       int flags = application ? application.isGUIApp : 0;
6200       bool inCompiler = (flags & 8) ? true : false;
6201       bool force32Bits = (flags & 4) ? true : false;
6202       if(!force32Bits || !inCompiler)
6203       {
6204          OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6205          Watcher watcher, next;
6206
6207          for(watcher = watchers->first; watcher; watcher = next)
6208          {
6209             next = watcher.next;
6210             watcher.callback(watcher.object, instance);
6211          }
6212       }
6213    }
6214 }
6215
6216 public dllexport void eProperty_Watchable(Property _property)
6217 {
6218    if(!_property.isWatchable)
6219    {
6220       Class _class = _property._class;
6221       if(!_class.computeSize)
6222       {
6223          _property.watcherOffset = _class.structSize;
6224          _class.structSize += sizeof(OldList);
6225
6226          // highly inefficient
6227          FixDerivativesBase(_class, _class);
6228       }
6229       _property.isWatchable = true;
6230    }
6231 }
6232
6233 public dllexport void eClass_DestructionWatchable(Class _class)
6234 {
6235    if(!_class.destructionWatchOffset)
6236    {
6237       _class.destructionWatchOffset = _class.structSize;
6238       _class.structSize += sizeof(OldList);
6239       // highly inefficient
6240       FixDerivativesBase(_class, _class);
6241    }
6242 }
6243
6244 public dllexport void eProperty_SelfWatch(Class _class, const char * name, void (*callback)(void *))
6245 {
6246    if(_class)
6247    {
6248       Property _property = eClass_FindProperty(_class, name, _class.module);
6249
6250       if(!_property)
6251          _property = eClass_AddProperty(_class, name, null, null, null, baseSystemAccess /*privateAccess*/);
6252       _class.selfWatchers.Add(SelfWatcher { _property = _property, callback = callback });
6253       _property.selfWatchable = true;
6254    }
6255 }
6256
6257 public dllexport void eInstance_Watch(void * instance, Property _property, void * object, void (*callback)(void *, void *))
6258 {
6259    if(_property.isWatchable)
6260    {
6261       OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6262       watchers->Add(Watcher { callback = callback, object = object });
6263    }
6264 }
6265
6266 public dllexport void eInstance_WatchDestruction(Instance instance, Instance object, void (*callback)(void *, void *))
6267 {
6268    OldList * watchers = (OldList *)((byte *)instance + instance._class.destructionWatchOffset);
6269    watchers->Add(Watcher { callback = callback, object = object });
6270 }
6271
6272 public dllexport void eInstance_StopWatching(Instance instance, Property _property, Instance object)
6273 {
6274    if(instance && (!_property || _property.isWatchable))
6275    {
6276       if(_property)
6277       {
6278          OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6279          Watcher watcher;
6280          for(watcher = watchers->first; watcher; watcher = watcher.next)
6281             if(watcher.object == object)
6282             {
6283                watchers->Delete(watcher);
6284                break;
6285             }
6286       }
6287       else
6288       {
6289          // Stop watching all properties as well as destruction
6290          Class _class, base;
6291          for(_class = instance._class; _class; _class = base)
6292          {
6293             if(_class.destructionWatchOffset)
6294             {
6295                OldList * watchers = (OldList *)((byte *)instance + _class.destructionWatchOffset);
6296                Watcher watcher;
6297
6298                for(watcher = watchers->first; watcher; watcher = watcher.next)
6299                {
6300                   watchers->Delete(watcher);
6301                   break;
6302                }
6303             }
6304             for(_property = (Property)_class.membersAndProperties.first; _property; _property = _property.next)
6305             {
6306                if(_property.isProperty && _property.isWatchable)
6307                {
6308                   OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6309                   Watcher watcher;
6310                   for(watcher = watchers->first; watcher; watcher = watcher.next)
6311                      if(watcher.object == object)
6312                      {
6313                         watchers->Delete(watcher);
6314                         break;
6315                      }
6316                }
6317             }
6318             base = _class.base;
6319             if(base && (base.type == systemClass || base.isInstanceClass)) base = null;
6320          }
6321       }
6322    }
6323 }
6324
6325 public dllexport subclass(ClassDesignerBase) eClass_GetDesigner(Class _class)
6326 {
6327    for(;_class;_class = _class.base)
6328    {
6329       if(_class.designerClass)
6330          return (subclass(ClassDesignerBase))eSystem_FindClass(_class.module, _class.designerClass);
6331    }
6332    return null;
6333 }
6334
6335
6336 public dllexport subclass(ClassDesignerBase) eInstance_GetDesigner(Instance instance)
6337 {
6338    if(instance)
6339       return eClass_GetDesigner(instance._class);
6340    return null;
6341 }
6342
6343 public bool LocateModule(const char * name, const char * fileName)
6344 {
6345    return Instance_LocateModule(name, fileName);
6346 }
6347
6348 /*
6349 #if (defined(__WORDSIZE) && __WORDSIZE == 8) || defined(__x86_64__)
6350 #define _64BIT 1
6351 #else
6352 #define _64BIT 0
6353 #endif
6354
6355 #define arch_PointerSize                  sizeof(void *)
6356 #define structSize_Instance               (_64BIT ? 24 : 12)
6357 #define structSize_Module                 (_64BIT ? 560 : 300)
6358 #define structSize_BinaryTree             (_64BIT ? 32 : 16)
6359 #define structSize_OldList                (_64BIT ? 32 : 20)
6360 #define structSize_NamedLink64            (_64BIT ? 32 : 24)
6361 #define structSize_ClassTemplateArgument  (_64BIT ? 16 : 8)
6362 #define structSize_ClassTemplateParameter (_64BIT ? 64 : 40)
6363 #define structSize_OldLink                (_64BIT ? 24 : 12)
6364 #define structSize_BTNamedLink            (_64BIT ? 48 : 24)
6365 #define structSize_Application            (_64BIT ? 800 : 428)
6366 #define structSize_Watcher                (_64BIT ? 32 : 16)
6367 #define structSize_SelfWatcher            (_64BIT ? 32 : 16)
6368 #define structSize_GlobalFunction         (_64BIT ? 72 : 36)
6369 #define structSize_DefinedExpression      (_64BIT ? 40 : 20)
6370 #define structSize_BitMember              (_64BIT ? 96 : 64)
6371 #define structSize_DataMember             (_64BIT ? 160 : 96)
6372 #define structSize_ClassProperty          (_64BIT ? 80 : 40)
6373 #define structSize_Method                 (_64BIT ? 96 : 52)
6374 #define structSize_Property               (_64BIT ? 152 : 88)
6375 #define structSize_Class                  (_64BIT ? 624 : 376)
6376 */
6377
6378 static void LoadCOM(Module module)
6379 {
6380    bool force64Bits = (module.application.isGUIApp & 2) ? true : false;
6381    bool force32Bits = (module.application.isGUIApp & 4) ? true : false;
6382    bool inCompiler = (module.application.isGUIApp & 8) ? true : false;
6383    int pointerSize = force64Bits ? 8 : force32Bits ? 4 : sizeof(void *);
6384    Class applicationClass;
6385    Class enumClass, structClass, boolClass;
6386    Class moduleClass;
6387
6388    // Create Base Class
6389    Class baseClass = eSystem_RegisterClass(normalClass, "class", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6390    baseClass.type = systemClass;
6391    baseClass.memberOffset = 0;
6392    baseClass.offset = 0;
6393    baseClass.structSize = 0;
6394    baseClass.typeSize = 0;
6395
6396    {
6397       Class instanceClass = eSystem_RegisterClass(normalClass, "ecere::com::Instance", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6398       instanceClass.type = normalClass;
6399       instanceClass.isInstanceClass = true;
6400       instanceClass.fixed = true;
6401       instanceClass.memberOffset = 0;
6402       instanceClass.offset = 0;
6403
6404       instanceClass.memberID = -3;
6405       instanceClass.startMemberID = -3;
6406
6407       eClass_AddDataMember(instanceClass, "_vTbl", "void **", pointerSize, pointerSize, publicAccess);
6408       eClass_AddDataMember(instanceClass, "_class", "ecere::com::Class", pointerSize, pointerSize, publicAccess);
6409       eClass_AddDataMember(instanceClass, "_refCount", "int", sizeof(int), sizeof(int), publicAccess);
6410    }
6411
6412    InitializeDataTypes1(module);
6413
6414    // Create Enum class
6415    enumClass = eSystem_RegisterClass(normalClass, "enum", null, 0, force64Bits ? 40 : sizeof(class EnumClassData), null, null, module, baseSystemAccess, publicAccess);
6416    eClass_AddClassProperty(enumClass, "enumSize", "int", null, GetEnumSize).constant = true;
6417    enumClass.type = systemClass;
6418
6419    delete (void *)enumClass.dataTypeString;
6420    enumClass.dataTypeString = CopyString(/*"unsigned int"*/"int");
6421
6422    // Create Struct (simple) class
6423    //structClass = eSystem_RegisterClass(structClass, "struct", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6424    structClass = eSystem_RegisterClass(normalClass, "struct", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6425    structClass.type = systemClass;
6426    structClass.memberOffset = 0;
6427    structClass.offset = 0;
6428    structClass.structSize = 0;
6429    structClass.typeSize = 0;
6430
6431    //eClass_AddMethod(enumClass, "AddValue", "int()", eEnum_AddValue);
6432    //eClass_AddMethod(enumClass, "AddFixedValue", "void()", eEnum_AddFixedValue);
6433
6434    InitializeDataTypes(module);
6435
6436    // Create bool class
6437    boolClass = eSystem_RegisterClass(ClassType::enumClass, "bool", "uint", 0, 0, null, null, module, baseSystemAccess, publicAccess);
6438    eEnum_AddFixedValue(boolClass, "true",  bool::true);
6439    eEnum_AddFixedValue(boolClass, "false", bool::false);
6440
6441    // Create Module class
6442    moduleClass = eSystem_RegisterClass(normalClass, "ecere::com::Module", null, force64Bits ? 8 + 32 + 32 + 32 + 32 + 8 + 8 + 8 + 8 + 8 + 4 + 4 + (32 + 8 + 8 + 4*32) + (32 + 8 + 8 + 4*32) :
6443                                                                                 sizeof(struct Module), 0, (void *)Module_Constructor, (void *)Module_Destructor, module, baseSystemAccess, publicAccess);
6444    eClass_AddVirtualMethod(moduleClass, "OnLoad", "bool()", null, publicAccess);
6445    eClass_AddVirtualMethod(moduleClass, "OnUnload", "void()", null, publicAccess);
6446    eClass_AddMethod(moduleClass, "Load", "Module(const char * name, AccessMode importAccess)", eModule_Load, publicAccess);
6447    eClass_AddMethod(moduleClass, "Unload", "void(Module module)", eModule_Unload, publicAccess);
6448    eClass_AddDataMember(moduleClass, "application", "Application", pointerSize, pointerSize, publicAccess);
6449    eClass_AddDataMember(moduleClass, "classes", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6450    eClass_AddDataMember(moduleClass, "defines", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6451    eClass_AddDataMember(moduleClass, "functions", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6452    eClass_AddDataMember(moduleClass, "modules", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6453    eClass_AddDataMember(moduleClass, "prev", "Module", pointerSize, pointerSize, publicAccess);
6454    eClass_AddDataMember(moduleClass, "next", "Module", pointerSize, pointerSize, publicAccess);
6455    eClass_AddDataMember(moduleClass, "name", "const char *", pointerSize, pointerSize, publicAccess);
6456    eClass_AddDataMember(moduleClass, "library", "void *", pointerSize, pointerSize, publicAccess);
6457    eClass_AddDataMember(moduleClass, "Unload", "void *", pointerSize, pointerSize, publicAccess);
6458    eClass_AddDataMember(moduleClass, "importType", "ImportType", sizeof(ImportType), 4, publicAccess);
6459    eClass_AddDataMember(moduleClass, "origImportType", "ImportType", sizeof(ImportType), 4, publicAccess);
6460    eClass_AddDataMember(moduleClass, "privateNameSpace", "NameSpace", force64Bits ? (32 + 8 + 8 + 4*32) : force32Bits ? (16 + 4 + 4 + 4*16) : sizeof(NameSpace), pointerSize, publicAccess);
6461    eClass_AddDataMember(moduleClass, "publicNameSpace", "NameSpace",  force64Bits ? (32 + 8 + 8 + 4*32) : force32Bits ? (16 + 4 + 4 + 4*16) : sizeof(NameSpace), pointerSize, publicAccess);
6462    moduleClass.fixed = true;
6463    moduleClass.count++;
6464    if(inCompiler && force32Bits)
6465       moduleClass.structSize = 12 + 4 + 20 + 20 + 20 + 20 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + (16 + 4 + 4 + 4*16) + (16 + 4 + 4 + 4*16);
6466
6467    // Create Application class
6468    applicationClass = eSystem_RegisterClass(normalClass, "ecere::com::Application", "Module", force64Bits ? (8+8+4+4 + 32 + 8 + 176) : sizeof(struct Application), 0, null, (void *)Application_Destructor, module, baseSystemAccess, publicAccess);
6469    if(inCompiler && force32Bits)
6470    {
6471       applicationClass.offset = 12 + 4 + 20 + 20 + 20 + 20 + 4 + 4 + 4 + 4 + 4 + 4 + 4 + (16 + 4 + 4 + 4*16) + (16 + 4 + 4 + 4*16);
6472       applicationClass.structSize = applicationClass.offset + (4+4+4+4 + 20 + 4 + 88);
6473    }
6474    eClass_AddVirtualMethod(applicationClass, "Main", "void()", null, publicAccess);
6475    eClass_AddDataMember(applicationClass, "argc", "int", sizeof(int), 4, publicAccess);
6476    eClass_AddDataMember(applicationClass, "argv", "const char **", pointerSize, pointerSize, publicAccess);
6477    eClass_AddDataMember(applicationClass, "exitCode", "int", sizeof(int), 4, publicAccess);
6478    eClass_AddDataMember(applicationClass, "isGUIApp", "bool", sizeof(bool), 4, publicAccess);
6479    eClass_AddDataMember(applicationClass, "allModules", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6480    eClass_AddDataMember(applicationClass, "parsedCommand", "char *", pointerSize, pointerSize, publicAccess);
6481    eClass_AddDataMember(applicationClass, "systemNameSpace", "NameSpace", force64Bits ? (32 + 8 + 8 + 4*32) : force32Bits ? (16 + 4 + 4 + 4*16) : sizeof(NameSpace), pointerSize, publicAccess);
6482    applicationClass.fixed = true;
6483    applicationClass.count++;
6484
6485    //AttachConsole(-1);
6486    //AllocConsole();
6487
6488    // --- Math ---
6489    eSystem_RegisterFunction("sin", "double sin(Angle number)", sin, module, baseSystemAccess);
6490    eSystem_RegisterFunction("sinh", "double sinh(Angle number)", sinh, module, baseSystemAccess);
6491    eSystem_RegisterFunction("cosh", "double cosh(Angle number)", cosh, module, baseSystemAccess);
6492    eSystem_RegisterFunction("tanh", "double tanh(Angle number)", tanh, module, baseSystemAccess);
6493    eSystem_RegisterFunction("sqrt", "double sqrt(double number)", sqrt, module, baseSystemAccess);
6494    eSystem_RegisterFunction("cos", "double cos(Angle number)", cos, module, baseSystemAccess);
6495    eSystem_RegisterFunction("tan", "double tan(Angle number)", tan, module, baseSystemAccess);
6496    eSystem_RegisterFunction("atan2", "Angle atan2(double y, double x)", atan2, module, baseSystemAccess);
6497    eSystem_RegisterFunction("asin", "Angle asin(double number)", asin, module, baseSystemAccess);
6498    eSystem_RegisterFunction("acos", "Angle acos(double number)", acos, module, baseSystemAccess);
6499    eSystem_RegisterFunction("atan", "Angle atan(double number)", atan, module, baseSystemAccess);
6500    eSystem_RegisterFunction("asinh", "Angle asinh(double number)", asinh, module, baseSystemAccess);
6501    eSystem_RegisterFunction("acosh", "Angle acosh(double number)", acosh, module, baseSystemAccess);
6502    eSystem_RegisterFunction("atanh", "Angle atanh(double number)", atanh, module, baseSystemAccess);
6503    eSystem_RegisterFunction("pow", "double pow(double number, double number2)", pow, module, baseSystemAccess);
6504    eSystem_RegisterFunction("fmod", "double fmod(double x, double y)", fmod, module, baseSystemAccess);
6505    eSystem_RegisterFunction("fabs", "double fabs(double number)", fabs, module, baseSystemAccess);
6506    eSystem_RegisterFunction("log", "double log(double number)", log, module, baseSystemAccess);
6507    eSystem_RegisterFunction("log10", "double log10(double number)", log10, module, baseSystemAccess);
6508    eSystem_RegisterFunction("ceil", "double ceil(double number)", ceil, module, baseSystemAccess);
6509    eSystem_RegisterFunction("floor", "double floor(double number)", floor, module, baseSystemAccess);
6510    eSystem_RegisterFunction("exp", "double exp(double number)", exp, module, baseSystemAccess);
6511
6512    // --- Stdlib ---
6513    eSystem_RegisterFunction("qsort", "void qsort(void *, uintsize, uintsize, int (*)(void *, void *))", qsort, module, baseSystemAccess);
6514    eSystem_RegisterFunction("strtod", "double strtod(const char*, char**)", strtod, module, baseSystemAccess);
6515    eSystem_RegisterFunction("strtol", "int strtol(const char*, char**, int base)", strtol, module, baseSystemAccess);
6516    eSystem_RegisterFunction("strtoul", "unsigned long strtoul(const char * nptr, char ** endptr, int base)", strtoul, module, baseSystemAccess);
6517    eSystem_RegisterFunction("strtoll", "int64 strtoll(const char * nptr, char ** endptr, int base)", strtoll, module, baseSystemAccess);
6518    eSystem_RegisterFunction("strtoull", "uint64 strtoull(const char * nptr, char ** endptr, int base)", strtoull, module, baseSystemAccess);
6519    eSystem_RegisterFunction("system", "int system(const char*)", system, module, baseSystemAccess);
6520    eSystem_RegisterFunction("atoi", "int atoi(const char*)", atoi, module, baseSystemAccess);
6521    eSystem_RegisterFunction("atof", "double atof(const char*)", atof, module, baseSystemAccess);
6522    eSystem_RegisterFunction("memset", "void * memset(void * area, int value, uintsize count)", memset, module, baseSystemAccess);
6523    eSystem_RegisterFunction("getenv", "char * getenv(const char * name)", getenv, module, baseSystemAccess);
6524    eSystem_RegisterFunction("rename", "int rename(const char *oldpath, const char *newpath)", rename, module, baseSystemAccess);
6525
6526    // --- String --- (These might move to the string class)
6527    eSystem_RegisterFunction("strlen", "uintsize strlen(const char *)", strlen, module, baseSystemAccess);
6528    eSystem_RegisterFunction("strcat", "char * strcat(char *, const char *)", strcat, module, baseSystemAccess);
6529    eSystem_RegisterFunction("strncat", "char * strncat(char *, const char *, uintsize n)", strncat, module, baseSystemAccess);
6530    eSystem_RegisterFunction("strchr", "char * strchr(const char *, int)", strchr, module, baseSystemAccess);
6531    eSystem_RegisterFunction("strstr", "char * strstr(const char *, const char *)", strstr, module, baseSystemAccess);
6532    eSystem_RegisterFunction("strspn", "uintsize strspn(const char *, const char *)", strspn, module, baseSystemAccess);
6533    eSystem_RegisterFunction("strcspn", "uintsize strcspn(const char *, const char *)", strcspn, module, baseSystemAccess);
6534    eSystem_RegisterFunction("strpbrk", "char * strpbrk(const char *, const char *)", strpbrk, module, baseSystemAccess);
6535
6536    eSystem_RegisterDefine("fstrcmp", "(__runtimePlatform == win32) ? strcmpi : strcmp", module, baseSystemAccess);
6537
6538 //#if defined(__GNUC__)
6539    eSystem_RegisterDefine("strcmpi", "strcasecmp", module, baseSystemAccess);
6540    eSystem_RegisterDefine("strnicmp", "strncasecmp", module, baseSystemAccess);
6541    eSystem_RegisterFunction("strcasecmp", "int strcasecmp(const char *, const char *)", strcmpi, module, baseSystemAccess);
6542    eSystem_RegisterFunction("strncasecmp", "int strncasecmp(const char *, const char *, uintsize n)", strnicmp, module, baseSystemAccess);
6543 /*
6544 #else
6545    eSystem_RegisterDefine("strcasecmp", "strcmpi", module, baseSystemAccess);
6546    eSystem_RegisterDefine("strncasecmp", "strnicmp", module, baseSystemAccess);
6547    eSystem_RegisterFunction("strcmpi", "int strcmpi(const char *, const char *)", strcmpi, module, baseSystemAccess);
6548    eSystem_RegisterFunction("strnicmp", "int strnicmp(const char *, const char *, int n)", strnicmp, module, baseSystemAccess);
6549 #endif
6550 */
6551
6552    eSystem_RegisterFunction("strcmp", "int strcmp(const char *, const char *)", strcmp, module, baseSystemAccess);
6553    eSystem_RegisterFunction("strncmp", "int strncmp(const char *, const char *, uintsize n)", strncmp, module, baseSystemAccess);
6554    eSystem_RegisterFunction("strlwr", "char * strlwr(char *)", strlwr, module, baseSystemAccess);
6555    eSystem_RegisterFunction("strupr", "char * strupr(char *)", strupr, module, baseSystemAccess);
6556    eSystem_RegisterFunction("strcpy", "char * strcpy(char *, const char *)", strcpy, module, baseSystemAccess);
6557    eSystem_RegisterFunction("strncpy", "char * strncpy(char *, const char *, uintsize n)", strncpy, module, baseSystemAccess);
6558    eSystem_RegisterFunction("memcpy", "void * memcpy(void *, const void *, uintsize size)", memcpy, module, baseSystemAccess);
6559    eSystem_RegisterFunction("memmove", "void * memmove(void *, const void *, uintsize size)", memmove, module, baseSystemAccess);
6560    eSystem_RegisterFunction("memcmp", "int memcmp(const void *, const void *, uintsize size)", memcmp, module, baseSystemAccess);
6561
6562    // --- Stdio ---
6563    eSystem_RegisterFunction("sprintf", "int sprintf(char *, const char *, ...)", sprintf, module, baseSystemAccess);
6564    eSystem_RegisterFunction("snprintf", "int snprintf(char *, uintsize, const char *, ...)", snprintf, module, baseSystemAccess);
6565    eSystem_RegisterFunction("printf", "int printf(const char *, ...)", printf, module, baseSystemAccess);
6566    eSystem_RegisterFunction("vsprintf", "int vsprintf(char*, const char*, __builtin_va_list)", vsprintf, module, baseSystemAccess);
6567    eSystem_RegisterFunction("vsnprintf", "int vsnprintf(char*, uintsize, const char*, __builtin_va_list)", vsnprintf, module, baseSystemAccess);
6568    eSystem_RegisterFunction("puts", "int puts(const char *)", puts, module, baseSystemAccess);
6569    eSystem_RegisterFunction("fputs", "int fputs(const char *, void * stream)", fputs, module, baseSystemAccess);
6570
6571    // --- Ctype ---
6572    eSystem_RegisterFunction("tolower", "int tolower(int)", tolower, module, baseSystemAccess);
6573    eSystem_RegisterFunction("toupper", "int toupper(int)", toupper, module, baseSystemAccess);
6574    eSystem_RegisterFunction("isdigit", "bool isdigit(int)", isdigit, module, baseSystemAccess);
6575    eSystem_RegisterFunction("isxdigit","bool isxdigit(int)", isxdigit, module, baseSystemAccess);
6576    eSystem_RegisterFunction("isalnum", "int isalnum(int c)", isalnum, module, baseSystemAccess);
6577    eSystem_RegisterFunction("isspace", "int isspace(int c)", isspace, module, baseSystemAccess);
6578    eSystem_RegisterFunction("isalpha", "int isalpha(int c)", isalpha, module, baseSystemAccess);
6579    eSystem_RegisterFunction("islower", "int islower(int c)", islower, module, baseSystemAccess);
6580    eSystem_RegisterFunction("isupper", "int isupper(int c)", isupper, module, baseSystemAccess);
6581    eSystem_RegisterFunction("isprint", "int isprint(int c)", isprint, module, baseSystemAccess);
6582    eSystem_RegisterFunction("isblank", "int isblank(int c)", isblank, module, baseSystemAccess);
6583
6584 }
6585
6586 public dllexport Application __ecere_COM_Initialize(bool guiApp, int argc, char * argv[])
6587 {
6588    Application app;
6589
6590 #ifdef __ANDROID__
6591    // Clean up global variables
6592    memoryInitialized = false;
6593    pools = null;
6594 #ifdef MEMINFO
6595    memset(&memStacks, 0, sizeof(BinaryTree));
6596    memoryErrorsCount = 0;
6597    memset(&memBlocks, 0, sizeof(BinaryTree));
6598    recurse = false;
6599    blockID = 0;
6600    allocateClass = null;
6601    allocateInternal = false;
6602    TOTAL_MEM = 0;
6603    OUTSIDE_MEM = 0;
6604 #endif
6605 #endif
6606
6607 #ifdef _DEBUG
6608    // printf("Using debug ecere runtime library\n");
6609 #endif
6610    app = _calloc(1, sizeof(class Application));
6611
6612    Module_Constructor(app);
6613    app.systemNameSpace.classes.CompareKey = (void *)BinaryTree::CompareString;
6614    app.systemNameSpace.defines.CompareKey = (void *)BinaryTree::CompareString;
6615    app.systemNameSpace.functions.CompareKey = (void *)BinaryTree::CompareString;
6616    app.systemNameSpace.nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
6617
6618    Instance_COM_Initialize(argc, argv, &app.parsedCommand, &app.argc, &app.argv);
6619
6620    app.application = app;
6621    app.allModules.offset = sizeof(class Instance) + (uint)(uintptr)&((struct Module *)0)->prev;
6622    app.isGUIApp = guiApp;
6623
6624    LoadCOM(app);
6625
6626    app._class = eSystem_FindClass(app, "Application");
6627
6628    return app;
6629 }
6630
6631 public dllexport void eSystem_SetArgs(Application app, int argc, char * argv[])
6632 {
6633    System_SetArgs(argc, argv, &app.argc, &app.argv);
6634 }
6635
6636 public dllexport ClassTemplateParameter eClass_AddTemplateParameter(Class _class, const char * name, TemplateParameterType type, const void * info, ClassTemplateArgument defaultArg)
6637 {
6638    if(_class && name)
6639    {
6640       ClassTemplateParameter param;
6641
6642       for(param = _class.templateParams.first; param; param = param.next)
6643       {
6644          if(!strcmp(param.name, name))
6645             return param;
6646       }
6647       param =
6648       {
6649          name = CopyString(name);
6650          type = type;
6651          (type == identifier) ? info : CopyString(info);
6652       };
6653       if(defaultArg != null)
6654       {
6655          param.defaultArg = defaultArg;
6656          CopyTemplateArg(param, param.defaultArg);
6657       }
6658       _class.templateParams.Add(param);
6659       return param;
6660    }
6661    return null;
6662 }
6663
6664 public dllexport void eClass_DoneAddingTemplateParameters(Class base)
6665 {
6666    if(base)
6667    {
6668       ClassTemplateParameter param;
6669       {
6670          void * first = base.templateParams.first;
6671          int count = base.templateParams.count;
6672
6673          FreeTemplateArgs(base);
6674          delete base.templateArgs;
6675
6676          base.templateParams.first = null;
6677          base.templateParams.count = 0;
6678
6679          FreeTemplatesDerivatives(base);
6680
6681          base.templateParams.first = first;
6682          base.templateParams.count = count;
6683       }
6684
6685       for(param = base.templateParams.first; param; param = param.next)
6686       {
6687          if(param.type == identifier && param.defaultArg.memberString)
6688          {
6689             Class memberClass = base;
6690             const char * colon = strstr(param.defaultArg.memberString, "::");
6691             const char * memberName;
6692             if(colon)
6693             {
6694                char className[1024];
6695                Class sClass;
6696
6697                memcpy(className, param.defaultArg.memberString, colon - param.defaultArg.memberString);
6698                className[colon - param.defaultArg.memberString] = '\0';
6699                memberName = colon + 2;
6700
6701                for(sClass = base; sClass; sClass = sClass.base)
6702                {
6703                   ClassTemplateParameter cParam;
6704                   Class nextClass;
6705                   int id = 0;
6706                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) id += nextClass.templateParams.count;
6707                   // Safety! What could cause base.templateArgs to be null?
6708                   if(sClass == base || base.templateArgs)
6709                   {
6710                      for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next)
6711                      {
6712                         if(cParam.type == type && !strcmp(cParam.name, className))
6713                            strcpy(className, (sClass == base) ? cParam.defaultArg.dataTypeString : base.templateArgs[id].dataTypeString);
6714                         id++;
6715                      }
6716                   }
6717                }
6718                memberClass = eSystem_FindClass(base.module, className);
6719                if(!memberClass)
6720                   memberClass = eSystem_FindClass(base.module.application, className);
6721             }
6722             else
6723                memberName = param.defaultArg.memberString;
6724
6725             if(memberClass)
6726             {
6727                switch(param.memberType)
6728                {
6729                   case dataMember:
6730                      param.defaultArg.member = eClass_FindDataMember(memberClass, memberName, memberClass.module, null, null);
6731                      break;
6732                   case method:
6733                      param.defaultArg.method = eClass_FindMethod(memberClass, memberName, memberClass.module);
6734                      break;
6735                   case prop:
6736                      param.defaultArg.prop = eClass_FindProperty(memberClass, memberName, memberClass.module);
6737                      break;
6738                }
6739             }
6740          }
6741       }
6742
6743       //ComputeClassParameters(base, null, null);
6744
6745       FixDerivativesBase(base, base);
6746    }
6747 }
6748
6749 static void FreeTemplatesDerivatives(Class base)
6750 {
6751    OldLink derivative, templateLink;
6752    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
6753    {
6754       Class _class = derivative.data;
6755       if(_class.templateArgs)
6756       {
6757          FreeTemplateArgs(_class);
6758          delete _class.templateArgs;
6759       }
6760       FreeTemplatesDerivatives(_class);
6761    }
6762
6763    for(templateLink = base.templatized.first; templateLink; templateLink = templateLink.next)
6764    {
6765       Class _class = templateLink.data;
6766       if(_class.templateArgs)
6767       {
6768          FreeTemplateArgs(_class);
6769          delete _class.templateArgs;
6770       }
6771       FreeTemplatesDerivatives(_class);
6772    }
6773 }
6774
6775 static const char * platformNames[Platform] = { "", "win32", "linux", "apple" }; // how to have this be accessible outside of dll/lib
6776 static const Platform firstPlatform = win32;
6777 static const Platform lastPlatform = apple;
6778
6779 public enum Platform
6780 {
6781    unknown, win32, tux, apple;
6782
6783    property const char *
6784    {
6785       get { return OnGetString(null, null, null); }
6786       set
6787       {
6788          if(value)
6789          {
6790             Platform c;
6791             for(c = firstPlatform; c <= lastPlatform; c++)
6792                if(!strcmpi(value, platformNames[c]))
6793                   return c;
6794          }
6795          return unknown;
6796       }
6797    };
6798
6799    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
6800    {
6801       if(this >= firstPlatform && this <= lastPlatform)
6802       {
6803          if(tempString)
6804             strcpy(tempString, platformNames[this]);
6805          return platformNames[this];
6806       }
6807       if(tempString && tempString[0])
6808          tempString[0] = '\0';
6809       return null;
6810    }
6811
6812    bool OnGetDataFromString(const char * string)
6813    {
6814       this = string;
6815       return this != unknown;
6816    }
6817 };
6818
6819 default extern Platform runtimePlatform;
6820
6821 public Platform GetRuntimePlatform()
6822 {
6823    return runtimePlatform;
6824 }
6825
6826 namespace gui;
6827
6828 class Window;
6829
6830 namespace com;
6831 // CLASS DESIGNER SUPPORT
6832
6833 public class ObjectInfo : struct
6834 {
6835 public:
6836    ObjectInfo prev, next;
6837    Instance instance;
6838    char * name;
6839    Instantiation instCode;
6840    bool deleted;
6841    ObjectInfo oClass;
6842    OldList instances;
6843    ClassDefinition classDefinition;
6844    bool modified;
6845    void * i18nStrings;
6846 };
6847
6848 public class DesignerBase : Window
6849 {
6850 public:
6851    virtual bool FindObject(Instance * instance, const char * string);
6852    virtual void RenameObject(ObjectInfo object, const char * name);
6853    virtual void SelectObjectFromDesigner(ObjectInfo object);
6854    virtual void CodeAddObject(Instance instance, ObjectInfo * object);
6855    virtual void SheetAddObject(ObjectInfo object);
6856    virtual void AddToolBoxClass(Class _class);
6857    virtual void AddDefaultMethod(Instance instance, Instance classInstance);
6858    virtual void DeleteObject(ObjectInfo object);
6859    virtual bool ObjectContainsCode(ObjectInfo object);
6860    virtual void ModifyCode(void);
6861    virtual void UpdateProperties(void);
6862
6863    ClassDesignerBase classDesigner;
6864    const char * objectClass;
6865    bool isDragging;
6866
6867    // FIX THIS WITH PUBLIC:
6868    property ClassDesignerBase classDesigner
6869    {
6870       get { return classDesigner; }
6871       set { classDesigner = value; }
6872    };
6873    property const char * objectClass
6874    {
6875       get { return objectClass; }
6876       set { objectClass = value; }
6877    };
6878    property bool isDragging
6879    {
6880       get { return isDragging; }
6881       set { isDragging = value; }
6882    };
6883 }
6884
6885 public class ClassDesignerBase : Window
6886 {
6887 public:
6888    virtual void Reset(void);
6889    virtual void AddObject(void);
6890    virtual void SelectObject(ObjectInfo object, Instance control);
6891
6892    virtual void ListToolBoxClasses(DesignerBase designer);
6893
6894    virtual void ::PrepareTestObject(DesignerBase designer, Instance test);
6895    virtual void ::CreateObject(DesignerBase designer, Instance instance, ObjectInfo object, bool isClass, Instance _class);
6896    virtual void ::PostCreateObject(Instance instance, ObjectInfo object, bool isClass, Instance _class);
6897    virtual void ::DroppedObject(Instance instance, ObjectInfo object, bool isClass, Instance _class);
6898    virtual void ::DestroyObject(Instance object);
6899    virtual void ::FixProperty(Property prop, Instance object);
6900    virtual void ::CreateNew(EditBox editBox, Size clientSize, const char * name, const char * inherit);
6901 }
6902
6903 DesignerBase activeDesigner;
6904
6905 public void SetActiveDesigner(DesignerBase designer)
6906 {
6907    activeDesigner = designer;
6908 }
6909
6910 public DesignerBase GetActiveDesigner()
6911 {
6912    return activeDesigner;
6913 }
6914
6915
6916 bool poolingDisabled;
6917
6918 public dllexport void eSystem_SetPoolingDisabled(bool disabled)
6919 {
6920    poolingDisabled = disabled;
6921 }
6922
6923 namespace sys;
6924
6925 // constants
6926 define LEAD_OFFSET      = 0xD800 - (0x10000 >> 10);
6927 define SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00;
6928
6929 public bool UTF8Validate(const char * source)
6930 {
6931    if(source)
6932    {
6933       int c;
6934       for(c = 0; source[c];)
6935       {
6936          byte ch = source[c];
6937          unichar codePoint = 0;
6938          int numBytes = 1;
6939          int i;
6940          byte mask = 0x7F;
6941          if(ch & 0x80)
6942          {
6943             if(ch & 0x40)
6944             {
6945                mask >>= 2;
6946                numBytes++;
6947                if(ch & 0x20)
6948                {
6949                   numBytes++;
6950                   mask >>= 1;
6951                   if(ch & 0x10)
6952                   {
6953                      if(ch & 0x08)
6954                         return false;
6955                      numBytes++;
6956                      mask >>= 1;
6957                   }
6958                }
6959             }
6960             else
6961                return false;
6962          }
6963          for(i = 0; i<numBytes && (ch = source[c]); i++, c++)
6964          {
6965             codePoint <<= 6;
6966             codePoint |= ch & mask;
6967             mask = 0x3F;
6968             if(i > 1)
6969             {
6970                if(!(ch & 0x80) || (ch & 0x40))
6971                   return false;
6972             }
6973          }
6974          if(i < numBytes) return false;
6975
6976          if(codePoint > 0x10FFFF || (codePoint >= 0xD800 && codePoint <= 0xDFFF) ||
6977            (codePoint < 0x80 && numBytes > 1) ||
6978            (codePoint < 0x800 && numBytes > 2) ||
6979            (codePoint < 0x10000 && numBytes > 3))
6980             return false;
6981       }
6982    }
6983    return true;
6984 }
6985
6986 public int ISO8859_1toUTF8(const char * source, char * dest, int max)
6987 {
6988    int c;
6989    int d = 0;
6990    byte * byteDest = (byte *)dest;
6991    for(c = 0; source[c]; c++)
6992    {
6993       unichar ch = ((byte *)source)[c];
6994       switch(ch)
6995       {
6996          case 128: ch = (unichar)0x20AC; break;
6997          case 130: ch = (unichar)0x201A; break;
6998          case 131: ch = (unichar)0x0192; break;
6999          case 132: ch = (unichar)0x201E; break;
7000          case 133: ch = (unichar)0x2026; break;
7001          case 134: ch = (unichar)0x2020; break;
7002          case 135: ch = (unichar)0x2021; break;
7003          case 136: ch = (unichar)0x02C6; break;
7004          case 137: ch = (unichar)0x2030; break;
7005          case 138: ch = (unichar)0x0160; break;
7006          case 139: ch = (unichar)0x2039; break;
7007          case 140: ch = (unichar)0x0152; break;
7008          case 142: ch = (unichar)0x017D; break;
7009          case 145: ch = (unichar)0x2018; break;
7010          case 146: ch = (unichar)0x2019; break;
7011          case 147: ch = (unichar)0x201C; break;
7012          case 148: ch = (unichar)0x201D; break;
7013          case 149: ch = (unichar)0x2022; break;
7014          case 150: ch = (unichar)0x2013; break;
7015          case 151: ch = (unichar)0x2014; break;
7016          case 152: ch = (unichar)0x02DC; break;
7017          case 153: ch = (unichar)0x2122; break;
7018          case 154: ch = (unichar)0x0161; break;
7019          case 155: ch = (unichar)0x203A; break;
7020          case 156: ch = (unichar)0x0153; break;
7021          case 158: ch = (unichar)0x017E; break;
7022          case 159: ch = (unichar)0x0178; break;
7023       }
7024       if(ch < 0x80)
7025       {
7026          if(d + 1 >= max) break;
7027          byteDest[d++] = (char)ch;
7028       }
7029       else if(ch < 0x800)
7030       {
7031          if(d + 2 >= max) break;
7032          byteDest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7033          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7034       }
7035       else if(ch < 0x10000)
7036       {
7037          if(d + 3 >= max) break;
7038          byteDest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7039          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7040          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7041       }
7042       else
7043       {
7044          if(d + 4 >= max) break;
7045          byteDest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7046          byteDest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7047          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7048          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7049       }
7050    }
7051    dest[d] = 0;
7052    return d;
7053 }
7054
7055 public char * UTF16toUTF8(const uint16 * source)
7056 {
7057    int c;
7058    int d = 0;
7059    int len;
7060    byte * dest;
7061    uint16 u16;
7062    bool invert = false;
7063
7064    for(len = 0; source[len]; len++);
7065    dest = new byte[len * 3 + 1];
7066    for(c = 0; (u16 = source[c]); c++)
7067    {
7068       unichar ch;
7069       if(!c && (u16 == 0xFFFE || u16 == 0xFEFF))
7070       {
7071          if(u16 == 0xFFFE) invert = true;
7072          continue;
7073       }
7074       if(invert) { u16 = ((u16 & 0xFF00) >> 8) | ((u16 & 0x00FF) << 8); }
7075
7076       if(u16 < 0xD800 || u16 > 0xDBFF)
7077          ch = (unichar)u16;
7078       else
7079          ch = ((unichar)u16 << 10) + source[c++] + SURROGATE_OFFSET;
7080
7081       if(ch < 0x80)
7082       {
7083          dest[d++] = (char)ch;
7084       }
7085       else if(ch < 0x800)
7086       {
7087          dest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7088          dest[d++] = 0x80 | (byte)(ch & 0x03F);
7089       }
7090       else if(ch < 0x10000)
7091       {
7092          dest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7093          dest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7094          dest[d++] = 0x80 | (byte)(ch & 0x03F);
7095       }
7096       else
7097       {
7098          dest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7099          dest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7100          dest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7101          dest[d++] = 0x80 | (byte)(ch & 0x03F);
7102       }
7103    }
7104    dest[d] = 0;
7105    dest = renew dest byte[d+1];
7106    return (char *)dest;
7107 }
7108
7109 public int UTF16toUTF8Buffer(const uint16 * source, char * dest, int max)
7110 {
7111    int c;
7112    int d = 0;
7113    uint16 u16;
7114    byte * byteDest = (byte *)dest;
7115    for(c = 0; (u16 = source[c]); c++)
7116    {
7117       unichar ch;
7118       if(u16 < 0xD800 || u16 > 0xDBFF)
7119          ch = (unichar)u16;
7120       else
7121          ch = ((unichar)u16 << 10) + source[c++] + SURROGATE_OFFSET;
7122
7123       if(ch < 0x80)
7124       {
7125          if(d + 1 >= max) break;
7126          byteDest[d++] = (char)ch;
7127       }
7128       else if(ch < 0x800)
7129       {
7130          if(d + 2 >= max) break;
7131          byteDest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7132          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7133       }
7134       else if(ch < 0x10000)
7135       {
7136          if(d + 3 >= max) break;
7137          byteDest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7138          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7139          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7140       }
7141       else
7142       {
7143          if(d + 4 >= max) break;
7144          byteDest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7145          byteDest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7146          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7147          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7148       }
7149    }
7150    byteDest[d] = 0;
7151    return d;
7152 }
7153
7154 // NOTE: UTF8GetChar now returns 0 into numBytes for the null-terminating character ('\0')
7155 public unichar UTF8GetChar(const char * string, int * numBytes)
7156 {
7157    unichar ch;
7158    byte b = ((byte *)string)[0];
7159    int i;
7160    byte mask = 0x7F;
7161    int nb = b ? 1 : 0;
7162    ch = 0;
7163    if(b & 0x80)
7164    {
7165       if(b & 0x40)
7166       {
7167          mask >>= 2;
7168          nb++;
7169          if(b & 0x20)
7170          {
7171             nb++;
7172             mask >>= 1;
7173             if(b & 0x10)
7174             {
7175                if(b & 0x08) { nb = 0; }
7176                nb++;
7177                mask >>= 1;
7178             }
7179          }
7180       }
7181       else
7182          nb = 0;
7183    }
7184    for(i = 0; i<nb; i++)
7185    {
7186       ch <<= 6;
7187       ch |= (b = ((byte *)string)[i]) & mask;
7188       mask = 0x3F;
7189       if(i > 1 && (!(b & 0x80) || (b & 0x40)))
7190       {
7191          nb = 0;
7192          ch = 0;
7193       }
7194    }
7195
7196    if(i < nb ||
7197       ch > 0x10FFFF || (ch >= 0xD800 && ch <= 0xDFFF) ||
7198      (ch < 0x80 && nb > 1) ||
7199      (ch < 0x800 && nb > 2) ||
7200      (ch < 0x10000 && nb > 3))
7201    {
7202       ch = 0;
7203       nb = 0;
7204    }
7205    if(numBytes) *numBytes = nb;
7206    return ch;
7207 }
7208
7209 public int UTF8toUTF16Buffer(const char * source, uint16 * dest, int max)
7210 {
7211    if(source)
7212    {
7213       int c;
7214       int d = 0;
7215       for(c = 0; source[c];)
7216       {
7217          byte ch = source[c];
7218          unichar codePoint = 0;
7219          int numBytes = 1;
7220          int i;
7221          byte mask = 0x7F;
7222          if(ch & 0x80 && ch & 0x40)
7223          {
7224             mask >>= 2;
7225             numBytes++;
7226             if(ch & 0x20)
7227             {
7228                numBytes++;
7229                mask >>= 1;
7230                if(ch & 0x10)
7231                {
7232                   numBytes++;
7233                   mask >>= 1;
7234                }
7235             }
7236          }
7237          for(i = 0; i<numBytes; i++)
7238          {
7239             codePoint <<= 6;
7240             codePoint |= source[c++] & mask;
7241             mask = 0x3F;
7242          }
7243
7244          if(codePoint > 0xFFFF)
7245          {
7246             uint16 lead = (uint16)(LEAD_OFFSET + (codePoint >> 10));
7247             uint16 trail = (uint16)(0xDC00 | (codePoint & 0x3FF));
7248             if(d >= max - 1) break;
7249             dest[d++] = lead;
7250             dest[d++] = trail;
7251          }
7252          else
7253          {
7254             if(d >= max) break;
7255             dest[d++] = (uint16)codePoint;
7256          }
7257       }
7258       dest[d] = 0;
7259       return d;
7260    }
7261    return 0;
7262 }
7263
7264 public int UTF32toUTF8Len(const unichar * source, int count, char * dest, int max)
7265 {
7266    int c;
7267    int d = 0;
7268    uint32 ch;
7269    byte * byteDest = (byte *)dest;
7270    for(c = 0; c<count && (ch = source[c]); c++)
7271    {
7272       if(ch < 0x80)
7273       {
7274          if(d + 1 >= max) break;
7275          byteDest[d++] = (char)ch;
7276       }
7277       else if(ch < 0x800)
7278       {
7279          if(d + 2 >= max) break;
7280          byteDest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7281          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7282       }
7283       else if(ch < 0x10000)
7284       {
7285          if(d + 3 >= max) break;
7286          byteDest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7287          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7288          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7289       }
7290       else
7291       {
7292          if(d + 4 >= max) break;
7293          byteDest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7294          byteDest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7295          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7296          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7297       }
7298    }
7299    byteDest[d] = 0;
7300    return d;
7301 }
7302
7303 public uint16 * UTF8toUTF16(const char * source, int * wordCount)
7304 {
7305    if(source)
7306    {
7307       int len = (int)strlen(source);
7308       uint16 * dest = new uint16[len + 1];
7309       int c;
7310       int d = 0;
7311       for(c = 0; source[c];)
7312       {
7313          byte ch = source[c];
7314          unichar codePoint = 0;
7315          int numBytes = 1;
7316          int i;
7317          byte mask = 0x7F;
7318          if(ch & 0x80 && ch & 0x40)
7319          {
7320             mask >>= 2;
7321             numBytes++;
7322             if(ch & 0x20)
7323             {
7324                numBytes++;
7325                mask >>= 1;
7326                if(ch & 0x10)
7327                {
7328                   numBytes++;
7329                   mask >>= 1;
7330                }
7331             }
7332          }
7333          for(i = 0; i<numBytes; i++)
7334          {
7335             codePoint <<= 6;
7336             codePoint |= source[c++] & mask;
7337             mask = 0x3F;
7338          }
7339
7340          if(codePoint > 0xFFFF)
7341          {
7342             uint16 lead = (uint16)(LEAD_OFFSET + (codePoint >> 10));
7343             uint16 trail = (uint16)(0xDC00 | (codePoint & 0x3FF));
7344             dest[d++] = lead;
7345             dest[d++] = trail;
7346          }
7347          else
7348          {
7349             dest[d++] = (uint16)codePoint;
7350          }
7351       }
7352       dest[d] = 0;
7353       if(wordCount) *wordCount = d;
7354       return dest;
7355    }
7356    return null;
7357 }
7358
7359 namespace com;
7360
7361 #if !defined(MEMINFO) && defined(MEMTRACKING)
7362 import "Map"
7363
7364 Map<Class, int> blocksByClass { };
7365 Map<Class, uintsize> sizeByClass { };
7366 #endif
7367
7368 public void queryMemInfo(char * string)
7369 {
7370 #if !defined(MEMINFO) && defined(MEMTRACKING) && !defined(DISABLE_MEMMGR)
7371    char s[1024];
7372    int p;
7373    uint numBlocks = 0;
7374    uintsize totalMemUsed = 0;
7375    sprintf(s, "Total System Memory Usage: %.02f\n", TOTAL_MEM / 1048576.0f);
7376    strcat(string, s);
7377
7378    for(p = 0; pools && p < NUM_POOLS; p++)
7379    {
7380       BlockPool * pool = &pools[p];
7381       if(pool->totalSize)
7382       {
7383          numBlocks += pool->totalSize;
7384          sprintf(s, "%8d bytes: %d blocks in %d parts (%.02f mb used; taking up %.02f mb space)\n",
7385             pool->blockSize, pool->numBlocks, pool->numParts, pool->usedSpace / 1048576.0f, pool->totalSize * pool->blockSpace / 1048576.0f);
7386          totalMemUsed += pool->usedSpace;
7387          strcat(string, s);
7388       }
7389    }
7390
7391
7392    blocksByClass.Free();
7393    sizeByClass.Free();
7394 #if !defined(__EMSCRIPTEN__)
7395    memMutex.Wait();
7396 #endif
7397    for(p = 0; pools && p < NUM_POOLS; p++)
7398    {
7399       BlockPool * pool = &pools[p];
7400       MemBlock block;
7401       for(block = pool->first; block; block = block.next)
7402       {
7403          Class c = block._class;
7404          blocksByClass[c]++;
7405          sizeByClass[c] += block.size;
7406       }
7407    }
7408 #if !defined(__EMSCRIPTEN__)
7409    memMutex.Release();
7410 #endif
7411
7412    //for(c : blocksByClass)
7413    {
7414       MapIterator<Class, int> it { map = blocksByClass };
7415       while(it.Next())
7416       {
7417          int c = it.data;
7418          Class _class = it.key; //&c;
7419          uintsize size = sizeByClass[_class];
7420          float totalSize = (float) size / 1048576.0f;
7421          if(totalSize > 1)
7422          {
7423             sprintf(s, "%s (%d bytes): %d instances (%.02f mb used)\n", _class ? _class.name : "(none)", (int)size, c, totalSize);
7424             strcat(string, s);
7425          }
7426       }
7427    }
7428
7429    sprintf(s, "Non-pooled memory: %.02f\n", OUTSIDE_MEM / 1048576.0f);
7430    strcat(string, s);
7431    sprintf(s, "Total Memory in use: %.02f\n", (float)(totalMemUsed + OUTSIDE_MEM) / 1048576.0f);
7432    strcat(string, s);
7433
7434    sprintf(s, "Total Blocks Count: %d (%.02f mb overhead)\n", numBlocks, (float)sizeof(struct MemBlock) * numBlocks / 1048576.0f);
7435    strcat(string, s);
7436 #ifdef MEMORYGUARD
7437    sprintf(s, "MemoryGuard: %d blocks (%.02f mb RedZone, %.02f mb MemInfo)\n", memBlocks.count,
7438       numBlocks * 2 * REDZONE / 1048576.0f, sizeof(struct MemInfo) * memBlocks.count / 1048576.0f);
7439    strcat(string, s);
7440 #endif
7441 #endif
7442 }