097b7328b91c51c4047491fedaf7e7217476f6e7
[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, "SymbolStyle"))
2818             {
2819                _class.offset = force32Bits ? 24 : 12;
2820             }
2821             // 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
2822             else if(strstr(name, "ecere::sys::EARHeader") ||
2823                strstr(name, "AnchorValue") ||
2824                !strcmp(name, "ecere::com::CustomAVLTree") ||
2825                !strcmp(name, "ecere::com::Array") ||
2826                !strcmp(name, "ecere::gui::Window") ||
2827                !strcmp(name, "ecere::sys::Mutex"));   // Never recompute these, they're always problematic (errors, crashes)
2828             else
2829             {
2830                if(!strcmp(name, "ecere::sys::FileListing"))
2831                {
2832                   size = 3*(force32Bits ? 4 : 8);
2833                   _class.structAlignment = force32Bits ? 4 : 8;   // FileListing is problematic because it is a struct with private data that the user allocates
2834                   _class.pointerAlignment = 1;
2835                }
2836                // These we want to recompute inside the IDE to help the debugger
2837                else if(!strcmp(name, "ecere::com::Class"))           size = 0; // 616
2838                else if(!strcmp(name, "ecere::com::ClassProperty"))   size = 0; // 80
2839                else if(!strcmp(name, "ecere::com::NameSpace"))       size = 0; // 176
2840                else if(!strcmp(name, "ecere::sys::BufferedFile"))    size = 0;
2841                else if(!strcmp(name, "ecere::sys::BTNode"))          size = 0;
2842                else if(!strcmp(name, "ecere::sys::StringBTNode"))    size = 0;
2843                else if(!strcmp(name, "ecere::sys::OldList"))         size = 0; // 32
2844                else if(!strcmp(name, "ecere::sys::Item"))            size = 0;
2845                else if(!strcmp(name, "ecere::sys::NamedLink"))       size = 0;
2846                else if(!strcmp(name, "ecere::sys::NamedLink64"))     size = 0;
2847                else if(!strcmp(name, "ecere::sys::OldLink"))         size = 0;
2848                else if(!strcmp(name, "ecere::sys::NamedItem"))       size = 0;
2849                else if(!strcmp(name, "ecere::sys::NamedItem64"))     size = 0;
2850                else if(!strcmp(name, "ecere::sys::BinaryTree"))      size = 0;
2851                else if(module != module.application && inCompiler)
2852                {
2853                   // These we only want to recompute inside the compiler
2854                   if(fixed || type == structClass)
2855                      size = 0;
2856                }
2857             }
2858          }
2859          if(type == structClass)
2860          {
2861             _class.memberOffset = (base && base.structSize && base.type != systemClass) ? base.structSize : 0;
2862             // THIS IS NEW...
2863             _class.typeSize = _class.structSize = _class.memberOffset + size;
2864          }
2865          else if(type == bitClass || type == enumClass || type == unitClass)
2866          {
2867             Class dataTypeClass = eSystem_FindClass(_class.module, dataTypeString);
2868             if(dataTypeClass)
2869                _class.typeSize = dataTypeClass.typeSize;
2870             _class.structSize = 0;
2871          }
2872          else if(type == normalClass || type == noHeadClass)
2873          {
2874             _class.structSize = _class.offset + size;
2875             _class.typeSize = sizeof(void *);
2876          }
2877          _class.offsetClass = offsetClass;
2878          _class.sizeClass = totalSizeClass;
2879          _class.Constructor = Constructor;
2880          _class.Destructor = Destructor;
2881          if(_class.type != systemClass)
2882             _class.type = type;
2883          if(!size)
2884             _class.computeSize = true;
2885          else
2886             _class.computeSize = false;
2887          _class.inheritanceAccess = inheritanceAccess;
2888
2889          /*if(type == bitClass)
2890             _class.size = 0;*/
2891          if(type == enumClass)
2892          {
2893             if(enumBase)
2894                _class.base = base = enumBase;
2895             //else
2896             {
2897                EnumClassData data = (EnumClassData)_class.data;
2898                // TOCHECK: Trying this (if specifiers specified, no class found...)
2899                // What about bit classes, unit classes...
2900                if(base && base.type != enumClass)
2901                   data.largest = -1;//_class.base = null;
2902                else
2903                   data.largest = ((EnumClassData)(base.data)).largest;
2904             }
2905          }
2906          if(base)
2907          {
2908             int i;
2909             uint oldSize = _class.vTblSize;
2910             if(base.vTblSize && _class.vTblSize < base.vTblSize)
2911             {
2912                _class.vTblSize = base.vTblSize;
2913                // OK to scrap existing virtual table?
2914                //delete _class._vTbl;
2915                //_class._vTbl = _malloc(sizeof(int(*)()) * _class.vTblSize);
2916                // memcpy(_class._vTbl, base._vTbl, sizeof(int(*)()) * _class.vTblSize);
2917                _class._vTbl = _realloc(_class._vTbl, sizeof(int(*)()) * _class.vTblSize);
2918             }
2919             if(!prevBase)
2920             {
2921                if(_class.type == normalClass && strcmp(_class.name, "ecere::com::Instance") && strcmp(_class.name, "enum") && strcmp(_class.name, "struct"))
2922                   prevBase = eSystem_FindClass(module, "ecere::com::Instance");
2923                else
2924                   prevBase = eSystem_FindClass(module, "class");
2925             }
2926             for(i = 0; i < base.vTblSize; i++)
2927             {
2928                if(i >= oldSize || _class._vTbl[i] == prevBase._vTbl[i])
2929                   _class._vTbl[i] = base._vTbl[i];
2930             }
2931          }
2932
2933          if(_class.base)
2934          {
2935             OldLink link { data = _class };
2936             /*(_class.base.templateClass ? _class.base.templateClass : _class.base)*/_class.base.derivatives.Add(link);
2937          }
2938
2939          FixDerivativesBase(_class, _class);
2940
2941          return _class;
2942       }
2943    }
2944    return null;
2945 }
2946
2947 static void DataMember_Free(DataMember parentMember)
2948 {
2949    DataMember member;
2950    BTNamedLink namedLink;
2951    delete (void *)parentMember.name;
2952    delete (void *)parentMember.dataTypeString;
2953
2954    while((member = parentMember.members.first))
2955    {
2956       DataMember_Free(member);
2957       parentMember.members.Delete(member);
2958    }
2959
2960    while((namedLink = (BTNamedLink)parentMember.membersAlpha.first))
2961    {
2962       parentMember.membersAlpha.Delete((BTNode)namedLink);
2963    }
2964 }
2965
2966 static void FreeEnumValue(NamedLink64 value)
2967 {
2968    delete value.name;
2969 }
2970
2971 static void FreeTemplateArg(Class template, ClassTemplateParameter param, int id)
2972 {
2973    switch(param.type)
2974    {
2975       case type:
2976          delete (void *)template.templateArgs[id].dataTypeString;
2977          template.templateArgs[id].dataTypeClass = null;
2978          break;
2979       case identifier:
2980          delete (void *)template.templateArgs[id].memberString;
2981          break;
2982       case expression:
2983
2984          break;
2985    }
2986 }
2987
2988 static void FreeTemplateArgs(Class template)
2989 {
2990    if(template.templateArgs)
2991    {
2992       Class _class;
2993       for(_class = template; _class; _class = _class.base)
2994       {
2995          Class prevClass;
2996          ClassTemplateParameter param;
2997          int id = 0;
2998          if(_class.templateClass) _class = _class.templateClass;
2999          for(prevClass = _class.base; prevClass; prevClass = prevClass.base)
3000          {
3001             if(prevClass.templateClass) prevClass = prevClass.templateClass;
3002             id += prevClass.templateParams.count;
3003          }
3004          if(id < template.numParams)
3005          {
3006             for(param = _class.templateParams.first; param; param = param.next)
3007             {
3008                switch(param.type)
3009                {
3010                   case type:
3011                      delete (void *)template.templateArgs[id].dataTypeString;
3012                      template.templateArgs[id].dataTypeClass = null;
3013                      break;
3014                   case identifier:
3015                      delete (void *)template.templateArgs[id].memberString;
3016                      break;
3017                   case expression:
3018                      // delete template.templateArgs[id].dataTypeString;
3019                      break;
3020                }
3021                id++;
3022             }
3023          }
3024       }
3025    }
3026 }
3027
3028 static void FreeTemplate(Class template)
3029 {
3030    OldLink deriv;
3031
3032    if(template.nameSpace)
3033    {
3034       BTNamedLink link = (BTNamedLink)template.nameSpace->classes.FindString(template.name);
3035       if(link)
3036          template.nameSpace->classes.Delete((BTNode)link);
3037    }
3038
3039    FreeTemplatesDerivatives(template);
3040    FreeTemplateArgs(template);
3041
3042    while((deriv = template.derivatives.first))
3043    {
3044       ((Class)deriv.data).base = null;
3045       template.derivatives.Delete(deriv);
3046    }
3047
3048    delete (void *)template.fullName;
3049    delete (void *)template.name;
3050    delete template.templateArgs;
3051    delete (void *)template.dataTypeString;
3052
3053    if(template.module)
3054       template.module.classes.Delete(template);
3055    else
3056       _free(template);
3057 }
3058
3059 static void FreeTemplates(Class _class)
3060 {
3061    OldLink deriv, template;
3062
3063    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
3064    {
3065       FreeTemplates(deriv.data);
3066    }
3067
3068    FreeTemplateArgs(_class);
3069    delete _class.templateArgs;
3070    delete (void *)_class.dataTypeString;
3071
3072    while((template = _class.templatized.first))
3073    {
3074       FreeTemplates(template.data);
3075       FreeTemplate(template.data);
3076       _class.templatized.Delete(template);
3077    }
3078 }
3079
3080 public dllexport void eClass_Unregister(Class _class)
3081 {
3082    BTNamedLink namedLink;
3083    DataMember member;
3084    Method method;
3085    OldLink deriv, template;
3086    ClassProperty classProp;
3087    ClassTemplateParameter param;
3088
3089    if(_class.templateClass)
3090    {
3091       // Unregistering templates... Used in IDE to address crash on Ecere classes templatized with imported modules
3092       OldLink templateLink;
3093       for(templateLink = _class.templateClass.templatized.first; templateLink; templateLink = templateLink.next)
3094       {
3095          if(templateLink.data == _class)
3096          {
3097             _class.templateClass.templatized.Delete(templateLink);
3098             break;
3099          }
3100       }
3101       FreeTemplate(_class);
3102       return;
3103    }
3104
3105    delete _class._vTbl;
3106
3107    FreeTemplates(_class);
3108
3109    while((template = _class.templatized.first))
3110    {
3111       FreeTemplate(template.data);
3112       _class.templatized.Delete(template);
3113    }
3114
3115    while((member = _class.membersAndProperties.first))
3116    {
3117       if(!member.isProperty && (member.type == unionMember || member.type == structMember))
3118          DataMember_Free(member);
3119       delete (void *)member.name;
3120       delete (void *)member.dataTypeString;
3121       _class.membersAndProperties.Delete(member);
3122    }
3123
3124    while((member = _class.conversions.first))
3125    {
3126       delete (void *)member.name;
3127       delete (void *)member.dataTypeString;
3128       _class.conversions.Delete(member);
3129    }
3130
3131    while((namedLink = (BTNamedLink)_class.prop.first))
3132    {
3133       _class.prop.Delete((BTNode)namedLink);
3134    }
3135
3136    while((namedLink = (BTNamedLink)_class.members.first))
3137    {
3138       _class.members.Delete((BTNode)namedLink);
3139    }
3140
3141    while((classProp = (ClassProperty)_class.classProperties.first))
3142    {
3143       delete (void *)classProp.name;
3144       delete (void *)classProp.dataTypeString;
3145       _class.classProperties.Delete((BTNode)classProp);
3146    }
3147
3148    while((method = (Method)_class.methods.first))
3149    {
3150       delete (void *)method.name;
3151       delete (void *)method.dataTypeString;
3152       _class.methods.Delete((BTNode)method);
3153    }
3154
3155    if(_class.type == enumClass)
3156    {
3157       EnumClassData data = (EnumClassData)_class.data;
3158
3159       data.values.Free((void *)FreeEnumValue);
3160    }
3161    _class.delayedCPValues.Free(null);
3162
3163    _class.selfWatchers.Free(null);
3164
3165    if(_class.base)
3166    {
3167       // Class base = _class.base.templateClass ? _class.base.templateClass : _class.base;
3168       Class base = _class.base;
3169       for(deriv = base.derivatives.first; deriv; deriv = deriv.next)
3170       {
3171          if(deriv.data == _class)
3172             break;
3173       }
3174       if(deriv)
3175          base.derivatives.Delete(deriv);
3176    }
3177    while((deriv = _class.derivatives.first))
3178    {
3179       ((Class)deriv.data).base = null;
3180       _class.derivatives.Delete(deriv);
3181    }
3182
3183    if(_class.nameSpace)
3184    {
3185       BTNamedLink link = (BTNamedLink)_class.nameSpace->classes.FindString(_class.name);
3186       _class.nameSpace->classes.Delete((BTNode)link);
3187    }
3188
3189    delete (void *)_class.name;
3190    delete (void *)_class.fullName;
3191
3192    delete (void *)_class.dataTypeString;
3193
3194    delete _class.data;
3195
3196    while((param = _class.templateParams.first))
3197    {
3198       switch(param.type)
3199       {
3200          case type:
3201             delete (void *)param.defaultArg.dataTypeString;
3202             break;
3203          case identifier:
3204             delete (void *)param.defaultArg.memberString;
3205             break;
3206          case expression:
3207
3208             break;
3209       }
3210       if(param.type != identifier) delete (void *)param.dataTypeString;
3211       delete (void *)param.name;
3212
3213       _class.templateParams.Delete(param);
3214    }
3215
3216    //_class.nameSpace->classes.Delete(_class);
3217    _free(_class);
3218 }
3219
3220 static BTNamedLink ScanNameSpace(NameSpace nameSpace, const char * name, void * listOffset)
3221 {
3222    BinaryTree * tree = (BinaryTree *)((byte *)nameSpace + (uintptr)listOffset);
3223    BTNamedLink link = (BTNamedLink)tree->Find((uintptr)name);
3224    NameSpace * child;
3225    if(!link)
3226    {
3227       for(child = (NameSpace *)nameSpace.nameSpaces.first; child; child = (NameSpace *)((BTNode)child).next)
3228       {
3229          link = ScanNameSpace(child, name, listOffset);
3230          if(link)
3231             break;
3232       }
3233    }
3234    return link;
3235 }
3236
3237 static BTNamedLink SearchNameSpace(NameSpace nameSpace, const char * name, void * listOffset)
3238 {
3239    int start = 0, c;
3240    char ch;
3241    int level = 0;
3242    for(c = 0; (ch = name[c]); c++)
3243    {
3244       if(ch == '<') level++;
3245       if(ch == '>') level--;
3246       if(level == 0 && (ch == '.' || (ch == ':' && name[c+1] == ':')))
3247       {
3248          NameSpace * newSpace;
3249          char * spaceName = _malloc(c - start + 1);
3250          memcpy(spaceName, name + start, c - start);
3251          spaceName[c-start] = '\0';
3252          newSpace = (NameSpace *)nameSpace.nameSpaces.FindString(spaceName);
3253          _free(spaceName);
3254          if(!newSpace)
3255             return null;
3256          nameSpace = newSpace;
3257          if(level == 0 && ch == ':') c++;
3258          start = c+1;
3259       }
3260    }
3261    if(c - start)
3262    {
3263       return ScanNameSpace(nameSpace, name + start, listOffset);
3264    }
3265    return null;
3266 }
3267
3268 static BTNamedLink SearchModule(Module module, const char * name, void * listOffset, bool searchPrivate)
3269 {
3270    SubModule subModule;
3271    BTNamedLink link;
3272
3273    if(searchPrivate)
3274    {
3275       link = SearchNameSpace(&module.privateNameSpace, name, listOffset);
3276       if(link) return link;
3277    }
3278    link = SearchNameSpace(&module.publicNameSpace, name, listOffset);
3279    if(link) return link;
3280
3281    for(subModule = module.modules.first; subModule; subModule = subModule.next)
3282    {
3283       if(searchPrivate || subModule.importMode == publicAccess)
3284       {
3285          // TOCHECK: Reverting to false to test what we were trying to fix by passing searchPrivate
3286          // Passing searchPrivate finds ALL classes private or not and thus classes clash
3287          // SearchModule here is called mainly from eSystem_FindClass, and also for Functions and Defines
3288
3289          link = SearchModule(subModule.module, name, listOffset, false);
3290          //link = SearchModule(subModule.module, name, listOffset, searchPrivate /*false*/);
3291          if(link) return link;
3292       }
3293    }
3294    return null;
3295 }
3296
3297 public int64 _strtoi64(const char * string, const char ** endString, int base)
3298 {
3299    int64 value = 0;
3300    int sign = 1;
3301    int c;
3302    char ch;
3303    for(c = 0; (ch = string[c]) && isspace(ch); c++);
3304    if(ch =='+') c++;
3305    else if(ch == '-') { sign = -1; c++; };
3306    if(!base)
3307    {
3308       if(ch == '0' && string[c+1] == 'x')
3309       {
3310          base = 16;
3311          c+=2;
3312       }
3313       else if(ch == '0')
3314       {
3315          base = 8;
3316          c++;
3317       }
3318       else
3319          base = 10;
3320    }
3321    for( ;(ch = string[c]); c++)
3322    {
3323       if(ch >= '0' && ch <= '9')
3324          ch -= '0';
3325       else if(ch >= 'a' && ch <= 'z')
3326          ch -= ('a' - 10);
3327       else if(ch >= 'A' && ch <= 'Z')
3328          ch -= ('A'- 10);
3329       else
3330          // Invalid character
3331          break;
3332       if(ch < base)
3333       {
3334          value *= base;
3335          value += ch;
3336       }
3337       else
3338          // Invalid character
3339          break;
3340    }
3341    if(endString)
3342       *endString = string + c;
3343
3344    return sign*value;
3345 }
3346
3347 public uint64 _strtoui64(const char * string, const char ** endString, int base)
3348 {
3349    uint64 value = 0;
3350    int sign = 1;
3351    int c;
3352    char ch;
3353    for(c = 0; (ch = string[c]) && isspace(ch); c++);
3354    if(ch =='+') c++;
3355    else if(ch == '-') { sign = -1; c++; };
3356    if(!base)
3357    {
3358       if(ch == '0' && string[c+1] == 'x')
3359       {
3360          base = 16;
3361          c+=2;
3362       }
3363       else if(ch == '0')
3364       {
3365          base = 8;
3366          c++;
3367       }
3368       else
3369          base = 10;
3370    }
3371    for( ;(ch = string[c]); c++)
3372    {
3373       if(ch >= '0' && ch <= '9')
3374          ch -= '0';
3375       else if(ch >= 'a' && ch <= 'z')
3376          ch -= ('a' - 10);
3377       else if(ch >= 'A' && ch <= 'Z')
3378          ch -= ('A' - 10);
3379       else
3380          // Invalid character
3381          break;
3382       if(ch < base)
3383       {
3384          value *= base;
3385          value += ch;
3386       }
3387       else
3388          // Invalid character
3389          break;
3390    }
3391    if(endString)
3392       *endString = string + c;
3393    return sign*value;
3394 }
3395
3396 public dllexport Class eSystem_FindClass(Module module, const char * name)
3397 {
3398    if(name && module)
3399    {
3400       BTNamedLink link;
3401       if(!strncmp(name, "const ", 6)) name += 6;
3402       link = SearchNameSpace(&module.application.systemNameSpace, name, &((NameSpace *)0)->classes);
3403       if(link) return link.data;
3404
3405       link = SearchModule(module, name, &((NameSpace *)0)->classes, true);
3406       if(link) return link.data;
3407
3408       {
3409          char noTemplateName[1024];
3410          char * templateParams = strchr(name, '<');
3411
3412          if(templateParams)
3413          {
3414             strncpy(noTemplateName, name, templateParams - name);
3415             noTemplateName[templateParams - name] = '\0';
3416          }
3417          else
3418             strcpy(noTemplateName, name);
3419
3420          link = SearchNameSpace(&module.application.systemNameSpace, noTemplateName, &((NameSpace *)0)->classes);
3421          if(!link)
3422             link = SearchModule(module, noTemplateName, &((NameSpace *)0)->classes, true);
3423          if(link)
3424          {
3425             Class _class = link.data;
3426             Class templatedClass = null;
3427             char className[1024];
3428             strcpy(className, _class.fullName);
3429             strcat(className, templateParams);
3430
3431             link = SearchNameSpace(&module.application.systemNameSpace, className, &((NameSpace *)0)->classes);
3432             if(link)
3433                return link.data;
3434
3435             link = SearchModule(module, className, &((NameSpace *)0)->classes, true);
3436             if(link)
3437                return link.data;
3438
3439             if(_class && templateParams)
3440             {
3441                // if(!numParams) return null;
3442
3443                templatedClass = Class { };
3444                *templatedClass = *_class;
3445                templatedClass.templateClass = _class;
3446                //templatedClass.fullName = CopyString(name);
3447                templatedClass.fullName = CopyString(className);
3448                templatedClass.dataTypeString = CopyString(_class.dataTypeString);
3449                templatedClass.name = CopyString(templatedClass.fullName + strlen(_class.fullName) - strlen(_class.name));
3450                templatedClass.nameSpace->classes.Add((BTNode)BTNamedLink { name = (char *)templatedClass.name, data = templatedClass });
3451                templatedClass.templateArgs = null;
3452                templatedClass.numParams = 0;
3453                templatedClass.derivatives = { };
3454                templatedClass.templatized = { };
3455                templatedClass.module = module;
3456                templatedClass.count = 0; // TOCHECK: Keeping track of individual templatized classes?
3457                templatedClass.prev = null;
3458                templatedClass.next = null;
3459
3460                module.classes.Add(templatedClass);
3461
3462                ComputeClassParameters(templatedClass, templateParams, module);
3463
3464                _class.templatized.Add(OldLink { data = templatedClass });
3465             }
3466             return templatedClass;
3467          }
3468       }
3469    }
3470    return null;
3471 }
3472
3473 static void CopyTemplateArg(ClassTemplateParameter param, ClassTemplateArgument arg)
3474 {
3475    switch(param.type)
3476    {
3477       case type:
3478             arg.dataTypeString = CopyString(arg.dataTypeString);
3479          break;
3480       case expression:
3481
3482          break;
3483       case identifier:
3484          arg.memberString = CopyString(arg.memberString);
3485          break;
3486    }
3487 }
3488
3489 static void ComputeClassParameters(Class templatedClass, const char * templateParams, Module findModule)
3490 {
3491    char ch;
3492    const char * nextParamStart = templateParams ? (templateParams + 1) : null;
3493    ClassTemplateParameter curParam = null;
3494    Class lastClass = null, sClass;
3495    int curParamID = 0;
3496    int numParams = 0;
3497    Class _class = templatedClass.templateClass ? templatedClass.templateClass : templatedClass;
3498
3499    for(sClass = _class; sClass; sClass = sClass.base)
3500    {
3501       if(sClass.templateClass) sClass = sClass.templateClass;
3502       numParams += sClass.templateParams.count;
3503    }
3504
3505    if(templatedClass.templateArgs)
3506       FreeTemplateArgs(templatedClass);
3507    delete templatedClass.templateArgs;
3508    templatedClass.templateArgs = new0 ClassTemplateArgument[numParams];
3509    templatedClass.numParams = numParams;
3510
3511    if(_class != templatedClass)
3512    {
3513       /*int c;
3514       Class sClass;
3515       memcpy(templatedClass.templateArgs, _class.templateArgs, numParams * sizeof(ClassTemplateArgument));
3516       for(sClass = _class; sClass; sClass = sClass.base)
3517       {
3518          ClassTemplateParameter param;
3519          Class prevClass;
3520          int id = 0;
3521          if(sClass.templateClass) sClass = sClass.templateClass;
3522          for(prevClass = sClass.base; prevClass; prevClass = prevClass.base)
3523          {
3524             if(prevClass.templateClass) prevClass = prevClass.templateClass;
3525             id += prevClass.templateParams.count;
3526          }
3527          for(param = sClass.templateParams.first; param; param = param.next)
3528            CopyTemplateArg(param, templatedClass.templateArgs[id++]);
3529       }*/
3530    }
3531
3532    if(templatedClass.base && templatedClass.base.templateArgs && _class == templatedClass)
3533    {
3534       Class sClass;
3535       memcpy(templatedClass.templateArgs, templatedClass.base.templateArgs,
3536          sizeof(ClassTemplateArgument) * (numParams - templatedClass.templateParams.count));
3537       for(sClass = templatedClass.base; sClass; sClass = sClass.base)
3538       {
3539          ClassTemplateParameter param;
3540          Class prevClass;
3541          int id = 0;
3542          for(prevClass = sClass.base; prevClass; prevClass = prevClass.base)
3543          {
3544             if(prevClass.templateClass) prevClass = prevClass.templateClass;
3545             id += prevClass.templateParams.count;
3546          }
3547
3548          if(sClass.templateClass) sClass = sClass.templateClass;
3549          for(param = sClass.templateParams.first; param; param = param.next)
3550             CopyTemplateArg(param, templatedClass.templateArgs[id++]);
3551       }
3552    }
3553
3554    while(nextParamStart)
3555    {
3556       const char * paramStart = nextParamStart;
3557       const char * paramEnd;
3558       int level = 0;
3559       while(*paramStart == ' ') paramStart++;
3560       paramEnd = paramStart;
3561       while((ch = *paramEnd, ch && (level > 0 || (ch != '>' && ch != ','))))
3562       {
3563          if(ch == '<') level++;
3564          if(ch == '>') level--;
3565
3566          paramEnd++;
3567       }
3568       nextParamStart = (ch == ',') ? (paramEnd + 1) : null;
3569       while(*paramEnd == ' ') paramEnd--;
3570       if(paramEnd > paramStart)
3571       {
3572          const char * ptr, * equal = null;
3573          for(ptr = paramStart; ptr <= paramEnd; ptr++)
3574          {
3575             if(*ptr == '=')
3576             {
3577                equal = ptr;
3578                break;
3579             }
3580          }
3581          if(equal)
3582          {
3583             const char * end = equal - 1;
3584             char ident[1024];
3585
3586             while(*end == ' ') end--;
3587             strncpy(ident, paramStart, end + 1 - paramStart);
3588             ident[end + 1 - paramStart] = 0;
3589
3590             for(sClass = _class; sClass; sClass = sClass.base)
3591             {
3592                if(sClass.templateClass) sClass = sClass.templateClass;
3593                for(curParam = sClass.templateParams.first; curParam; curParam = curParam.next)
3594                {
3595                   if(!strcmp(curParam.name, ident))
3596                      break;
3597                }
3598                if(curParam)
3599                {
3600                   Class nextClass;
3601                   ClassTemplateParameter prevParam;
3602                   curParamID = 0;
3603                   for(prevParam = curParam.prev; prevParam; prevParam = prevParam.prev) curParamID++;
3604                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3605                   {
3606                      if(nextClass.templateClass) nextClass = nextClass.templateClass;
3607                      curParamID += nextClass.templateParams.count;
3608                   }
3609                   break;
3610                }
3611             }
3612             lastClass = sClass;
3613          }
3614          else
3615          {
3616             if(curParam)
3617             {
3618                curParam = curParam.next;
3619                curParamID++;
3620             }
3621
3622             if(!curParam)
3623             {
3624                for(sClass = lastClass ? lastClass.base : _class; sClass; sClass = sClass.base)
3625                {
3626                   ClassTemplateParameter param;
3627                   curParamID = 0;
3628                   if(sClass.templateClass) sClass = sClass.templateClass;
3629                   for(param = sClass.templateParams.first; param; param = param.next, curParamID++)
3630                   {
3631                      curParam = param;
3632                      break;
3633                   }
3634                   if(curParam)
3635                   {
3636                      Class nextClass;
3637                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3638                      {
3639                         if(nextClass.templateClass) nextClass = nextClass.templateClass;
3640                         curParamID += nextClass.templateParams.count;
3641                      }
3642                      lastClass = sClass;
3643                      break;
3644                   }
3645                }
3646                /*
3647                for(sClass = _class; sClass; sClass = sClass.base)
3648                {
3649                   if(sClass.templateParams.first)
3650                   {
3651                      Class nextClass;
3652                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3653                         if(nextClass.templateParams.first)
3654                            break;
3655                      if(nextClass != lastClass) continue;
3656
3657                      curParam = sClass.templateParams.first;
3658                      lastClass = sClass;
3659
3660                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3661                         if(nextClass.templateParams.first)
3662                         {
3663                            curParamID += nextClass.templateParams.count;
3664                            break;
3665                         }
3666                      break;
3667                   }
3668                }
3669                */
3670             }
3671          }
3672
3673          if(curParam)
3674          {
3675             ClassTemplateArgument argument { };
3676             char value[1024];
3677             if(equal)
3678             {
3679                equal++;
3680                while(*equal == ' ') equal++;
3681                memcpy(value, equal, paramEnd - equal);
3682                value[paramEnd - equal] = 0;
3683             }
3684             else
3685             {
3686                memcpy(value, paramStart, paramEnd - paramStart);
3687                value[paramEnd - paramStart] = 0;
3688             }
3689             TrimRSpaces(value, value);
3690
3691             switch(curParam.type)
3692             {
3693                case type:
3694                   argument.dataTypeString = CopyString(value);
3695                   argument.dataTypeClass = eSystem_FindClass(findModule, value);
3696                   if(!argument.dataTypeClass)
3697                      argument.dataTypeClass = eSystem_FindClass(_class.module, value);
3698                   if(!argument.dataTypeClass)
3699                      argument.dataTypeClass = eSystem_FindClass(_class.module.application, value);
3700                   break;
3701                case expression:
3702                {
3703                   Class expClass = eSystem_FindClass(_class.module, curParam.dataTypeString);
3704                   if(!expClass) expClass = eSystem_FindClass(_class.module.application, curParam.dataTypeString);
3705                   if(expClass)
3706                   {
3707                      //if(expClass.type ==
3708                      ((bool (*)(void *, void *, const char *))(void *)expClass._vTbl[__ecereVMethodID_class_OnGetDataFromString])(expClass, &argument.expression, value);
3709                   }
3710                   // Expression should be pre simplified here
3711                   else if(value[0] == '\"')
3712                   {
3713                      char * endQuote = value + strlen(value) - 1;
3714                      if(*endQuote != '\"') endQuote++;
3715                      *endQuote = '\0';
3716                      argument.expression.p = CopyString(value + 1);
3717                   }
3718                   else if(value[0] == '\'')
3719                   {
3720                      int nb;
3721                      unichar ch = UTF8GetChar(value + 1, &nb);
3722                      argument.expression.ui = ch;
3723                   }
3724                   else if(!strcmp(curParam.dataTypeString, "uint"))
3725                   {
3726                      argument.expression.ui = (uint)strtoul(value, null, 0);
3727                   }
3728                   else if(!strcmp(curParam.dataTypeString, "char"))
3729                   {
3730                      argument.expression.c = (char)strtol(value, null, 0);
3731                   }
3732                   else if(!strcmp(curParam.dataTypeString, "byte"))
3733                   {
3734                      argument.expression.uc = (unsigned char)strtoul(value, null, 0);
3735                   }
3736                   else if(!strcmp(curParam.dataTypeString, "short"))
3737                   {
3738                      argument.expression.s = (short)strtol(value, null, 0);
3739                   }
3740                   else if(!strcmp(curParam.dataTypeString, "uint16"))
3741                   {
3742                      argument.expression.us = (unsigned short)strtoul(value, null, 0);
3743                   }
3744                   else if(!strcmp(curParam.dataTypeString, "int64"))
3745                   {
3746                      argument.expression.i64 = _strtoi64(value, null, 0);
3747                   }
3748                   else if(!strcmp(curParam.dataTypeString, "uint64"))
3749                   {
3750                      argument.expression.ui64 = _strtoui64(value, null, 0);
3751                   }
3752                   else if(!strcmp(curParam.dataTypeString, "float"))
3753                   {
3754                      argument.expression.f = (float)strtod(value, null);
3755                   }
3756                   else if(!strcmp(curParam.dataTypeString, "double"))
3757                   {
3758                      argument.expression.d = strtod(value, null);
3759                   }
3760                   else // if(!strcmp(curParam.dataTypeString, "int"))
3761                   {
3762                      argument.expression.i = (int)strtol(value, null, 0);
3763                   }
3764                   break;
3765                }
3766                case identifier:
3767                   argument.memberString = CopyString(value);
3768                   break;
3769             }
3770             FreeTemplateArg(templatedClass, curParam, curParamID);
3771             templatedClass.templateArgs[curParamID] = argument;
3772          }
3773       }
3774    }
3775
3776    // TESTING THIS BEFORE...
3777    if(templatedClass == _class)
3778    {
3779       Class sClass = _class;
3780       int curParamID = 0;
3781       Class nextClass;
3782       ClassTemplateParameter param;
3783       for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3784       {
3785          if(nextClass.templateClass) nextClass = nextClass.templateClass;
3786          curParamID += nextClass.templateParams.count;
3787       }
3788
3789       for(param = sClass.templateParams.first; param; param = param.next)
3790       {
3791          if(!templatedClass.templateArgs[curParamID].dataTypeString)
3792          {
3793             templatedClass.templateArgs[curParamID] = param.defaultArg;
3794             CopyTemplateArg(param, templatedClass.templateArgs[curParamID]);
3795             if(param.type == type && param.defaultArg.dataTypeString)
3796             {
3797                templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(findModule, param.defaultArg.dataTypeString);
3798                if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3799                   templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module, param.defaultArg.dataTypeString);
3800                if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3801                   templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module.application, param.defaultArg.dataTypeString);
3802             }
3803          }
3804          curParamID++;
3805       }
3806    }
3807
3808    if(templatedClass.base && templatedClass.base.templateArgs && numParams - _class.templateParams.count)
3809    {
3810       int c = numParams - _class.templateParams.count-1;
3811
3812       for(sClass = _class.base; sClass; sClass = sClass.base)
3813       {
3814          ClassTemplateParameter param;
3815          if(sClass.templateClass) sClass = sClass.templateClass;
3816          for(param = sClass.templateParams.last; param; param = param.prev)
3817          {
3818             ClassTemplateArgument * arg = &templatedClass.templateArgs[c];
3819             ClassTemplateArgument * baseArg = &templatedClass.base.templateArgs[c];
3820             if(!arg->dataTypeString)
3821             {
3822                *arg = templatedClass.base.templateArgs[c];
3823                CopyTemplateArg(param, arg);
3824                if(param.type == type)
3825                {
3826                   if(arg->dataTypeClass && strchr(arg->dataTypeString, '<') && arg->dataTypeClass.templateArgs)
3827                   {
3828                      Class expClass = arg->dataTypeClass;
3829                      Class cClass = null;
3830                      int paramCount = 0;
3831                      int lastParam = -1;
3832
3833                      char templateString[1024];
3834                      sprintf(templateString, "%s<", expClass.templateClass.fullName);
3835                      for(cClass = expClass; cClass; cClass = cClass.base)
3836                      {
3837                         int p = 0;
3838                         ClassTemplateParameter param;
3839                         for(param = cClass.templateParams.first; param; param = param.next)
3840                         {
3841                            int id = p;
3842                            Class sClass;
3843                            // NOTE: This struct 'arg' here is only to build up templateString
3844                            ClassTemplateArgument arg;
3845                            for(sClass = expClass.base; sClass; sClass = sClass.base) id += sClass.templateParams.count;
3846                            arg = expClass.templateArgs[id];
3847
3848                            {
3849                               ClassTemplateParameter cParam;
3850                               int p = numParams - _class.templateParams.count;
3851                               for(cParam = _class.templateParams.first; cParam; cParam = cParam.next, p++)
3852                               {
3853                                  if(cParam.type == type && arg.dataTypeString && !strcmp(cParam.name, arg.dataTypeString))
3854                                  {
3855                                     arg = templatedClass.templateArgs[p];
3856                                     break;
3857                                  }
3858                               }
3859                            }
3860
3861                            {
3862                               char argument[256];
3863                               argument[0] = '\0';
3864                               switch(param.type)
3865                               {
3866                                  case expression:
3867                                  {
3868                                     // THIS WHOLE THING IS A WILD GUESS... FIX IT UP
3869                                     /*
3870                                     char expString[1024];
3871                                     OldList * specs = MkList();
3872                                     Declarator decl = SpecDeclFromString(param.dataTypeString, specs, null);
3873                                     Expression exp;
3874                                     char * string = PrintHexUInt64(arg.expression.ui64);
3875                                     exp = MkExpCast(MkTypeName(specs, decl), MkExpConstant(string));
3876
3877                                     ProcessExpressionType(exp);
3878                                     ComputeExpression(exp);
3879                                     expString[0] = '\0';
3880                                     PrintExpression(exp, expString);
3881                                     strcat(argument, expString);
3882                                     //delete exp;
3883                                     FreeExpression(exp);
3884                                     */
3885                                     break;
3886                                  }
3887                                  case identifier:
3888                                  {
3889                                     strcat(argument, arg.member.name);
3890                                     break;
3891                                  }
3892                                  case TemplateParameterType::type:
3893                                  {
3894                                     if(arg.dataTypeString)
3895                                        strcat(argument, arg.dataTypeString);
3896                                     break;
3897                                  }
3898                               }
3899                               if(argument[0])
3900                               {
3901                                  if(paramCount) strcat(templateString, ", ");
3902                                  if(lastParam != p - 1)
3903                                  {
3904                                     strcat(templateString, param.name);
3905                                     strcat(templateString, " = ");
3906                                  }
3907                                  strcat(templateString, argument);
3908                                  paramCount++;
3909                                  lastParam = p;
3910                               }
3911                            }
3912                            p++;
3913                         }
3914                      }
3915                      {
3916                         int len = (int)strlen(templateString);
3917                         if(templateString[len-1] == '>') templateString[len++] = ' ';
3918                         templateString[len++] = '>';
3919                         templateString[len++] = '\0';
3920                      }
3921
3922                      FreeTemplateArg(templatedClass, param, c);
3923
3924                      arg->dataTypeString = CopyString(templateString);
3925                      arg->dataTypeClass = eSystem_FindClass(findModule, templateString);
3926                      if(!arg->dataTypeClass)
3927                         arg->dataTypeClass = eSystem_FindClass(templatedClass.module, templateString);
3928                      if(!arg->dataTypeClass)
3929                         arg->dataTypeClass = eSystem_FindClass(templatedClass.module.application, templateString);
3930                   }
3931                   else
3932                   {
3933                      ClassTemplateParameter cParam;
3934                      int p = numParams - _class.templateParams.count;
3935                      for(cParam = _class.templateParams.first; cParam; cParam = cParam.next, p++)
3936                      {
3937                         // if(cParam.type == type && !strcmp(cParam.name, param.name))
3938                         if(cParam.type == type && baseArg->dataTypeString && !strcmp(cParam.name, baseArg->dataTypeString))
3939                         {
3940                            FreeTemplateArg(templatedClass, param, c);
3941
3942                            // TRICKY: This copies from equivalent parameters
3943                            arg->dataTypeString = templatedClass.templateArgs[p].dataTypeString;
3944                            arg->dataTypeClass = templatedClass.templateArgs[p].dataTypeClass;
3945                            CopyTemplateArg(cParam, arg);
3946                            break;
3947                         }
3948                      }
3949                   }
3950                }
3951             }
3952             c--;
3953          }
3954       }
3955    }
3956
3957    {
3958       Class sClass;
3959       for(sClass = _class; sClass; sClass = sClass.base)
3960       {
3961          int curParamID = 0;
3962          Class nextClass;
3963          ClassTemplateParameter param;
3964          if(sClass.templateClass) sClass = sClass.templateClass;
3965
3966          for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
3967          {
3968             if(nextClass.templateClass) nextClass = nextClass.templateClass;
3969             curParamID += nextClass.templateParams.count;
3970          }
3971
3972          for(param = sClass.templateParams.first; param; param = param.next)
3973          {
3974             if(!templatedClass.templateArgs[curParamID].dataTypeString)
3975             {
3976                templatedClass.templateArgs[curParamID] = param.defaultArg;
3977                CopyTemplateArg(param, templatedClass.templateArgs[curParamID]);
3978                if(param.type == type && param.defaultArg.dataTypeString)
3979                {
3980                   templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(findModule, param.defaultArg.dataTypeString);
3981                   if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3982                      templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module, param.defaultArg.dataTypeString);
3983                   if(!templatedClass.templateArgs[curParamID].dataTypeClass)
3984                      templatedClass.templateArgs[curParamID].dataTypeClass = eSystem_FindClass(templatedClass.module.application, param.defaultArg.dataTypeString);
3985                }
3986             }
3987             curParamID++;
3988          }
3989       }
3990    }
3991
3992    {
3993       int c = numParams - 1;
3994       for(sClass = _class; sClass; sClass = sClass.base)
3995       {
3996          ClassTemplateParameter param;
3997          if(sClass.templateClass) sClass = sClass.templateClass;
3998          for(param = sClass.templateParams.last; param; param = param.prev)
3999          {
4000             if(param.type == type)
4001             {
4002                ClassTemplateArgument * arg = &templatedClass.templateArgs[c];
4003                ClassTemplateParameter cParam;
4004                Class dClass;
4005                int p = numParams - 1;
4006                for(dClass = _class; dClass; dClass = dClass.base)
4007                {
4008                   if(dClass.templateClass) dClass = dClass.templateClass;
4009                   for(cParam = dClass.templateParams.last; cParam; cParam = cParam.prev, p--)
4010                   {
4011                      if(cParam.type == type && arg->dataTypeString && !strcmp(cParam.name, arg->dataTypeString))
4012                      {
4013                         if(templatedClass.templateArgs[p].dataTypeString && c != p)
4014                         {
4015                            FreeTemplateArg(templatedClass, param, c);
4016
4017                            arg->dataTypeString = templatedClass.templateArgs[p].dataTypeString;
4018                            arg->dataTypeClass = templatedClass.templateArgs[p].dataTypeClass;
4019                            CopyTemplateArg(cParam, arg);
4020                         }
4021                      }
4022                   }
4023                }
4024             }
4025             c--;
4026          }
4027       }
4028    }
4029
4030    {
4031       Class tClass;
4032       int c = numParams - 1;
4033       for(tClass = _class; tClass; tClass = tClass.base)
4034       {
4035          ClassTemplateParameter param;
4036          if(tClass.templateClass) tClass = tClass.templateClass;
4037          for(param = tClass.templateParams.last; param; param = param.prev)
4038          {
4039             ClassTemplateArgument * arg = &templatedClass.templateArgs[c];
4040             if(param.type == identifier && arg->memberString)
4041             {
4042                Class memberClass = templatedClass;
4043                const char * memberString = arg->memberString;
4044                const char * colon = strstr(memberString, "::");
4045                const char * memberName = memberString;
4046                if(colon) memberName = colon + 2;
4047                if(!colon)
4048                {
4049                   memberString = param.defaultArg.memberString;
4050                   colon = memberString ? strstr(memberString, "::") : null;
4051                }
4052
4053                if(colon)
4054                {
4055                   char className[1024];
4056                   Class sClass;
4057
4058                   memcpy(className, memberString, colon - memberString);
4059                   className[colon - memberString] = '\0';
4060
4061                   for(sClass = _class; sClass; sClass = sClass.base)
4062                   {
4063                      ClassTemplateParameter cParam;
4064                      Class nextClass;
4065                      int id = 0;
4066
4067                      if(sClass.templateClass) sClass = sClass.templateClass;
4068                      for(nextClass = sClass.base; nextClass; nextClass = nextClass.base)
4069                      {
4070                         if(nextClass.templateClass) nextClass = nextClass.templateClass;
4071                         id += nextClass.templateParams.count;
4072                      }
4073                      for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next)
4074                      {
4075                         if(cParam.type == type && !strcmp(cParam.name, className) && templatedClass.templateArgs[id].dataTypeString)
4076                         {
4077                            strcpy(className, templatedClass.templateArgs[id].dataTypeString);
4078                         }
4079                         id++;
4080                      }
4081                   }
4082                   // TESTING: Added this here...
4083                   memberClass = eSystem_FindClass(findModule, className);
4084                   if(!memberClass)
4085                      memberClass = eSystem_FindClass(templatedClass.module, className);
4086                   if(!memberClass)
4087                      memberClass = eSystem_FindClass(templatedClass.module.application, className);
4088                }
4089
4090                if(memberClass)
4091                {
4092                   switch(param.memberType)
4093                   {
4094                      case dataMember:
4095                         arg->member = eClass_FindDataMember(memberClass, memberName, memberClass.module, null, null);
4096                         break;
4097                      case method:
4098                         arg->method = eClass_FindMethod(memberClass, memberName, memberClass.module);
4099                         break;
4100                      case prop:
4101                         arg->prop = eClass_FindProperty(memberClass, memberName, memberClass.module);
4102                         break;
4103                   }
4104                }
4105             }
4106             c--;
4107          }
4108       }
4109    }
4110 }
4111
4112 /*static */bool DefaultFunction()
4113 {
4114    return true;
4115 }
4116
4117 public dllexport bool eClass_IsDerived(Class _class, Class from)
4118 {
4119    if(!_class && !from)
4120       return true;
4121
4122    if(_class && from && (_class.templateClass || from.templateClass))
4123    {
4124       if(eClass_IsDerived(_class.templateClass ? _class.templateClass : _class, from.templateClass ? from.templateClass : from))
4125       {
4126          if(!from.templateClass)
4127             return true;
4128          else if(!_class.templateClass && _class == from.templateClass)
4129             return false;
4130          else
4131          {
4132             Class sClass;
4133             for(sClass = from; sClass; sClass = sClass.base)
4134             {
4135                if(sClass.templateParams.first)
4136                {
4137                   ClassTemplateParameter param;
4138                   Class nextClass;
4139                   int p = 0;
4140                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) p += nextClass.templateParams.count;
4141                   for(param = sClass.templateParams.first; param; param = param.next, p++)
4142                   {
4143                      ClassTemplateArgument * arg = &_class.templateArgs[p];
4144                      ClassTemplateArgument * fArg = &from.templateArgs[p];
4145                      if(param.type == type)
4146                      {
4147                         if(arg->dataTypeString != fArg->dataTypeString && arg->dataTypeString && fArg->dataTypeString &&
4148                           strcmp(arg->dataTypeString, fArg->dataTypeString))
4149                            break;
4150                      }
4151                      else if(param.type == identifier)
4152                      {
4153                         if(arg->member != fArg->member)
4154                            break;
4155                      }
4156                      else if(param.type == expression)
4157                      {
4158                         if(arg->expression.ui64 != fArg->expression.ui64)
4159                            break;
4160                      }
4161                   }
4162                   if(param)
4163                      return false;
4164                }
4165             }
4166             return true;
4167          }
4168       }
4169    }
4170    else
4171    {
4172       for(; _class && from; _class = _class.base)
4173       {
4174          if(_class == from || _class.templateClass == from || ((_class.type == systemClass || (_class.type == normalClass && _class.isInstanceClass)) && from.name && !strcmp(_class.name, from.name)))
4175             return true;
4176       }
4177    }
4178    return false;
4179 }
4180
4181 static void FixDerivativeVirtualMethod(Class base, const char * name, int vid, void * origFunction, const char * type)
4182 {
4183    OldLink derivative;
4184    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
4185    {
4186       Class _class = derivative.data;
4187       Method method, next;
4188       void * function = origFunction;
4189
4190       _class.vTblSize++;
4191       _class._vTbl = renew _class._vTbl void *[_class.vTblSize];
4192       memmove(_class._vTbl + vid + 1, _class._vTbl + vid, (_class.vTblSize - vid - 1) * sizeof(void *));
4193
4194       method = (Method) _class.methods.FindString(name);
4195       if(method)
4196       {
4197          if(method.function) function = method.function;
4198
4199          if(!method.symbol)
4200          {
4201             delete (void *)method.name;
4202             delete (void *)method.dataTypeString;
4203             _class.methods.Delete((BTNode)method);
4204          }
4205          else
4206          {
4207             delete (void *)method.dataTypeString;
4208             method.type = virtualMethod;
4209             method.dataTypeString = CopyString(type);
4210             method._class = base;
4211          }
4212       }
4213       for(method = (Method)_class.methods.first; method; method = next)
4214       {
4215          next = (Method)((BTNode)method).next;
4216          if(method.type == virtualMethod)
4217             method.vid++;
4218       }
4219       _class._vTbl[vid] = function;
4220
4221       {
4222          OldLink templateLink;
4223          for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4224          {
4225             Class template = templateLink.data;
4226             template._vTbl = _class._vTbl;
4227          }
4228       }
4229       if(_class.derivatives.first || _class.templatized.first)
4230          FixDerivativeVirtualMethod(_class, name, vid, function, type);
4231    }
4232    {
4233       OldLink templateLink;
4234       for(templateLink = base.templatized.first; templateLink; templateLink = templateLink.next)
4235       {
4236          Class template = templateLink.data;
4237          template._vTbl = base._vTbl;
4238          FixDerivativeVirtualMethod(template, name, vid, origFunction, type);
4239       }
4240    }
4241 }
4242
4243 public dllexport Method eClass_AddMethod(Class _class, const char * name, const char * type, void * function, AccessMode declMode)
4244 {
4245    if(_class && !_class.comRedefinition && name)
4246    {
4247       Class base;
4248       for(base = _class; base; base = base.base)
4249       {
4250          Method method;
4251          if(base.templateClass) base = base.templateClass;
4252          method = (Method)base.methods.FindString(name);
4253          if(method)
4254          {
4255             // If this overrides a virtual method
4256             if(method.type == virtualMethod)
4257             {
4258                OldLink deriv;
4259                void * oldFunction = _class._vTbl[method.vid];
4260                if(method.vid >= _class.vTblSize)
4261                   printf("error: virtual methods overriding failure\n");
4262                else
4263                   _class._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
4264                for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
4265                {
4266                   Class derivClass = deriv.data;
4267                   if(derivClass._vTbl[method.vid] == oldFunction)
4268                      eClass_AddMethod(derivClass, name, type, function, declMode);
4269                }
4270                {
4271                   OldLink templateLink;
4272                   for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4273                   {
4274                      Class template = templateLink.data;
4275                      for(deriv = template.derivatives.first; deriv; deriv = deriv.next)
4276                      {
4277                         Class derivClass = deriv.data;
4278                         if(derivClass._vTbl[method.vid] == oldFunction)
4279                            eClass_AddMethod(derivClass, name, type, function, declMode);
4280                      }
4281                   }
4282                }
4283
4284             }
4285             else
4286             {
4287                if(base == _class)
4288                {
4289                   // printf("error: Redefinition of method %s in class %s\n", name, _class.name);
4290                   break;
4291                }
4292                base = null;
4293                break;
4294             }
4295             return method;
4296          }
4297       }
4298
4299       if(!base)
4300       {
4301          Method method
4302          {
4303             name = CopyString(name),
4304             function = function ? function : null; //DefaultFunction;
4305             _class = _class;
4306             dataTypeString = CopyString(type);
4307             memberAccess = declMode;
4308          };
4309          _class.methods.Add((BTNode)method);
4310          return method;
4311       }
4312    }
4313    return null;
4314 }
4315
4316 public dllexport Method eClass_AddVirtualMethod(Class _class, const char * name, const char * type, void * function, AccessMode declMode)
4317 {
4318    if(_class && !_class.comRedefinition && name)
4319    {
4320       Class base;
4321       for(base = _class; base; base = base.base)
4322       {
4323          Method method = (Method)base.methods.FindString(name);
4324          if(method)
4325          {
4326             // If this overides a virtual method
4327             if(method.type == virtualMethod)
4328             {
4329                if(method.vid >= _class.vTblSize)
4330                   printf("error: virtual methods overriding failure\n");
4331                else
4332                   _class._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
4333             }
4334             else
4335                base = null;
4336             return method;
4337          }
4338       }
4339
4340       if(!base)
4341       {
4342          Method method
4343          {
4344             name = CopyString(name);
4345             function = function ? function : null; //DefaultFunction;
4346             type = virtualMethod;
4347             _class = _class;
4348             vid = _class.vTblSize++;
4349             dataTypeString = CopyString(type);
4350             memberAccess = declMode;
4351          };
4352          _class.methods.Add((BTNode)method);
4353          _class._vTbl = renew _class._vTbl void *[_class.vTblSize];
4354          _class._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
4355
4356          // TODO: Fix derived classes
4357          if(_class.derivatives.first || _class.templatized.first)
4358             FixDerivativeVirtualMethod(_class, name, method.vid, function ? function : null /*(void *)DefaultFunction*/, type);
4359          return method;
4360       }
4361    }
4362    return null;
4363 }
4364
4365 static void FixDerivativeProperty(Class base, Property _property)
4366 {
4367    OldLink derivative;
4368    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
4369    {
4370       Class _class = derivative.data;
4371       Property prop;
4372       BTNamedLink link = (BTNamedLink)_class.prop.FindString(_property.name);
4373       if(link)
4374       {
4375          prop = link.data;
4376          if(!prop.Set && !prop.Get && prop.memberAccess == baseSystemAccess)
4377          {
4378             SelfWatcher watcher;
4379             for(watcher = _class.selfWatchers.first; watcher; watcher = watcher.next)
4380             {
4381                if(watcher._property == prop)
4382                   watcher._property = _property;
4383             }
4384             _property.selfWatchable = true;
4385
4386             delete (void *)prop.name;
4387             delete (void *)prop.dataTypeString;
4388             _class.membersAndProperties.Delete(prop);
4389             _class.prop.Delete((BTNode)link);
4390          }
4391       }
4392
4393       for(prop = _class.membersAndProperties.first; prop; prop = prop.next)
4394          prop.id++;
4395       _class.memberID++;
4396       _class.startMemberID++;
4397
4398       FixDerivativeProperty(_class, _property);
4399    }
4400 }
4401
4402 public dllexport Property eClass_AddProperty(Class _class, const char * name, const char * dataType, void * setStmt, void * getStmt, AccessMode declMode)
4403 {
4404    Property _property = null;
4405    if(_class)
4406    {
4407       BTNamedLink link = (BTNamedLink)_class.prop.FindString(name ? name : dataType);
4408       bool isConversion = name ? false : true;
4409       if(!name && dataType && !strncmp(dataType, "const ", 6))
4410       {
4411          name = dataType + 6;
4412          isConversion = true;
4413       }
4414       if(link)
4415          _property = link.data;
4416       if(!_property)
4417       {
4418          _property =
4419          {
4420             isProperty = true;
4421             name = CopyString(name ? name : dataType);
4422             id = (name && (setStmt || getStmt || dataType)) ? _class.memberID++ : 0;
4423             Set = setStmt;
4424             Get = getStmt;
4425             dataTypeString = CopyString(dataType);
4426             _class = _class;
4427             compiled = true;
4428             conversion = isConversion;
4429             memberAccess = declMode;
4430          };
4431          if(!isConversion)
4432             _class.membersAndProperties.Add(_property);
4433          else
4434             _class.conversions.Add(_property);
4435          _class.prop.Add((BTNode)BTNamedLink { name = _property.name, data = _property });
4436
4437          if(!_property.conversion)
4438          {
4439             FixDerivativeProperty(_class, _property);
4440          }
4441       }
4442    }
4443    return _property;
4444 }
4445
4446 static void SetDelayedCPValues(Class _class, ClassProperty _property)
4447 {
4448    OldLink deriv;
4449    NamedLink64 value, next;
4450
4451    for(value = _class.delayedCPValues.first; value; value = next)
4452    {
4453       next = value.next;
4454       if(!strcmp(value.name, _property.name))
4455       {
4456          // eClass_SetProperty(_class, _property.name, value.data);
4457          _property.Set(_class, value.data);
4458          _class.delayedCPValues.Delete(value);
4459       }
4460    }
4461
4462    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
4463    {
4464       SetDelayedCPValues(deriv.data, _property);
4465    }
4466 }
4467
4468 public dllexport ClassProperty eClass_AddClassProperty(Class _class, const char * name, const char * dataType, void * setStmt, void * getStmt)
4469 {
4470    if(name && !_class.classProperties.FindString(name))
4471    {
4472       ClassProperty _property
4473       {
4474          name = CopyString(name);
4475          Set = setStmt;
4476          Get = getStmt;
4477          dataTypeString = CopyString(dataType);
4478       };
4479       _class.classProperties.Add((BTNode)_property);
4480       SetDelayedCPValues(_class, _property);
4481       return _property;
4482    }
4483    return null;
4484 }
4485
4486 /*import "Time"
4487
4488 Time classFindTotalTime;
4489
4490 public dllexport void ResetClassFindTime()
4491 {
4492    classFindTotalTime = 0;
4493 }
4494
4495 public dllexport Time GetClassFindTime()
4496 {
4497    return classFindTotalTime;
4498 }
4499 */
4500 public dllexport ClassProperty eClass_FindClassProperty(Class _class, const char * name)
4501 {
4502    //Time startTime = GetTime();
4503    ClassProperty _property = null;
4504    if(name && _class)
4505    {
4506       Class origClass = _class;
4507       for(; _class; _class = _class.base)
4508       {
4509          _property = (ClassProperty)_class.classProperties.FindString(name);
4510          if(_property)
4511             break;
4512       }
4513       // For enum class deriving off something else than enum to find enumSize...
4514       if(!_property && origClass.type == enumClass)
4515       {
4516          Class enumClass = eSystem_FindClass(origClass.module, "enum");
4517          _property = eClass_FindClassProperty(enumClass, name);
4518       }
4519    }
4520    /*if(!_property)
4521       eSystem_Logf("No such property (%s) for class %s\n", name, _class.name);*/
4522    //classFindTotalTime += GetTime() - startTime;
4523    return _property;
4524 }
4525
4526 public dllexport int64 eClass_GetProperty(Class _class, const char * name)
4527 {
4528    ClassProperty _property = eClass_FindClassProperty(_class, name);
4529    if(_property && _property.Get && _property.Get != (void *)1)
4530    {
4531       int64 result = _property.Get(_class);
4532       return result;
4533    }
4534    return 0;
4535 }
4536
4537 public dllexport void eClass_SetProperty(Class _class, const char * name, int64 value)
4538 {
4539    ClassProperty _property = eClass_FindClassProperty(_class, name);
4540    if(_property)
4541    {
4542       if(_property.Set)
4543          ((void(*)(void *, int64))_property.Set)(_class, value);
4544    }
4545    else
4546    {
4547       _class.delayedCPValues.Add(NamedLink64 { name = (char *)name, value });
4548    }
4549 }
4550
4551 public dllexport Method eClass_FindMethod(Class _class, const char * name, Module module)
4552 {
4553    //Time startTime = GetTime();
4554    if(_class && name)
4555    {
4556       for(; _class; _class = _class.base)
4557       {
4558          Method method;
4559          if(_class.templateClass) _class = _class.templateClass;
4560          method = (Method)_class.methods.FindString(name);
4561          if(method && (method.memberAccess == publicAccess || _class.module == module || !method.dataTypeString))
4562          {
4563             if(!method.dataTypeString)
4564             {
4565                if(_class.module != module)
4566                {
4567                   if(method.memberAccess == publicAccess)
4568                      module = _class.module;
4569                   else
4570                   {
4571                      //classFindTotalTime += GetTime() - startTime;
4572                      return null;
4573                   }
4574                }
4575             }
4576             else
4577             {
4578                //classFindTotalTime += GetTime() - startTime;
4579                return method;
4580             }
4581          }
4582          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
4583       }
4584    }
4585    //classFindTotalTime += GetTime() - startTime;
4586    return null;
4587 }
4588
4589 // Construct an instance
4590 static bool ConstructInstance(void * instance, Class _class, Class from)
4591 {
4592    if(_class.templateClass) _class = _class.templateClass;
4593    if(_class.base && from != _class.base)
4594    {
4595       if(!ConstructInstance(instance, _class.base, from))
4596          return false;
4597    }
4598    if(_class.Initialize)
4599    {
4600       void (* Initialize)(Module module) = (void *)_class.Initialize;
4601       _class.Initialize = null;
4602       Initialize(_class.module);
4603    }
4604    if(_class.Constructor)
4605    {
4606       if(!_class.Constructor(instance))
4607       {
4608          for(; _class; _class = _class.base)
4609          {
4610             if(_class.templateClass) _class = _class.templateClass;
4611             if(_class.Destructor)
4612                _class.Destructor(instance);
4613          }
4614          return false;
4615       }
4616    }
4617    (_class.templateClass ? _class.templateClass : _class).count++;
4618    return true;
4619 }
4620
4621 public dllexport void * eInstance_New(Class _class)
4622 {
4623    Instance instance = null;
4624    if(_class)
4625    {
4626       // instance = _malloc(_class.size);
4627 #ifdef MEMINFO
4628
4629 #undef malloc
4630 #if !defined(__EMSCRIPTEN__)
4631    memMutex.Wait();
4632 #endif
4633       //allocateClass = _class;
4634       allocateClass = malloc(strlen(_class.name)+1);
4635       allocateInternal = _class.module == __thisModule;
4636       strcpy(allocateClass, _class.name);
4637 #ifndef MEMINFO
4638 #define malloc _mymalloc
4639 #endif
4640
4641 #endif
4642       {
4643          int size = _class.structSize;
4644          int flags = _class.module.application.isGUIApp;
4645          bool inCompiler = (flags & 8) ? true : false;
4646          bool force32Bits = (flags & 4) ? true : false;
4647          if(force32Bits && inCompiler)
4648          {
4649             // Allocate 64 bit sizes for these when cross-compiling for 32 bit to allow loaded libraries to work properly
4650             if(!strcmp(_class.name, "Module"))
4651                size = 560;
4652             else if(_class.templateClass && !strcmp(_class.templateClass.name, "Map"))
4653                size = 40;
4654             else
4655                size *= 3;
4656          }
4657          instance = _calloc(1, size);
4658          if(!instance && size)
4659             printf("Failed to allocate memory instantiating %s object!\n", _class.name);
4660          else if(!size)
4661             printf("Warning: 0 size instantiating %s object!\n", _class.name);
4662       }
4663 #ifdef MEMINFO
4664       allocateClass = null;
4665 #if !defined(__EMSCRIPTEN__)
4666    memMutex.Release();
4667 #endif
4668 #endif
4669
4670 #if !defined(MEMINFO) && defined(MEMTRACKING)
4671       {
4672          MemBlock block = (MemBlock)((byte *)instance - sizeof(class MemBlock));
4673          block._class = _class;
4674       }
4675 #endif
4676
4677       if(instance && _class.type == normalClass)
4678       {
4679          instance._class = _class;
4680          // Copy the virtual table initially
4681          instance._vTbl = _class._vTbl;
4682       }
4683       if(instance && !ConstructInstance(instance, _class, null))
4684       {
4685          _free(instance);
4686          instance = null;
4687       }
4688       /*if(_class.type == normalClass && _class.count > 1000)
4689          printf("%s: %d instances\n", _class.name, _class.count);*/
4690    }
4691    return instance;
4692 }
4693
4694 public dllexport void eInstance_Evolve(Instance * instancePtr, Class _class)
4695 {
4696    if(_class && instancePtr && *instancePtr)
4697    {
4698       bool wasApp = false, wasGuiApp = false;
4699       Instance oldInstance = *instancePtr;
4700       Instance instance = (Instance)renew *instancePtr byte[_class.structSize];
4701       Class fromClass = instance._class;
4702       *instancePtr = instance;
4703       memset(((byte *)instance) + instance._class.structSize, 0, _class.structSize - instance._class.structSize);
4704       // Fix pointers to application
4705       if((wasApp = !strcmp(instance._class.name, "Application")) ||
4706          (wasGuiApp = !strcmp(instance._class.name, "GuiApplication")))
4707       {
4708          Module module;
4709          Application app = (Application) instance;
4710          BTNamedLink link;
4711          Class _class;
4712          NameSpace * nameSpace;
4713          for(module = app.allModules.first; module; module = module.next)
4714             module.application = app;
4715
4716          for(link = (BTNamedLink)app.privateNameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
4717          {
4718             OldLink t;
4719             ((Class)link.data).nameSpace = &app.privateNameSpace;
4720             for(t = ((Class)link.data).templatized.first; t; t = t.next) { Class template = t.data; template.nameSpace = ((Class)link.data).nameSpace; }
4721          }
4722          for(link = (BTNamedLink)app.publicNameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
4723          {
4724             OldLink t;
4725             ((Class)link.data).nameSpace = &app.publicNameSpace;
4726             for(t = ((Class)link.data).templatized.first; t; t = t.next) { Class template = t.data; template.nameSpace = ((Class)link.data).nameSpace; }
4727          }
4728
4729          for(link = (BTNamedLink)app.privateNameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next)
4730             ((DefinedExpression)link.data).nameSpace = &app.privateNameSpace;
4731          for(link = (BTNamedLink)app.publicNameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next)
4732             ((DefinedExpression)link.data).nameSpace = &app.publicNameSpace;
4733
4734          for(link = (BTNamedLink)app.privateNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4735             ((GlobalFunction)link.data).nameSpace = &app.privateNameSpace;
4736          for(link = (BTNamedLink)app.publicNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4737             ((GlobalFunction)link.data).nameSpace = &app.publicNameSpace;
4738
4739          for(nameSpace = (NameSpace *)app.privateNameSpace.nameSpaces.first; nameSpace; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
4740             nameSpace->parent = &app.privateNameSpace;
4741          for(nameSpace = (NameSpace *)app.publicNameSpace.nameSpaces.first; nameSpace; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
4742             nameSpace->parent = &app.publicNameSpace;
4743
4744          // --------------------------------------------------
4745          for(link = (BTNamedLink)app.systemNameSpace.classes.first; link; link = (BTNamedLink)((BTNode)link).next)
4746          {
4747             OldLink t;
4748             ((Class)link.data).nameSpace = &app.systemNameSpace;
4749             for(t = ((Class)link.data).templatized.first; t; t = t.next) { Class template = t.data; template.nameSpace = ((Class)link.data).nameSpace; }
4750          }
4751          for(link = (BTNamedLink)app.systemNameSpace.defines.first; link; link = (BTNamedLink)((BTNode)link).next)
4752             ((DefinedExpression)link.data).nameSpace = &app.systemNameSpace;
4753          for(link = (BTNamedLink)app.systemNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4754             ((GlobalFunction)link.data).nameSpace = &app.systemNameSpace;
4755          for(link = (BTNamedLink)app.systemNameSpace.functions.first; link; link = (BTNamedLink)((BTNode)link).next)
4756             ((GlobalFunction)link.data).nameSpace = &app.systemNameSpace;
4757          for(nameSpace = (NameSpace *)app.systemNameSpace.nameSpaces.first; nameSpace; nameSpace = (NameSpace *)((BTNode)nameSpace).next)
4758             nameSpace->parent = &app.systemNameSpace;
4759          // --------------------------------------------------
4760
4761          for(_class = app.classes.first; _class; _class = _class.next)
4762          {
4763             OldLink templateLink;
4764             _class.module = (Module) app;
4765             for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4766             {
4767                Class template = templateLink.data;
4768                if(template.module == oldInstance)
4769                   template.module = _class.module;
4770             }
4771          }
4772
4773          for(module = app.allModules.first; module; module = module.next)
4774          {
4775             for(_class = module.classes.first; _class; _class = _class.next)
4776             {
4777                OldLink templateLink;
4778                Module oldModule = _class.module;
4779                _class.module = module;
4780                for(templateLink = _class.templatized.first; templateLink; templateLink = templateLink.next)
4781                {
4782                   Class template = templateLink.data;
4783                   if(template.module == oldModule)
4784                      template.module = _class.module;
4785                }
4786             }
4787          }
4788
4789          app.application = app;
4790       }
4791
4792       {
4793          Class base;
4794          for(base = instance._class; base && base.type == normalClass && base.count; base = base.base)
4795             (base.templateClass ? base.templateClass : base).count--;
4796       }
4797
4798       instance._class = _class;
4799       // Copy the virtual table initially
4800       instance._vTbl = _class._vTbl;
4801
4802       // We don't want to reconstruct the portion already constructed...
4803       if(!ConstructInstance(instance, _class, fromClass))
4804       {
4805          _free(instance);
4806          *instancePtr = null;
4807       }
4808    }
4809 }
4810
4811 public dllexport void eInstance_Delete(Instance instance)
4812 {
4813 #ifdef MEMINFO
4814    bool checkMemory = false;
4815 #endif
4816    if(instance)
4817    {
4818       Class _class, base;
4819       bool ownVtbl;
4820
4821 #ifdef MEMINFO
4822 #if (defined(__WORDSIZE) && __WORDSIZE == 8) || defined(__x86_64__)
4823       if(instance._class == (void *)0xecececececececec)
4824 #else
4825       if(instance._class == (void *)0xecececec)
4826 #endif
4827          _free(instance);
4828 #endif
4829
4830       ownVtbl = instance._vTbl != instance._class._vTbl;
4831
4832       for(_class = instance._class; _class; _class = base)
4833       {
4834          if(_class.templateClass) _class = _class.templateClass;
4835          if(_class.destructionWatchOffset)
4836          {
4837             OldList * watchers = (OldList *)((byte *)instance + _class.destructionWatchOffset);
4838             Watcher watcher, next;
4839
4840             for(watcher = watchers->first; watcher; watcher = next)
4841             {
4842                next = watcher.next;
4843                watchers->Remove(watcher);
4844                watcher.callback(watcher.object, instance);
4845                watchers->Delete(watcher);
4846             }
4847          }
4848
4849          /*// Loop through properties to delete all watchers? Might slow down destruction...
4850          {
4851             Property _property;
4852             for(_property = _class.membersAndProperties.first; _property; _property = _property.next)
4853             {
4854                if(_property.isProperty && _property.isWatchable)
4855                {
4856                   OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
4857                   Watcher watcher, next;
4858                   for(watcher = watchers->first; watcher; watcher = next)
4859                   {
4860                      next = watcher.next;
4861                      watchers->Delete(watcher);
4862                   }
4863                }
4864             }
4865          }*/
4866
4867
4868          base = _class.base;
4869          if(base && (base.type == systemClass || base.isInstanceClass)) base = null;
4870          if(_class.Destructor)
4871             _class.Destructor(instance);
4872 #ifdef MEMINFO
4873          if(_class == class(Application))
4874             checkMemory = true;
4875 #endif
4876       }
4877
4878       for(_class = instance._class; _class; _class = base)
4879       {
4880          if(_class.templateClass) _class = _class.templateClass;
4881
4882          base = _class.base;
4883          (_class.templateClass ? _class.templateClass : _class).count--;
4884          if(_class.type == normalClass && !_class.count && !_class.module)
4885          {
4886 #ifdef MEMINFO
4887             // printf("Now Destructing class %s\n", _class.name);
4888 #endif
4889             eClass_Unregister(_class);
4890          }
4891       }
4892
4893       if(ownVtbl)
4894       {
4895          delete instance._vTbl;
4896       }
4897       //instance.prop.Free(null);
4898       _free(instance);
4899 #ifdef MEMINFO
4900       if(checkMemory) CheckMemory();
4901 #endif
4902    }
4903 }
4904
4905 public dllexport Property eClass_FindProperty(Class _class, const char * name, Module module)
4906 {
4907    //Time startTime = GetTime();
4908    if(_class && name)
4909    {
4910       if(!strncmp(name, "const ", 6))
4911          name += 6;
4912
4913       for(; _class; _class = _class.base)
4914       {
4915          BTNamedLink link;
4916          if(_class.templateClass) _class = _class.templateClass;
4917          link = (BTNamedLink)_class.prop.FindString(name);
4918          if(link)
4919          {
4920             Property _property = (Property)link.data;
4921             if(_property.memberAccess == publicAccess || _class.module == module || !_property.dataTypeString)
4922             {
4923                if(!_property.dataTypeString)
4924                {
4925                   if(_class.module != module)
4926                   {
4927                      if(_property.memberAccess == publicAccess)
4928                         module = _class.module;
4929                      else
4930                      {
4931                         //classFindTotalTime += GetTime() - startTime;
4932                         return null;
4933                      }
4934                   }
4935                }
4936                else
4937                {
4938                   //classFindTotalTime += GetTime() - startTime;
4939                   return _property;
4940                }
4941             }
4942          }
4943          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
4944       }
4945    }
4946    //classFindTotalTime += GetTime() - startTime;
4947    return null;
4948 }
4949
4950 static DataMember FindDataMember(OldList list, BinaryTree alist, const char * name, uint * offset, int * id, bool searchPrivate, DataMember * subMemberStack, int * subMemberStackPos)
4951 {
4952    BTNamedLink link;
4953    DataMember dataMember;
4954
4955    link = (BTNamedLink)alist.FindString(name);
4956    if(link)
4957    {
4958       dataMember = link.data;
4959       if(dataMember.type == normalMember && (dataMember.memberAccess == publicAccess || searchPrivate || !dataMember.dataTypeString))
4960       {
4961          if(offset)
4962             *offset += dataMember.offset;
4963          if(id) *id = dataMember.id;
4964          return dataMember;
4965       }
4966       return null;
4967    }
4968    for(dataMember = list.first; dataMember; dataMember = dataMember.next)
4969    {
4970       if(!dataMember.isProperty && (dataMember.memberAccess == publicAccess || searchPrivate) && !dataMember.name && (dataMember.type == unionMember || dataMember.type == structMember))
4971       {
4972          DataMember childMember;
4973          if(subMemberStackPos) subMemberStack[(*subMemberStackPos)++] = dataMember;
4974          childMember = FindDataMember(dataMember.members, dataMember.membersAlpha, name, offset, id, searchPrivate, subMemberStack, subMemberStackPos);
4975          if(childMember)
4976          {
4977             if(offset)
4978                *offset += dataMember.offset;
4979             if(id) *id += dataMember.id;
4980             return childMember;
4981          }
4982          if(subMemberStackPos) (*subMemberStackPos)--;
4983       }
4984    }
4985    return null;
4986 }
4987
4988 public dllexport DataMember eClass_FindDataMember(Class _class, const char * name, Module module, DataMember * subMemberStack, int * subMemberStackPos)
4989 {
4990    //Time startTime = GetTime();
4991    DataMember dataMember = null;
4992    if(subMemberStackPos) *subMemberStackPos = 0;
4993    if(_class && name)
4994    {
4995       for(; _class; _class = _class.base)
4996       {
4997          if(_class.templateClass) _class = _class.templateClass;
4998          dataMember = FindDataMember(_class.membersAndProperties, _class.members, name, null, null, _class.module == module, subMemberStack, subMemberStackPos);
4999          if(dataMember)
5000          {
5001             if(!dataMember.dataTypeString)
5002             {
5003                if(_class.module != module)
5004                {
5005                   if(dataMember.memberAccess == publicAccess)
5006                      module = _class.module;
5007                   else
5008                   {
5009                      //classFindTotalTime += GetTime() - startTime;
5010                      return null;
5011                   }
5012                }
5013                dataMember = null;
5014             }
5015             else
5016             {
5017                // HACK: Is this good enough? avoiding setting it when adding...
5018                dataMember._class = _class.templateClass ? _class.templateClass : _class;
5019                //classFindTotalTime += GetTime() - startTime;
5020                return dataMember;
5021             }
5022          }
5023          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
5024       }
5025    }
5026    //classFindTotalTime += GetTime() - startTime;
5027    return dataMember;
5028 }
5029
5030 public dllexport DataMember eClass_FindDataMemberAndOffset(Class _class, const char * name, uint * offset, Module module, DataMember * subMemberStack, int * subMemberStackPos)
5031 {
5032    //Time startTime = GetTime();
5033    DataMember dataMember = null;
5034    if(subMemberStackPos) *subMemberStackPos = 0;
5035    if(offset) *offset = 0;
5036    if(_class)
5037    {
5038       for(; _class; _class = _class.base)
5039       {
5040          if(_class.templateClass) _class = _class.templateClass;
5041          dataMember = FindDataMember(_class.membersAndProperties, _class.members, name, offset, null, _class.module == module, subMemberStack, subMemberStackPos);
5042          if(dataMember)
5043          {
5044             if(!dataMember.dataTypeString)
5045             {
5046                if(_class.module != module)
5047                {
5048                   if(dataMember.memberAccess == publicAccess)
5049                      module = _class.module;
5050                   else
5051                   {
5052                      //classFindTotalTime += GetTime() - startTime;
5053                      return null;
5054                   }
5055                }
5056                dataMember = null;
5057             }
5058             else
5059             {
5060                // HACK: Is this good enouh? avoiding setting it when adding...
5061                dataMember._class = _class;
5062                //classFindTotalTime += GetTime() - startTime;
5063                return dataMember;
5064             }
5065          }
5066          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
5067       }
5068    }
5069    //classFindTotalTime += GetTime() - startTime;
5070    return dataMember;
5071 }
5072
5073 public dllexport DataMember eClass_FindDataMemberAndId(Class _class, const char * name, int * id, Module module, DataMember * subMemberStack, int * subMemberStackPos)
5074 {
5075    //Time startTime = GetTime();
5076    DataMember dataMember = null;
5077    if(subMemberStackPos) *subMemberStackPos = 0;
5078    if(_class)
5079    {
5080       for(; _class; _class = _class.base)
5081       {
5082          if(_class.templateClass) _class = _class.templateClass;
5083          dataMember = FindDataMember(_class.membersAndProperties, _class.members, name, null, id, _class.module == module, subMemberStack, subMemberStackPos);  // TOCHECK: Why was this null? null, null);
5084          if(dataMember)
5085          {
5086             if(!dataMember.dataTypeString)
5087             {
5088                if(_class.module != module)
5089                {
5090                   if(dataMember.memberAccess == publicAccess)
5091                      module = _class.module;
5092                   else
5093                   {
5094                      //classFindTotalTime += GetTime() - startTime;
5095                      return null;
5096                   }
5097                }
5098                dataMember = null;
5099             }
5100             else
5101             {
5102                // HACK: Is this good enouh? avoiding setting it when adding...
5103                dataMember._class = _class;
5104                //classFindTotalTime += GetTime() - startTime;
5105                return dataMember;
5106             }
5107          }
5108          if(_class.inheritanceAccess == privateAccess && _class.module != module) break;
5109       }
5110    }
5111    //classFindTotalTime += GetTime() - startTime;
5112    return dataMember;
5113 }
5114
5115 public dllexport void eClass_FindNextMember(Class _class, Class * curClass, DataMember * curMember, DataMember * subMemberStack, int * subMemberStackPos)
5116 {
5117    // THIS CODE WILL FIND NEXT MEMBER... (PUBLIC MEMBERS ONLY)
5118    if(*curMember)
5119    {
5120       *curMember = (*curMember).next;
5121
5122       if(subMemberStackPos && *subMemberStackPos > 0 && subMemberStack[*subMemberStackPos-1].type == unionMember)
5123       {
5124          *curMember = subMemberStack[--(*subMemberStackPos)];
5125          *curMember = (*curMember).next;
5126       }
5127
5128       if(subMemberStackPos && *subMemberStackPos > 0)
5129       {
5130          while(*curMember && ((*curMember).memberAccess == privateAccess))
5131             *curMember = (*curMember).next;
5132       }
5133       else
5134          while(*curMember && (*curMember).name)      // ADDED THIS HERE for eComPacket packet { Connect, 0, { ECOMMUNICATOR_PROTOCOL_VERSION } };
5135          {
5136             DataMember dataMember = eClass_FindDataMember(_class, curMember->name, null, null, null);
5137             if(!dataMember) dataMember = (DataMember)eClass_FindProperty(_class, curMember->name, null);
5138             if(dataMember && dataMember.memberAccess != privateAccess)
5139             {
5140                *curMember = dataMember;
5141                break;
5142             }
5143             else
5144                *curMember = (*curMember).next;
5145          }
5146
5147       if(subMemberStackPos)
5148       {
5149          while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
5150          {
5151             subMemberStack[(*subMemberStackPos)++] = *curMember;
5152
5153             *curMember = (*curMember).members.first;
5154             while(*curMember && ((*curMember).memberAccess == privateAccess))
5155                *curMember = (*curMember).next;
5156          }
5157       }
5158    }
5159    while(!*curMember)
5160    {
5161       if(!*curMember)
5162       {
5163          if(subMemberStackPos && *subMemberStackPos)
5164          {
5165             *curMember = subMemberStack[--(*subMemberStackPos)];
5166             *curMember = (*curMember).next;
5167          }
5168          else
5169          {
5170             Class lastCurClass = *curClass;
5171
5172             if(*curClass == _class) break;     // REACHED THE END
5173
5174             for(*curClass = _class; (*curClass).base != lastCurClass && (*curClass).base.type != systemClass && (*curClass).inheritanceAccess != privateAccess; *curClass = (*curClass).base);
5175             *curMember = (*curClass).membersAndProperties.first;
5176          }
5177
5178          if(subMemberStackPos && *subMemberStackPos > 0)
5179          {
5180             while(*curMember && ((*curMember).memberAccess == privateAccess))
5181                *curMember = (*curMember).next;
5182          }
5183          else
5184             while(*curMember && (*curMember).name)      // ADDED THIS HERE for eComPacket packet { Connect, 0, { ECOMMUNICATOR_PROTOCOL_VERSION } };
5185             {
5186                DataMember dataMember = null;
5187                if(((*curMember).memberAccess != privateAccess))
5188                {
5189                   dataMember = eClass_FindDataMember(_class, curMember->name, null, null, null);
5190                   if(!dataMember) dataMember = (DataMember)eClass_FindProperty(_class, curMember->name, null);
5191                }
5192                if(dataMember && dataMember.memberAccess != privateAccess && dataMember.id >= 0) // Skip _vTbl, _refCount and _class in Instance
5193                {
5194                   *curMember = dataMember;
5195                   break;
5196                }
5197                else
5198                   *curMember = (*curMember).next;
5199             }
5200
5201          if(subMemberStackPos)
5202          {
5203             while((*curMember) && !(*curMember).isProperty && !(*curMember).name && ((*curMember).type == structMember || (*curMember).type == unionMember))
5204             {
5205                subMemberStack[(*subMemberStackPos)++] = *curMember;
5206
5207                *curMember = (*curMember).members.first;
5208                while(*curMember && (*curMember).memberAccess == privateAccess)
5209                   *curMember = (*curMember).next;
5210             }
5211          }
5212       }
5213    }
5214 }
5215
5216 public dllexport void eInstance_SetMethod(Instance instance, const char * name, void * function)     // YET TO BE DECIDED:   , Module module)
5217 {
5218    if(instance && name)
5219    {
5220       Class _class;
5221       for(_class = instance._class; _class; _class = _class.base)
5222       {
5223          Method method = (Method)_class.methods.FindString(name);
5224          if(method && method.type == virtualMethod)
5225          {
5226             if(instance._vTbl == instance._class._vTbl)
5227             {
5228                instance._vTbl = _malloc(sizeof(void *) * instance._class.vTblSize);
5229                memcpy(instance._vTbl, instance._class._vTbl,
5230                   sizeof(int(*)()) * instance._class.vTblSize);
5231             }
5232             instance._vTbl[method.vid] = function ? function : null; //(void *)DefaultFunction;
5233          }
5234       }
5235    }
5236 }
5237
5238 public dllexport bool eInstance_IsDerived(Instance instance, Class from)
5239 {
5240    if(instance)
5241    {
5242       Class _class = instance._class;
5243       for(; _class; _class = _class.base)
5244       {
5245          if(_class == from)
5246             return true;
5247       }
5248    }
5249    return false;
5250 }
5251
5252 public dllexport void eInstance_IncRef(Instance instance)
5253 {
5254    if(instance)
5255       instance._refCount++;
5256 }
5257
5258 public dllexport void eInstance_DecRef(Instance instance)
5259 {
5260    if(instance)
5261    {
5262       instance._refCount--;
5263       //if(!instance._refCount)
5264       if(instance._refCount <= 0)
5265       {
5266          eInstance_Delete(instance);
5267       }
5268    }
5269 }
5270
5271 static void FixOffsets(Class _class)
5272 {
5273    OldLink deriv;
5274    _class.structSize += _class.base.structSize - _class.offset;
5275
5276    _class.offset = _class.base.structSize;
5277
5278    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
5279       FixOffsets(deriv.data);
5280 }
5281
5282 public dllexport void eClass_Resize(Class _class, int newSize)
5283 {
5284    OldLink deriv;
5285    _class.structSize = newSize;
5286    for(deriv = _class.derivatives.first; deriv; deriv = deriv.next)
5287       FixOffsets(deriv.data);
5288 }
5289                                                                                                                         // F000F000 will mean a pointer size alignment
5290 public dllexport DataMember eClass_AddDataMember(Class _class, const char * name, const char * type, unsigned int size, unsigned int alignment, AccessMode declMode)
5291 {
5292    if(_class && name)
5293    {
5294       if(!_class.members.FindString(name))
5295       {
5296          DataMember dataMember;
5297
5298          if(alignment)
5299          {
5300             bool pointerAlignment = alignment == 0xF000F000;
5301             bool force64Bits = (_class.module.application.isGUIApp & 2) ? true : false;
5302             bool force32Bits = (_class.module.application.isGUIApp & 4) ? true : false;
5303             if((force32Bits || force64Bits) && !strcmp(_class.name, "AVLNode") && !strcmp(name, "__ecerePrivateData0"))
5304             {
5305                if(force64Bits)
5306                {
5307                   type = "byte[32]";
5308                   size = 32;
5309                }
5310                if(force32Bits)
5311                {
5312                   type = "byte[16]";
5313                   size = 16;
5314                }
5315             }
5316
5317             if(pointerAlignment) alignment = force64Bits ? 8 : force32Bits ? 4 : sizeof(void *);
5318
5319             if(pointerAlignment && _class.structAlignment <= 4)
5320                _class.pointerAlignment = 1;
5321             else if(!pointerAlignment && alignment >= 8)
5322                _class.pointerAlignment = 0;
5323
5324             _class.structAlignment = Max(_class.structAlignment, alignment);
5325
5326             if(_class.offset % alignment)
5327             {
5328                _class.structSize += alignment - (_class.offset % alignment);
5329                _class.offset += alignment - (_class.offset % alignment);
5330             }
5331             if(_class.memberOffset % alignment)
5332                _class.memberOffset += alignment - (_class.memberOffset % alignment);
5333          }
5334
5335          dataMember = DataMember {
5336             name = CopyString(name);
5337             dataTypeString = CopyString(type);
5338             id = _class.memberID++;
5339             _class = _class;
5340             offset = _class.memberOffset;
5341             memberOffset = size;
5342             memberAccess = declMode;
5343             membersAlpha.CompareKey = (void *)BinaryTree::CompareString;
5344          };
5345          _class.membersAndProperties.Add(dataMember);
5346          _class.memberOffset += size;
5347
5348          _class.members.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5349          return dataMember;
5350       }
5351    }
5352    return null;
5353 }
5354                                                                                                                               // F000F000 will mean a pointer size alignment
5355 public dllexport DataMember eMember_AddDataMember(DataMember member, const char * name, const char * type, unsigned int size, unsigned int alignment, AccessMode declMode)
5356 {
5357    if(name && !member.membersAlpha.FindString(name))
5358    {
5359       DataMember dataMember;
5360
5361       if(alignment)
5362       {
5363          bool pointerAlignment = alignment == 0xF000F000;
5364          bool force64Bits = false; //(member._class.module.application.isGUIApp & 2) ? true : false;
5365          bool force32Bits = false; //(member._class.module.application.isGUIApp & 4) ? true : false;
5366          if(pointerAlignment) alignment = force64Bits ? 8 : force32Bits ? 4 : sizeof(void *);
5367
5368          if(pointerAlignment && member.structAlignment <= 4)
5369             member.pointerAlignment = 1;
5370          else if(!pointerAlignment && alignment >= 8)
5371             member.pointerAlignment = 0;
5372
5373          member.structAlignment = Max(member.structAlignment, alignment);
5374
5375          if(member.memberOffset % alignment)
5376             member.memberOffset += alignment - (member.memberOffset % alignment);
5377       }
5378       dataMember = DataMember {
5379          name = CopyString(name);
5380          _class = member._class;
5381          dataTypeString = CopyString(type);
5382          id = member.memberID++;
5383          offset = (member.type == unionMember) ? 0 : member.memberOffset;
5384          memberAccess = declMode;
5385          membersAlpha.CompareKey = (void *)BinaryTree::CompareString;
5386       };
5387       member.members.Add(dataMember);
5388       if(member.type == unionMember)
5389       {
5390          if(size > member.memberOffset)
5391             member.memberOffset = size;
5392       }
5393       else
5394          member.memberOffset += size;
5395       member.membersAlpha.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5396       return dataMember;
5397    }
5398    return null;
5399 }
5400
5401 public dllexport DataMember eMember_New(DataMemberType type, AccessMode declMode)
5402 {
5403    return DataMember { type = type, memberAccess = declMode, membersAlpha.CompareKey = (void *)BinaryTree::CompareString };
5404 }
5405
5406 static void SetMemberClass(DataMember member, Class _class)
5407 {
5408    DataMember dataMember;
5409    member._class = _class;
5410    for(dataMember = member.members.first; dataMember; dataMember = dataMember.next)
5411       SetMemberClass(dataMember, _class);
5412 }
5413
5414 public dllexport bool eMember_AddMember(DataMember addTo, DataMember dataMember)
5415 {
5416    if(dataMember.name && addTo.membersAlpha.FindString(dataMember.name))
5417    {
5418       DataMember_Free(dataMember);
5419       delete dataMember;
5420       return false;
5421    }
5422    addTo.members.Add(dataMember);
5423
5424    if(dataMember.name)
5425       addTo.membersAlpha.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5426
5427    dataMember._class = addTo._class;
5428    // ? SetMemberClass(dataMember, addTo._class);
5429
5430    //dataMember.id = addTo.memberID++;
5431    dataMember.id = addTo.memberID;
5432    if(dataMember.type == unionMember)
5433       addTo.memberID += 1;
5434    else
5435       addTo.memberID += dataMember.memberID;
5436
5437    if(dataMember.pointerAlignment && dataMember.structAlignment <= 4)
5438       addTo.pointerAlignment = 1;
5439    else if(!dataMember.pointerAlignment && dataMember.structAlignment >= 8)
5440       addTo.pointerAlignment = 0;
5441
5442    addTo.structAlignment = Max(addTo.structAlignment, dataMember.structAlignment);
5443
5444    dataMember.offset = (addTo.type == unionMember) ? 0 : addTo.memberOffset;
5445
5446    if(dataMember.structAlignment)
5447    {
5448       if(addTo.memberOffset % dataMember.structAlignment)
5449          addTo.memberOffset += dataMember.structAlignment - (addTo.memberOffset % dataMember.structAlignment);
5450    }
5451
5452    if(addTo.type == unionMember)
5453    {
5454       if(dataMember.memberOffset > addTo.memberOffset)
5455          addTo.memberOffset = dataMember.memberOffset;
5456    }
5457    else
5458       addTo.memberOffset += dataMember.memberOffset;
5459    return true;
5460 }
5461
5462 public dllexport bool eClass_AddMember(Class _class, DataMember dataMember)
5463 {
5464    if(!_class || _class.comRedefinition || (dataMember.name && _class.members.FindString(dataMember.name)))
5465    {
5466       DataMember_Free(dataMember);
5467       delete dataMember;
5468       return false;
5469    }
5470    _class.membersAndProperties.Add(dataMember);
5471
5472    if(dataMember.name)
5473       _class.members.Add((BTNode)BTNamedLink { name = dataMember.name, data = dataMember });
5474
5475    //dataMember._class = _class;
5476    SetMemberClass(dataMember, _class);
5477
5478    //dataMember.id = _class.memberID++;
5479    dataMember.id = _class.memberID;
5480
5481    if(dataMember.pointerAlignment && dataMember.structAlignment <= 4)
5482       _class.pointerAlignment = 1;
5483    else if(!dataMember.pointerAlignment && dataMember.structAlignment >= 8)
5484       _class.pointerAlignment = 0;
5485
5486    _class.structAlignment = Max(_class.structAlignment, dataMember.structAlignment);
5487    if(dataMember.type == unionMember)
5488       _class.memberID += 1;
5489    else
5490       _class.memberID += dataMember.memberID;
5491
5492    if(dataMember.structAlignment)
5493    {
5494       if(_class.memberOffset % dataMember.structAlignment)
5495          _class.memberOffset += dataMember.structAlignment - (_class.memberOffset % dataMember.structAlignment);
5496    }
5497
5498    dataMember.offset = _class.memberOffset;
5499    _class.memberOffset += dataMember.memberOffset;
5500    return true;
5501 }
5502
5503 public dllexport BitMember eClass_AddBitMember(Class _class, const char * name, const char * type, int bitSize, int bitPos, AccessMode declMode)
5504 {
5505    if(_class && name && !_class.members.FindString(name))
5506    {
5507       uint64 mask = 0;
5508       int c;
5509       BitMember bitMember
5510       {
5511          name = CopyString(name);
5512          _class = _class;
5513          dataTypeString = CopyString(type);
5514          id = _class.memberID++;
5515          memberAccess = declMode;
5516       };
5517       _class.membersAndProperties.Add(bitMember);
5518       if(bitSize)
5519       {
5520          bitMember.pos = (bitPos == -1) ? _class.memberOffset : bitPos;
5521          bitMember.size = bitSize;
5522          _class.memberOffset = bitMember.pos + bitMember.size;
5523          for(c = 0; c<bitSize; c++)
5524          {
5525             if(c)
5526                mask <<= 1;
5527             mask |= 1;
5528          }
5529          bitMember.mask = mask << bitMember.pos;
5530       }
5531
5532      _class.members.Add((BTNode)BTNamedLink { name = bitMember.name, data = bitMember });
5533       return bitMember;
5534    }
5535    return null;
5536 }
5537
5538 static Module Module_Load(Module fromModule, const char * name, AccessMode importAccess, bool ensureCOM)
5539 {
5540    bool (stdcall * Load)(Module module) = null;
5541    bool (stdcall * Unload)(Module module) = null;
5542    Module module;
5543
5544    for(module = fromModule.application.allModules.first; module; module = module.next)
5545    {
5546       if(!strcmp(module.name, name))
5547          break;
5548    }
5549    if(ensureCOM && (!strcmp(name, "ecereCOM") || !strcmp(name, "ecere")))
5550    {
5551       for(module = fromModule.application.allModules.first; module; module = module.next)
5552       {
5553          if(!strcmp(module.name, "ecere") || !strcmp(module.name, "ecereCOM"))
5554             break;
5555       }
5556    }
5557    if(!module)
5558    {
5559       void * library = null;
5560
5561       if(ensureCOM && !strcmp(name, "ecereCOM"))
5562       {
5563          Load = COM_LOAD_FUNCTION;
5564          Unload = COM_UNLOAD_FUNCTION;
5565       }
5566       else
5567       {
5568          const char * libLocation = null;
5569 #if defined(__ANDROID__)
5570          libLocation = AndroidInterface_GetLibLocation();
5571 #endif
5572          library = Instance_Module_Load(libLocation, name, &Load, &Unload);
5573       }
5574       if(Load)
5575       {
5576          module = (Module)eInstance_New(eSystem_FindClass(fromModule, "Module"));
5577          module.application = fromModule.application;
5578          module.library = library;
5579          {
5580             char moduleName[MAX_FILENAME];
5581             char ext[MAX_EXTENSION];
5582             GetLastDirectory(name, moduleName);
5583             GetExtension(moduleName, ext);
5584             StripExtension(moduleName);
5585             if((!strcmpi(ext, "dylib") || !strcmpi(ext, "so")) && strstr(moduleName, "lib") == moduleName)
5586             {
5587                int len = (int)strlen(moduleName) - 3;
5588                memmove(moduleName, moduleName + 3, len);
5589                moduleName[len] = 0;
5590             }
5591             module.name = CopyString(moduleName);
5592          }
5593          module.Unload = Unload;
5594          module.origImportType = normalImport;
5595
5596          if(!Load(module))
5597          {
5598             eInstance_Delete((Instance)module);
5599             module = null;
5600          }
5601       }
5602       fromModule.application.allModules.Add(module);
5603    }
5604    if(ensureCOM && !strcmp(name, "ecere") && module)
5605    {
5606       name = !strcmp(module.name, "ecereCOM") ? "ecere" : "ecereCOM";
5607       if((!Load && !strcmp(module.name, "ecereCOM")) ||
5608          (Load && (!__thisModule || !__thisModule.name || !strcmp(__thisModule.name, "ecereCOM")) && Load != (void *)COM_LOAD_FUNCTION))
5609       {
5610          Module module;
5611          for(module = fromModule.application.allModules.first; module; module = module.next)
5612          {
5613             if(!strcmp(module.name, name))
5614                break;
5615          }
5616          if(!module)
5617          {
5618             Load = COM_LOAD_FUNCTION;
5619             Unload = COM_UNLOAD_FUNCTION;
5620
5621             module = (Module)eInstance_New(eSystem_FindClass(fromModule, "Module"));
5622             module.application = fromModule.application;
5623             module.library = null;
5624             module.name = CopyString(name);
5625             module.Unload = Unload;
5626
5627             if(!Load(module))
5628             {
5629                eInstance_Delete((Instance)module);
5630                module = null;
5631             }
5632
5633             fromModule.application.allModules.Add(module);
5634          }
5635          if(module)
5636          {
5637             if(fromModule)
5638             {
5639                fromModule.modules.Add(SubModule { module = module, importMode = importAccess });
5640             }
5641             incref module;
5642          }
5643       }
5644    }
5645    if(module)
5646    {
5647       if(fromModule)
5648       {
5649          fromModule.modules.Add(SubModule { module = module, importMode = importAccess });
5650       }
5651       incref module;
5652    }
5653 #if defined(_DEBUG)
5654    InternalModuleLoadBreakpoint();
5655 #endif
5656    return module;
5657 }
5658
5659 public dllexport Module eModule_Load(Module fromModule, const char * name, AccessMode importAccess)
5660 {
5661    return Module_Load(fromModule, name, importAccess, true);
5662 }
5663
5664 public dllexport Module eModule_LoadStrict(Module fromModule, const char * name, AccessMode importAccess)
5665 {
5666    return Module_Load(fromModule, name, importAccess, false);
5667 }
5668
5669 public dllexport Module eModule_LoadStatic(Module fromModule, const char * name, AccessMode importAccess, bool (* Load)(Module module), bool (* Unload)(Module module))
5670 {
5671    Module module;
5672    for(module = fromModule.application.allModules.first; module; module = module.next)
5673    {
5674       if(!strcmp(module.name, name))
5675          break;
5676    }
5677    if(!module)
5678    {
5679       if(Load)
5680       {
5681          module = (Module)eInstance_New(eSystem_FindClass(fromModule, "Module"));
5682          module.application = fromModule.application;
5683          module.name = CopyString(name);
5684          module.origImportType = staticImport;
5685          module.Unload = (void *)Unload;
5686          if(!Load(module))
5687          {
5688             eInstance_Delete((Instance)module);
5689             module = null;
5690          }
5691       }
5692       fromModule.application.allModules.Add(module);
5693    }
5694    if(module)
5695    {
5696       if(fromModule)
5697       {
5698          fromModule.modules.Add(SubModule { module = module, importMode = importAccess });
5699       }
5700       incref module;
5701    }
5702    return module;
5703 }
5704
5705 public dllexport void eModule_Unload(Module fromModule, Module module)
5706 {
5707    OldLink m;
5708    for(m = fromModule.modules.first; m; m = m.next)
5709    {
5710       if(m.data == module)
5711          break;
5712    }
5713    if(m)
5714    {
5715       fromModule.modules.Delete(m);
5716       delete module;
5717    }
5718 }
5719
5720 public dllexport void eEnum_AddFixedValue(Class _class, const char * string, int64 value)
5721 {
5722    if(_class && _class.type == enumClass)
5723    {
5724       EnumClassData data = (EnumClassData)_class.data;
5725       NamedLink64 item;
5726
5727       for(item = data.values.first; item; item = item.next)
5728          if(!strcmp(item.name, string))
5729             break;
5730       if(!item)
5731       {
5732          data.values.Add(NamedLink64 { data = value, name = CopyString(string) });
5733          if(value > data.largest)
5734             data.largest = value;
5735       }
5736    }
5737 }
5738
5739 public dllexport int64 eEnum_AddValue(Class _class, const char * string)
5740 {
5741    if(_class && _class.type == enumClass)
5742    {
5743       EnumClassData data = (EnumClassData)_class.data;
5744       int64 value = data.largest + 1;
5745       NamedLink64 item;
5746       for(item = data.values.first; item; item = item.next)
5747          if(!strcmp(item.name, string))
5748             break;
5749       if(!item)
5750       {
5751          data.values.Add(NamedLink64 { data = value, name = CopyString(string) });
5752          if(value > data.largest)
5753             data.largest = value;
5754          return value;
5755       }
5756    }
5757    return -1;
5758 }
5759
5760 static void NameSpace_Free(NameSpace parentNameSpace)
5761 {
5762    NameSpace * nameSpace;
5763    delete (void *)parentNameSpace.name;
5764
5765          /*   {
5766       BTNamedLink n, next;
5767       for(n = (BTNamedLink)parentNameSpace.classes.first; n; n = next)
5768       {
5769          Class c = n.data;
5770
5771          next = (BTNamedLink)((BTNode)n).next;
5772
5773          if(c.templateClass)
5774             eClass_Unregister(c);
5775       }
5776    }         */
5777
5778    while((nameSpace = (NameSpace *)parentNameSpace.nameSpaces.first))
5779    {
5780       NameSpace_Free(nameSpace);
5781       parentNameSpace.nameSpaces.Delete((BTNode)nameSpace);
5782    }
5783 }
5784
5785 static void Application_Destructor(Application app)
5786 {
5787    if(app.parsedCommand)
5788    {
5789       delete (void *)app.argv;
5790       delete app.parsedCommand;
5791    }
5792 }
5793
5794 static bool Module_Constructor(Module module)
5795 {
5796    module.privateNameSpace.classes.CompareKey = (void *)BinaryTree::CompareString;
5797    module.privateNameSpace.defines.CompareKey = (void *)BinaryTree::CompareString;
5798    module.privateNameSpace.functions.CompareKey = (void *)BinaryTree::CompareString;
5799    module.privateNameSpace.nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
5800
5801    module.publicNameSpace.classes.CompareKey = (void *)BinaryTree::CompareString;
5802    module.publicNameSpace.defines.CompareKey = (void *)BinaryTree::CompareString;
5803    module.publicNameSpace.functions.CompareKey = (void *)BinaryTree::CompareString;
5804    module.publicNameSpace.nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
5805    return true;
5806 }
5807
5808 static void Module_Destructor(Module module)
5809 {
5810    Class _class;
5811    DefinedExpression def;
5812    GlobalFunction function;
5813    Module m;
5814    SubModule handle;
5815
5816    // printf("Destructing module %s\n", module.name);
5817
5818    // Take out references from all modules
5819    for(m = module.application.allModules.first; m; m = m.next)
5820    {
5821       SubModule next;
5822       for(handle = m.modules.first; handle; handle = next)
5823       {
5824          next = handle.next;
5825          if(handle.module == module)
5826             m.modules.Delete(handle);
5827       }
5828    }
5829
5830    if(module.Unload)
5831    {
5832       if(module.origImportType == staticImport)
5833       {
5834          bool (* Unload)(Module module) = (void *)module.Unload;
5835          Unload(module);
5836       }
5837       else
5838       {
5839          bool (stdcall * Unload)(Module module) = (void *)module.Unload;
5840          Unload(module);
5841       }
5842    }
5843
5844    // Unload dependencies
5845    {
5846       Module ourWorld = class(Class).module;
5847       void * ourHandle = null;
5848       while((handle = module.modules.last))  // STARTING WITH LAST SO THAT ecereCOM IS UNLOADED LAST...
5849       {
5850          Module depModule = handle.module;
5851          if(depModule == ourWorld)
5852          {
5853             module.modules.Remove(handle);
5854             ourHandle = handle;
5855          }
5856          else
5857          {
5858             module.modules.Delete(handle);
5859             delete depModule;
5860          }
5861       }
5862       if(ourHandle)
5863       {
5864          delete ourHandle;
5865          delete ourWorld;
5866       }
5867    }
5868
5869    // Unload classes
5870    for(;(_class = module.classes.first);)
5871    {
5872       if(_class.nameSpace)
5873       {
5874          BTNamedLink classLink = (BTNamedLink)_class.nameSpace->classes.FindString(_class.name);
5875          if(classLink)
5876          {
5877             OldLink t;
5878             for(t = _class.templatized.first; t; t = t.next)
5879             {
5880                Class template = t.data;
5881                BTNamedLink link;
5882                link = (BTNamedLink)template.nameSpace->classes.FindString(template.name);
5883
5884                template.nameSpace->classes.Delete((BTNode)link);
5885                template.nameSpace = null;
5886             }
5887             _class.nameSpace->classes.Delete((BTNode)classLink);
5888          }
5889 #ifdef _DEBUG
5890          else
5891          {
5892             printf("Warning: Could not find %s in namespace classes while destructing module %s\n", _class.name, module.name);
5893          }
5894 #endif
5895          _class.nameSpace = null;
5896       }
5897       _class.module = null;
5898       module.classes.Remove(_class);
5899       if(_class.count <= 0 || _class.type != normalClass || _class.isInstanceClass)
5900          eClass_Unregister(_class);
5901       else
5902       {
5903 #ifdef MEMINFO
5904          // printf("Delayed destruction of class %s\n", _class.name);
5905 #endif
5906       }
5907    }
5908
5909    // Unload defines
5910    for(;(def = module.defines.first);)
5911    {
5912       if(def.nameSpace)
5913       {
5914          BTNamedLink defLink;
5915          for(defLink = (BTNamedLink)def.nameSpace->defines.first; defLink; defLink = (BTNamedLink)((BTNode)defLink).next)
5916             if(defLink.data == def)
5917             {
5918                def.nameSpace->defines.Delete((BTNode)defLink);
5919                break;
5920             }
5921       }
5922       delete (void *)def.name;
5923       delete (void *)def.value;
5924       module.defines.Delete(def);
5925    }
5926
5927    // Unload functions
5928    for(;(function = module.functions.first);)
5929    {
5930       if(function.nameSpace)
5931       {
5932          BTNamedLink functionLink;
5933          for(functionLink = (BTNamedLink)function.nameSpace->functions.first; functionLink; functionLink = (BTNamedLink)((BTNode)functionLink).next)
5934             if(functionLink.data == function)
5935             {
5936                function.nameSpace->functions.Delete((BTNode)functionLink);
5937                break;
5938             }
5939       }
5940       delete (void *)function.name;
5941       delete (void *)function.dataTypeString;
5942       module.functions.Delete(function);
5943    }
5944
5945    delete (void *)module.name;
5946
5947    NameSpace_Free(module.privateNameSpace);
5948    NameSpace_Free(module.publicNameSpace);
5949
5950    if(module != module.application)
5951       module.application.allModules.Remove(module);
5952    else
5953       NameSpace_Free(module.application.systemNameSpace);
5954
5955 #ifndef MEMINFO
5956    Instance_Module_Free(module.library);
5957 #endif
5958 }
5959
5960 static int64 GetEnumSize(Class _class)
5961 {
5962    EnumClassData data = (EnumClassData)_class.data;
5963    return data.largest+1;
5964 }
5965
5966 #if defined(__GNUC__)
5967 #define strcmpi strcasecmp
5968 #define strnicmp strncasecmp
5969 #endif
5970
5971 #if defined(ECERE_BOOTSTRAP) || (defined(__GNUC__) && !defined(__DJGPP__) && !defined(__WIN32__) && !defined(__EMSCRIPTEN__))
5972 #undef strlwr
5973 #undef strupr
5974 default dllexport char * strlwr(char *string)
5975 {
5976    int c;
5977    for(c=0; string[c]; c++)
5978       if(string[c]>='A' && string[c]<='Z')
5979          string[c]+='a'-'A';
5980    return string;
5981 }
5982 default dllexport char * strupr(char *string)
5983 {
5984    int c;
5985    for(c=0; string[c]; c++)
5986       if(string[c]>='a' && string[c]<='z')
5987          string[c]-='a'-'A';
5988    return string;
5989 }
5990 #endif
5991
5992 public dllexport DefinedExpression eSystem_RegisterDefine(const char * name, const char * value, Module module, AccessMode declMode)
5993 {
5994    NameSpace * nameSpace = null;
5995
5996    int start = 0, c;
5997
5998    nameSpace = (declMode == publicAccess) ? &module.publicNameSpace : &module.privateNameSpace;
5999    if(declMode == baseSystemAccess) nameSpace = &module.application.systemNameSpace;
6000
6001    if(declMode != staticAccess)
6002    {
6003       for(c = 0; name[c]; c++)
6004       {
6005          if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
6006          {
6007             NameSpace * newSpace;
6008
6009             char * spaceName = _malloc(c - start + 1);
6010             strncpy(spaceName, name + start, c - start);
6011             spaceName[c-start] = '\0';
6012
6013             newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
6014             if(!newSpace)
6015             {
6016                newSpace = new0 NameSpace[1];
6017                newSpace->classes.CompareKey = (void *)BinaryTree::CompareString;
6018                newSpace->defines.CompareKey = (void *)BinaryTree::CompareString;
6019                newSpace->functions.CompareKey = (void *)BinaryTree::CompareString;
6020                newSpace->nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
6021                newSpace->name = spaceName;
6022                newSpace->parent = nameSpace;
6023                nameSpace->nameSpaces.Add((BTNode)newSpace);
6024             }
6025             else
6026                delete spaceName;
6027             nameSpace = newSpace;
6028             if(name[c] == ':') c++;
6029             start = c+1;
6030          }
6031       }
6032    }
6033    else
6034       c = (int)strlen(name);
6035
6036    if(c - start && !nameSpace->defines.FindString(name + start))
6037    {
6038       DefinedExpression def
6039       {
6040          name = CopyString(name);
6041          nameSpace = nameSpace;
6042          value = CopyString(value);
6043       };
6044       nameSpace->defines.Add((BTNode)BTNamedLink { name = def.name + start, data = def });
6045       // Reference the definition in the module
6046       module.defines.Add(def);
6047       return def;
6048    }
6049    return null;
6050 }
6051
6052 public dllexport GlobalFunction eSystem_RegisterFunction(const char * name, const char * type, void * func, Module module, AccessMode declMode)
6053 {
6054    NameSpace * nameSpace = null;
6055    int start = 0, c;
6056
6057    nameSpace = (declMode == publicAccess) ? &module.publicNameSpace : &module.privateNameSpace;
6058    if(declMode == baseSystemAccess) nameSpace = &module.application.systemNameSpace;
6059
6060    if(declMode != staticAccess)
6061    {
6062       for(c = 0; name[c]; c++)
6063       {
6064          if(name[c] == '.' || (name[c] == ':' && name[c+1] == ':'))
6065          {
6066             NameSpace * newSpace;
6067
6068             char * spaceName = _malloc(c - start + 1);
6069             strncpy(spaceName, name + start, c - start);
6070             spaceName[c-start] = '\0';
6071
6072             newSpace = (NameSpace *)nameSpace->nameSpaces.FindString(spaceName);
6073             if(!newSpace)
6074             {
6075                newSpace = new0 NameSpace[1];
6076                newSpace->classes.CompareKey = (void *)BinaryTree::CompareString;
6077                newSpace->defines.CompareKey = (void *)BinaryTree::CompareString;
6078                newSpace->functions.CompareKey = (void *)BinaryTree::CompareString;
6079                newSpace->nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
6080                newSpace->name = spaceName;
6081                newSpace->parent = nameSpace;
6082                nameSpace->nameSpaces.Add((BTNode)newSpace);
6083             }
6084             else
6085                delete spaceName;
6086             nameSpace = newSpace;
6087             if(name[c] == ':') c++;
6088             start = c+1;
6089          }
6090       }
6091    }
6092    else
6093       c = (int)strlen(name);
6094
6095    if(c - start && !nameSpace->functions.FindString(name + start))
6096    {
6097       GlobalFunction function
6098       {
6099          name = CopyString(name);
6100          nameSpace = nameSpace;
6101          dataTypeString = CopyString(type);
6102          function = func;
6103          module = module;
6104       };
6105       nameSpace->functions.Add((BTNode)BTNamedLink { name = function.name + start, data = function });
6106       // Reference the definition in the module
6107       module.functions.Add(function);
6108       return function;
6109    }
6110    return null;
6111 }
6112
6113 public dllexport DefinedExpression eSystem_FindDefine(Module module, const char * name)
6114 {
6115    if(name && module)
6116    {
6117       BTNamedLink link;
6118       link = SearchNameSpace(&module.application.systemNameSpace, name, &((NameSpace *)0)->defines);
6119       if(link) return link.data;
6120
6121       link = SearchModule(module, name, &((NameSpace *)0)->defines, true);
6122       if(link) return link.data;
6123    }
6124    return null;
6125 }
6126
6127 public dllexport GlobalFunction eSystem_FindFunction(Module module, const char * name)
6128 {
6129    if(name && module)
6130    {
6131       BTNamedLink link;
6132       link = SearchNameSpace(&module.application.systemNameSpace, name, &((NameSpace *)0)->functions);
6133       if(link) return link.data;
6134
6135       link = SearchModule(module, name, &((NameSpace *)0)->functions, true);
6136       if(link) return link.data;
6137    }
6138    return null;
6139 }
6140
6141 public dllexport void * eSystem_Renew(void * memory, unsigned int size)
6142 {
6143    return _realloc(memory, size);
6144 }
6145
6146 public dllexport void * eSystem_Renew0(void * memory, unsigned int size)
6147 {
6148    return _crealloc(memory, size);
6149 }
6150
6151 public dllexport void * eSystem_New(unsigned int size)
6152 {
6153 /*#ifdef _DEBUG
6154    void * pointer = _malloc(size);
6155    memset(pointer, 0xec, size);
6156    return pointer;
6157 #else*/
6158    return _malloc(size);
6159 //#endif
6160 }
6161
6162 public dllexport void * eSystem_New0(unsigned int size)
6163 {
6164    return _calloc(1,size);
6165 }
6166
6167 public dllexport void eSystem_Delete(void * memory)
6168 {
6169    if(memory)
6170       _free(memory);
6171 }
6172
6173 // Properties
6174 public dllexport void eInstance_FireSelfWatchers(Instance instance, Property _property)
6175 {
6176    if(instance && _property && _property.selfWatchable)
6177    {
6178       Class _class;
6179       for(_class = instance._class; _class; _class = _class.base)
6180       {
6181          SelfWatcher selfWatcher, next;
6182          for(selfWatcher = _class.selfWatchers.first; selfWatcher; selfWatcher = next)
6183          {
6184             next = selfWatcher.next;
6185             if(selfWatcher._property == _property)
6186                selfWatcher.callback(instance);
6187          }
6188       }
6189    }
6190 }
6191
6192 public dllexport void eInstance_FireWatchers(Instance instance, Property _property)
6193 {
6194    if(instance && _property && _property.isWatchable)
6195    {
6196       Module module = instance._class ? instance._class.module : null;
6197       Application application = module ? module.application : null;
6198       int flags = application ? application.isGUIApp : 0;
6199       bool inCompiler = (flags & 8) ? true : false;
6200       bool force32Bits = (flags & 4) ? true : false;
6201       if(!force32Bits || !inCompiler)
6202       {
6203          OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6204          Watcher watcher, next;
6205
6206          for(watcher = watchers->first; watcher; watcher = next)
6207          {
6208             next = watcher.next;
6209             watcher.callback(watcher.object, instance);
6210          }
6211       }
6212    }
6213 }
6214
6215 public dllexport void eProperty_Watchable(Property _property)
6216 {
6217    if(!_property.isWatchable)
6218    {
6219       Class _class = _property._class;
6220       if(!_class.computeSize)
6221       {
6222          _property.watcherOffset = _class.structSize;
6223          _class.structSize += sizeof(OldList);
6224
6225          // highly inefficient
6226          FixDerivativesBase(_class, _class);
6227       }
6228       _property.isWatchable = true;
6229    }
6230 }
6231
6232 public dllexport void eClass_DestructionWatchable(Class _class)
6233 {
6234    if(!_class.destructionWatchOffset)
6235    {
6236       _class.destructionWatchOffset = _class.structSize;
6237       _class.structSize += sizeof(OldList);
6238       // highly inefficient
6239       FixDerivativesBase(_class, _class);
6240    }
6241 }
6242
6243 public dllexport void eProperty_SelfWatch(Class _class, const char * name, void (*callback)(void *))
6244 {
6245    if(_class)
6246    {
6247       Property _property = eClass_FindProperty(_class, name, _class.module);
6248
6249       if(!_property)
6250          _property = eClass_AddProperty(_class, name, null, null, null, baseSystemAccess /*privateAccess*/);
6251       _class.selfWatchers.Add(SelfWatcher { _property = _property, callback = callback });
6252       _property.selfWatchable = true;
6253    }
6254 }
6255
6256 public dllexport void eInstance_Watch(void * instance, Property _property, void * object, void (*callback)(void *, void *))
6257 {
6258    if(_property.isWatchable)
6259    {
6260       OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6261       watchers->Add(Watcher { callback = callback, object = object });
6262    }
6263 }
6264
6265 public dllexport void eInstance_WatchDestruction(Instance instance, Instance object, void (*callback)(void *, void *))
6266 {
6267    OldList * watchers = (OldList *)((byte *)instance + instance._class.destructionWatchOffset);
6268    watchers->Add(Watcher { callback = callback, object = object });
6269 }
6270
6271 public dllexport void eInstance_StopWatching(Instance instance, Property _property, Instance object)
6272 {
6273    if(instance && (!_property || _property.isWatchable))
6274    {
6275       if(_property)
6276       {
6277          OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6278          Watcher watcher;
6279          for(watcher = watchers->first; watcher; watcher = watcher.next)
6280             if(watcher.object == object)
6281             {
6282                watchers->Delete(watcher);
6283                break;
6284             }
6285       }
6286       else
6287       {
6288          // Stop watching all properties as well as destruction
6289          Class _class, base;
6290          for(_class = instance._class; _class; _class = base)
6291          {
6292             if(_class.destructionWatchOffset)
6293             {
6294                OldList * watchers = (OldList *)((byte *)instance + _class.destructionWatchOffset);
6295                Watcher watcher;
6296
6297                for(watcher = watchers->first; watcher; watcher = watcher.next)
6298                {
6299                   watchers->Delete(watcher);
6300                   break;
6301                }
6302             }
6303             for(_property = (Property)_class.membersAndProperties.first; _property; _property = _property.next)
6304             {
6305                if(_property.isProperty && _property.isWatchable)
6306                {
6307                   OldList * watchers = (OldList *)((byte *)instance + _property.watcherOffset);
6308                   Watcher watcher;
6309                   for(watcher = watchers->first; watcher; watcher = watcher.next)
6310                      if(watcher.object == object)
6311                      {
6312                         watchers->Delete(watcher);
6313                         break;
6314                      }
6315                }
6316             }
6317             base = _class.base;
6318             if(base && (base.type == systemClass || base.isInstanceClass)) base = null;
6319          }
6320       }
6321    }
6322 }
6323
6324 public dllexport subclass(ClassDesignerBase) eClass_GetDesigner(Class _class)
6325 {
6326    for(;_class;_class = _class.base)
6327    {
6328       if(_class.designerClass)
6329          return (subclass(ClassDesignerBase))eSystem_FindClass(_class.module, _class.designerClass);
6330    }
6331    return null;
6332 }
6333
6334
6335 public dllexport subclass(ClassDesignerBase) eInstance_GetDesigner(Instance instance)
6336 {
6337    if(instance)
6338       return eClass_GetDesigner(instance._class);
6339    return null;
6340 }
6341
6342 public bool LocateModule(const char * name, const char * fileName)
6343 {
6344    return Instance_LocateModule(name, fileName);
6345 }
6346
6347 /*
6348 #if (defined(__WORDSIZE) && __WORDSIZE == 8) || defined(__x86_64__)
6349 #define _64BIT 1
6350 #else
6351 #define _64BIT 0
6352 #endif
6353
6354 #define arch_PointerSize                  sizeof(void *)
6355 #define structSize_Instance               (_64BIT ? 24 : 12)
6356 #define structSize_Module                 (_64BIT ? 560 : 300)
6357 #define structSize_BinaryTree             (_64BIT ? 32 : 16)
6358 #define structSize_OldList                (_64BIT ? 32 : 20)
6359 #define structSize_NamedLink64            (_64BIT ? 32 : 24)
6360 #define structSize_ClassTemplateArgument  (_64BIT ? 16 : 8)
6361 #define structSize_ClassTemplateParameter (_64BIT ? 64 : 40)
6362 #define structSize_OldLink                (_64BIT ? 24 : 12)
6363 #define structSize_BTNamedLink            (_64BIT ? 48 : 24)
6364 #define structSize_Application            (_64BIT ? 800 : 428)
6365 #define structSize_Watcher                (_64BIT ? 32 : 16)
6366 #define structSize_SelfWatcher            (_64BIT ? 32 : 16)
6367 #define structSize_GlobalFunction         (_64BIT ? 72 : 36)
6368 #define structSize_DefinedExpression      (_64BIT ? 40 : 20)
6369 #define structSize_BitMember              (_64BIT ? 96 : 64)
6370 #define structSize_DataMember             (_64BIT ? 160 : 96)
6371 #define structSize_ClassProperty          (_64BIT ? 80 : 40)
6372 #define structSize_Method                 (_64BIT ? 96 : 52)
6373 #define structSize_Property               (_64BIT ? 152 : 88)
6374 #define structSize_Class                  (_64BIT ? 624 : 376)
6375 */
6376
6377 static void LoadCOM(Module module)
6378 {
6379    bool force64Bits = (module.application.isGUIApp & 2) ? true : false;
6380    bool force32Bits = (module.application.isGUIApp & 4) ? true : false;
6381    bool inCompiler = (module.application.isGUIApp & 8) ? true : false;
6382    int pointerSize = force64Bits ? 8 : force32Bits ? 4 : sizeof(void *);
6383    Class applicationClass;
6384    Class enumClass, structClass, boolClass;
6385    Class moduleClass;
6386
6387    // Create Base Class
6388    Class baseClass = eSystem_RegisterClass(normalClass, "class", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6389    baseClass.type = systemClass;
6390    baseClass.memberOffset = 0;
6391    baseClass.offset = 0;
6392    baseClass.structSize = 0;
6393    baseClass.typeSize = 0;
6394
6395    {
6396       Class instanceClass = eSystem_RegisterClass(normalClass, "ecere::com::Instance", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6397       instanceClass.type = normalClass;
6398       instanceClass.isInstanceClass = true;
6399       instanceClass.fixed = true;
6400       instanceClass.memberOffset = 0;
6401       instanceClass.offset = 0;
6402
6403       instanceClass.memberID = -3;
6404       instanceClass.startMemberID = -3;
6405
6406       eClass_AddDataMember(instanceClass, "_vTbl", "void **", pointerSize, pointerSize, publicAccess);
6407       eClass_AddDataMember(instanceClass, "_class", "ecere::com::Class", pointerSize, pointerSize, publicAccess);
6408       eClass_AddDataMember(instanceClass, "_refCount", "int", sizeof(int), sizeof(int), publicAccess);
6409    }
6410
6411    InitializeDataTypes1(module);
6412
6413    // Create Enum class
6414    enumClass = eSystem_RegisterClass(normalClass, "enum", null, 0, force64Bits ? 40 : sizeof(class EnumClassData), null, null, module, baseSystemAccess, publicAccess);
6415    eClass_AddClassProperty(enumClass, "enumSize", "int", null, GetEnumSize).constant = true;
6416    enumClass.type = systemClass;
6417
6418    delete (void *)enumClass.dataTypeString;
6419    enumClass.dataTypeString = CopyString(/*"unsigned int"*/"int");
6420
6421    // Create Struct (simple) class
6422    //structClass = eSystem_RegisterClass(structClass, "struct", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6423    structClass = eSystem_RegisterClass(normalClass, "struct", null, 0, 0, null, null, module, baseSystemAccess, publicAccess);
6424    structClass.type = systemClass;
6425    structClass.memberOffset = 0;
6426    structClass.offset = 0;
6427    structClass.structSize = 0;
6428    structClass.typeSize = 0;
6429
6430    //eClass_AddMethod(enumClass, "AddValue", "int()", eEnum_AddValue);
6431    //eClass_AddMethod(enumClass, "AddFixedValue", "void()", eEnum_AddFixedValue);
6432
6433    InitializeDataTypes(module);
6434
6435    // Create bool class
6436    boolClass = eSystem_RegisterClass(ClassType::enumClass, "bool", "uint", 0, 0, null, null, module, baseSystemAccess, publicAccess);
6437    eEnum_AddFixedValue(boolClass, "true",  bool::true);
6438    eEnum_AddFixedValue(boolClass, "false", bool::false);
6439
6440    // Create Module class
6441    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) :
6442                                                                                 sizeof(struct Module), 0, (void *)Module_Constructor, (void *)Module_Destructor, module, baseSystemAccess, publicAccess);
6443    eClass_AddVirtualMethod(moduleClass, "OnLoad", "bool()", null, publicAccess);
6444    eClass_AddVirtualMethod(moduleClass, "OnUnload", "void()", null, publicAccess);
6445    eClass_AddMethod(moduleClass, "Load", "Module(const char * name, AccessMode importAccess)", eModule_Load, publicAccess);
6446    eClass_AddMethod(moduleClass, "Unload", "void(Module module)", eModule_Unload, publicAccess);
6447    eClass_AddDataMember(moduleClass, "application", "Application", pointerSize, pointerSize, publicAccess);
6448    eClass_AddDataMember(moduleClass, "classes", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6449    eClass_AddDataMember(moduleClass, "defines", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6450    eClass_AddDataMember(moduleClass, "functions", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6451    eClass_AddDataMember(moduleClass, "modules", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6452    eClass_AddDataMember(moduleClass, "prev", "Module", pointerSize, pointerSize, publicAccess);
6453    eClass_AddDataMember(moduleClass, "next", "Module", pointerSize, pointerSize, publicAccess);
6454    eClass_AddDataMember(moduleClass, "name", "const char *", pointerSize, pointerSize, publicAccess);
6455    eClass_AddDataMember(moduleClass, "library", "void *", pointerSize, pointerSize, publicAccess);
6456    eClass_AddDataMember(moduleClass, "Unload", "void *", pointerSize, pointerSize, publicAccess);
6457    eClass_AddDataMember(moduleClass, "importType", "ImportType", sizeof(ImportType), 4, publicAccess);
6458    eClass_AddDataMember(moduleClass, "origImportType", "ImportType", sizeof(ImportType), 4, publicAccess);
6459    eClass_AddDataMember(moduleClass, "privateNameSpace", "NameSpace", force64Bits ? (32 + 8 + 8 + 4*32) : force32Bits ? (16 + 4 + 4 + 4*16) : sizeof(NameSpace), pointerSize, publicAccess);
6460    eClass_AddDataMember(moduleClass, "publicNameSpace", "NameSpace",  force64Bits ? (32 + 8 + 8 + 4*32) : force32Bits ? (16 + 4 + 4 + 4*16) : sizeof(NameSpace), pointerSize, publicAccess);
6461    moduleClass.fixed = true;
6462    moduleClass.count++;
6463    if(inCompiler && force32Bits)
6464       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);
6465
6466    // Create Application class
6467    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);
6468    if(inCompiler && force32Bits)
6469    {
6470       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);
6471       applicationClass.structSize = applicationClass.offset + (4+4+4+4 + 20 + 4 + 88);
6472    }
6473    eClass_AddVirtualMethod(applicationClass, "Main", "void()", null, publicAccess);
6474    eClass_AddDataMember(applicationClass, "argc", "int", sizeof(int), 4, publicAccess);
6475    eClass_AddDataMember(applicationClass, "argv", "const char **", pointerSize, pointerSize, publicAccess);
6476    eClass_AddDataMember(applicationClass, "exitCode", "int", sizeof(int), 4, publicAccess);
6477    eClass_AddDataMember(applicationClass, "isGUIApp", "bool", sizeof(bool), 4, publicAccess);
6478    eClass_AddDataMember(applicationClass, "allModules", "OldList", force64Bits ? 32 : force32Bits ? 20 : sizeof(OldList), pointerSize, publicAccess);
6479    eClass_AddDataMember(applicationClass, "parsedCommand", "char *", pointerSize, pointerSize, publicAccess);
6480    eClass_AddDataMember(applicationClass, "systemNameSpace", "NameSpace", force64Bits ? (32 + 8 + 8 + 4*32) : force32Bits ? (16 + 4 + 4 + 4*16) : sizeof(NameSpace), pointerSize, publicAccess);
6481    applicationClass.fixed = true;
6482    applicationClass.count++;
6483
6484    //AttachConsole(-1);
6485    //AllocConsole();
6486
6487    // --- Math ---
6488    eSystem_RegisterFunction("sin", "double sin(Angle number)", sin, module, baseSystemAccess);
6489    eSystem_RegisterFunction("sinh", "double sinh(Angle number)", sinh, module, baseSystemAccess);
6490    eSystem_RegisterFunction("cosh", "double cosh(Angle number)", cosh, module, baseSystemAccess);
6491    eSystem_RegisterFunction("tanh", "double tanh(Angle number)", tanh, module, baseSystemAccess);
6492    eSystem_RegisterFunction("sqrt", "double sqrt(double number)", sqrt, module, baseSystemAccess);
6493    eSystem_RegisterFunction("cos", "double cos(Angle number)", cos, module, baseSystemAccess);
6494    eSystem_RegisterFunction("tan", "double tan(Angle number)", tan, module, baseSystemAccess);
6495    eSystem_RegisterFunction("atan2", "Angle atan2(double y, double x)", atan2, module, baseSystemAccess);
6496    eSystem_RegisterFunction("asin", "Angle asin(double number)", asin, module, baseSystemAccess);
6497    eSystem_RegisterFunction("acos", "Angle acos(double number)", acos, module, baseSystemAccess);
6498    eSystem_RegisterFunction("atan", "Angle atan(double number)", atan, module, baseSystemAccess);
6499    eSystem_RegisterFunction("asinh", "Angle asinh(double number)", asinh, module, baseSystemAccess);
6500    eSystem_RegisterFunction("acosh", "Angle acosh(double number)", acosh, module, baseSystemAccess);
6501    eSystem_RegisterFunction("atanh", "Angle atanh(double number)", atanh, module, baseSystemAccess);
6502    eSystem_RegisterFunction("pow", "double pow(double number, double number2)", pow, module, baseSystemAccess);
6503    eSystem_RegisterFunction("fmod", "double fmod(double x, double y)", fmod, module, baseSystemAccess);
6504    eSystem_RegisterFunction("fabs", "double fabs(double number)", fabs, module, baseSystemAccess);
6505    eSystem_RegisterFunction("log", "double log(double number)", log, module, baseSystemAccess);
6506    eSystem_RegisterFunction("log10", "double log10(double number)", log10, module, baseSystemAccess);
6507    eSystem_RegisterFunction("ceil", "double ceil(double number)", ceil, module, baseSystemAccess);
6508    eSystem_RegisterFunction("floor", "double floor(double number)", floor, module, baseSystemAccess);
6509    eSystem_RegisterFunction("exp", "double exp(double number)", exp, module, baseSystemAccess);
6510
6511    // --- Stdlib ---
6512    eSystem_RegisterFunction("qsort", "void qsort(void *, uintsize, uintsize, int (*)(void *, void *))", qsort, module, baseSystemAccess);
6513    eSystem_RegisterFunction("strtod", "double strtod(const char*, char**)", strtod, module, baseSystemAccess);
6514    eSystem_RegisterFunction("strtol", "int strtol(const char*, char**, int base)", strtol, module, baseSystemAccess);
6515    eSystem_RegisterFunction("strtoul", "unsigned long strtoul(const char * nptr, char ** endptr, int base)", strtoul, module, baseSystemAccess);
6516    eSystem_RegisterFunction("strtoll", "int64 strtoll(const char * nptr, char ** endptr, int base)", strtoll, module, baseSystemAccess);
6517    eSystem_RegisterFunction("strtoull", "uint64 strtoull(const char * nptr, char ** endptr, int base)", strtoull, module, baseSystemAccess);
6518    eSystem_RegisterFunction("system", "int system(const char*)", system, module, baseSystemAccess);
6519    eSystem_RegisterFunction("atoi", "int atoi(const char*)", atoi, module, baseSystemAccess);
6520    eSystem_RegisterFunction("atof", "double atof(const char*)", atof, module, baseSystemAccess);
6521    eSystem_RegisterFunction("memset", "void * memset(void * area, int value, uintsize count)", memset, module, baseSystemAccess);
6522    eSystem_RegisterFunction("getenv", "char * getenv(const char * name)", getenv, module, baseSystemAccess);
6523    eSystem_RegisterFunction("rename", "int rename(const char *oldpath, const char *newpath)", rename, module, baseSystemAccess);
6524
6525    // --- String --- (These might move to the string class)
6526    eSystem_RegisterFunction("strlen", "uintsize strlen(const char *)", strlen, module, baseSystemAccess);
6527    eSystem_RegisterFunction("strcat", "char * strcat(char *, const char *)", strcat, module, baseSystemAccess);
6528    eSystem_RegisterFunction("strncat", "char * strncat(char *, const char *, uintsize n)", strncat, module, baseSystemAccess);
6529    eSystem_RegisterFunction("strchr", "char * strchr(const char *, int)", strchr, module, baseSystemAccess);
6530    eSystem_RegisterFunction("strstr", "char * strstr(const char *, const char *)", strstr, module, baseSystemAccess);
6531    eSystem_RegisterFunction("strspn", "uintsize strspn(const char *, const char *)", strspn, module, baseSystemAccess);
6532    eSystem_RegisterFunction("strcspn", "uintsize strcspn(const char *, const char *)", strcspn, module, baseSystemAccess);
6533    eSystem_RegisterFunction("strpbrk", "char * strpbrk(const char *, const char *)", strpbrk, module, baseSystemAccess);
6534
6535    eSystem_RegisterDefine("fstrcmp", "(__runtimePlatform == win32) ? strcmpi : strcmp", module, baseSystemAccess);
6536
6537 //#if defined(__GNUC__)
6538    eSystem_RegisterDefine("strcmpi", "strcasecmp", module, baseSystemAccess);
6539    eSystem_RegisterDefine("strnicmp", "strncasecmp", module, baseSystemAccess);
6540    eSystem_RegisterFunction("strcasecmp", "int strcasecmp(const char *, const char *)", strcmpi, module, baseSystemAccess);
6541    eSystem_RegisterFunction("strncasecmp", "int strncasecmp(const char *, const char *, uintsize n)", strnicmp, module, baseSystemAccess);
6542 /*
6543 #else
6544    eSystem_RegisterDefine("strcasecmp", "strcmpi", module, baseSystemAccess);
6545    eSystem_RegisterDefine("strncasecmp", "strnicmp", module, baseSystemAccess);
6546    eSystem_RegisterFunction("strcmpi", "int strcmpi(const char *, const char *)", strcmpi, module, baseSystemAccess);
6547    eSystem_RegisterFunction("strnicmp", "int strnicmp(const char *, const char *, int n)", strnicmp, module, baseSystemAccess);
6548 #endif
6549 */
6550
6551    eSystem_RegisterFunction("strcmp", "int strcmp(const char *, const char *)", strcmp, module, baseSystemAccess);
6552    eSystem_RegisterFunction("strncmp", "int strncmp(const char *, const char *, uintsize n)", strncmp, module, baseSystemAccess);
6553    eSystem_RegisterFunction("strlwr", "char * strlwr(char *)", strlwr, module, baseSystemAccess);
6554    eSystem_RegisterFunction("strupr", "char * strupr(char *)", strupr, module, baseSystemAccess);
6555    eSystem_RegisterFunction("strcpy", "char * strcpy(char *, const char *)", strcpy, module, baseSystemAccess);
6556    eSystem_RegisterFunction("strncpy", "char * strncpy(char *, const char *, uintsize n)", strncpy, module, baseSystemAccess);
6557    eSystem_RegisterFunction("memcpy", "void * memcpy(void *, const void *, uintsize size)", memcpy, module, baseSystemAccess);
6558    eSystem_RegisterFunction("memmove", "void * memmove(void *, const void *, uintsize size)", memmove, module, baseSystemAccess);
6559    eSystem_RegisterFunction("memcmp", "int memcmp(const void *, const void *, uintsize size)", memcmp, module, baseSystemAccess);
6560
6561    // --- Stdio ---
6562    eSystem_RegisterFunction("sprintf", "int sprintf(char *, const char *, ...)", sprintf, module, baseSystemAccess);
6563    eSystem_RegisterFunction("snprintf", "int snprintf(char *, uintsize, const char *, ...)", snprintf, module, baseSystemAccess);
6564    eSystem_RegisterFunction("printf", "int printf(const char *, ...)", printf, module, baseSystemAccess);
6565    eSystem_RegisterFunction("vsprintf", "int vsprintf(char*, const char*, __builtin_va_list)", vsprintf, module, baseSystemAccess);
6566    eSystem_RegisterFunction("vsnprintf", "int vsnprintf(char*, uintsize, const char*, __builtin_va_list)", vsnprintf, module, baseSystemAccess);
6567    eSystem_RegisterFunction("puts", "int puts(const char *)", puts, module, baseSystemAccess);
6568    eSystem_RegisterFunction("fputs", "int fputs(const char *, void * stream)", fputs, module, baseSystemAccess);
6569
6570    // --- Ctype ---
6571    eSystem_RegisterFunction("tolower", "int tolower(int)", tolower, module, baseSystemAccess);
6572    eSystem_RegisterFunction("toupper", "int toupper(int)", toupper, module, baseSystemAccess);
6573    eSystem_RegisterFunction("isdigit", "bool isdigit(int)", isdigit, module, baseSystemAccess);
6574    eSystem_RegisterFunction("isxdigit","bool isxdigit(int)", isxdigit, module, baseSystemAccess);
6575    eSystem_RegisterFunction("isalnum", "int isalnum(int c)", isalnum, module, baseSystemAccess);
6576    eSystem_RegisterFunction("isspace", "int isspace(int c)", isspace, module, baseSystemAccess);
6577    eSystem_RegisterFunction("isalpha", "int isalpha(int c)", isalpha, module, baseSystemAccess);
6578    eSystem_RegisterFunction("islower", "int islower(int c)", islower, module, baseSystemAccess);
6579    eSystem_RegisterFunction("isupper", "int isupper(int c)", isupper, module, baseSystemAccess);
6580    eSystem_RegisterFunction("isprint", "int isprint(int c)", isprint, module, baseSystemAccess);
6581    eSystem_RegisterFunction("isblank", "int isblank(int c)", isblank, module, baseSystemAccess);
6582
6583 }
6584
6585 public dllexport Application __ecere_COM_Initialize(bool guiApp, int argc, char * argv[])
6586 {
6587    Application app;
6588
6589 #ifdef __ANDROID__
6590    // Clean up global variables
6591    memoryInitialized = false;
6592    pools = null;
6593 #ifdef MEMINFO
6594    memset(&memStacks, 0, sizeof(BinaryTree));
6595    memoryErrorsCount = 0;
6596    memset(&memBlocks, 0, sizeof(BinaryTree));
6597    recurse = false;
6598    blockID = 0;
6599    allocateClass = null;
6600    allocateInternal = false;
6601    TOTAL_MEM = 0;
6602    OUTSIDE_MEM = 0;
6603 #endif
6604 #endif
6605
6606 #ifdef _DEBUG
6607    // printf("Using debug ecere runtime library\n");
6608 #endif
6609    app = _calloc(1, sizeof(class Application));
6610
6611    Module_Constructor(app);
6612    app.systemNameSpace.classes.CompareKey = (void *)BinaryTree::CompareString;
6613    app.systemNameSpace.defines.CompareKey = (void *)BinaryTree::CompareString;
6614    app.systemNameSpace.functions.CompareKey = (void *)BinaryTree::CompareString;
6615    app.systemNameSpace.nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
6616
6617    Instance_COM_Initialize(argc, argv, &app.parsedCommand, &app.argc, &app.argv);
6618
6619    app.application = app;
6620    app.allModules.offset = sizeof(class Instance) + (uint)(uintptr)&((struct Module *)0)->prev;
6621    app.isGUIApp = guiApp;
6622
6623    LoadCOM(app);
6624
6625    app._class = eSystem_FindClass(app, "Application");
6626
6627    return app;
6628 }
6629
6630 public dllexport void eSystem_SetArgs(Application app, int argc, char * argv[])
6631 {
6632    System_SetArgs(argc, argv, &app.argc, &app.argv);
6633 }
6634
6635 public dllexport ClassTemplateParameter eClass_AddTemplateParameter(Class _class, const char * name, TemplateParameterType type, const void * info, ClassTemplateArgument defaultArg)
6636 {
6637    if(_class && name)
6638    {
6639       ClassTemplateParameter param;
6640
6641       for(param = _class.templateParams.first; param; param = param.next)
6642       {
6643          if(!strcmp(param.name, name))
6644             return param;
6645       }
6646       param =
6647       {
6648          name = CopyString(name);
6649          type = type;
6650          (type == identifier) ? info : CopyString(info);
6651       };
6652       if(defaultArg != null)
6653       {
6654          param.defaultArg = defaultArg;
6655          CopyTemplateArg(param, param.defaultArg);
6656       }
6657       _class.templateParams.Add(param);
6658       return param;
6659    }
6660    return null;
6661 }
6662
6663 public dllexport void eClass_DoneAddingTemplateParameters(Class base)
6664 {
6665    if(base)
6666    {
6667       ClassTemplateParameter param;
6668       {
6669          void * first = base.templateParams.first;
6670          int count = base.templateParams.count;
6671
6672          FreeTemplateArgs(base);
6673          delete base.templateArgs;
6674
6675          base.templateParams.first = null;
6676          base.templateParams.count = 0;
6677
6678          FreeTemplatesDerivatives(base);
6679
6680          base.templateParams.first = first;
6681          base.templateParams.count = count;
6682       }
6683
6684       for(param = base.templateParams.first; param; param = param.next)
6685       {
6686          if(param.type == identifier && param.defaultArg.memberString)
6687          {
6688             Class memberClass = base;
6689             const char * colon = strstr(param.defaultArg.memberString, "::");
6690             const char * memberName;
6691             if(colon)
6692             {
6693                char className[1024];
6694                Class sClass;
6695
6696                memcpy(className, param.defaultArg.memberString, colon - param.defaultArg.memberString);
6697                className[colon - param.defaultArg.memberString] = '\0';
6698                memberName = colon + 2;
6699
6700                for(sClass = base; sClass; sClass = sClass.base)
6701                {
6702                   ClassTemplateParameter cParam;
6703                   Class nextClass;
6704                   int id = 0;
6705                   for(nextClass = sClass.base; nextClass; nextClass = nextClass.base) id += nextClass.templateParams.count;
6706                   // Safety! What could cause base.templateArgs to be null?
6707                   if(sClass == base || base.templateArgs)
6708                   {
6709                      for(cParam = sClass.templateParams.first; cParam; cParam = cParam.next)
6710                      {
6711                         if(cParam.type == type && !strcmp(cParam.name, className))
6712                            strcpy(className, (sClass == base) ? cParam.defaultArg.dataTypeString : base.templateArgs[id].dataTypeString);
6713                         id++;
6714                      }
6715                   }
6716                }
6717                memberClass = eSystem_FindClass(base.module, className);
6718                if(!memberClass)
6719                   memberClass = eSystem_FindClass(base.module.application, className);
6720             }
6721             else
6722                memberName = param.defaultArg.memberString;
6723
6724             if(memberClass)
6725             {
6726                switch(param.memberType)
6727                {
6728                   case dataMember:
6729                      param.defaultArg.member = eClass_FindDataMember(memberClass, memberName, memberClass.module, null, null);
6730                      break;
6731                   case method:
6732                      param.defaultArg.method = eClass_FindMethod(memberClass, memberName, memberClass.module);
6733                      break;
6734                   case prop:
6735                      param.defaultArg.prop = eClass_FindProperty(memberClass, memberName, memberClass.module);
6736                      break;
6737                }
6738             }
6739          }
6740       }
6741
6742       //ComputeClassParameters(base, null, null);
6743
6744       FixDerivativesBase(base, base);
6745    }
6746 }
6747
6748 static void FreeTemplatesDerivatives(Class base)
6749 {
6750    OldLink derivative, templateLink;
6751    for(derivative = base.derivatives.first; derivative; derivative = derivative.next)
6752    {
6753       Class _class = derivative.data;
6754       if(_class.templateArgs)
6755       {
6756          FreeTemplateArgs(_class);
6757          delete _class.templateArgs;
6758       }
6759       FreeTemplatesDerivatives(_class);
6760    }
6761
6762    for(templateLink = base.templatized.first; templateLink; templateLink = templateLink.next)
6763    {
6764       Class _class = templateLink.data;
6765       if(_class.templateArgs)
6766       {
6767          FreeTemplateArgs(_class);
6768          delete _class.templateArgs;
6769       }
6770       FreeTemplatesDerivatives(_class);
6771    }
6772 }
6773
6774 static const char * platformNames[Platform] = { "", "win32", "linux", "apple" }; // how to have this be accessible outside of dll/lib
6775 static const Platform firstPlatform = win32;
6776 static const Platform lastPlatform = apple;
6777
6778 public enum Platform
6779 {
6780    unknown, win32, tux, apple;
6781
6782    property const char *
6783    {
6784       get { return OnGetString(null, null, null); }
6785       set
6786       {
6787          if(value)
6788          {
6789             Platform c;
6790             for(c = firstPlatform; c <= lastPlatform; c++)
6791                if(!strcmpi(value, platformNames[c]))
6792                   return c;
6793          }
6794          return unknown;
6795       }
6796    };
6797
6798    const char * OnGetString(char * tempString, void * fieldData, bool * needClass)
6799    {
6800       if(this >= firstPlatform && this <= lastPlatform)
6801       {
6802          if(tempString)
6803             strcpy(tempString, platformNames[this]);
6804          return platformNames[this];
6805       }
6806       if(tempString && tempString[0])
6807          tempString[0] = '\0';
6808       return null;
6809    }
6810
6811    bool OnGetDataFromString(const char * string)
6812    {
6813       this = string;
6814       return this != unknown;
6815    }
6816 };
6817
6818 default extern Platform runtimePlatform;
6819
6820 public Platform GetRuntimePlatform()
6821 {
6822    return runtimePlatform;
6823 }
6824
6825 namespace gui;
6826
6827 class Window;
6828
6829 namespace com;
6830 // CLASS DESIGNER SUPPORT
6831
6832 public class ObjectInfo : struct
6833 {
6834 public:
6835    ObjectInfo prev, next;
6836    Instance instance;
6837    char * name;
6838    Instantiation instCode;
6839    bool deleted;
6840    ObjectInfo oClass;
6841    OldList instances;
6842    ClassDefinition classDefinition;
6843    bool modified;
6844    void * i18nStrings;
6845 };
6846
6847 public class DesignerBase : Window
6848 {
6849 public:
6850    virtual bool FindObject(Instance * instance, const char * string);
6851    virtual void RenameObject(ObjectInfo object, const char * name);
6852    virtual void SelectObjectFromDesigner(ObjectInfo object);
6853    virtual void CodeAddObject(Instance instance, ObjectInfo * object);
6854    virtual void SheetAddObject(ObjectInfo object);
6855    virtual void AddToolBoxClass(Class _class);
6856    virtual void AddDefaultMethod(Instance instance, Instance classInstance);
6857    virtual void DeleteObject(ObjectInfo object);
6858    virtual bool ObjectContainsCode(ObjectInfo object);
6859    virtual void ModifyCode(void);
6860    virtual void UpdateProperties(void);
6861
6862    ClassDesignerBase classDesigner;
6863    const char * objectClass;
6864    bool isDragging;
6865
6866    // FIX THIS WITH PUBLIC:
6867    property ClassDesignerBase classDesigner
6868    {
6869       get { return classDesigner; }
6870       set { classDesigner = value; }
6871    };
6872    property const char * objectClass
6873    {
6874       get { return objectClass; }
6875       set { objectClass = value; }
6876    };
6877    property bool isDragging
6878    {
6879       get { return isDragging; }
6880       set { isDragging = value; }
6881    };
6882 }
6883
6884 public class ClassDesignerBase : Window
6885 {
6886 public:
6887    virtual void Reset(void);
6888    virtual void AddObject(void);
6889    virtual void SelectObject(ObjectInfo object, Instance control);
6890
6891    virtual void ListToolBoxClasses(DesignerBase designer);
6892
6893    virtual void ::PrepareTestObject(DesignerBase designer, Instance test);
6894    virtual void ::CreateObject(DesignerBase designer, Instance instance, ObjectInfo object, bool isClass, Instance _class);
6895    virtual void ::PostCreateObject(Instance instance, ObjectInfo object, bool isClass, Instance _class);
6896    virtual void ::DroppedObject(Instance instance, ObjectInfo object, bool isClass, Instance _class);
6897    virtual void ::DestroyObject(Instance object);
6898    virtual void ::FixProperty(Property prop, Instance object);
6899    virtual void ::CreateNew(EditBox editBox, Size clientSize, const char * name, const char * inherit);
6900 }
6901
6902 DesignerBase activeDesigner;
6903
6904 public void SetActiveDesigner(DesignerBase designer)
6905 {
6906    activeDesigner = designer;
6907 }
6908
6909 public DesignerBase GetActiveDesigner()
6910 {
6911    return activeDesigner;
6912 }
6913
6914
6915 bool poolingDisabled;
6916
6917 public dllexport void eSystem_SetPoolingDisabled(bool disabled)
6918 {
6919    poolingDisabled = disabled;
6920 }
6921
6922 namespace sys;
6923
6924 // constants
6925 define LEAD_OFFSET      = 0xD800 - (0x10000 >> 10);
6926 define SURROGATE_OFFSET = 0x10000 - (0xD800 << 10) - 0xDC00;
6927
6928 public bool UTF8Validate(const char * source)
6929 {
6930    if(source)
6931    {
6932       int c;
6933       for(c = 0; source[c];)
6934       {
6935          byte ch = source[c];
6936          unichar codePoint = 0;
6937          int numBytes = 1;
6938          int i;
6939          byte mask = 0x7F;
6940          if(ch & 0x80)
6941          {
6942             if(ch & 0x40)
6943             {
6944                mask >>= 2;
6945                numBytes++;
6946                if(ch & 0x20)
6947                {
6948                   numBytes++;
6949                   mask >>= 1;
6950                   if(ch & 0x10)
6951                   {
6952                      if(ch & 0x08)
6953                         return false;
6954                      numBytes++;
6955                      mask >>= 1;
6956                   }
6957                }
6958             }
6959             else
6960                return false;
6961          }
6962          for(i = 0; i<numBytes && (ch = source[c]); i++, c++)
6963          {
6964             codePoint <<= 6;
6965             codePoint |= ch & mask;
6966             mask = 0x3F;
6967             if(i > 1)
6968             {
6969                if(!(ch & 0x80) || (ch & 0x40))
6970                   return false;
6971             }
6972          }
6973          if(i < numBytes) return false;
6974
6975          if(codePoint > 0x10FFFF || (codePoint >= 0xD800 && codePoint <= 0xDFFF) ||
6976            (codePoint < 0x80 && numBytes > 1) ||
6977            (codePoint < 0x800 && numBytes > 2) ||
6978            (codePoint < 0x10000 && numBytes > 3))
6979             return false;
6980       }
6981    }
6982    return true;
6983 }
6984
6985 public int ISO8859_1toUTF8(const char * source, char * dest, int max)
6986 {
6987    int c;
6988    int d = 0;
6989    byte * byteDest = (byte *)dest;
6990    for(c = 0; source[c]; c++)
6991    {
6992       unichar ch = ((byte *)source)[c];
6993       switch(ch)
6994       {
6995          case 128: ch = (unichar)0x20AC; break;
6996          case 130: ch = (unichar)0x201A; break;
6997          case 131: ch = (unichar)0x0192; break;
6998          case 132: ch = (unichar)0x201E; break;
6999          case 133: ch = (unichar)0x2026; break;
7000          case 134: ch = (unichar)0x2020; break;
7001          case 135: ch = (unichar)0x2021; break;
7002          case 136: ch = (unichar)0x02C6; break;
7003          case 137: ch = (unichar)0x2030; break;
7004          case 138: ch = (unichar)0x0160; break;
7005          case 139: ch = (unichar)0x2039; break;
7006          case 140: ch = (unichar)0x0152; break;
7007          case 142: ch = (unichar)0x017D; break;
7008          case 145: ch = (unichar)0x2018; break;
7009          case 146: ch = (unichar)0x2019; break;
7010          case 147: ch = (unichar)0x201C; break;
7011          case 148: ch = (unichar)0x201D; break;
7012          case 149: ch = (unichar)0x2022; break;
7013          case 150: ch = (unichar)0x2013; break;
7014          case 151: ch = (unichar)0x2014; break;
7015          case 152: ch = (unichar)0x02DC; break;
7016          case 153: ch = (unichar)0x2122; break;
7017          case 154: ch = (unichar)0x0161; break;
7018          case 155: ch = (unichar)0x203A; break;
7019          case 156: ch = (unichar)0x0153; break;
7020          case 158: ch = (unichar)0x017E; break;
7021          case 159: ch = (unichar)0x0178; break;
7022       }
7023       if(ch < 0x80)
7024       {
7025          if(d + 1 >= max) break;
7026          byteDest[d++] = (char)ch;
7027       }
7028       else if(ch < 0x800)
7029       {
7030          if(d + 2 >= max) break;
7031          byteDest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7032          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7033       }
7034       else if(ch < 0x10000)
7035       {
7036          if(d + 3 >= max) break;
7037          byteDest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7038          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7039          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7040       }
7041       else
7042       {
7043          if(d + 4 >= max) break;
7044          byteDest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7045          byteDest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7046          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7047          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7048       }
7049    }
7050    dest[d] = 0;
7051    return d;
7052 }
7053
7054 public char * UTF16toUTF8(const uint16 * source)
7055 {
7056    int c;
7057    int d = 0;
7058    int len;
7059    byte * dest;
7060    uint16 u16;
7061    bool invert = false;
7062
7063    for(len = 0; source[len]; len++);
7064    dest = new byte[len * 3 + 1];
7065    for(c = 0; (u16 = source[c]); c++)
7066    {
7067       unichar ch;
7068       if(!c && (u16 == 0xFFFE || u16 == 0xFEFF))
7069       {
7070          if(u16 == 0xFFFE) invert = true;
7071          continue;
7072       }
7073       if(invert) { u16 = ((u16 & 0xFF00) >> 8) | ((u16 & 0x00FF) << 8); }
7074
7075       if(u16 < 0xD800 || u16 > 0xDBFF)
7076          ch = (unichar)u16;
7077       else
7078          ch = ((unichar)u16 << 10) + source[c++] + SURROGATE_OFFSET;
7079
7080       if(ch < 0x80)
7081       {
7082          dest[d++] = (char)ch;
7083       }
7084       else if(ch < 0x800)
7085       {
7086          dest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7087          dest[d++] = 0x80 | (byte)(ch & 0x03F);
7088       }
7089       else if(ch < 0x10000)
7090       {
7091          dest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7092          dest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7093          dest[d++] = 0x80 | (byte)(ch & 0x03F);
7094       }
7095       else
7096       {
7097          dest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7098          dest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7099          dest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7100          dest[d++] = 0x80 | (byte)(ch & 0x03F);
7101       }
7102    }
7103    dest[d] = 0;
7104    dest = renew dest byte[d+1];
7105    return (char *)dest;
7106 }
7107
7108 public int UTF16toUTF8Buffer(const uint16 * source, char * dest, int max)
7109 {
7110    int c;
7111    int d = 0;
7112    uint16 u16;
7113    byte * byteDest = (byte *)dest;
7114    for(c = 0; (u16 = source[c]); c++)
7115    {
7116       unichar ch;
7117       if(u16 < 0xD800 || u16 > 0xDBFF)
7118          ch = (unichar)u16;
7119       else
7120          ch = ((unichar)u16 << 10) + source[c++] + SURROGATE_OFFSET;
7121
7122       if(ch < 0x80)
7123       {
7124          if(d + 1 >= max) break;
7125          byteDest[d++] = (char)ch;
7126       }
7127       else if(ch < 0x800)
7128       {
7129          if(d + 2 >= max) break;
7130          byteDest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7131          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7132       }
7133       else if(ch < 0x10000)
7134       {
7135          if(d + 3 >= max) break;
7136          byteDest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7137          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7138          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7139       }
7140       else
7141       {
7142          if(d + 4 >= max) break;
7143          byteDest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7144          byteDest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7145          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7146          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7147       }
7148    }
7149    byteDest[d] = 0;
7150    return d;
7151 }
7152
7153 // NOTE: UTF8GetChar now returns 0 into numBytes for the null-terminating character ('\0')
7154 public unichar UTF8GetChar(const char * string, int * numBytes)
7155 {
7156    unichar ch;
7157    byte b = ((byte *)string)[0];
7158    int i;
7159    byte mask = 0x7F;
7160    int nb = b ? 1 : 0;
7161    ch = 0;
7162    if(b & 0x80)
7163    {
7164       if(b & 0x40)
7165       {
7166          mask >>= 2;
7167          nb++;
7168          if(b & 0x20)
7169          {
7170             nb++;
7171             mask >>= 1;
7172             if(b & 0x10)
7173             {
7174                if(b & 0x08) { nb = 0; }
7175                nb++;
7176                mask >>= 1;
7177             }
7178          }
7179       }
7180       else
7181          nb = 0;
7182    }
7183    for(i = 0; i<nb; i++)
7184    {
7185       ch <<= 6;
7186       ch |= (b = ((byte *)string)[i]) & mask;
7187       mask = 0x3F;
7188       if(i > 1 && (!(b & 0x80) || (b & 0x40)))
7189       {
7190          nb = 0;
7191          ch = 0;
7192       }
7193    }
7194
7195    if(i < nb ||
7196       ch > 0x10FFFF || (ch >= 0xD800 && ch <= 0xDFFF) ||
7197      (ch < 0x80 && nb > 1) ||
7198      (ch < 0x800 && nb > 2) ||
7199      (ch < 0x10000 && nb > 3))
7200    {
7201       ch = 0;
7202       nb = 0;
7203    }
7204    if(numBytes) *numBytes = nb;
7205    return ch;
7206 }
7207
7208 public int UTF8toUTF16Buffer(const char * source, uint16 * dest, int max)
7209 {
7210    if(source)
7211    {
7212       int c;
7213       int d = 0;
7214       for(c = 0; source[c];)
7215       {
7216          byte ch = source[c];
7217          unichar codePoint = 0;
7218          int numBytes = 1;
7219          int i;
7220          byte mask = 0x7F;
7221          if(ch & 0x80 && ch & 0x40)
7222          {
7223             mask >>= 2;
7224             numBytes++;
7225             if(ch & 0x20)
7226             {
7227                numBytes++;
7228                mask >>= 1;
7229                if(ch & 0x10)
7230                {
7231                   numBytes++;
7232                   mask >>= 1;
7233                }
7234             }
7235          }
7236          for(i = 0; i<numBytes; i++)
7237          {
7238             codePoint <<= 6;
7239             codePoint |= source[c++] & mask;
7240             mask = 0x3F;
7241          }
7242
7243          if(codePoint > 0xFFFF)
7244          {
7245             uint16 lead = (uint16)(LEAD_OFFSET + (codePoint >> 10));
7246             uint16 trail = (uint16)(0xDC00 | (codePoint & 0x3FF));
7247             if(d >= max - 1) break;
7248             dest[d++] = lead;
7249             dest[d++] = trail;
7250          }
7251          else
7252          {
7253             if(d >= max) break;
7254             dest[d++] = (uint16)codePoint;
7255          }
7256       }
7257       dest[d] = 0;
7258       return d;
7259    }
7260    return 0;
7261 }
7262
7263 public int UTF32toUTF8Len(const unichar * source, int count, char * dest, int max)
7264 {
7265    int c;
7266    int d = 0;
7267    uint32 ch;
7268    byte * byteDest = (byte *)dest;
7269    for(c = 0; c<count && (ch = source[c]); c++)
7270    {
7271       if(ch < 0x80)
7272       {
7273          if(d + 1 >= max) break;
7274          byteDest[d++] = (char)ch;
7275       }
7276       else if(ch < 0x800)
7277       {
7278          if(d + 2 >= max) break;
7279          byteDest[d++] = 0xC0 | (byte)((ch & 0x7C0) >> 6);
7280          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7281       }
7282       else if(ch < 0x10000)
7283       {
7284          if(d + 3 >= max) break;
7285          byteDest[d++] = 0xE0 | (byte)((ch & 0xF000) >> 12);
7286          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7287          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7288       }
7289       else
7290       {
7291          if(d + 4 >= max) break;
7292          byteDest[d++] = 0xF0 | (byte)((ch & 0x1C0000) >> 18);
7293          byteDest[d++] = 0x80 | (byte)((ch & 0x3F000) >> 12);
7294          byteDest[d++] = 0x80 | (byte)((ch & 0xFC0) >> 6);
7295          byteDest[d++] = 0x80 | (byte)(ch & 0x03F);
7296       }
7297    }
7298    byteDest[d] = 0;
7299    return d;
7300 }
7301
7302 public uint16 * UTF8toUTF16(const char * source, int * wordCount)
7303 {
7304    if(source)
7305    {
7306       int len = (int)strlen(source);
7307       uint16 * dest = new uint16[len + 1];
7308       int c;
7309       int d = 0;
7310       for(c = 0; source[c];)
7311       {
7312          byte ch = source[c];
7313          unichar codePoint = 0;
7314          int numBytes = 1;
7315          int i;
7316          byte mask = 0x7F;
7317          if(ch & 0x80 && ch & 0x40)
7318          {
7319             mask >>= 2;
7320             numBytes++;
7321             if(ch & 0x20)
7322             {
7323                numBytes++;
7324                mask >>= 1;
7325                if(ch & 0x10)
7326                {
7327                   numBytes++;
7328                   mask >>= 1;
7329                }
7330             }
7331          }
7332          for(i = 0; i<numBytes; i++)
7333          {
7334             codePoint <<= 6;
7335             codePoint |= source[c++] & mask;
7336             mask = 0x3F;
7337          }
7338
7339          if(codePoint > 0xFFFF)
7340          {
7341             uint16 lead = (uint16)(LEAD_OFFSET + (codePoint >> 10));
7342             uint16 trail = (uint16)(0xDC00 | (codePoint & 0x3FF));
7343             dest[d++] = lead;
7344             dest[d++] = trail;
7345          }
7346          else
7347          {
7348             dest[d++] = (uint16)codePoint;
7349          }
7350       }
7351       dest[d] = 0;
7352       if(wordCount) *wordCount = d;
7353       return dest;
7354    }
7355    return null;
7356 }
7357
7358 namespace com;
7359
7360 #if !defined(MEMINFO) && defined(MEMTRACKING)
7361 import "Map"
7362
7363 Map<Class, int> blocksByClass { };
7364 Map<Class, uintsize> sizeByClass { };
7365 #endif
7366
7367 public void queryMemInfo(char * string)
7368 {
7369 #if !defined(MEMINFO) && defined(MEMTRACKING) && !defined(DISABLE_MEMMGR)
7370    char s[1024];
7371    int p;
7372    uint numBlocks = 0;
7373    uintsize totalMemUsed = 0;
7374    sprintf(s, "Total System Memory Usage: %.02f\n", TOTAL_MEM / 1048576.0f);
7375    strcat(string, s);
7376
7377    for(p = 0; pools && p < NUM_POOLS; p++)
7378    {
7379       BlockPool * pool = &pools[p];
7380       if(pool->totalSize)
7381       {
7382          numBlocks += pool->totalSize;
7383          sprintf(s, "%8d bytes: %d blocks in %d parts (%.02f mb used; taking up %.02f mb space)\n",
7384             pool->blockSize, pool->numBlocks, pool->numParts, pool->usedSpace / 1048576.0f, pool->totalSize * pool->blockSpace / 1048576.0f);
7385          totalMemUsed += pool->usedSpace;
7386          strcat(string, s);
7387       }
7388    }
7389
7390
7391    blocksByClass.Free();
7392    sizeByClass.Free();
7393 #if !defined(__EMSCRIPTEN__)
7394    memMutex.Wait();
7395 #endif
7396    for(p = 0; pools && p < NUM_POOLS; p++)
7397    {
7398       BlockPool * pool = &pools[p];
7399       MemBlock block;
7400       for(block = pool->first; block; block = block.next)
7401       {
7402          Class c = block._class;
7403          blocksByClass[c]++;
7404          sizeByClass[c] += block.size;
7405       }
7406    }
7407 #if !defined(__EMSCRIPTEN__)
7408    memMutex.Release();
7409 #endif
7410
7411    //for(c : blocksByClass)
7412    {
7413       MapIterator<Class, int> it { map = blocksByClass };
7414       while(it.Next())
7415       {
7416          int c = it.data;
7417          Class _class = it.key; //&c;
7418          uintsize size = sizeByClass[_class];
7419          float totalSize = (float) size / 1048576.0f;
7420          if(totalSize > 1)
7421          {
7422             sprintf(s, "%s (%d bytes): %d instances (%.02f mb used)\n", _class ? _class.name : "(none)", (int)size, c, totalSize);
7423             strcat(string, s);
7424          }
7425       }
7426    }
7427
7428    sprintf(s, "Non-pooled memory: %.02f\n", OUTSIDE_MEM / 1048576.0f);
7429    strcat(string, s);
7430    sprintf(s, "Total Memory in use: %.02f\n", (float)(totalMemUsed + OUTSIDE_MEM) / 1048576.0f);
7431    strcat(string, s);
7432
7433    sprintf(s, "Total Blocks Count: %d (%.02f mb overhead)\n", numBlocks, (float)sizeof(struct MemBlock) * numBlocks / 1048576.0f);
7434    strcat(string, s);
7435 #ifdef MEMORYGUARD
7436    sprintf(s, "MemoryGuard: %d blocks (%.02f mb RedZone, %.02f mb MemInfo)\n", memBlocks.count,
7437       numBlocks * 2 * REDZONE / 1048576.0f, sizeof(struct MemInfo) * memBlocks.count / 1048576.0f);
7438    strcat(string, s);
7439 #endif
7440 #endif
7441 }