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