eda, compiler, documentor: Proper prototypes for invoking virtual methods directly
[sdk] / compiler / ecs / ecs.ec
1 #ifdef ECERE_STATIC
2 import static "ecere"
3 import static "ec"
4 #else
5 import "ecere"
6 import "ec"
7 #endif
8
9 static define localeDir = "locale";
10 static bool i18n;
11
12 static Platform targetPlatform;
13 static int targetBits;
14
15 static bool isConsole;
16 static bool isDynamicLibrary;
17 static bool isStaticLibrary;
18 static OldList modules;
19 static File dcomSymbols;
20
21 static OldList _defines { };
22 static OldList _imports { };
23 static OldList _excludedSymbols { offset = (uint)&((Symbol)0).left };
24 static NameSpace globalData
25 {
26    classes.CompareKey = (void *)BinaryTree::CompareString;
27    defines.CompareKey = (void *)BinaryTree::CompareString;
28    functions.CompareKey = (void *)BinaryTree::CompareString;
29    nameSpaces.CompareKey = (void *)BinaryTree::CompareString;
30 };
31 static Context theGlobalContext { };
32 static ModuleImport mainModule;
33 static Module privateModule;
34
35 static char mainModuleName[MAX_LOCATION];
36 static char projectName[MAX_LOCATION];
37 static void LoadImports(char * fileName)
38 {
39    File f = FileOpen(fileName, read);
40    if(f)
41    {
42       for(;;)
43       {
44          char line[1024];
45          if(!f.GetLine(line, sizeof(line))) break;
46          TrimLSpaces(line, line);
47
48          if(line[0] == '[')
49          {
50             if(!strcmp(line, "[Imported Modules]"))
51             {
52                ModuleImport module = null;
53                for(;;)
54                {
55                   if(!f.GetLine(line, sizeof(line))) break;
56                   TrimLSpaces(line, line);
57                   if(!strcmp(line, ".")) break;
58
59                   if(line[0] == '[')
60                   {
61                      ClassImport _class = null;
62                      FunctionImport function = null;
63                      
64                      if(!strcmp(line, "[This]"))
65                      {
66                         if((mainModule = GetMainModule()))
67                            module = mainModule;
68                         else
69                         {
70                            mainModule = ModuleImport { };
71                            SetMainModule(mainModule);
72                            module = mainModule;
73                            _imports.AddName(module);
74                         }
75                      }
76                      else if(!strcmp(line, "[Static]"))
77                      {
78                         module.importType = staticImport;
79                      }
80                      else if(!strcmp(line, "[Remote]"))
81                      {
82                         module.importType = remoteImport;
83                      }
84                      else if(!strcmp(line, "[Private]"))
85                      {
86                         if(module.importAccess != publicAccess)
87                            module.importAccess = privateAccess;
88                      }
89                      else if(!strcmp(line, "[Public]"))
90                      {
91                         module.importAccess = publicAccess;
92                      }
93                      else if(!strcmp(line, "[Imported Classes]"))
94                      {
95                         for(;;)
96                         {
97                            if(!f.GetLine(line, sizeof(line))) break;
98                            TrimLSpaces(line, line);
99                            if(!strcmp(line, ".")) break;
100
101                            if(line[0] == '[')
102                            {
103                               if(!strcmp(line, "[Instantiated]"))
104                               {
105                                  _class.itself = true;
106                               }
107                               else if(!strcmp(line, "[Remote]"))
108                               {
109                                  _class.isRemote = 1;
110                               }
111                               else if(!strcmp(line, "[Imported Methods]"))
112                               {
113                                  MethodImport method = null;
114                                  for(;;)
115                                  {
116                                     if(!f.GetLine(line, sizeof(line))) break;
117                                     TrimLSpaces(line, line);
118                                     if(!strcmp(line, ".")) break;
119                                     if(line[0] != '[')
120                                     {
121                                        if(!(method = _class.methods.FindName(line, false)))
122                                        {
123                                           method = MethodImport { name = CopyString(line) };
124                                           _class.methods.AddName(method);
125                                        }
126                                     }
127                                     else if(!strcmp(line, "[Virtual]"))
128                                        method.isVirtual = true;
129
130                                  }
131                               }
132                               else if(!strcmp(line, "[Imported Properties]"))
133                               {
134                                  PropertyImport prop = null;
135                                  for(;;)
136                                  {
137                                     if(!f.GetLine(line, sizeof(line))) break;
138                                     TrimLSpaces(line, line);
139                                     if(!strcmp(line, ".")) break;
140                                     if(line[0] != '[')
141                                     {
142                                        if(!(prop = _class.properties.FindName(line, false)))
143                                        {
144                                           prop = PropertyImport { name = CopyString(line) };
145                                           _class.properties.AddName(prop);
146                                        }
147                                     }
148                                     else if(!strcmp(line, "[Set]"))
149                                           prop.hasSet = true;
150                                     else if(!strcmp(line, "[Get]"))
151                                        prop.hasGet = true;
152                                     else if(!strcmp(line, "[Virtual]"))
153                                        prop.isVirtual = true;
154                                  }
155                               }
156                            }
157                            else
158                            {
159                               if(!(_class = module.classes.FindName(line, false)))
160                               {
161                                  _class = ClassImport { name = CopyString(line) };
162                                  module.classes.AddName(_class); 
163                               }
164                            }
165                         }
166                      }
167                      else if(!strcmp(line, "[Imported Functions]"))
168                      {
169                         for(;;)
170                         {
171                            if(!f.GetLine(line, sizeof(line))) break;
172                            TrimLSpaces(line, line);
173                            if(!strcmp(line, ".")) break;
174
175                            if(line[0] == '[')
176                            {
177                            }
178                            else
179                            {
180                               if(!(function = module.functions.FindName(line, false)))
181                               {
182                                  function = FunctionImport { name = CopyString(line) };
183                                  module.functions.AddName(function);
184                               }
185                            }
186                         }
187                      }
188                   }
189                   else
190                   {
191                      if(!(module = _imports.FindName(line, false)))
192                      {
193                         if(!strcmp(line, "ecereCOM"))
194                         {
195                            module = _imports.FindName("ecere", false);
196                         }
197                         else if(!strcmp(line, "ecere"))
198                         {
199                            module = _imports.FindName("ecereCOM", false);
200                            if(module)
201                            {
202                               delete module.name;
203                               module.name = CopyString("ecere");
204                            }
205                         }
206                         if(!module)
207                         {
208                            module = ModuleImport { name = CopyString(line) };
209                            _imports.AddName(module);
210                         }
211                      }
212                   }
213                }
214             }
215          }
216       }
217       delete f;
218    }
219 }
220
221 // static Class applicationClass;
222 static Class thisAppClass;
223
224 class ModuleInfo : struct
225 {
226    ModuleInfo prev, next;
227    char * name;
228    bool globalInstance;
229 };
230
231 /* OBSOLETE
232 static bool SeardchModuleName(Module searchIn, char * name)
233 {
234    SubModule subModule;
235    
236    if(searchIn.name && !strcmp(searchIn.name, name))
237       return true;
238
239    for(subModule = searchIn.modules.first; subModule; subModule = subModule.next)
240    {
241       if(SearchModuleName(subModule.module, name))
242          return true;
243    }
244    return false;
245 }
246 */
247 static void WriteMain(char * fileName)
248 {
249    File f = FileOpen(fileName, write);
250    if(f)
251    {
252       ModuleImport module;
253       ModuleInfo defModule;
254       bool nonInst = false, anyMethod = false, anyProp = false, anyFunction = false;
255       ImportedModule importedModule;
256       
257       GetLastDirectory(fileName, mainModuleName);
258       StripExtension(mainModuleName);
259       if(!projectName[0])
260       {
261          strcpy(projectName, mainModuleName);
262          StripExtension(projectName);
263       }
264       ChangeCh(mainModuleName, '.', '_');
265       ChangeCh(mainModuleName, '-', '_');
266       ChangeCh(mainModuleName, ' ', '_');
267
268       if(targetPlatform == win32 && !isConsole && !isStaticLibrary && !isDynamicLibrary)
269       {
270          //f.Puts("#include <windows.h>\n\n");
271
272          f.Puts("typedef void * HINSTANCE;\n");
273          f.Puts("#define WINAPI __stdcall\n");
274       }
275
276       for(importedModule = ::_defines.first; importedModule; importedModule = importedModule.next)
277       {
278          if(importedModule.type == moduleDefinition)
279          {
280             f.Printf("import ");
281             if(importedModule.importType == staticImport)
282                f.Printf("static ", importedModule.name);
283             f.Printf("\"%s\"\n", importedModule.name);
284          }
285       }
286
287       f.Puts("default:\n");
288       f.Puts("static Module __currentModule;\n\n");
289
290       if(!isStaticLibrary)
291          f.Puts("Module __thisModule;\n\n");
292
293       // TOCHECK: Problem compiling Scrabble.main.ec when binding Client first
294       BindDCOMServer();
295       BindDCOMClient();
296
297       if(dcomSymbols)
298          f.Printf("void __ecereRegisterModule_%s(Module module);\n\n", mainModuleName);
299
300       for(module = _imports.first; module; module = module.next)
301       {
302          ClassImport _class;
303          FunctionImport function;
304          if(module.importType == staticImport)
305          {
306             /*if(targetPlatform == win32)
307             {
308                f.Printf("bool __stdcall __ecereDll_Load_%s(Module module);\n", module.name);
309                f.Printf("bool __stdcall __ecereDll_Unload_%s(Module module);\n", module.name);
310             }
311             else*/
312             {
313                f.Printf("bool __ecereDll_Load_%s(Module module);\n", module.name);
314                f.Printf("bool __ecereDll_Unload_%s(Module module);\n", module.name);
315             }
316          }
317          for(_class = module.classes.first; _class; _class = _class.next)
318          {
319             MethodImport method;
320             PropertyImport prop;
321             char className[1024] = "";
322             Class regClass = eSystem_FindClass(privateModule, _class.name);
323
324             FullClassNameCat(className, _class.name, true);
325             MangleClassName(className);
326
327             if(_class.itself)
328                f.Printf("Class __ecereClass_%s;\n", className);
329             else
330                nonInst = true;
331             //if(!_class.isRemote)
332             {
333                //if(strcmp(_class.name, "SerialBuffer"))
334                {
335                   for(method = _class.methods.first; method; method = method.next)
336                   {
337                      Method meth = eClass_FindMethod(regClass, method.name, privateModule);
338                      if(meth && !meth.dataType)
339                      {
340                         Context context = SetupTemplatesContext(regClass);
341                         meth.dataType = ProcessTypeString(meth.dataTypeString, false);
342                         FinishTemplatesContext(context);
343                      }
344
345                      if(method.isVirtual)
346                         f.Printf("int __ecereVMethodID_%s_%s;\n", className, method.name);
347                      else if(module.name && module.importType != staticImport && (!meth || !meth.dataType.dllExport))
348                      {
349                         /*char name[4096];
350                         
351                         Type type
352                         {
353                            kind = TypePointer,
354                            type = method.
355                         };
356                         type.refCount++;
357                         sprintf(name, "__ecereMethod_%s_%s", className, method.name);
358                         PrintType(type, name, true);
359                         f.Printf("%s;\n", name);
360                         delete type;
361                         */
362                         //f.Printf("void * __ecereMethod_%s_%s;\n", className, method.name);
363
364                         f.Printf("int (*__ecereMethod_%s_%s)();\n", className, method.name);
365                      }
366
367                      anyMethod = true;
368                   }
369                }
370
371                for(prop = _class.properties.first; prop; prop = prop.next)
372                {
373                   char propName[1024];
374                   propName[0] = 0;
375                   FullClassNameCat(propName, prop.name, true);
376                   // strcpy(propName, prop.name);
377                   MangleClassName(propName);
378
379                   if(module.name && module.importType != staticImport)
380                   {
381                      if(prop.hasSet)
382                         f.Printf("void * __ecereProp_%s_Set_%s;\n", className, propName);
383                      if(prop.hasGet)
384                         f.Printf("void * __ecereProp_%s_Get_%s;\n", className, propName);
385                   }
386                   f.Printf("Property __ecereProp_%s_%s;\n", className, propName);
387                   anyProp = true;
388                }
389             }
390          }
391          for(function = module.functions.first; function; function = function.next)
392          {
393             GlobalFunction func = eSystem_FindFunction(privateModule, function.name);
394             if(func && !func.dataType)
395                func.dataType = ProcessTypeString(func.dataTypeString, false);
396
397             if(module.name && module.importType != staticImport && (!func || !func.dataType || !func.dataType.dllExport))
398             {
399                char functionName[1024];
400                functionName[0] = 0;
401                FullClassNameCat(functionName, function.name, false);
402                f.Printf("void * __ecereFunction_%s;\n", functionName);
403                anyFunction = true;
404             }
405          }
406       }
407
408       for(defModule = ::modules.first; defModule; defModule = defModule.next)
409       {
410          char moduleName[1024];
411          strcpy(moduleName, defModule.name);
412          ChangeCh(moduleName, ' ', '_');
413          ChangeCh(moduleName, '-', '_');
414          ChangeCh(moduleName, '.', '_');
415
416          f.Printf("void __ecereRegisterModule_%s(Module module);\n", moduleName);
417          f.Printf("void __ecereUnregisterModule_%s(Module module);\n", moduleName);
418          if(defModule.globalInstance)
419          {
420             f.Printf("void __ecereCreateModuleInstances_%s();\n", moduleName);
421             f.Printf("void __ecereDestroyModuleInstances_%s();\n", moduleName);
422          }
423       }
424
425       // DCOM Stuff
426       if(dcomSymbols)
427       {
428          f.Printf("\n");
429
430          // Insert DCOM bindings here
431          dcomSymbols.Seek(0, start);
432          while(!dcomSymbols.Eof())
433          {
434             char buffer[4096];
435             int read = dcomSymbols.Read(buffer, 1, sizeof(buffer));
436             if(!read) break;
437             f.Write(buffer, 1, read);
438          }
439          f.Printf("\n");
440       }
441
442       // Main Function
443
444       if(isStaticLibrary)
445       {
446          /*if(targetPlatform == win32)
447             f.Printf("\nbool __stdcall __ecereDll_Load_%s(Module module)\n{\n", projectName);
448          else*/
449             f.Printf("\nbool __ecereDll_Load_%s(Module module)\n{\n", projectName);
450       }
451       else if(isDynamicLibrary)
452       {
453          if(targetPlatform == win32)
454             f.Puts("\ndllexport bool __stdcall __ecereDll_Load(Module module)\n{\n");
455          else
456             f.Puts("\ndllexport bool __ecereDll_Load(Module module)\n{\n");
457       }
458       else if(targetPlatform == win32 && !isConsole)
459       {
460          f.Puts("\nint WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInst, char * cmdLine, int show)\n{\n");
461       }
462       else
463          f.Puts("\nint main(int _argc, char * _argv[])\n{\n");
464
465       if(!isDynamicLibrary)
466       {
467          f.Puts("   int exitCode;\n");
468          f.Puts("   Module module;\n");
469       }
470
471       //if(nonInst || thisAppClass)    // We use it all the time to get "Application" for the exit code now...
472          f.Puts("   Class _class;\n");
473
474       if(anyMethod)
475          f.Puts("   Method method;\n");
476       if(anyProp)
477          f.Puts("   Property _property;\n");
478       if(anyFunction)
479          f.Puts("   GlobalFunction function;\n");
480       
481       f.Puts("\n");
482
483       if(isDynamicLibrary)
484       {
485          f.Puts("   if(!__currentModule)\n");
486          f.Puts("   {\n");
487          f.Puts("      __currentModule = module;\n");
488          if(!isStaticLibrary)
489             f.Puts("      __thisModule = module;\n");
490          f.Puts("   }\n\n");
491       }
492       else if(targetPlatform == win32 && !isConsole)
493          f.Puts("   __thisModule = __currentModule = module = __ecere_COM_Initialize(1, 0, null);\n\n");
494       else
495          f.Puts("   __thisModule = __currentModule = module = __ecere_COM_Initialize(1, _argc, (void *)_argv);\n\n");
496
497       // First load all modules
498       if(_imports.count)
499       {
500          for(module = _imports.first; module; module = module.next)
501          {
502             if(module.name)
503             {
504                //if(strcmp(module.name, "ecereCOM") && strcmp(module.name, "ecere") )
505                {
506                   if(module.importType == staticImport)
507                      f.Printf("   eModule_LoadStatic(module, \"%s\", %s, __ecereDll_Load_%s, __ecereDll_Unload_%s);\n", module.name, (module.importAccess == privateAccess) ? "privateAccess" : "publicAccess", module.name,module.name);
508                   else
509                      f.Printf("   eModule_Load(module, \"%s\", %s);\n", module.name, (module.importAccess == privateAccess) ? "privateAccess" : "publicAccess");
510                }
511             }
512          }
513          f.Printf("\n");
514       }
515
516       // Then define the classes
517       if(::modules.count)
518       {
519          for(defModule = ::modules.first; defModule; defModule = defModule.next)
520          {
521             char moduleName[1024];
522             strcpy(moduleName, defModule.name);
523             ChangeCh(moduleName, ' ', '_');
524             ChangeCh(moduleName, '-', '_');
525             ChangeCh(moduleName, '.', '_');
526
527             f.Printf("   __ecereRegisterModule_%s(module);\n", moduleName);
528          }
529          f.Printf("\n");
530       }
531
532       // Register Remote Modules
533       if(dcomSymbols)
534       {
535          f.Printf("   __ecereRegisterModule_%s(module);\n\n", mainModuleName);
536          delete dcomSymbols;
537       }
538
539       if(isDynamicLibrary)
540       {
541          f.Puts("   if(__currentModule == module)\n");
542          f.Puts("   {\n");
543       }
544       // Then load the imports
545       for(module = _imports.first; module; module = module.next)
546       {
547          ClassImport _class;
548          FunctionImport function;
549          if(module.classes.count)
550          {
551             for(_class = module.classes.first; _class; _class = _class.next)
552             {
553                Class regClass = eSystem_FindClass(privateModule, _class.name);
554
555                //if(!_class.isRemote)
556                {
557                   MethodImport method;
558                   PropertyImport prop;
559                   char classID[1024];
560                   char className[1024] = "";
561                   FullClassNameCat(className, _class.name, true);
562                   MangleClassName(className);
563             
564                   if(_class.itself)
565                      sprintf(classID, "__ecereClass_%s", className);
566                   else
567                      strcpy(classID, "_class");
568             
569                   if(isDynamicLibrary && !isStaticLibrary)
570                      f.Printf("   %s = eSystem_FindClass(__currentModule, \"%s\");\n", classID, _class.name);
571                   else
572                      f.Printf("   %s = eSystem_FindClass(module, \"%s\");\n", classID, _class.name);
573
574                   for(method = _class.methods.first; method; method = method.next)
575                   {
576                      Method meth = eClass_FindMethod(regClass, method.name, privateModule);
577                      if(!meth || !meth.dataType.dllExport)
578                      {
579                         if(method.isVirtual || (module.name && module.importType != staticImport))
580                         {
581                            f.Printf("   method = eClass_FindMethod(%s, \"%s\", module);\n", 
582                               classID, method.name);
583                            if(method.isVirtual)
584                               f.Printf("   if(method) __ecereVMethodID_%s_%s = method.vid;\n", className, method.name);
585                            else
586                               f.Printf("   if(method) __ecereMethod_%s_%s = method.function;\n", className, method.name);
587                         }
588                      }
589                   }
590
591                   for(prop = _class.properties.first; prop; prop = prop.next)
592                   {
593                      char propName[1024];
594                      propName[0] = 0;
595                      FullClassNameCat(propName, prop.name, true);
596                      // strcpy(propName, prop.name);
597                      MangleClassName(propName);
598
599                      f.Printf("   __ecereProp_%s_%s = _property = eClass_FindProperty(%s, \"%s\", module);\n", 
600                         className, propName, classID, prop.name);
601
602                      if(module.name && module.importType != staticImport)
603                      {
604                         if(prop.hasSet)
605                            f.Printf("   __ecereProp_%s_Set_%s = _property.Set;\n", className, propName);
606                         if(prop.hasGet)
607                            f.Printf("   __ecereProp_%s_Get_%s = _property.Get;\n", className, propName);
608                      }
609                   }
610                   f.Printf("\n");
611                }
612             }
613          }
614          if(module.functions.count)
615          {
616             for(function = module.functions.first; function; function = function.next)
617             {
618                GlobalFunction func = eSystem_FindFunction(privateModule, function.name);
619                if(module.name && module.importType != staticImport && (!func || !func.dataType || !func.dataType.dllExport))
620                {
621                   char functionName[1024];
622                   functionName[0] = 0;
623                   FullClassNameCat(functionName, function.name, false);
624
625                   if(isDynamicLibrary && !isStaticLibrary)
626                      f.Printf("   function = eSystem_FindFunction(__currentModule, \"%s\");\n", function.name);
627                   else
628                      f.Printf("   function = eSystem_FindFunction(module, \"%s\");\n", function.name);
629
630                   f.Printf("   if(function) __ecereFunction_%s = function.function;\n", functionName);
631                   f.Printf("\n");
632                }
633             }
634             f.Printf("\n");
635          }
636       }
637
638       for(defModule = ::modules.first; defModule; defModule = defModule.next)
639          if(defModule.globalInstance)
640          {
641             if(!strcmp(defModule.name, "i18n"))
642                f.Printf("   __ecereCreateModuleInstances_i18n();\n");
643          }
644       if(i18n)
645          f.Printf("      LoadTranslatedStrings(module, \"%s\");\n", projectName);
646       if(isDynamicLibrary)
647       {
648          //f.Printf("   module._vTbl[10](module);\n");
649          f.Puts("   }\n");
650       }
651
652       if(!isDynamicLibrary && thisAppClass)
653       {
654          f.Printf("   _class = eSystem_FindClass(__currentModule, \"%s\");\n", thisAppClass.name);
655          f.Printf("   eInstance_Evolve((Instance *)&__currentModule, _class);\n");
656          f.Printf("   __thisModule = __currentModule;\n");
657       }
658
659       if(isDynamicLibrary)
660       {
661          f.Puts("   if(__currentModule == module)\n");
662          f.Puts("   {\n");
663       }
664
665       // Then check if there's any global instances to create
666       if(::modules.count)
667       {
668          for(defModule = ::modules.first; defModule; defModule = defModule.next)
669             if(defModule.globalInstance)
670             {
671                char moduleName[1024];
672                if(!strcmp(defModule.name, "i18n")) continue;
673                strcpy(moduleName, defModule.name);
674                ChangeCh(moduleName, ' ', '_');
675                ChangeCh(moduleName, '-', '_');
676                ChangeCh(moduleName, '.', '_');
677
678                f.Printf("   __ecereCreateModuleInstances_%s();\n", moduleName);
679             }
680
681          f.Printf("\n");
682       }
683
684       if(isDynamicLibrary)
685       {
686          f.Puts("   }\n");
687       }
688       if(!isDynamicLibrary && thisAppClass)
689       {
690          f.Printf("   ((void(*)(void *))(void *)__currentModule._vTbl[12])(__currentModule);\n");
691       }
692
693       if(isDynamicLibrary)
694       {
695          f.Puts("   return true;\n");
696          f.Puts("}\n");
697          if(isStaticLibrary)
698          {
699             /*if(targetPlatform == win32)
700                f.Printf("\nbool __stdcall __ecereDll_Unload_%s(Module module)\n{\n", projectName);
701             else*/
702                f.Printf("\nbool __ecereDll_Unload_%s(Module module)\n{\n", projectName);
703          }
704          else
705          {
706             if(targetPlatform == win32)
707                f.Puts("\ndllexport bool __stdcall __ecereDll_Unload(Module module)\n{\n");
708             else
709                f.Puts("\ndllexport bool __ecereDll_Unload(Module module)\n{\n");
710          }
711       }
712
713       if(isDynamicLibrary)
714       {
715          f.Puts("   if(__currentModule == module)\n");
716          f.Puts("   {\n");
717       }
718       // Then check if there's any global instances to destroy
719       {
720          bool destroyI18n = false;
721          if(::modules.count)
722          {
723             for(defModule = ::modules.first; defModule; defModule = defModule.next)
724                if(defModule.globalInstance)
725                {
726                   char moduleName[1024];
727                   if(!strcmp(defModule.name, "i18n")) { destroyI18n = true; continue; }
728                   strcpy(moduleName, defModule.name);
729                   ChangeCh(moduleName, ' ', '_');
730                   ChangeCh(moduleName, '-', '_');
731                   ChangeCh(moduleName, '.', '_');
732                   f.Printf("   __ecereDestroyModuleInstances_%s();\n", moduleName);
733                }
734
735             f.Printf("\n");
736          }
737          if(i18n)
738             f.Printf("   UnloadTranslatedStrings(__currentModule);\n");
739          if(destroyI18n)
740             f.Printf("   __ecereDestroyModuleInstances_i18n();\n");
741       }
742       if(isDynamicLibrary)
743       {
744          f.Puts("   }\n");
745
746          if(isDynamicLibrary)
747          {
748             //f.Printf("   module._vTbl[11](module);\n");
749          }
750
751          if(::modules.count)
752          {
753             for(defModule = ::modules.first; defModule; defModule = defModule.next)
754             {
755                char moduleName[1024];
756                strcpy(moduleName, defModule.name);
757                ChangeCh(moduleName, ' ', '_');
758                ChangeCh(moduleName, '-', '_');
759                ChangeCh(moduleName, '.', '_');
760                f.Printf("   __ecereUnregisterModule_%s(module);\n", moduleName);
761             }
762             f.Printf("\n");
763          }
764          f.Puts("   if(__currentModule == module)\n");
765          f.Puts("      __currentModule = (void *)0;\n");
766          if(!isStaticLibrary)
767          {
768             f.Puts("   if(__thisModule == module)\n");
769             f.Puts("      __thisModule = (void *)0;\n");
770          }
771       }
772
773       if(!isDynamicLibrary)
774       {
775          f.Puts(
776             "\n"
777             "   _class = eSystem_FindClass(__currentModule, \"ecere::com::Application\");\n"
778             "   exitCode = ((ecere::com::Application)__currentModule).exitCode;\n"
779             "   delete __currentModule;\n"
780             "   return exitCode;\n");
781       }
782       else
783          f.Puts("   return true;\n");
784       f.Puts("}\n");
785       eInstance_Delete(f);
786    }
787 }
788
789 static Class FindAppClass(NameSpace * nameSpace, bool thisModule)
790 {
791    BTNamedLink link;
792    NameSpace * ns;
793    for(link = (BTNamedLink)nameSpace->classes.first; link; link = (BTNamedLink)((BTNode)link).next)
794    {
795       Class _class = link.data;
796       /*
797       applicationClass = eSystem_FindClass(_class.module, "Application");
798       if(_class != applicationClass && eClass_IsDerived(_class, applicationClass) && (!thisModule || _class.module == privateModule))
799          return _class;
800       */
801       if(strcmp(_class.fullName, "ecere::com::Application") && (!thisModule || _class.module == privateModule))
802       {
803          Class base;
804          for(base = _class.base; base && base.type != systemClass; base = base.base)
805             if(!strcmp(base.fullName, "ecere::com::Application"))
806                return _class;
807       }
808    }
809
810    for(ns = (NameSpace *)nameSpace->nameSpaces.first; ns; ns = (NameSpace *)((BTNode)ns).next)
811    {
812       Class _class = FindAppClass(ns, thisModule);
813       if(_class) // && _class != applicationClass)
814          return _class;
815    }
816    return null; //applicationClass;
817 }
818
819 static Class SearchAppClass_Module(Module module)
820 {
821    Class appClass;
822    SubModule subModule;
823
824    appClass = FindAppClass(module.publicNameSpace, false);
825    if(appClass) return appClass;
826    appClass = FindAppClass(module.privateNameSpace, false);
827    if(appClass) return appClass;
828
829    for(subModule = module.modules.first; subModule; subModule = subModule.next)
830    {
831       appClass = SearchAppClass_Module(subModule.module);
832       if(appClass) return appClass;
833    }
834    return null;
835 }
836
837 static void BindDCOMClient()
838 {
839    Class dcomClientObjectClass = eSystem_FindClass(privateModule, "ecere::net::DCOMClientObject");
840    OldLink deriv;
841
842    if(dcomClientObjectClass && dcomClientObjectClass.derivatives.first)
843    {
844       File f;
845       if(!dcomSymbols) dcomSymbols = TempFile { };
846       f = dcomSymbols;
847
848       // CLIENT BINDINGS
849       for(deriv = dcomClientObjectClass.derivatives.first; deriv; deriv = deriv.next)
850       {
851          Class _class = deriv.data;
852          Method method, next;
853          int id = 0;
854          int vid;
855          bool doVirtual;
856
857          DeclareClass(FindClass("ecere::net::DCOMClientObject"), "__ecereClass___ecereNameSpace__ecere__net__DCOMClientObject");
858          f.Printf("class %s : ecere::net::DCOMClientObject\n", _class.fullName);
859          f.Printf("{\n");
860
861          // CLIENT VIRTUAL METHODS BINDINGS
862          if(_class.vTblSize > _class.base.vTblSize)
863          {
864             int vid;
865             f.Printf("   virtual void CallVirtualMethod(uint __ecereMethodID, SerialBuffer __ecereBuffer)\n");
866             f.Printf("   {\n");
867             f.Printf("      switch(__ecereMethodID)\n");
868             f.Printf("      {\n");
869
870             for(vid = _class.base.vTblSize; vid < _class.vTblSize; vid++)
871             {
872                Method method;
873                for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
874                {
875                   if(method.type == virtualMethod && method._class == _class && method.vid == vid)
876                      break;
877                }
878                if(method)
879                {
880                   Type param;
881                   method.dataType = ProcessTypeString(method.dataTypeString, false);
882                   if(method.dataType && method.dataType.name)
883                   {
884                      f.Printf("         case %d:\n", vid - _class.base.vTblSize);
885                      f.Printf("         {\n");
886                      {
887                         if(method.dataType.returnType.kind != voidType)
888                         {
889                            TypeName resultType;
890                            OldList * specs = MkList();
891                            Declarator decl;
892                            char type[1024] = "";
893                            char className[1024];
894                            Symbol classSym;
895
896                            if(method.dataType.returnType.kind == classType)
897                               classSym = method.dataType.returnType._class; // VERIFY THIS FindClass(method.dataType.returnType._class.string);
898                            else
899                            {
900                               PrintType(method.dataType.returnType, type, false, true);
901                               classSym = FindClass(type);
902                               type[0] = 0;
903                            }
904                            strcpy(className, "__ecereClass_");
905                            FullClassNameCat(className, classSym.string, true);
906                            MangleClassName(className);
907                            DeclareClass(classSym, className);
908
909                            PrintType(method.dataType.returnType, type, true, true);
910
911                            decl = SpecDeclFromString(type, specs, MkDeclaratorIdentifier(MkIdentifier("__ecereResult")));
912                            resultType = MkTypeName(specs, decl);
913
914                            f.Printf("            ");
915                            OutputTypeName(resultType, f);
916                            f.Printf(";\n");
917                         }
918
919                         for(param = method.dataType.params.first; param; param = param.next)
920                         {
921                            if(param.kind == classType && !strcmp(param._class.string, "String"))
922                            {
923                               // Hardcode 1024 chars max string for now
924                               f.Printf("            char %s[1024];\n", param.name);
925                               DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
926                               DeclareClass(FindClass("String"), "__ecereClass_String");
927                            }
928                            else
929                            {
930                               TypeName paramTypeName;
931                               OldList * specs = MkList();
932                               Declarator decl;
933                               char type[1024] = "";
934                               char className[1024];
935                               Symbol classSym;
936
937                               if(param.kind == classType)
938                                  classSym = param._class; // VERIFY THIS FindClass(param._class.string);
939                               else
940                               {
941                                  PrintType(param, type, false, true);
942                                  classSym = FindClass(type);
943                                  type[0] = 0;
944                               }
945
946                               strcpy(className, "__ecereClass_");
947                               FullClassNameCat(className, classSym.string, true);
948                               MangleClassName(className);
949                               DeclareClass(classSym, className);
950
951                               PrintType(param, type, true, true);
952
953                               decl = SpecDeclFromString(type, specs, MkDeclaratorIdentifier(MkIdentifier(param.name /*"__ecereResult"*/)));
954                               paramTypeName = MkTypeName(specs, decl);
955
956                               f.Printf("            ");
957                               OutputTypeName(paramTypeName, f);
958
959                               f.Printf(";\n");
960                            }
961                         }
962                         f.Printf("\n");
963
964                         for(param = method.dataType.params.first; param; param = param.next)
965                         {
966                            f.Printf("            __ecereBuffer.Unserialize(");
967                            if(param.kind == classType && !strcmp(param._class.string, "String"))
968                            {
969                               DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
970                               f.Printf("(StaticString)");
971                            }
972                            f.Puts(param.name);
973                            f.Printf(");\n");
974                         }
975
976                         f.Printf("            ");
977                         if(method.dataType.returnType.kind != voidType)
978                            f.Printf("__ecereResult = ");
979
980                         // f.Printf("this.instance.%s(", method.name);
981                         f.Printf("%s(", method.name);
982                         
983                         for(param = method.dataType.params.first; param; param = param.next)
984                         {
985                            if(param.prev)
986                               f.Printf(", ");
987                            f.Printf("%s", param.name);
988                         }
989
990                         f.Printf(");\n");
991
992                         for(param = method.dataType.params.first; param; param = param.next)
993                         {
994                            if(param.kind == classType && ((param._class && param._class.registered && param._class.registered.type == structClass) || !strcmp(param._class.string, "String")) && !param.constant)
995                            {
996                               if(!strcmp(param._class.string, "String"))
997                               {
998                                  DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
999                                  f.Printf("            __ecereBuffer.Serialize((StaticString)%s);\n", param.name);
1000                               }
1001                               else
1002                                  f.Printf("            __ecereBuffer.Serialize(%s);\n", param.name);
1003                            }
1004                         }
1005                         if(method.dataType.returnType.kind != voidType)
1006                         {
1007                            f.Printf("            __ecereBuffer.Serialize(__ecereResult);\n");
1008                         }
1009
1010                         for(param = method.dataType.params.first; param; param = param.next)
1011                         {
1012                            if(param.kind == classType && strcmp(param._class.string, "String") && param._class.registered && 
1013                               (param._class.registered.type == normalClass || param._class.registered.type == noHeadClass))
1014                            {
1015                               f.Printf("            delete %s;\n", param.name);
1016                            }
1017                         }
1018                         if(method.dataType.returnType.kind == classType && strcmp(method.dataType.returnType._class.string, "String") && method.dataType.returnType._class.registered && 
1019                               (method.dataType.returnType._class.registered.type == normalClass || method.dataType.returnType._class.registered.type == noHeadClass))
1020                         {
1021                            f.Printf("            delete __ecereResult;\n");
1022                         }
1023                      }
1024
1025                      f.Printf("            break;\n");
1026                      f.Printf("         }\n");
1027                   }
1028                }
1029             }
1030             f.Printf("      }\n");
1031             f.Printf("   }\n");
1032             f.Printf("\n");
1033          } 
1034
1035          doVirtual = true;
1036          id = 0;
1037          vid = _class.base.vTblSize;
1038
1039          next = (Method)_class.methods.first;
1040          while(next && ((next.type == virtualMethod) != doVirtual || (doVirtual && next.vid != vid)))
1041          {
1042             id++;
1043             next = (Method)((BTNode)next).next;
1044             if(!next && doVirtual)
1045             {
1046                if(vid == _class.vTblSize)
1047                   doVirtual = false;
1048                else
1049                   vid++;
1050                id = 0;
1051                next = (Method)_class.methods.first;
1052             }
1053          }
1054          for(method = next; method; method = next)
1055          {
1056             Type param;
1057
1058             if(!method.dataType)
1059                method.dataType = ProcessTypeString(method.dataTypeString, false);
1060
1061             if(method.dataType.name)
1062             {
1063                f.Printf("   ");
1064                if(doVirtual)
1065                {
1066                   char name[1024];
1067                   strcpy(name, "__ecereVMethodID_");
1068                   FullClassNameCat(name, method._class.fullName, true);
1069                   strcat(name, "_");
1070                   strcat(name, method.name);
1071                   DeclareMethod(method, name);
1072
1073                   f.Printf("virtual ");
1074                }
1075                f.Printf("%s\n", method.dataTypeString);
1076                f.Printf("   {\n");
1077
1078                if(method.dataType)
1079                {
1080                   if(method.dataType.returnType.kind != voidType)
1081                   {
1082                      TypeName resultType;
1083                      OldList * specs = MkList();
1084                      Declarator decl;
1085                      char type[1024] = "";
1086                      char className[1024];
1087                      Symbol classSym;
1088
1089                      if(method.dataType.returnType.kind == classType)
1090                         classSym = method.dataType.returnType._class; // VERIFY THIS FindClass(method.dataType.returnType._class.string);
1091                      else
1092                      {
1093                         PrintType(method.dataType.returnType, type, false, true);
1094                         classSym = FindClass(type);
1095                         type[0] = 0;
1096                      }
1097
1098                      strcpy(className, "__ecereClass_");
1099                      FullClassNameCat(className, classSym.string, true);
1100                      MangleClassName(className);
1101                      DeclareClass(classSym, className);
1102
1103                      PrintType(method.dataType.returnType, type, true, true);
1104
1105                      decl = SpecDeclFromString(type, specs, MkDeclaratorIdentifier(MkIdentifier("__ecereResult")));
1106                      resultType = MkTypeName(specs, decl);
1107
1108                      f.Printf("      ");
1109                      OutputTypeName(resultType, f);
1110                      if(method.dataType.returnType.kind == structType)
1111                         f.Printf(" = { 0 }");
1112                      else if(method.dataType.returnType.kind == classType && method.dataType.returnType._class.registered && method.dataType.returnType._class.registered.type == structClass)
1113                         f.Printf(" { }");
1114                      else
1115                         f.Printf(" = 0");
1116                      f.Printf(";\n\n");
1117                   }
1118                   f.Printf("      incref this;\n");
1119                   for(param = method.dataType.params.first; param; param = param.next)
1120                   {
1121                      char type[1024] = "";
1122                      char className[1024];
1123                      Symbol classSym;
1124
1125                      if(param.kind == classType)
1126                         classSym = param._class; // VERIFY THIS FindClass(param._class.string);
1127                      else
1128                      {
1129                         PrintType(param, type, false, true);
1130                         classSym = FindClass(type);
1131                         type[0] = 0;
1132                      }
1133                      strcpy(className, "__ecereClass_");
1134                      FullClassNameCat(className, classSym.string, true);
1135
1136                      MangleClassName(className);
1137                      DeclareClass(classSym, className);
1138
1139                      if(param.kind == classType && !strcmp(param._class.string, "String"))
1140                      {
1141                         DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1142                         f.Printf("      __ecereBuffer.Serialize((StaticString)%s);\n", param.name);
1143                      }
1144                      else
1145                         f.Printf("      __ecereBuffer.Serialize(%s);\n", param.name);
1146                   }
1147                   DeclareMethod(
1148                      eClass_FindMethod(
1149                         eSystem_FindClass(privateModule, "ecere::net::DCOMClientObject"), "CallMethod", privateModule), 
1150                      "__ecereMethod___ecereNameSpace__ecere__net__DCOMClientObject_CallMethod");
1151
1152                   f.Printf("      if(DCOMClientObject::CallMethod(%d))\n", id++);
1153                   f.Printf("      {\n");
1154                   for(param = method.dataType.params.first; param; param = param.next)
1155                   {
1156                      if(param.kind == classType && ((param._class && param._class.registered && param._class.registered.type == structClass) || !strcmp(param._class.string, "String")) && !param.constant)
1157                      {
1158                         if(!strcmp(param._class.string, "String"))
1159                         {
1160                            DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1161                            f.Printf("         __ecereBuffer.Unserialize((StaticString)%s);\n", param.name);
1162                         }
1163                         else
1164                            f.Printf("         __ecereBuffer.Unserialize(%s);\n", param.name);
1165                      }
1166                   }
1167                   if(method.dataType.returnType.kind != voidType)
1168                   {
1169                      if(method.dataType.returnType.kind == classType && !strcmp(method.dataType.returnType._class.string, "String"))
1170                      {
1171                         DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1172                         f.Printf("         __ecereBuffer.Unserialize((StaticString)__ecereResult);\n");
1173                      }
1174                      else
1175                         f.Printf("         __ecereBuffer.Unserialize(__ecereResult);\n");
1176                   }
1177                   f.Printf("      }\n");
1178                   f.Printf("      __ecereBuffer.Free();\n");
1179                   f.Printf("      delete this;\n");
1180                   if(method.dataType.returnType.kind != voidType)
1181                   {
1182                      f.Printf("      return __ecereResult;\n");
1183                   }
1184                }
1185
1186                f.Printf("   }\n");
1187             }
1188             next = (Method)((BTNode)method).next;
1189             while(next && ((next.type == virtualMethod) != doVirtual || (doVirtual && next.vid != vid)))
1190             {
1191                id++;
1192                next = (Method)((BTNode)next).next;
1193                if(!next && doVirtual)
1194                {
1195                   if(vid == _class.vTblSize)
1196                      doVirtual = false;
1197                   else
1198                      vid++;
1199                   id = 0;
1200                   next = (Method)_class.methods.first;
1201                }
1202             }
1203             
1204             if(next) 
1205                f.Printf("\n");
1206          }
1207
1208          f.Printf("}\n");
1209          if(deriv.next) 
1210             f.Printf("\n");
1211       }
1212    }
1213 }
1214
1215 static void BindDCOMServer()
1216 {
1217    bool mutexDeclared = false;
1218    Class _class;
1219    for(_class = privateModule.classes.first; _class; _class = _class.next)
1220    {
1221       if(_class.isRemote == 3) //)
1222          break;
1223    }
1224
1225    if(_class)
1226    {
1227       File f;
1228       if(!dcomSymbols) dcomSymbols = TempFile { };
1229       f = dcomSymbols;
1230
1231       DeclareClass(FindClass("ecere::net::DCOMServerObject"), "__ecereClass___ecereNameSpace__ecere__net__DCOMServerObject");
1232
1233       // SERVER BINDINGS
1234       for(_class = privateModule.classes.first; _class; _class = _class.next)
1235       {
1236          if(_class.isRemote == 3) //2 && !strncmp(_class.fullName, "DCOMServer_", strlen("DCOMServer_")))
1237          {
1238             Method method;
1239             int id = 0;
1240             int vid;
1241
1242             f.Printf("class DCOM%s : ecere::net::DCOMServerObject\n", _class.fullName);
1243             // f.Printf("class DCOM%s\n", _class.fullName);
1244             f.Printf("{\n");
1245             /*
1246             f.Printf("   %s instance;\n", _class.fullName);
1247             f.Printf("   unsigned int id;\n");
1248             f.Printf("   SerialBuffer buffer { };\n");
1249             */
1250
1251             /*
1252             f.Printf("   DCOM%s()\n", _class.fullName);
1253             f.Printf("   {\n");
1254             f.Printf("      instance = eInstance_New(class(%s));\n", _class.fullName);
1255             f.Printf("   }\n");
1256             */
1257             // f.Printf("\n");
1258             f.Printf("   virtual void CallMethod(uint __ecereMethodID, SerialBuffer __ecereBuffer)\n");
1259             f.Printf("   {\n");
1260             f.Printf("      %s inst = (%s)instance;\n", _class.fullName, _class.fullName);
1261             f.Printf("      incref inst;\n");
1262             f.Printf("      switch(__ecereMethodID)\n");
1263             f.Printf("      {\n");
1264
1265             for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
1266             {
1267                Type param;
1268                method.dataType = ProcessTypeString(method.dataTypeString, false);
1269                if(method.dataType && method.dataType.name)
1270                {
1271                   f.Printf("         case %d:\n", id++);
1272                   f.Printf("         {\n");
1273
1274                   {
1275                      if(method.dataType.returnType.kind != voidType)
1276                      {
1277                         TypeName resultType;
1278                         OldList * specs = MkList();
1279                         Declarator decl;
1280                         char type[1024] = "";
1281                         char className[1024];
1282                         Symbol classSym;
1283
1284                         if(method.dataType.returnType.kind == classType)
1285                            classSym = method.dataType.returnType._class; // VERIFY THIS FindClass(method.dataType.returnType._class.string);
1286                         else
1287                         {
1288                            PrintType(method.dataType.returnType, type, false, true);
1289                            classSym = FindClass(type);
1290                            type[0] = 0;
1291                         }
1292                         strcpy(className, "__ecereClass_");
1293                         FullClassNameCat(className, classSym.string, true);
1294                         MangleClassName(className);
1295                         DeclareClass(classSym, className);
1296
1297                         PrintType(method.dataType.returnType, type, true, true);
1298
1299                         decl = SpecDeclFromString(type, specs, MkDeclaratorIdentifier(MkIdentifier("__ecereResult")));
1300                         resultType = MkTypeName(specs, decl);
1301
1302                         f.Printf("            ");
1303                         OutputTypeName(resultType, f);
1304                         f.Printf(";\n");
1305                      }
1306
1307                      for(param = method.dataType.params.first; param; param = param.next)
1308                      {
1309                         if(param.kind == classType && !strcmp(param._class.string, "String"))
1310                         {
1311                            // Hardcode 1024 chars max string for now
1312                            f.Printf("            char %s[1024];\n", param.name);
1313                            DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1314                            DeclareClass(FindClass("String"), "__ecereClass_String");
1315                         }
1316                         else
1317                         {
1318                            TypeName paramTypeName;
1319                            OldList * specs = MkList();
1320                            Declarator decl;
1321                            char type[1024] = "";
1322                            char className[1024];
1323                            Symbol classSym;
1324
1325                            if(param.kind == classType)
1326                               classSym = param._class; // VERIFY THIS FindClass(param._class.string);
1327                            else
1328                            {
1329                               PrintType(param, type, false, true);
1330                               classSym = FindClass(type);
1331                               type[0] = 0;
1332                            }
1333
1334                            strcpy(className, "__ecereClass_");
1335                            FullClassNameCat(className, classSym.string, true);
1336                            MangleClassName(className);
1337                            DeclareClass(classSym, className);
1338
1339                            PrintType(param, type, true, true);
1340
1341                            decl = SpecDeclFromString(type, specs, MkDeclaratorIdentifier(MkIdentifier(param.name /*"__ecereResult"*/)));
1342                            paramTypeName = MkTypeName(specs, decl);
1343
1344                            f.Printf("            ");
1345                            OutputTypeName(paramTypeName, f);
1346
1347                            f.Printf(";\n");
1348                         }
1349                      }
1350                      f.Printf("\n");
1351
1352                      for(param = method.dataType.params.first; param; param = param.next)
1353                      {
1354                         f.Printf("            __ecereBuffer.Unserialize(");
1355                         if(param.kind == classType && !strcmp(param._class.string, "String"))
1356                         {
1357                            DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1358                            f.Printf("(StaticString)");
1359                         }
1360                         f.Puts(param.name);
1361                         f.Printf(");\n");
1362                      }
1363
1364                      f.Printf("            ");
1365                      if(method.dataType.returnType.kind != voidType)
1366                         f.Printf("__ecereResult = ");
1367
1368                      // f.Printf("this.instance.%s(", method.name);
1369                      f.Printf("((%s)instance).%s(", _class.fullName, method.name);
1370                      
1371                      for(param = method.dataType.params.first; param; param = param.next)
1372                      {
1373                         if(param.prev)
1374                            f.Printf(", ");
1375                         f.Printf("%s", param.name);
1376                      }
1377
1378                      f.Printf(");\n");
1379
1380                      for(param = method.dataType.params.first; param; param = param.next)
1381                      {
1382                         if(param.kind == classType && ((param._class && param._class.registered && param._class.registered.type == structClass) || !strcmp(param._class.string, "String")) && !param.constant)
1383                         {
1384                            if(!strcmp(param._class.string, "String"))
1385                            {
1386                               DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1387                               f.Printf("            __ecereBuffer.Serialize((StaticString)%s);\n", param.name);
1388                            }
1389                            else
1390                               f.Printf("            __ecereBuffer.Serialize(%s);\n", param.name);
1391                         }
1392                      }
1393                      if(method.dataType.returnType.kind != voidType)
1394                      {
1395                         f.Printf("            __ecereBuffer.Serialize(__ecereResult);\n");
1396                      }
1397
1398                      for(param = method.dataType.params.first; param; param = param.next)
1399                      {
1400                         if(param.kind == classType && strcmp(param._class.string, "String") && param._class.registered && 
1401                            (param._class.registered.type == normalClass || param._class.registered.type == noHeadClass))
1402                         {
1403                            f.Printf("            delete %s;\n", param.name);
1404                         }
1405                      }
1406                      if(method.dataType.returnType.kind == classType && strcmp(method.dataType.returnType._class.string, "String") && method.dataType.returnType._class.registered && 
1407                            (method.dataType.returnType._class.registered.type == normalClass || method.dataType.returnType._class.registered.type == noHeadClass))
1408                      {
1409                         f.Printf("            delete __ecereResult;\n");
1410                      }
1411                   }
1412
1413                   f.Printf("            break;\n");
1414                   f.Printf("         }\n");
1415                }
1416             }
1417             f.Printf("      }\n");
1418             f.Printf("      delete inst;\n");
1419             f.Printf("   }\n");
1420
1421             // *** VIRTUAL FUNCTIONS BINDINGS ***
1422             for(vid = _class.base.vTblSize; vid < _class.vTblSize; vid++)
1423             {
1424                Method method;
1425                Type param;
1426
1427                for(method = (Method)_class.methods.first; method; method = (Method)((BTNode)method).next)
1428                   if(method.type == virtualMethod && method._class == _class && method.vid == vid)
1429                      break;
1430                if(method)
1431                {
1432                   if(!mutexDeclared)
1433                   {
1434                      DeclareClass(FindClass("ecere::sys::Mutex"), "__ecereClass___ecereNameSpace__ecere__sys__Mutex");
1435                      DeclareMethod(
1436                         eClass_FindMethod(
1437                            eSystem_FindClass(privateModule, "ecere::sys::Mutex"), "Wait", privateModule), 
1438                               "__ecereMethod___ecereNameSpace__ecere__sys__Mutex_Wait");
1439                      DeclareMethod(
1440                         eClass_FindMethod(
1441                            eSystem_FindClass(privateModule, "ecere::sys::Mutex"), "Release", privateModule), 
1442                               "__ecereMethod___ecereNameSpace__ecere__sys__Mutex_Release");
1443                      mutexDeclared = true;
1444                   }
1445
1446                   f.Printf("\n");
1447                   if(!method.dataType)
1448                      method.dataType = ProcessTypeString(method.dataTypeString, false);
1449
1450                   if(method.dataType.name)
1451                   {
1452                      f.Printf("   virtual %s\n", method.dataTypeString);
1453                      f.Printf("   {\n");
1454
1455                      if(method.dataType)
1456                      {
1457                         f.Printf("      DCOM%s __ecereObject = (void *)_vTbl[-1];\n", _class.fullName);
1458                         if(method.dataType.returnType.kind != voidType)
1459                         {
1460                            TypeName resultType;
1461                            OldList * specs = MkList();
1462                            Declarator decl;
1463                            char type[1024] = "";
1464                            char className[1024];
1465                            Symbol classSym;
1466
1467                            if(method.dataType.returnType.kind == classType)
1468                               classSym = method.dataType.returnType._class; // VERIFY THIS FindClass(method.dataType.returnType._class.string);
1469                            else
1470                            {
1471                               PrintType(method.dataType.returnType, type, false, true);
1472                               classSym = FindClass(type);
1473                               type[0] = 0;
1474                            }
1475
1476                            strcpy(className, "__ecereClass_");
1477                            FullClassNameCat(className, classSym.string, true);
1478                            MangleClassName(className);
1479                            DeclareClass(classSym, className);
1480
1481                            PrintType(method.dataType.returnType, type, true, true);
1482
1483                            decl = SpecDeclFromString(type, specs, MkDeclaratorIdentifier(MkIdentifier("__ecereResult")));
1484                            resultType = MkTypeName(specs, decl);
1485
1486                            f.Printf("      ");
1487                            OutputTypeName(resultType, f);
1488                            if(method.dataType.returnType.kind == structType)
1489                               f.Printf(" = { 0 }");
1490                            else if(method.dataType.returnType.kind == classType && method.dataType.returnType._class.registered && method.dataType.returnType._class.registered.type == structClass)
1491                               f.Printf(" { }");
1492                            else
1493                               f.Printf(" = 0");
1494                            f.Printf(";\n\n");
1495                         }
1496                         
1497                         f.Printf("      incref __ecereObject;\n");
1498                         f.Printf("      __ecereMethod___ecereNameSpace__ecere__sys__Mutex_Wait(__ecereObject.mutex);\n");
1499
1500                         //f.Printf("      incref this;\n");
1501                         for(param = method.dataType.params.first; param; param = param.next)
1502                         {
1503                            char type[1024] = "";
1504                            char className[1024];
1505                            Symbol classSym;
1506
1507                            if(param.kind == classType)
1508                               classSym = param._class; // VERIFY THIS FindClass(param._class.string);
1509                            else
1510                            {
1511                               PrintType(param, type, false, true);
1512                               classSym = FindClass(type);
1513                               type[0] = 0;
1514                            }
1515                            strcpy(className, "__ecereClass_");
1516                            FullClassNameCat(className, classSym.string, true);
1517                            MangleClassName(className);
1518                            DeclareClass(classSym, className);
1519
1520                            if(param.kind == classType && !strcmp(param._class.string, "String"))
1521                            {
1522                               DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1523                               f.Printf("      __ecereObject.argsBuffer.Serialize((StaticString)%s);\n", param.name);
1524                            }
1525                            else
1526                               f.Printf("      __ecereObject.argsBuffer.Serialize(%s);\n", param.name);
1527                         }
1528
1529                         DeclareMethod(
1530                            eClass_FindMethod(
1531                               eSystem_FindClass(privateModule, "ecere::net::DCOMServerObject"), "CallVirtualMethod", privateModule), 
1532                            "__ecereMethod___ecereNameSpace__ecere__net__DCOMServerObject_CallVirtualMethod");
1533
1534                         // Check if this method needs to return anything (hasReturnValue)
1535                         {
1536                            bool hasReturnValue = method.dataType.returnType.kind != voidType;
1537                            if(!hasReturnValue)
1538                            {
1539                               for(param = method.dataType.params.first; param; param = param.next)
1540                               {
1541                                  if(param.kind == classType && ((param._class && param._class.registered && param._class.registered.type == structClass) || !strcmp(param._class.string, "String")) && !param.constant)
1542                                  {
1543                                     hasReturnValue = true;
1544                                     break;
1545                                  }
1546                               }
1547                            }
1548                            f.Printf("      if(__ecereObject.CallVirtualMethod(%d, %s))\n", vid - _class.base.vTblSize,
1549                               hasReturnValue ? "true" : "false");
1550                         }
1551                         f.Printf("      {\n");
1552                         for(param = method.dataType.params.first; param; param = param.next)
1553                         {
1554                            if(param.kind == classType && ((param._class && param._class.registered && param._class.registered.type == structClass) || !strcmp(param._class.string, "String")) && !param.constant)
1555                            {
1556                               if(!strcmp(param._class.string, "String"))
1557                               {
1558                                  DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1559                                  f.Printf("         __ecereObject.returnBuffer.Unserialize((StaticString)%s);\n", param.name);
1560                               }
1561                               else
1562                                  f.Printf("         __ecereObject.returnBuffer.Unserialize(%s);\n", param.name);
1563                            }
1564                         }
1565                         if(method.dataType.returnType.kind != voidType)
1566                         {
1567                            if(method.dataType.returnType.kind == classType && !strcmp(method.dataType.returnType._class.string, "String"))
1568                            {
1569                               DeclareClass(FindClass("StaticString"), "__ecereClass_StaticString");
1570                               f.Printf("         __ecereObject.returnBuffer.Unserialize((StaticString)__ecereResult);\n");
1571                            }
1572                            else
1573                               f.Printf("         __ecereObject.returnBuffer.Unserialize(__ecereResult);\n");
1574                         }
1575                         f.Printf("      }\n");
1576                         f.Printf("      else\n");
1577                         f.Printf("         ((%s)this).%s::%s(", _class.fullName, _class.fullName, method.name);
1578                         for(param = method.dataType.params.first; param; param = param.next)
1579                         {
1580                            f.Printf("%s", param.name);
1581                            if(param.next) f.Printf(", ");
1582                         }
1583                         f.Printf(");\n");
1584
1585                         f.Printf("      __ecereObject.returnBuffer.Free();\n");
1586                         f.Printf("      __ecereMethod___ecereNameSpace__ecere__sys__Mutex_Release(__ecereObject.mutex);\n");
1587                         //f.Printf("      delete this;\n");
1588                         f.Printf("      delete __ecereObject;\n");
1589                         if(method.dataType.returnType.kind != voidType)
1590                         {
1591                            f.Printf("      return __ecereResult;\n");
1592                         }
1593                      }
1594
1595                      f.Printf("   }\n");
1596                      /*if(vid < _class.vTblSize) 
1597                         f.Printf("\n");*/
1598                   }
1599                }
1600             }
1601             f.Printf("}\n");
1602          }
1603       }
1604    }
1605 }
1606
1607 class SymbolgenApp : Application
1608 {
1609    void Main()
1610    {
1611       /*
1612       char ** argv = null;
1613       int argc = 0;
1614       */
1615       int c;
1616       bool valid = true;
1617       char * output = null;
1618
1619       targetPlatform = GetRuntimePlatform();
1620       targetBits = GetHostBits();
1621
1622       /*
1623       for(c = 0; c<this.argc; c++)
1624       {
1625          char * arg = this.argv[c];
1626          int argLen = strlen(arg);
1627
1628          argv = renew argv char *[argc + 1];
1629          argv[argc] = new char[argLen+1];
1630          strcpy(argv[argc], arg);
1631
1632          while(argv[argc][argLen-1] == '\\' && c < this.argc-1)
1633          {
1634             int len;
1635
1636             c++;
1637             arg = this.argv[c];
1638             len = strlen(arg);
1639             argv[argc] = renew argv[argc] char[argLen + len + 1];
1640
1641             argv[argc][argLen-1] = ' ';
1642             strcpy(argv[argc] + argLen, arg);
1643             argLen += len;
1644          }
1645          argc++;
1646       }
1647       */
1648
1649       for(c = 1; c<argc; c++)
1650       {
1651          char * arg = argv[c];
1652          if(arg[0] == '-')
1653          {
1654             if(!strcmp(arg + 1, "m32") || !strcmp(arg + 1, "m64"))
1655             {
1656                targetBits = !strcmp(arg + 1, "m32") ? 32 : 64;
1657             }
1658             else if(!strcmp(arg+1, "o"))
1659             {
1660                if(!output && c + 1 < argc)
1661                {
1662                   output = argv[c+1];
1663                   c++;
1664                }
1665                else
1666                   valid = false;
1667             }
1668             else if(!strcmp(arg, "-name"))
1669             {
1670                if(c + 1 < argc)
1671                {
1672                   strcpy(projectName, argv[c+1]);
1673                   c++;
1674                }
1675                else
1676                   valid = false;
1677             }
1678             else if(!strcmp(arg, "-t"))
1679             {
1680                if(++c < argc)
1681                   targetPlatform = argv[c];
1682                else
1683                   valid = false;
1684             }
1685             else if(!strcmp(arg, "-console"))
1686                isConsole = true;
1687             else if(!strcmp(arg, "-dynamiclib"))
1688                isDynamicLibrary = true;
1689             else if(!strcmp(arg, "-staticlib"))
1690             {
1691                isDynamicLibrary = true;   // TOFIX: unmixup
1692                isStaticLibrary = true;
1693             }
1694             else if(!strcmp(arg, "-symbols"))
1695             {
1696                if(c + 1 < argc)
1697                {
1698                   SetSymbolsDir(argv[c+1]);
1699                   c++;
1700                }
1701                else
1702                   valid = false;
1703             }
1704          }
1705       }
1706       if(!output)
1707          valid = false;
1708      
1709       if(!valid)
1710          printf($"Syntax:\n   ecs [-t <target platform>] <input>[, <input>]* -o <output>\n");
1711       else
1712       {
1713          int c;
1714          char ext[MAX_EXTENSION];
1715          char symbolModule[MAX_FILENAME];
1716          GetExtension(output, ext);
1717          GetLastDirectory(output, symbolModule);
1718          
1719          SetDefines(&::_defines);
1720          SetImports(&_imports);
1721          SetGlobalData(&globalData);
1722          SetExcludedSymbols(&_excludedSymbols);
1723          SetGlobalContext(theGlobalContext);
1724          SetTopContext(theGlobalContext);
1725          SetCurrentContext(theGlobalContext);
1726          SetTargetPlatform(targetPlatform);
1727          SetTargetBits(targetBits);
1728
1729          privateModule = (Module)__ecere_COM_Initialize(true | (targetBits == sizeof(uintptr)*8 ? 0 : targetBits == 64 ? 2 : targetBits==32 ? 4 : 0) | 8, 1, null);
1730          SetPrivateModule(privateModule);
1731          mainModule = ModuleImport { };
1732          SetMainModule(mainModule);
1733          _imports.Add(mainModule);
1734
1735          //if(!strcmp(ext, "c"))
1736          {
1737             String symbolsDir = GetSymbolsDir();
1738             // Only generating .pot files when building from release.* directory for now
1739             bool outputPot = symbolsDir && SearchString(symbolsDir, 0, "release.", false, false);
1740             Map<ContextStringPair, List<String> > intlStrings { };
1741             MapIterator<ContextStringPair, List<String>> it { map = intlStrings };
1742
1743             for(c = 1; c<argc; c++)
1744             {
1745                char * file = argv[c];
1746                if(file[0] == '-')
1747                {
1748                   if(!strcmp(file, "-c"))
1749                      c++;
1750                }
1751                else
1752                {
1753                   char ext[MAX_EXTENSION];
1754                   GetExtension(file,ext);
1755                   if(!strcmp(ext, "imp"))
1756                      LoadImports(file);
1757                }
1758             }
1759
1760             // What is this supposed to do?
1761             for(c = 1; c<argc; c++)
1762             {
1763                char * file = argv[c];
1764                if(file[0] == '-')
1765                {
1766                   if(!strcmp(file, "-c"))
1767                      c++;
1768                }
1769             }
1770
1771             for(c = 1; c<argc; c++)
1772             {
1773                char * file = argv[c];
1774                if(file[0] == '-')
1775                {
1776                   // Don't even know what it does here?
1777                   if(!strcmp(file, "-c"))
1778                      c++;
1779                }
1780                else
1781                {
1782                   char ext[MAX_EXTENSION];
1783                   char moduleName[MAX_LOCATION];
1784
1785                   GetExtension(file,ext);
1786
1787                   GetLastDirectory(file, moduleName);
1788                   StripExtension(moduleName);
1789                   strcat(moduleName, ".ec");
1790
1791                   if(fstrcmp(moduleName, symbolModule) && (!strcmp(ext, "sym") || !strcmp(ext, "ec")))
1792                   {
1793                      ImportedModule importedModule;
1794                      ModuleInfo module { };
1795                      char fileName[MAX_FILENAME];
1796                      ::modules.Add(module);
1797
1798                      GetLastDirectory(file, fileName);
1799
1800                      module.name = CopyString(fileName);
1801                      
1802                      StripExtension(module.name);                     
1803
1804                      for(importedModule = ::_defines.first; importedModule; importedModule = importedModule.next)
1805                      {
1806                         if(importedModule.type == moduleDefinition && !strcmpi(importedModule.name, module.name) && !(importedModule.importType == remoteImport))
1807                            break;
1808                      }
1809
1810                      if(importedModule)
1811                         module.globalInstance = importedModule.globalInstance;
1812                      else
1813                      {
1814                         importedModule = ImportedModule
1815                         {
1816                            name = CopyString(module.name),
1817                            type = moduleDefinition,
1818                            importType = normalImport
1819                         };
1820                         ::_defines.AddName(importedModule);
1821
1822                         module.globalInstance = LoadSymbols(file, normalImport, false);
1823                         CheckDataRedefinitions();
1824                      }
1825
1826                      // I18n code
1827                      {
1828                         File f;
1829                         ChangeExtension(file, "bowl", fileName);
1830                         f = FileOpen(fileName, read);
1831                         if(f)
1832                         {
1833                            static char line[65536];
1834                            List<String> comments { };
1835                            String msgid = null, msgstr = null, msgctxt = null;
1836                            while(!f.Eof())
1837                            {
1838                               if(f.GetLine(line, sizeof(line)))
1839                               {
1840                                  int len;
1841                                  TrimLSpaces(line, line);
1842                                  if(line[0] == '#')
1843                                  {
1844                                     comments.Add(CopyString(line));
1845                                  }
1846                                  else if(strstr(line, "msgid \"") == line)
1847                                  {
1848                                     delete msgid;
1849                                     msgid = CopyString(line + 7);
1850                                     len = strlen(msgid);
1851                                     if(len) msgid[len-1] = 0;
1852                                  }
1853                                  else if(strstr(line, "msgctxt \"") == line)
1854                                  {
1855                                     delete msgctxt;
1856                                     msgctxt = CopyString(line + 9);
1857                                     len = strlen(msgctxt);
1858                                     if(len) msgctxt[len-1] = 0;
1859                                  }
1860                                  else if(strstr(line, "msgstr \"") == line)
1861                                  {
1862                                     delete msgstr;
1863                                     msgstr = CopyString(line + 8);
1864                                     len = strlen(msgstr);
1865                                     if(len) msgstr[len-1] = 0;
1866                                  }
1867
1868                                  if(msgid && msgstr)
1869                                  {
1870                                     ContextStringPair pair { msgid, msgctxt };
1871                                     i18n = true;
1872                                     if(!it.Index(pair, false))
1873                                     {
1874                                        msgid = null; msgctxt = null;
1875                                        intlStrings[pair] = comments;
1876                                        comments = { };
1877                                     }
1878                                     else
1879                                     {
1880                                        for(s : comments)
1881                                           it.data.Add(s);
1882                                        comments.RemoveAll();
1883                                     }
1884
1885                                     delete msgid;
1886                                     delete msgctxt;
1887                                     delete msgstr;
1888                                  }
1889                               }
1890                            }
1891                            comments.Free();
1892                            delete comments;
1893                            delete f;
1894                         }
1895                      }
1896                   }
1897                }
1898             }
1899
1900             ComputeModuleClasses(privateModule);
1901
1902             if(!isDynamicLibrary)
1903             {
1904                // applicationClass = eSystem_FindClass(privateModule, "Application");
1905                /*
1906                thisAppClass = FindAppClass(&privateModule.application.publicNameSpace, true);
1907                if(!thisAppClass)
1908                   thisAppClass = FindAppClass(&privateModule.application.privateNameSpace, true);
1909                if(!thisAppClass)
1910                   thisAppClass = FindAppClass(&privateModule.application.publicNameSpace, false);
1911                if(!thisAppClass)
1912                   thisAppClass = FindAppClass(&privateModule.application.privateNameSpace, false);
1913                */
1914                thisAppClass = SearchAppClass_Module(privateModule);
1915             }
1916             WriteMain(output);
1917
1918             if(outputPot && intlStrings.count)
1919             {
1920                File potFile;
1921                char potFileName[MAX_LOCATION];
1922                //strcpy(potFileName, output);
1923                //StripExtension(potFileName);
1924                strcpy(potFileName, "locale");
1925                MakeDir(potFileName);
1926                PathCat(potFileName, projectName);
1927                ChangeExtension(potFileName, "pot", potFileName);
1928                potFile = FileOpen(potFileName, write);
1929                if(potFile)
1930                {
1931                   // Write header:
1932                   potFile.Puts("msgid \"\"\n");
1933                   potFile.Puts("msgstr \"\"\n");
1934                   potFile.Puts("\"Project-Id-Version: \\n\"\n");
1935                   potFile.Puts("\"POT-Creation-Date: \\n\"\n");
1936                   potFile.Puts("\"PO-Revision-Date: \\n\"\n");
1937                   potFile.Puts("\"Last-Translator: \\n\"\n");
1938                   potFile.Puts("\"Language-Team: \\n\"\n");
1939                   potFile.Puts("\"MIME-Version: 1.0\\n\"\n");
1940                   potFile.Puts("\"Content-Type: text/plain; charset=iso-8859-1\\n\"\n");
1941                   potFile.Puts("\"Content-Transfer-Encoding: 8bit\\n\"\n");
1942                   potFile.Puts("\"X-Poedit-Basepath: ../\\n\"\n");
1943                   potFile.Puts("\n");
1944
1945                   for(i : intlStrings)
1946                   {
1947                      ContextStringPair pair = &i;
1948                      List<String> comments = i;
1949                      for(s : comments)
1950                      {
1951                         potFile.Printf(s);
1952                         potFile.Puts("\n");
1953                      }
1954
1955                      if(pair.context)
1956                      {
1957                         potFile.Puts("msgctxt \""); potFile.Puts(pair.context); potFile.Puts("\"\n");
1958                      }
1959                      potFile.Puts("msgid \""); potFile.Puts(pair.string); potFile.Puts("\"\n");
1960                      potFile.Puts("msgstr \""); potFile.Puts(pair.string); potFile.Puts("\"\n");
1961                      potFile.Puts("\n");
1962                   }
1963                   intlStrings.Free();
1964                   delete intlStrings;
1965                   delete potFile;
1966                }
1967             }
1968          }
1969
1970          FreeContext(theGlobalContext);
1971          FreeExcludedSymbols(_excludedSymbols);
1972
1973          ::_defines.Free(FreeModuleDefine);
1974          _imports.Free(FreeModuleImport);
1975
1976          //precompDefines.Free(FreeDefinition);   
1977
1978          FreeTypeData(privateModule);
1979          FreeIncludeFiles();
1980          FreeGlobalData(globalData);
1981
1982          delete privateModule;
1983       }
1984
1985       SetSymbolsDir(null); // Free symbols dir
1986
1987       /*
1988       for(c = 0; c<argc; c++)
1989          delete argv[c];
1990       delete argv;
1991       */
1992
1993 #ifdef _DEBUG
1994       getch();
1995 #endif
1996    }
1997 }