Report missed type registry hits after generation.
[mono.git] / mcs / tools / cilc / cilc.cs
1 // cilc -- a CIL-to-C binding generator
2 // Copyright (C) 2003, 2004 Alp Toker <alp@atoker.com>
3 // Licensed under the terms of the GNU GPL
4
5 using System;
6 using System.IO;
7 using System.Reflection;
8 using System.Collections;
9
10 public class cilc
11 {
12         private cilc () {}
13
14         static CodeWriter C, H, Cindex, Hindex, Hdecls;
15         static string ns, dllname;
16         static string cur_type, CurType;
17         static string target_dir;
18
19         static ArrayList funcs_done = new ArrayList ();
20
21         public static int Main (string[] args)
22         {
23                 if (args.Length < 1 || args.Length > 2) {
24                         Console.WriteLine ("Mono CIL-to-C binding generator");
25                         Console.WriteLine ("Usage: cilc [options] assembly target");
26                         return 1;
27                 }
28
29                 ns = "Unnamed";
30
31                 if (args.Length == 1)
32                         Generate (args[0], Path.GetFileNameWithoutExtension (args[0]));
33                 else
34                         Generate (args[0], args[1]);
35
36                 return 0;
37         }
38
39         public static void Generate (string assembly, string target)
40         {
41                 target_dir = target + Path.DirectorySeparatorChar;
42
43                 if (Directory.Exists (target_dir)) {
44                         Console.WriteLine ("Error: Target directory " + target_dir + " already exists.");
45                         return;
46                 }
47
48                 Directory.CreateDirectory (target_dir);
49
50                 //TODO: parse given .h files here and register the type names
51
52                 Assembly a = Assembly.LoadFrom (assembly);
53                 dllname = Path.GetFileName (assembly);
54                 AssemblyGen (a);
55
56                 string soname = NsToFlat (Path.GetFileNameWithoutExtension (assembly)).ToLower ();
57
58                 //create a makefile
59                 CodeWriter makefile = new CodeWriter (target_dir + "Makefile");
60                 makefile.Indenter = "\t";
61                 makefile.WriteLine (@"OBJS = $(shell ls *.c | sed -e 's/\.c/.o/')");
62                 makefile.WriteLine (@"CFLAGS = -static -fpic $(shell pkg-config --cflags glib-2.0 gobject-2.0 mono) -I.");
63                 makefile.WriteLine ();
64                 makefile.WriteLine ("all: lib" + soname + ".so");
65                 makefile.WriteLine ();
66                 makefile.WriteLine ("lib" + soname + ".so: $(OBJS)");
67                 makefile.Indent ();
68                 makefile.WriteLine ("gcc -Wall -fpic -shared `pkg-config --libs glib-2.0 gobject-2.0 mono` -lpthread $(OBJS) -o lib" + soname + ".so");
69                 makefile.Outdent ();
70                 makefile.WriteLine ();
71                 makefile.WriteLine ("clean:");
72                 makefile.Indent ();
73                 makefile.WriteLine ("rm -rf core *~ *.o *.so");
74                 makefile.Outdent ();
75                 makefile.Close ();
76
77                 Console.WriteLine ();
78                 Console.WriteLine ("Type registry missed hits (by namespace):");
79                 MakeReport (registry_hits);
80         }
81
82         static void MakeReport (Hashtable ctable)
83         {
84                 string[] reg_keys = (string[]) (new ArrayList (ctable.Keys)).ToArray (typeof (string));
85                 int[] reg_vals = (int[]) (new ArrayList (ctable.Values)).ToArray (typeof (int));
86                 Array.Sort (reg_vals, reg_keys);
87
88                 Array.Reverse (reg_vals);
89                 Array.Reverse (reg_keys);
90
91                 for (int i = 0 ; i != reg_keys.Length ; i++) {
92                         Console.WriteLine ("  " + reg_keys[i] + ": " + reg_vals[i]);
93                 }
94         }
95
96         static void AssemblyGen (Assembly a)
97         {
98                 Type[] types = a.GetTypes ();
99                 Hashtable ns_types = new Hashtable ();
100
101                 foreach (Type t in types) {
102                         if (t.IsNotPublic) {
103                                 Console.WriteLine ("Ignoring non-public type: " + t.Name);
104                                 continue;
105                         }
106
107                         if (!t.IsClass) {
108                                 Console.WriteLine ("Ignoring unrecognised type: " + t.Name);
109                                 continue;
110                         }
111
112                         RegisterCsType (t);
113
114                         if (!ns_types.Contains (t.Namespace))
115                                 ns_types[t.Namespace] = new ArrayList ();
116
117                         ((ArrayList) ns_types[t.Namespace]).Add (t);
118                 }
119
120                 namespaces = (string[]) (new ArrayList (ns_types.Keys)).ToArray (typeof (string));
121
122                 foreach (DictionaryEntry de in ns_types)
123                         NamespaceGen ((string) de.Key, (Type[]) ((ArrayList) de.Value).ToArray (typeof (Type)));
124         }
125
126         static string[] namespaces;
127
128         static void NamespaceGen (string given_ns, Type[] types)
129         {
130                 //ns = types[0].Namespace;
131                 ns = given_ns;
132                 
133                 Hindex = new CodeWriter (target_dir + NsToFlat (ns).ToLower () + ".h");
134                 Hdecls = new CodeWriter (target_dir + NsToFlat (ns).ToLower () + "-decls.h");
135                 Cindex = new CodeWriter (target_dir + NsToFlat (ns).ToLower () + ".c");
136
137                 string Hindex_id = "__" + NsToFlat (ns).ToUpper () + "_H__";
138                 Hindex.WriteLine ("#ifndef " + Hindex_id);
139                 Hindex.WriteLine ("#define " + Hindex_id);
140                 Hindex.WriteLine ();
141
142                 string Hdecls_id = "__" + NsToFlat (ns).ToUpper () + "_DECLS_H__";
143                 Hdecls.WriteLine ("#ifndef " + Hdecls_id);
144                 Hdecls.WriteLine ("#define " + Hdecls_id);
145                 Hdecls.WriteLine ();
146
147                 Cindex.WriteLine ("#include <glib.h>");
148                 Cindex.WriteLine ("#include <mono/jit/jit.h>");
149                 Cindex.WriteLine ();
150
151                 Cindex.WriteLine ("MonoDomain *" + NsToC (ns) + "_get_mono_domain (void)");
152                 Cindex.WriteLine ("{");
153                 Cindex.WriteLine ("static MonoDomain *domain = NULL;");
154                 Cindex.WriteLine ("if (domain != NULL) return domain;");
155                 Cindex.WriteLine ("domain = mono_jit_init (\"cilc\");");
156                 Cindex.WriteLine ();
157
158                 Cindex.WriteLine ("return domain;");
159                 Cindex.WriteLine ("}");
160                 Cindex.WriteLine ();
161
162                 Cindex.WriteLine ("MonoAssembly *" + NsToC (ns) + "_get_mono_assembly (void)");
163                 Cindex.WriteLine ("{");
164                 Cindex.WriteLine ("static MonoAssembly *assembly = NULL;");
165                 Cindex.WriteLine ("assembly = mono_domain_assembly_open (" + NsToC (ns) + "_get_mono_domain (), \"" + dllname + "\");");
166                 Cindex.WriteLine ();
167
168                 Cindex.WriteLine ("return assembly;");
169                 Cindex.WriteLine ("}");
170
171
172                 foreach (Type t in types)
173                         TypeGen (t);
174
175                 Hindex.WriteLine ();
176                 Hindex.WriteLine ("#endif /* " + Hindex_id + " */");
177                 
178                 Hdecls.WriteLine ();
179                 Hdecls.WriteLine ("#endif /* " + Hdecls_id + " */");
180
181                 Cindex.Close ();
182                 Hindex.Close ();
183                 Hdecls.Close ();
184         }
185
186         static void TypeGen (Type t)
187         {
188                 //TODO: we only handle ordinary classes for now
189                 /*
190                   else if (t.IsSubclassOf (typeof (Delegate))) {
191                         Console.WriteLine ("Ignoring delegate: " + t.Name);
192                         return;
193                 }
194                 */
195
196                 cur_type = NsToC (ns) + "_" + CamelToC (t.Name);
197                 CurType = NsToFlat (ns) + t.Name;
198
199                 //ns = t.Namespace;
200                 string fname = NsToFlat (ns).ToLower () + t.Name.ToLower ();
201                 C = new CodeWriter (target_dir + fname + ".c");
202                 H = new CodeWriter (target_dir + fname + ".h");
203                 Hindex.WriteLine ("#include <" + fname + ".h" + ">");
204
205
206                 string H_id = "__" + NsToFlat (ns).ToUpper () + "_" + t.Name.ToUpper () + "_H__";
207                 H.WriteLine ("#ifndef " + H_id);
208                 H.WriteLine ("#define " + H_id);
209                 H.WriteLine ();
210
211                 H.WriteLine ("#include <glib.h>");
212                 H.WriteLine ("#include <glib-object.h>");
213                 H.WriteLine ("#include <mono/metadata/object.h>");
214                 H.WriteLine ("#include <mono/metadata/debug-helpers.h>");
215                 H.WriteLine ("#include <mono/metadata/appdomain.h>");
216                 H.WriteLine ();
217                 
218                 if (IsRegistered (t.BaseType))
219                         H.WriteLine ("#include \"" + NsToFlat (t.BaseType.Namespace).ToLower () + t.BaseType.Name.ToLower () + ".h\"");
220
221                 //H.WriteLine ("#include \"" + NsToFlat (t.Namespace).ToLower () + "-decls.h\"");
222                 foreach (string ext_ns in namespaces)
223                         H.WriteLine ("#include \"" + NsToFlat (ext_ns).ToLower () + "-decls.h\"");
224
225                 H.WriteLine ();
226
227                 H.WriteLine ("#ifdef __cplusplus");
228                 H.WriteLine ("extern \"C\" {");
229                 H.WriteLine ("#endif /* __cplusplus */");
230                 H.WriteLine ();
231
232                 C.WriteLine ("#include \"" + fname + ".h" + "\"");
233                 C.WriteLine ();
234
235                 if (t.IsClass)
236                         ClassGen (t);
237                 //else if (t.IsEnum)
238                 //      EnumGen (t);
239
240                 H.WriteLine ();
241                 H.WriteLine ("#ifdef __cplusplus");
242                 H.WriteLine ("}");
243                 H.WriteLine ("#endif /* __cplusplus */");
244                 H.WriteLine ();
245
246                 H.WriteLine ("#endif /* " + H_id + " */");
247
248                 C.Close ();
249                 H.Close ();
250         }
251
252         static void EnumGen (Type t)
253         {
254                 //TODO: we needn't split out each enum into its own file
255                 //TODO: just use glib-mkenums
256
257                 C.WriteLine ("GType " + cur_type + "_get_type (void)");
258                 C.WriteLine ("{");
259                 C.WriteLine ("static GType etype = 0;");
260                 C.WriteLine ("etype = g_enum_register_static (\"" + "\", NULL);");
261                 C.WriteLine ("return etype;");
262                 C.WriteLine ("}");
263         }
264
265         static void ClassGen (Type t)
266         {
267                 //TODO: what flags do we want for GetEvents and GetConstructors?
268
269                 //events as signals
270                 EventInfo[] events;
271                 events = t.GetEvents (BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
272
273
274                 H.WriteLine ("G_BEGIN_DECLS");
275                 H.WriteLine ();
276                 
277                 {
278                         string NS = NsToC (ns).ToUpper ();
279                         string T = CamelToC (t.Name).ToUpper ();
280                         string NST = NS + "_" + T;
281                         string NSTT = NS + "_TYPE_" + T;
282
283                         H.WriteLine ("#define " + NSTT + " (" + cur_type + "_get_type ())");
284                         H.WriteLine ("#define " + NST + "(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), " + NSTT + ", " + CurType + "))");
285                         H.WriteLine ("#define " + NST + "_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), " + NSTT + ", " + CurType + "Class))");
286                         H.WriteLine ("#define " + NS + "_IS_" + T + "(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), " + NSTT + "))");
287                         H.WriteLine ("#define " + NS + "_IS_" + T + "_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), " + NSTT + "))");
288                         H.WriteLine ("#define " + NST + "_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), " + NSTT + ", " + CurType + "Class))");
289                 }
290                 
291                 if (!C.IsDuplicate) {
292                         Hdecls.WriteLine ("typedef struct _" + CurType + " " + CurType + ";");
293                         Hdecls.WriteLine ("typedef struct _" + CurType + "Class " + CurType + "Class;");
294                         Hdecls.WriteLine ();
295                 }
296
297                 H.WriteLine ();
298                 //H.WriteLine ("typedef struct _" + CurType + " " + CurType + ";");
299                 
300                 //H.WriteLine ();
301                 //H.WriteLine ("typedef struct _" + CurType + "Class " + CurType + "Class;");
302                 H.WriteLine ("typedef struct _" + CurType + "Private " + CurType + "Private;");
303                 H.WriteLine ();
304                 H.WriteLine ("struct _" + CurType);
305                 H.WriteLine ("{");
306
307                 string ParentName;
308                 if (IsRegistered (t.BaseType))
309                         ParentName = NsToFlat (t.BaseType.Namespace) + t.BaseType.Name;
310                 else
311                         ParentName = "GObject";
312
313                 //H.WriteLine ("GObject parent_instance;");
314                 H.WriteLine (ParentName + " parent_instance;");
315                 H.WriteLine (CurType + "Private *priv;");
316                 H.WriteLine ("};");
317                 H.WriteLine ();
318                 H.WriteLine ("struct _" + CurType + "Class");
319                 H.WriteLine ("{");
320                 H.WriteLine (ParentName + "Class parent_class;" + " /* inherits " + t.BaseType.Namespace + " " + t.BaseType.Name + " */");
321                 H.WriteLine ();
322                 
323                 //TODO: event arguments
324                 foreach (EventInfo ei in events)
325                         H.WriteLine ("void (* " + CamelToC (ei.Name) + ") (" + CurType + " *thiz" + ");");
326                 
327                 H.WriteLine ("};");
328                 H.WriteLine ();
329
330                 //generate c file
331
332                 //private struct
333                 C.WriteLine ("struct _" + CurType + "Private");
334                 C.WriteLine ("{");
335                 C.WriteLine ("MonoObject *mono_object;");
336                 C.WriteLine ("};");
337
338                 C.WriteLine ();
339
340                 //events
341                 if (events.Length != 0) {
342                         C.WriteLine ("enum {");
343
344                         foreach (EventInfo ei in events)
345                                 C.WriteLine (CamelToC (ei.Name).ToUpper () + ",");
346
347                         C.WriteLine ("LAST_SIGNAL");
348                         C.WriteLine ("};");
349                         C.WriteLine ();
350                 }
351
352
353                 //TODO: if the class inherits a known GLib Object, use its raw handle
354                 C.WriteLine ("static gpointer parent_class;");
355                 
356                 if (events.Length == 0)
357                         C.WriteLine ("static guint signals[0];");
358                 else
359                         C.WriteLine ("static guint signals[LAST_SIGNAL] = { 0 };");
360                 C.WriteLine ();
361
362                 C.WriteLine ("static MonoClass *" + cur_type + "_get_mono_class (void)");
363                 C.WriteLine ("{");
364                 C.WriteLine ("MonoAssembly *assembly;");
365                 C.WriteLine ("static MonoClass *class = NULL;");
366                 C.WriteLine ("if (class != NULL) return class;");
367
368                 C.WriteLine ("assembly = (MonoAssembly*) " + NsToC (ns) + "_get_mono_assembly ();");
369                 C.WriteLine ("class = (MonoClass*) mono_class_from_name ((MonoImage*) mono_assembly_get_image (assembly)" + ", \"" + ns + "\", \"" + t.Name + "\");");
370
371                 C.WriteLine ("mono_class_init (class);");
372                 C.WriteLine ();
373
374                 C.WriteLine ("return class;");
375                 C.WriteLine ("}");
376
377                 C.WriteLine ();
378
379                 //generate the GObject init function
380                 C.WriteLine ("static void " + cur_type + "_init (" + CurType + " *thiz" + ")");
381                 C.WriteLine ("{");
382                 C.WriteLine ("thiz->priv = g_new0 (" + CurType + "Private, 1);");
383                 C.WriteLine ("}");
384
385                 C.WriteLine ();
386         
387                 
388                 //generate the GObject class init function
389                 C.WriteLine ("static void " + cur_type + "_class_init (" + CurType + "Class *klass" + ")");
390                 C.WriteLine ("{");
391
392                 C.WriteLine ("GObjectClass *object_class = G_OBJECT_CLASS (klass);");
393                 C.WriteLine ("parent_class = g_type_class_peek_parent (klass);");
394                 //C.WriteLine ("object_class->finalize = _finalize;");
395
396                 foreach (EventInfo ei in events)
397                         EventGen (ei, t);
398                 
399                 C.WriteLine ("}");
400                 
401                 C.WriteLine ();
402
403
404                 //generate the GObject get_type function
405                 C.WriteLine ("GType " + cur_type + "_get_type (void)", H, ";");
406                 C.WriteLine ("{");
407                 C.WriteLine ("static GType object_type = 0;");
408                 C.WriteLine ("g_type_init ();");
409                 C.WriteLine ();
410                 C.WriteLine ("if (object_type) return object_type;");
411                 C.WriteLine ();
412                 C.WriteLine ("static const GTypeInfo object_info =");
413                 C.WriteLine ("{");
414                 C.WriteLine ("sizeof (" + CurType + "Class),");
415                 C.WriteLine ("(GBaseInitFunc) NULL,");
416                 C.WriteLine ("(GBaseFinalizeFunc) NULL,");
417                 C.WriteLine ("(GClassInitFunc) " + cur_type + "_class_init,");
418                 C.WriteLine ("NULL, /* class_finalize */");
419                 C.WriteLine ("NULL, /* class_data */");
420                 C.WriteLine ("sizeof (" + CurType + "),");
421                 C.WriteLine ("0, /* n_preallocs */");
422                 C.WriteLine ("(GInstanceInitFunc) " + cur_type + "_init,");
423                 C.WriteLine ("};");
424                 C.WriteLine ();
425                 
426                 string parent_type = "G_TYPE_OBJECT";
427                 if (IsRegistered (t.BaseType))
428                         parent_type = NsToC (t.BaseType.Namespace).ToUpper () + "_TYPE_" + CamelToC (t.BaseType.Name).ToUpper ();
429
430                 C.WriteLine ("object_type = g_type_register_static (" + parent_type + ", \"" + CurType + "\", &object_info, 0);");
431                 C.WriteLine ();
432                 C.WriteLine ("return object_type;");
433                 C.WriteLine ("}");
434
435
436                 //generate constructors
437                 ConstructorInfo[] constructors;
438                 constructors = t.GetConstructors ();
439                 foreach (ConstructorInfo c in constructors)
440                         ConstructorGen (c, t);
441
442                 //generate static methods
443                 MethodInfo[] methods;
444                 methods = t.GetMethods (BindingFlags.Public|BindingFlags.Static|BindingFlags.DeclaredOnly);
445                 foreach (MethodInfo m in methods)
446                         MethodGen (m, t);
447
448                 //generate instance methods
449                 methods = t.GetMethods (BindingFlags.Public|BindingFlags.Instance|BindingFlags.DeclaredOnly);
450                 foreach (MethodInfo m in methods)
451                         MethodGen (m, t);
452         
453                 H.WriteLine ();
454                 H.WriteLine ("G_END_DECLS");
455         }
456
457         //FIXME: this won't work in the general case. arraylist should contain just type names, not Types
458         static ArrayList registered_types = new ArrayList ();
459         static Hashtable registry_hits = new Hashtable ();
460
461         static bool IsRegistered (Type t)
462         {
463                 bool isreg = registered_types.Contains (t);
464
465                 //TODO: use our list of supported primitive types instead
466                 if (!isreg && !t.IsPrimitive) {
467                         if (!registry_hits.Contains (t.Namespace)) {
468                                 int count = 0;
469                                 registry_hits[t.Namespace] = count;
470                         }
471
472                         registry_hits[t.Namespace] = (int) registry_hits[t.Namespace] + 1;
473                 }
474
475                 return isreg;
476         }
477         
478         static void RegisterCsType (Type t)
479         {
480                 if (IsRegistered (t))
481                         return;
482
483                 registered_types.Add (t);
484         }
485
486         static string CsTypeToC (Type t)
487         {
488                 //TODO: use this method everywhere
489
490                 //if (t.Namespace == ns)
491                 if (IsRegistered (t))
492                         return NsToFlat (t.Namespace) + t.Name + " *";
493                 
494                 string ptype = "MonoClass *";
495
496                 switch (t.FullName)
497                 {
498                         case "System.String":
499                                 ptype = "const gchar *";
500                         break;
501
502                         case "System.Int32":
503                                 ptype = "gint ";
504                         break;
505                 }
506
507                 return ptype;
508         }
509
510         static void EventGen (EventInfo ei, Type t)
511         {
512                 //Console.WriteLine ("TODO: event: " + ei.Name);
513                 //Console.WriteLine ("\t" + CamelToC (ei.Name));
514                 string name = CamelToC (ei.Name);
515
516                 C.WriteLine ();
517                 C.WriteLine ("signals[" + name.ToUpper () + "] = g_signal_new (");
518                 C.WriteLine ("\"" + name + "\",");
519                 C.WriteLine ("G_OBJECT_CLASS_TYPE (object_class),");
520                 C.WriteLine ("G_SIGNAL_RUN_LAST,");
521                 C.WriteLine ("G_STRUCT_OFFSET (" + CurType + "Class" + ", " + name + "),");
522                 C.WriteLine ("NULL, NULL,");
523                 C.WriteLine ("g_cclosure_marshal_VOID__VOID,");
524                 C.WriteLine ("G_TYPE_NONE, 0");
525                 C.WriteLine (");");
526         }
527
528         static void ConstructorGen (ConstructorInfo c, Type t)
529         {
530                 ParameterInfo[] parameters = c.GetParameters ();
531                 FunctionGen (parameters, (MethodBase) c, t, null, true);
532         }
533
534         static void MethodGen (MethodInfo m, Type t)
535         {
536                 ParameterInfo[] parameters = m.GetParameters ();
537                 FunctionGen (parameters, (MethodBase) m, t, m.ReturnType, false);
538         }
539
540         static string ToValidFuncName (string name)
541         {
542                 //avoid generated function name conflicts with internal functions
543
544                 switch (name.ToLower ()) {
545                         case "init":
546                                 return "initialize";
547                         case "class_init":
548                                 return "class_initialize";
549                         case "get_type":
550                                 return "retrieve_type";
551                         default:
552                                 return name;
553                 }
554         }
555
556         static void FunctionGen (ParameterInfo[] parameters, MethodBase m, Type t, Type ret_type, bool ctor)
557         {
558                 string myargs = "";
559
560                 bool has_return = false;
561                 bool stat = false;
562                 bool inst = false;
563
564                 if (ctor) {
565                         has_return = true;
566                         stat = true;
567                 }
568                 else {
569                         stat = m.IsStatic;
570                 }
571                 
572                 inst = !stat;
573
574                 string mytype;
575                 mytype = CurType + " *";
576
577                 /*
578                    Console.WriteLine (ret_type);
579                    if (ret_type != null && ret_type != typeof (Void)) {
580                    has_return = true;
581                 //TODO: return simple gint or gchar if possible
582                 mytype = "MonoObject *";
583                 }
584                  */
585
586                 string params_arg = "NULL";
587                 if (parameters.Length != 0)
588                         params_arg = "_mono_params";
589
590                 string instance = "thiz";
591                 string instance_arg = instance + "->priv->mono_object";
592
593                 //TODO: also check, !static
594                 if (inst) {
595                         myargs = mytype + instance;
596                         if (parameters.Length > 0) myargs += ", ";
597                 }
598
599                 string myname;
600
601                 myname = cur_type + "_";
602                 if (ctor)
603                         myname += "new";
604                 else
605                         myname += ToValidFuncName (CamelToC (m.Name));
606
607                 //handle overloaded methods
608                 //TODO: generate an alias function for the default ctor etc.
609                 
610                 //TODO: how do we choose the default ctor/method overload? perhaps the
611                 //first/shortest, but we need scope for this
612                 //perhaps use DefaultMemberAttribute, Type.GetDefaultMembers
613
614                 if (funcs_done.Contains (myname)) {
615                         for (int i = 0 ; i < parameters.Length ; i++) {
616                                 ParameterInfo p = parameters[i];
617
618                                 if (i == 0)
619                                         myname += "_with_";
620                                 else if (i != parameters.Length - 1)
621                                         myname += "_and_";
622
623                                 myname += p.Name;
624                         }
625                 }
626
627                 if (funcs_done.Contains (myname))
628                         return;
629
630                 funcs_done.Add (myname);
631                 
632                 //handle the parameters
633                 string param_assign = "";
634                 string mycsargs = "";
635
636                 for (int i = 0 ; i < parameters.Length ; i++) {
637                         ParameterInfo p = parameters[i];
638                         mycsargs += GetMonoType (Type.GetTypeCode (p.ParameterType));
639                         myargs += CsTypeToC (p.ParameterType) + p.Name;
640                         if (i != parameters.Length - 1) {
641                                 mycsargs += ",";
642                                 myargs += ", ";
643                         }
644                 }
645
646                 if (myargs == "") myargs = "void";
647
648                 C.WriteLine ();
649
650                 if (has_return)
651                         C.WriteLine (mytype + myname + " (" + myargs + ")", H, ";");
652                 else
653                         C.WriteLine ("void " + myname + " (" + myargs + ")", H, ";");
654
655                 C.WriteLine ("{");
656
657                 C.WriteLine ("static MonoMethod *_mono_method = NULL;");
658                 if (parameters.Length != 0) C.WriteLine ("gpointer " + params_arg + "[" + parameters.Length + "];");
659                 if (ctor) {
660                         C.WriteLine (CurType + " *" + instance + ";");
661                         C.WriteLine ();
662                         C.WriteLine (instance + " = g_object_new (" + NsToC (ns).ToUpper () + "_TYPE_" + CamelToC (t.Name).ToUpper () + ", NULL);");
663                 }
664
665                 C.WriteLine ();
666
667                 C.WriteLine ("if (_mono_method == NULL) {");
668
669                 //if (ctor) C.WriteLine ("MonoMethodDesc *_mono_method_desc = mono_method_desc_new (\":.ctor()\", FALSE);");
670                 if (ctor) C.WriteLine ("MonoMethodDesc *_mono_method_desc = mono_method_desc_new (\":.ctor(" + mycsargs + ")\", FALSE);");
671                 else {
672                         C.WriteLine ("MonoMethodDesc *_mono_method_desc = mono_method_desc_new (\":" + m.Name + "(" + mycsargs + ")" + "\", FALSE);");
673                 }
674
675                 C.WriteLine ("_mono_method = mono_method_desc_search_in_class (_mono_method_desc, " + cur_type + "_get_mono_class ());");
676
677                 C.WriteLine ("}");
678                 C.WriteLine ();
679
680                 //assign the parameters
681                 for (int i = 0 ; i < parameters.Length ; i++) {
682                         ParameterInfo p = parameters[i];
683                         C.WriteLine  (params_arg + "[" + i + "] = " + GetMonoVal (p.Name, p.ParameterType.ToString ()) + ";");
684                 }
685                 if (parameters.Length != 0) C.WriteLine ();
686
687                 if (ctor) C.WriteLine (instance_arg + " = (MonoObject*) mono_object_new ((MonoDomain*) " + NsToC (ns) + "_get_mono_domain ()" + ", " + cur_type + "_get_mono_class ());");
688
689                 //invoke the method
690                 
691                 if (ctor || inst)
692                         C.WriteLine ("mono_runtime_invoke (_mono_method, " + instance_arg + ", " + params_arg + ", NULL);");
693                 else
694                         C.WriteLine ("mono_runtime_invoke (_mono_method, " + "NULL" + ", " + params_arg + ", NULL);");
695
696                 if (ctor) C.WriteLine ("return " + instance + ";");
697
698                 C.WriteLine ("}");
699         }
700
701         static string GetMonoType (TypeCode tc)
702         {
703                 //see mcs/class/corlib/System/TypeCode.cs
704                 //see mono/mono/dis/get.c
705
706                 switch (tc)
707                 {
708                         case TypeCode.Int32:
709                                 return "int";
710
711                         case TypeCode.String:
712                                 return "string";
713
714                         default:
715                                 return tc.ToString ();
716                 }
717         }
718
719         static string GetMonoVal (string name, string type)
720         {
721                 switch (type) {
722                         case "System.String":
723                                 return "(gpointer*) mono_string_new ((MonoDomain*) mono_domain_get (), " + name + ")";
724
725                         case "System.Int32":
726                                 return "&" + name;
727
728                         default:
729                         return "&" + name;
730                 }
731         }
732
733         static string NsToC (string s)
734         {
735                 s = s.Replace ('.', '_');
736                 return CamelToC (s);
737         }
738
739         static string NsToFlat (string s)
740         {
741                 s = s.Replace (".", "");
742                 return s;
743         }
744
745         static string CamelToC (string s)
746         {
747                 //converts camel case to c-style
748
749                 string o = "";
750
751                 bool prev_is_cap = true;
752
753                 foreach  (char c in s) {
754                         char cl = c.ToString ().ToLower ()[0];
755                         bool is_cap = c != cl;
756
757                         if (!prev_is_cap && is_cap) {
758                                 o += "_";
759                         }
760
761                         o += cl;
762                         prev_is_cap = is_cap;
763
764                         if (c == '_')
765                                 prev_is_cap = true;
766                 }
767
768                 return o;
769         }
770 }
771
772 class CodeWriter
773 {
774         private StreamWriter w;
775
776         public CodeWriter (string fname)
777         {
778                 Init (fname);
779         }
780
781         public bool IsDuplicate = false;
782
783         void Init (string fname)
784         {
785                 if (File.Exists (fname)) {
786                         string newfname = fname + ".x";
787                         Console.WriteLine ("Warning: File " + fname + " already exists, using " + newfname);
788                         IsDuplicate = true;
789                         Init (newfname);
790                         return;
791                 }
792
793                 FileStream fs = new FileStream (fname, FileMode.OpenOrCreate, FileAccess.Write);
794                 w = new StreamWriter (fs);
795         }
796
797         public string Indenter = "  ";
798         string cur_indent = "";
799         int level = 0;
800
801         public void Indent ()
802         {
803                 level++;
804                 cur_indent = "";
805                 for (int i = 0; i != level ; i++) cur_indent += Indenter;
806         }
807
808         public void Outdent ()
809         {
810                 level--;
811                 cur_indent = "";
812                 for (int i = 0; i != level ; i++) cur_indent += Indenter;
813         }
814
815         public void Write (string text)
816         {
817                 w.Write (text);
818         }
819
820         public void WriteLine (string text)
821         {
822                 char[] opentags = {'{', '('};
823                 char[] closetags = {'}', ')'};
824
825                 if (text.TrimStart (closetags) != text)
826                         Outdent ();
827
828                 w.Write (cur_indent);
829                 w.WriteLine (text);
830
831                 if (text.TrimEnd (opentags) != text)
832                         Indent ();
833         }
834
835         public void WriteLine (string text, CodeWriter cc)
836         {
837                 WriteLine (text, "", cc, "");
838         }
839
840         public void WriteLine (string text, CodeWriter cc, string suffix)
841         {
842                 WriteLine (text, "", cc, suffix);
843         }
844
845         public void WriteLine (string text, string prefix, CodeWriter cc)
846         {
847                 WriteLine (text, prefix, cc, "");
848         }
849
850         public void WriteLine (string text, string prefix, CodeWriter cc, string suffix)
851         {
852                 WriteLine (text);
853                 cc.WriteLine (prefix + text + suffix);
854         }
855
856         public void WriteComment (string text)
857         {
858                 w.WriteLine ("/* " + text + " */");
859         }
860
861         public void WriteLine ()
862         {
863                 w.WriteLine ("");
864         }
865
866         public void Close ()
867         {
868                 w.Flush ();
869                 w.Close ();
870         }
871 }