diff options
Diffstat (limited to 'Source/Modules/csharp.cxx')
| -rw-r--r-- | Source/Modules/csharp.cxx | 3960 |
1 files changed, 3960 insertions, 0 deletions
diff --git a/Source/Modules/csharp.cxx b/Source/Modules/csharp.cxx new file mode 100644 index 0000000..5713257 --- /dev/null +++ b/Source/Modules/csharp.cxx @@ -0,0 +1,3960 @@ +/* ----------------------------------------------------------------------------- + * See the LICENSE file for information on copyright, usage and redistribution + * of SWIG, and the README file for authors - http://www.swig.org/release.html. + * + * csharp.cxx + * + * C# language module for SWIG. + * ----------------------------------------------------------------------------- */ + +char cvsroot_csharp_cxx[] = "$Id: csharp.cxx 11583 2009-08-15 23:22:20Z wsfulton $"; + +#include "swigmod.h" +#include <limits.h> // for INT_MAX +#include "cparse.h" +#include <ctype.h> + +/* Hash type used for upcalls from C/C++ */ +typedef DOH UpcallData; + +class CSHARP:public Language { + static const char *usage; + const String *empty_string; + const String *public_string; + const String *protected_string; + + Hash *swig_types_hash; + File *f_begin; + File *f_runtime; + File *f_runtime_h; + File *f_header; + File *f_wrappers; + File *f_init; + File *f_directors; + File *f_directors_h; + List *filenames_list; + + bool proxy_flag; // Flag for generating proxy classes + bool native_function_flag; // Flag for when wrapping a native function + bool enum_constant_flag; // Flag for when wrapping an enum or constant + bool static_flag; // Flag for when wrapping a static functions or member variables + bool variable_wrapper_flag; // Flag for when wrapping a nonstatic member variable + bool wrapping_member_flag; // Flag for when wrapping a member variable/enum/const + bool global_variable_flag; // Flag for when wrapping a global variable + bool old_variable_names; // Flag for old style variable names in the intermediary class + bool generate_property_declaration_flag; // Flag for generating properties + + String *imclass_name; // intermediary class name + String *module_class_name; // module class name + String *imclass_class_code; // intermediary class code + String *proxy_class_def; + String *proxy_class_code; + String *module_class_code; + String *proxy_class_name; + String *variable_name; //Name of a variable being wrapped + String *proxy_class_constants_code; + String *module_class_constants_code; + String *enum_code; + String *dllimport; // DllImport attribute name + String *namespce; // Optional namespace name + String *imclass_imports; //intermediary class imports from %pragma + String *module_imports; //module imports from %pragma + String *imclass_baseclass; //inheritance for intermediary class class from %pragma + String *module_baseclass; //inheritance for module class from %pragma + String *imclass_interfaces; //interfaces for intermediary class class from %pragma + String *module_interfaces; //interfaces for module class from %pragma + String *imclass_class_modifiers; //class modifiers for intermediary class overriden by %pragma + String *module_class_modifiers; //class modifiers for module class overriden by %pragma + String *upcasts_code; //C++ casts for inheritance hierarchies C++ code + String *imclass_cppcasts_code; //C++ casts up inheritance hierarchies intermediary class code + String *director_callback_typedefs; // Director function pointer typedefs for callbacks + String *director_callbacks; // Director callback function pointer member variables + String *director_delegate_callback; // Director callback method that delegates are set to call + String *director_delegate_definitions; // Director delegates definitions in proxy class + String *director_delegate_instances; // Director delegates member variables in proxy class + String *director_method_types; // Director method types + String *director_connect_parms; // Director delegates parameter list for director connect call + String *destructor_call; //C++ destructor call if any + + // Director method stuff: + List *dmethods_seq; + Hash *dmethods_table; + int n_dmethods; + int n_directors; + int first_class_dmethod; + int curr_class_dmethod; + + enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum }; + + static Parm *NewParmFromNode(SwigType *type, const_String_or_char_ptr name, Node *n) { + Parm *p = NewParm(type, name); + Setfile(p, Getfile(n)); + Setline(p, Getline(n)); + return p; + } + +public: + + /* ----------------------------------------------------------------------------- + * CSHARP() + * ----------------------------------------------------------------------------- */ + + CSHARP():empty_string(NewString("")), + public_string(NewString("public")), + protected_string(NewString("protected")), + swig_types_hash(NULL), + f_begin(NULL), + f_runtime(NULL), + f_runtime_h(NULL), + f_header(NULL), + f_wrappers(NULL), + f_init(NULL), + f_directors(NULL), + f_directors_h(NULL), + filenames_list(NULL), + proxy_flag(true), + native_function_flag(false), + enum_constant_flag(false), + static_flag(false), + variable_wrapper_flag(false), + wrapping_member_flag(false), + global_variable_flag(false), + old_variable_names(false), + generate_property_declaration_flag(false), + imclass_name(NULL), + module_class_name(NULL), + imclass_class_code(NULL), + proxy_class_def(NULL), + proxy_class_code(NULL), + module_class_code(NULL), + proxy_class_name(NULL), + variable_name(NULL), + proxy_class_constants_code(NULL), + module_class_constants_code(NULL), + enum_code(NULL), + dllimport(NULL), + namespce(NULL), + imclass_imports(NULL), + module_imports(NULL), + imclass_baseclass(NULL), + module_baseclass(NULL), + imclass_interfaces(NULL), + module_interfaces(NULL), + imclass_class_modifiers(NULL), + module_class_modifiers(NULL), + upcasts_code(NULL), + imclass_cppcasts_code(NULL), + director_callback_typedefs(NULL), + director_callbacks(NULL), + director_delegate_callback(NULL), + director_delegate_definitions(NULL), + director_delegate_instances(NULL), + director_method_types(NULL), + director_connect_parms(NULL), + destructor_call(NULL), + dmethods_seq(NULL), + dmethods_table(NULL), + n_dmethods(0), + n_directors(0) { + /* for now, multiple inheritance in directors is disabled, this + should be easy to implement though */ + director_multiple_inheritance = 0; + director_language = 1; + } + + /* ----------------------------------------------------------------------------- + * getProxyName() + * + * Test to see if a type corresponds to something wrapped with a proxy class + * Return NULL if not otherwise the proxy class name + * ----------------------------------------------------------------------------- */ + + String *getProxyName(SwigType *t) { + if (proxy_flag) { + Node *n = classLookup(t); + if (n) { + return Getattr(n, "sym:name"); + } + } + return NULL; + } + + /* ----------------------------------------------------------------------------- + * directorClassName() + * ----------------------------------------------------------------------------- */ + + String *directorClassName(Node *n) { + String *dirclassname; + const char *attrib = "director:classname"; + + if (!(dirclassname = Getattr(n, attrib))) { + String *classname = Getattr(n, "sym:name"); + + dirclassname = NewStringf("SwigDirector_%s", classname); + Setattr(n, attrib, dirclassname); + } + + return dirclassname; + } + + /* ------------------------------------------------------------ + * main() + * ------------------------------------------------------------ */ + + virtual void main(int argc, char *argv[]) { + + SWIG_library_directory("csharp"); + + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i], "-dllimport") == 0) { + if (argv[i + 1]) { + dllimport = NewString(""); + Printf(dllimport, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i], "-namespace") == 0) { + if (argv[i + 1]) { + namespce = NewString(""); + Printf(namespce, argv[i + 1]); + Swig_mark_arg(i); + Swig_mark_arg(i + 1); + i++; + } else { + Swig_arg_error(); + } + } else if ((strcmp(argv[i], "-noproxy") == 0)) { + Swig_mark_arg(i); + proxy_flag = false; + } else if (strcmp(argv[i], "-oldvarnames") == 0) { + Swig_mark_arg(i); + old_variable_names = true; + } else if (strcmp(argv[i], "-help") == 0) { + Printf(stdout, "%s\n", usage); + } + } + } + + // Add a symbol to the parser for conditional compilation + Preprocessor_define("SWIGCSHARP 1", 0); + + // Add typemap definitions + SWIG_typemap_lang("csharp"); + SWIG_config_file("csharp.swg"); + + allow_overloading(); + } + + /* --------------------------------------------------------------------- + * top() + * --------------------------------------------------------------------- */ + + virtual int top(Node *n) { + + // Get any options set in the module directive + Node *optionsnode = Getattr(Getattr(n, "module"), "options"); + + if (optionsnode) { + if (Getattr(optionsnode, "imclassname")) + imclass_name = Copy(Getattr(optionsnode, "imclassname")); + /* check if directors are enabled for this module. note: this + * is a "master" switch, without which no director code will be + * emitted. %feature("director") statements are also required + * to enable directors for individual classes or methods. + * + * use %module(directors="1") modulename at the start of the + * interface file to enable director generation. + */ + if (Getattr(optionsnode, "directors")) { + allow_directors(); + } + if (Getattr(optionsnode, "dirprot")) { + allow_dirprot(); + } + allow_allprotected(GetFlag(optionsnode, "allprotected")); + } + + /* Initialize all of the output files */ + String *outfile = Getattr(n, "outfile"); + String *outfile_h = Getattr(n, "outfile_h"); + + if (!outfile) { + Printf(stderr, "Unable to determine outfile\n"); + SWIG_exit(EXIT_FAILURE); + } + + f_begin = NewFile(outfile, "w", SWIG_output_files()); + if (!f_begin) { + FileErrorDisplay(outfile); + SWIG_exit(EXIT_FAILURE); + } + + if (directorsEnabled()) { + if (!outfile_h) { + Printf(stderr, "Unable to determine outfile_h\n"); + SWIG_exit(EXIT_FAILURE); + } + f_runtime_h = NewFile(outfile_h, "w", SWIG_output_files()); + if (!f_runtime_h) { + FileErrorDisplay(outfile_h); + SWIG_exit(EXIT_FAILURE); + } + } + + f_runtime = NewString(""); + f_init = NewString(""); + f_header = NewString(""); + f_wrappers = NewString(""); + f_directors_h = NewString(""); + f_directors = NewString(""); + + /* Register file targets with the SWIG file handler */ + Swig_register_filebyname("header", f_header); + Swig_register_filebyname("wrapper", f_wrappers); + Swig_register_filebyname("begin", f_begin); + Swig_register_filebyname("runtime", f_runtime); + Swig_register_filebyname("init", f_init); + Swig_register_filebyname("director", f_directors); + Swig_register_filebyname("director_h", f_directors_h); + + swig_types_hash = NewHash(); + filenames_list = NewList(); + + // Make the intermediary class and module class names. The intermediary class name can be set in the module directive. + if (!imclass_name) { + imclass_name = NewStringf("%sPINVOKE", Getattr(n, "name")); + module_class_name = Copy(Getattr(n, "name")); + } else { + // Rename the module name if it is the same as intermediary class name - a backwards compatibility solution + if (Cmp(imclass_name, Getattr(n, "name")) == 0) + module_class_name = NewStringf("%sModule", Getattr(n, "name")); + else + module_class_name = Copy(Getattr(n, "name")); + } + + imclass_class_code = NewString(""); + proxy_class_def = NewString(""); + proxy_class_code = NewString(""); + module_class_constants_code = NewString(""); + imclass_baseclass = NewString(""); + imclass_interfaces = NewString(""); + imclass_class_modifiers = NewString(""); + module_class_code = NewString(""); + module_baseclass = NewString(""); + module_interfaces = NewString(""); + module_imports = NewString(""); + module_class_modifiers = NewString(""); + imclass_imports = NewString(""); + imclass_cppcasts_code = NewString(""); + director_connect_parms = NewString(""); + upcasts_code = NewString(""); + dmethods_seq = NewList(); + dmethods_table = NewHash(); + n_dmethods = 0; + n_directors = 0; + if (!namespce) + namespce = NewString(""); + if (!dllimport) + dllimport = Copy(module_class_name); + + Swig_banner(f_begin); + + Printf(f_runtime, "\n"); + Printf(f_runtime, "#define SWIGCSHARP\n"); + + if (directorsEnabled()) { + Printf(f_runtime, "#define SWIG_DIRECTORS\n"); + + /* Emit initial director header and director code: */ + Swig_banner(f_directors_h); + Printf(f_directors_h, "\n"); + Printf(f_directors_h, "#ifndef SWIG_%s_WRAP_H_\n", module_class_name); + Printf(f_directors_h, "#define SWIG_%s_WRAP_H_\n\n", module_class_name); + + Printf(f_directors, "\n\n"); + Printf(f_directors, "/* ---------------------------------------------------\n"); + Printf(f_directors, " * C++ director class methods\n"); + Printf(f_directors, " * --------------------------------------------------- */\n\n"); + if (outfile_h) + Printf(f_directors, "#include \"%s\"\n\n", Swig_file_filename(outfile_h)); + } + + Printf(f_runtime, "\n"); + + Swig_name_register((char *) "wrapper", (char *) "CSharp_%f"); + if (old_variable_names) { + Swig_name_register((char *) "set", (char *) "set_%v"); + Swig_name_register((char *) "get", (char *) "get_%v"); + } + + Printf(f_wrappers, "\n#ifdef __cplusplus\n"); + Printf(f_wrappers, "extern \"C\" {\n"); + Printf(f_wrappers, "#endif\n\n"); + + /* Emit code */ + Language::top(n); + + if (directorsEnabled()) { + // Insert director runtime into the f_runtime file (make it occur before %header section) + Swig_insert_file("director.swg", f_runtime); + } + // Generate the intermediary class + { + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), imclass_name); + File *f_im = NewFile(filen, "w", SWIG_output_files()); + if (!f_im) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the intermediary class file + emitBanner(f_im); + + addOpenNamespace(namespce, f_im); + + if (imclass_imports) + Printf(f_im, "%s\n", imclass_imports); + + if (Len(imclass_class_modifiers) > 0) + Printf(f_im, "%s ", imclass_class_modifiers); + Printf(f_im, "%s ", imclass_name); + + if (imclass_baseclass && *Char(imclass_baseclass)) + Printf(f_im, ": %s ", imclass_baseclass); + if (Len(imclass_interfaces) > 0) + Printv(f_im, "implements ", imclass_interfaces, " ", NIL); + Printf(f_im, "{\n"); + + // Add the intermediary class methods + Replaceall(imclass_class_code, "$module", module_class_name); + Replaceall(imclass_class_code, "$imclassname", imclass_name); + Replaceall(imclass_class_code, "$dllimport", dllimport); + Printv(f_im, imclass_class_code, NIL); + Printv(f_im, imclass_cppcasts_code, NIL); + + // Finish off the class + Printf(f_im, "}\n"); + addCloseNamespace(namespce, f_im); + + Close(f_im); + } + + // Generate the C# module class + { + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), module_class_name); + File *f_module = NewFile(filen, "w", SWIG_output_files()); + if (!f_module) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the module class file + emitBanner(f_module); + + addOpenNamespace(namespce, f_module); + + if (module_imports) + Printf(f_module, "%s\n", module_imports); + + if (Len(module_class_modifiers) > 0) + Printf(f_module, "%s ", module_class_modifiers); + Printf(f_module, "%s ", module_class_name); + + if (module_baseclass && *Char(module_baseclass)) + Printf(f_module, ": %s ", module_baseclass); + if (Len(module_interfaces) > 0) + Printv(f_module, "implements ", module_interfaces, " ", NIL); + Printf(f_module, "{\n"); + + Replaceall(module_class_code, "$module", module_class_name); + Replaceall(module_class_constants_code, "$module", module_class_name); + + Replaceall(module_class_code, "$imclassname", imclass_name); + Replaceall(module_class_constants_code, "$imclassname", imclass_name); + + Replaceall(module_class_code, "$dllimport", dllimport); + Replaceall(module_class_constants_code, "$dllimport", dllimport); + + // Add the wrapper methods + Printv(f_module, module_class_code, NIL); + + // Write out all the global constants + Printv(f_module, module_class_constants_code, NIL); + + // Finish off the class + Printf(f_module, "}\n"); + addCloseNamespace(namespce, f_module); + + Close(f_module); + } + + if (upcasts_code) + Printv(f_wrappers, upcasts_code, NIL); + + Printf(f_wrappers, "#ifdef __cplusplus\n"); + Printf(f_wrappers, "}\n"); + Printf(f_wrappers, "#endif\n"); + + // Output a C# type wrapper class for each SWIG type + for (Iterator swig_type = First(swig_types_hash); swig_type.key; swig_type = Next(swig_type)) { + emitTypeWrapperClass(swig_type.key, swig_type.item); + } + + // Check for overwriting file problems on filesystems that are case insensitive + Iterator it1; + Iterator it2; + for (it1 = First(filenames_list); it1.item; it1 = Next(it1)) { + String *item1_lower = Swig_string_lower(it1.item); + for (it2 = Next(it1); it2.item; it2 = Next(it2)) { + String *item2_lower = Swig_string_lower(it2.item); + if (it1.item && it2.item) { + if (Strcmp(item1_lower, item2_lower) == 0) { + Swig_warning(WARN_LANG_PORTABILITY_FILENAME, input_file, line_number, + "Portability warning: File %s will be overwritten by %s on case insensitive filesystems such as " + "Windows' FAT32 and NTFS unless the class/module name is renamed\n", it1.item, it2.item); + } + } + Delete(item2_lower); + } + Delete(item1_lower); + } + + Delete(swig_types_hash); + swig_types_hash = NULL; + Delete(filenames_list); + filenames_list = NULL; + Delete(imclass_name); + imclass_name = NULL; + Delete(imclass_class_code); + imclass_class_code = NULL; + Delete(proxy_class_def); + proxy_class_def = NULL; + Delete(proxy_class_code); + proxy_class_code = NULL; + Delete(module_class_constants_code); + module_class_constants_code = NULL; + Delete(imclass_baseclass); + imclass_baseclass = NULL; + Delete(imclass_interfaces); + imclass_interfaces = NULL; + Delete(imclass_class_modifiers); + imclass_class_modifiers = NULL; + Delete(module_class_name); + module_class_name = NULL; + Delete(module_class_code); + module_class_code = NULL; + Delete(module_baseclass); + module_baseclass = NULL; + Delete(module_interfaces); + module_interfaces = NULL; + Delete(module_imports); + module_imports = NULL; + Delete(module_class_modifiers); + module_class_modifiers = NULL; + Delete(imclass_imports); + imclass_imports = NULL; + Delete(imclass_cppcasts_code); + imclass_cppcasts_code = NULL; + Delete(upcasts_code); + upcasts_code = NULL; + Delete(dmethods_seq); + dmethods_seq = NULL; + Delete(dmethods_table); + dmethods_table = NULL; + Delete(namespce); + namespce = NULL; + n_dmethods = 0; + + /* Close all of the files */ + Dump(f_runtime, f_begin); + Dump(f_header, f_begin); + + if (directorsEnabled()) { + Dump(f_directors, f_begin); + Dump(f_directors_h, f_runtime_h); + + Printf(f_runtime_h, "\n"); + Printf(f_runtime_h, "#endif\n"); + + Close(f_runtime_h); + Delete(f_runtime_h); + f_runtime_h = NULL; + Delete(f_directors); + f_directors = NULL; + Delete(f_directors_h); + f_directors_h = NULL; + } + + Dump(f_wrappers, f_begin); + Wrapper_pretty_print(f_init, f_begin); + Delete(f_header); + Delete(f_wrappers); + Delete(f_init); + Close(f_begin); + Delete(f_runtime); + Delete(f_begin); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * emitBanner() + * ----------------------------------------------------------------------------- */ + + void emitBanner(File *f) { + Printf(f, "/* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ----------------------------------------------------------------------------- */\n\n"); + } + + /*----------------------------------------------------------------------- + * Add new director upcall signature + *----------------------------------------------------------------------*/ + + UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *decl, String *overloaded_name) { + UpcallData *udata; + String *imclass_methodidx; + String *class_methodidx; + Hash *new_udata; + String *key = NewStringf("%s|%s", imclass_method, decl); + + ++curr_class_dmethod; + + /* Do we know about this director class already? */ + if ((udata = Getattr(dmethods_table, key))) { + Delete(key); + return Getattr(udata, "methodoff"); + } + + imclass_methodidx = NewStringf("%d", n_dmethods); + class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod); + n_dmethods++; + + new_udata = NewHash(); + Append(dmethods_seq, new_udata); + Setattr(dmethods_table, key, new_udata); + + Setattr(new_udata, "method", Copy(class_method)); + // TODO: remove fdesc +// Setattr(new_udata, "fdesc", Copy(class_desc)); +// Setattr(new_udata, "imclass_method", Copy(imclass_method)); +// Setattr(new_udata, "imclass_methodidx", imclass_methodidx); + Setattr(new_udata, "class_methodidx", class_methodidx); + Setattr(new_udata, "decl", Copy(decl)); + Setattr(new_udata, "overname", Copy(overloaded_name)); + + Delete(key); + return new_udata; + } + + /*----------------------------------------------------------------------- + * Get director upcall signature + *----------------------------------------------------------------------*/ + + /* + UpcallData * getUpcallMethodData(String *director_class, String *decl) { + String *key = NewStringf("%s|%s", director_class, decl); + UpcallData *udata = Getattr(dmethods_table, key); + + Delete(key); + return udata; + } + */ + + /* ---------------------------------------------------------------------- + * nativeWrapper() + * ---------------------------------------------------------------------- */ + + virtual int nativeWrapper(Node *n) { + String *wrapname = Getattr(n, "wrap:name"); + + if (!addSymbol(wrapname, n)) + return SWIG_ERROR; + + if (Getattr(n, "type")) { + Swig_save("nativeWrapper", n, "name", NIL); + Setattr(n, "name", wrapname); + native_function_flag = true; + functionWrapper(n); + Swig_restore(n); + native_function_flag = false; + } else { + Printf(stderr, "%s : Line %d. No return type for %%native method %s.\n", input_file, line_number, Getattr(n, "wrap:name")); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * functionWrapper() + * ---------------------------------------------------------------------- */ + + virtual int functionWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *c_return_type = NewString(""); + String *im_return_type = NewString(""); + String *cleanup = NewString(""); + String *outarg = NewString(""); + String *body = NewString(""); + String *im_outattributes = 0; + int num_arguments = 0; + int num_required = 0; + bool is_void_return; + String *overloaded_name = getOverloadedName(n); + + if (!Getattr(n, "sym:overloaded")) { + if (!addSymbol(Getattr(n, "sym:name"), n)) + return SWIG_ERROR; + } + + /* + The rest of this function deals with generating the intermediary class wrapper function (that wraps + a c/c++ function) and generating the PInvoke c code. Each C# wrapper function has a + matching PInvoke c function call. + */ + + // A new wrapper function object + Wrapper *f = NewWrapper(); + + // Make a wrapper name for this function + String *wname = Swig_name_wrapper(overloaded_name); + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("ctype", l, f); + Swig_typemap_attach_parms("imtype", l, f); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("ctype", n, "", 0))) { + String *ctypeout = Getattr(n, "tmap:ctype:out"); // the type in the ctype typemap's out attribute overrides the type in the typemap + if (ctypeout) + tm = ctypeout; + Printf(c_return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if ((tm = Swig_typemap_lookup("imtype", n, "", 0))) { + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + Printf(im_return_type, "%s", tm); + im_outattributes = Getattr(n, "tmap:imtype:outattributes"); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(t, 0)); + } + + is_void_return = (Cmp(c_return_type, "void") == 0); + if (!is_void_return) + Wrapper_add_localv(f, "jresult", c_return_type, "jresult", NIL); + + Printv(f->def, " SWIGEXPORT ", c_return_type, " SWIGSTDCALL ", wname, "(", NIL); + + // Emit all of the local variables for holding arguments. + emit_parameter_variables(l, f); + + /* Attach the standard typemaps */ + emit_attach_parmmaps(l, f); + + // Parameter overloading + Setattr(n, "wrap:parms", l); + Setattr(n, "wrap:name", wname); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "sym:overloaded")) { + // Emit warnings for the few cases that can't be overloaded in C# and give up on generating wrapper + Swig_overload_check(n); + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + } + + Printv(imclass_class_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", overloaded_name, "\")]\n", NIL); + + if (im_outattributes) + Printf(imclass_class_code, " %s\n", im_outattributes); + + Printf(imclass_class_code, " public static extern %s %s(", im_return_type, overloaded_name); + + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + int gencomma = 0; + + // Now walk the function parameter list and generate code to get arguments + for (i = 0, p = l; i < num_arguments; i++) { + + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Getattr(p, "lname"); + String *im_param_type = NewString(""); + String *c_param_type = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* Get the ctype types of the parameter */ + if ((tm = Getattr(p, "tmap:ctype"))) { + Printv(c_param_type, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Get the intermediary class parameter types of the parameter */ + if ((tm = Getattr(p, "tmap:imtype"))) { + const String *inattributes = Getattr(p, "tmap:imtype:inattributes"); + Printf(im_param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to intermediary class method */ + if (gencomma) + Printf(imclass_class_code, ", "); + Printf(imclass_class_code, "%s %s", im_param_type, arg); + + // Add parameter to C function + Printv(f->def, gencomma ? ", " : "", c_param_type, " ", arg, NIL); + + gencomma = 1; + + // Get typemap for this argument + if ((tm = Getattr(p, "tmap:in"))) { + canThrow(n, "in", p); + Replaceall(tm, "$source", arg); /* deprecated */ + Replaceall(tm, "$target", ln); /* deprecated */ + Replaceall(tm, "$arg", arg); /* deprecated? */ + Replaceall(tm, "$input", arg); + Setattr(p, "emit:input", arg); + Printf(f->code, "%s\n", tm); + p = Getattr(p, "tmap:in:next"); + } else { + Swig_warning(WARN_TYPEMAP_IN_UNDEF, input_file, line_number, "Unable to use type %s as a function argument.\n", SwigType_str(pt, 0)); + p = nextSibling(p); + } + Delete(im_param_type); + Delete(c_param_type); + Delete(arg); + } + + /* Insert constraint checking code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:check"))) { + canThrow(n, "check", p); + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(f->code, tm, "\n", NIL); + p = Getattr(p, "tmap:check:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert cleanup code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:freearg"))) { + canThrow(n, "freearg", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(cleanup, tm, "\n", NIL); + p = Getattr(p, "tmap:freearg:next"); + } else { + p = nextSibling(p); + } + } + + /* Insert argument output code */ + for (p = l; p;) { + if ((tm = Getattr(p, "tmap:argout"))) { + canThrow(n, "argout", p); + Replaceall(tm, "$source", Getattr(p, "emit:input")); /* deprecated */ + Replaceall(tm, "$target", Getattr(p, "lname")); /* deprecated */ + Replaceall(tm, "$arg", Getattr(p, "emit:input")); /* deprecated? */ + Replaceall(tm, "$result", "jresult"); + Replaceall(tm, "$input", Getattr(p, "emit:input")); + Printv(outarg, tm, "\n", NIL); + p = Getattr(p, "tmap:argout:next"); + } else { + p = nextSibling(p); + } + } + + // Look for usage of throws typemap and the canthrow flag + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "catchlist"))) { + Swig_typemap_attach_parms("throws", throw_parm_list, f); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + canThrow(n, "throws", p); + } + } + } + + String *null_attribute = 0; + // Now write code to make the function call + if (!native_function_flag) { + if (Cmp(nodeType(n), "constant") == 0) { + // Wrapping a constant hack + Swig_save("functionWrapper", n, "wrap:action", NIL); + + // below based on Swig_VargetToFunction() + SwigType *ty = Swig_wrapped_var_type(Getattr(n, "type"), use_naturalvar_mode(n)); + Setattr(n, "wrap:action", NewStringf("result = (%s) %s;", SwigType_lstr(ty, 0), Getattr(n, "value"))); + } + + Swig_director_emit_dynamic_cast(n, f); + String *actioncode = emit_action(n); + + if (Cmp(nodeType(n), "constant") == 0) + Swig_restore(n); + + /* Return value if necessary */ + if ((tm = Swig_typemap_lookup_out("out", n, "result", f, actioncode))) { + canThrow(n, "out", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Replaceall(tm, "$target", "jresult"); /* deprecated */ + Replaceall(tm, "$result", "jresult"); + + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "1"); + else + Replaceall(tm, "$owner", "0"); + + Printf(f->code, "%s", tm); + null_attribute = Getattr(n, "tmap:out:null"); + if (Len(tm)) + Printf(f->code, "\n"); + } else { + Swig_warning(WARN_TYPEMAP_OUT_UNDEF, input_file, line_number, "Unable to use return type %s in function %s.\n", SwigType_str(t, 0), Getattr(n, "name")); + } + emit_return_variable(n, t, f); + } + + /* Output argument output code */ + Printv(f->code, outarg, NIL); + + /* Output cleanup code */ + Printv(f->code, cleanup, NIL); + + /* Look to see if there is any newfree cleanup code */ + if (GetFlag(n, "feature:new")) { + if ((tm = Swig_typemap_lookup("newfree", n, "result", 0))) { + canThrow(n, "newfree", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* See if there is any return cleanup code */ + if (!native_function_flag) { + if ((tm = Swig_typemap_lookup("ret", n, "result", 0))) { + canThrow(n, "ret", n); + Replaceall(tm, "$source", "result"); /* deprecated */ + Printf(f->code, "%s\n", tm); + } + } + + /* Finish C function and intermediary class function definitions */ + Printf(imclass_class_code, ")"); + Printf(imclass_class_code, ";\n"); + + Printf(f->def, ") {"); + + if (!is_void_return) + Printv(f->code, " return jresult;\n", NIL); + Printf(f->code, "}\n"); + + /* Substitute the cleanup code */ + Replaceall(f->code, "$cleanup", cleanup); + + /* Substitute the function name */ + Replaceall(f->code, "$symname", symname); + + /* Contract macro modification */ + if (Replaceall(f->code, "SWIG_contract_assert(", "SWIG_contract_assert($null, ") > 0) { + Setattr(n, "csharp:canthrow", "1"); + } + + if (!null_attribute) + Replaceall(f->code, "$null", "0"); + else + Replaceall(f->code, "$null", null_attribute); + + /* Dump the function out */ + if (!native_function_flag) { + Wrapper_print(f, f_wrappers); + + // Handle %csexception which sets the canthrow attribute + if (Getattr(n, "feature:except:canthrow")) + Setattr(n, "csharp:canthrow", "1"); + + // A very simple check (it is not foolproof) to help typemap/feature writers for + // throwing C# exceptions from unmanaged code. It checks for the common methods which + // set a pending C# exception... the 'canthrow' typemap/feature attribute must be set + // so that code which checks for pending exceptions is added in the C# proxy method. + if (!Getattr(n, "csharp:canthrow")) { + if (Strstr(f->code, "SWIG_exception")) { + Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, + "Unmanaged code contains a call to SWIG_exception and C# code does not handle pending exceptions via the canthrow attribute.\n"); + } else if (Strstr(f->code, "SWIG_CSharpSetPendingException")) { + Swig_warning(WARN_CSHARP_CANTHROW, input_file, line_number, + "Unmanaged code contains a call to a SWIG_CSharpSetPendingException method and C# code does not handle pending exceptions via the canthrow attribute.\n"); + } + } + } + + if (!(proxy_flag && is_wrapping_class()) && !enum_constant_flag) { + moduleClassFunctionHandler(n); + } + + /* + * Generate the proxy class properties for public member variables. + * Not for enums and constants. + */ + if (proxy_flag && wrapping_member_flag && !enum_constant_flag) { + // Capitalize the first letter in the variable in the getter/setter function name + bool getter_flag = Cmp(symname, Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) != 0; + + String *getter_setter_name = NewString(""); + if (!getter_flag) + Printf(getter_setter_name, "set"); + else + Printf(getter_setter_name, "get"); + Putc(toupper((int) *Char(variable_name)), getter_setter_name); + Printf(getter_setter_name, "%s", Char(variable_name) + 1); + + Setattr(n, "proxyfuncname", getter_setter_name); + Setattr(n, "imfuncname", symname); + + proxyClassFunctionHandler(n); + Delete(getter_setter_name); + } + + Delete(c_return_type); + Delete(im_return_type); + Delete(cleanup); + Delete(outarg); + Delete(body); + Delete(overloaded_name); + DelWrapper(f); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * variableWrapper() + * ----------------------------------------------------------------------- */ + + virtual int variableWrapper(Node *n) { + Language::variableWrapper(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * globalvariableHandler() + * ------------------------------------------------------------------------ */ + + virtual int globalvariableHandler(Node *n) { + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + global_variable_flag = true; + int ret = Language::globalvariableHandler(n); + global_variable_flag = false; + generate_property_declaration_flag = false; + + if (proxy_flag) { + Printf(module_class_code, "\n }\n\n"); + } + + return ret; + } + + /* ---------------------------------------------------------------------- + * enumDeclaration() + * + * C/C++ enums can be mapped in one of 4 ways, depending on the cs:enum feature specified: + * 1) Simple enums - simple constant within the proxy class or module class + * 2) Typeunsafe enums - simple constant in a C# class (class named after the c++ enum name) + * 3) Typesafe enum - typesafe enum pattern (class named after the c++ enum name) + * 4) Proper enums - proper C# enum + * Anonymous enums always default to 1) + * ---------------------------------------------------------------------- */ + + virtual int enumDeclaration(Node *n) { + + if (!ImportMode) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + enum_code = NewString(""); + String *symname = Getattr(n, "sym:name"); + String *constants_code = (proxy_flag && is_wrapping_class())? proxy_class_constants_code : module_class_constants_code; + EnumFeature enum_feature = decodeEnumFeature(n); + String *typemap_lookup_type = Getattr(n, "name"); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + + // Pure C# baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "csinterfaces", typemap_lookup_type, WARN_NONE); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(enum_code, "%s\n", csattributes); + + // Emit the enum + Printv(enum_code, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers (enum modifiers really) + " ", symname, (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {\n", NIL); + } else { + // Wrap C++ enum with integers - just indicate start of enum with a comment, no comment for anonymous enums of any sort + if (symname && !Getattr(n, "unnamedinstance")) + Printf(constants_code, " // %s \n", symname); + } + + // Emit each enum item + Language::enumDeclaration(n); + + if ((enum_feature != SimpleEnum) && symname && typemap_lookup_type) { + // Wrap (non-anonymous) C/C++ enum within a typesafe, typeunsafe or proper C# enum + // Finish the enum declaration + // Typemaps are used to generate the enum definition in a similar manner to proxy classes. + Printv(enum_code, (enum_feature == ProperEnum) ? "\n" : typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "}", NIL); + + Replaceall(enum_code, "$csclassname", symname); + + // Substitute $enumvalues - intended usage is for typesafe enums + if (Getattr(n, "enumvalues")) + Replaceall(enum_code, "$enumvalues", Getattr(n, "enumvalues")); + else + Replaceall(enum_code, "$enumvalues", ""); + + if (proxy_flag && is_wrapping_class()) { + // Enums defined within the C++ class are defined within the proxy class + + // Add extra indentation + Replaceall(enum_code, "\n", "\n "); + Replaceall(enum_code, " \n", "\n"); + + Printv(proxy_class_constants_code, " ", enum_code, "\n\n", NIL); + } else { + // Global enums are defined in their own file + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), symname); + File *f_enum = NewFile(filen, "w", SWIG_output_files()); + if (!f_enum) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the enum file + emitBanner(f_enum); + + addOpenNamespace(namespce, f_enum); + + Printv(f_enum, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", enum_code, "\n", NIL); + + addCloseNamespace(namespce, f_enum); + + Close(f_enum); + } + } else { + // Wrap C++ enum with simple constant + Printf(enum_code, "\n"); + if (proxy_flag && is_wrapping_class()) + Printv(proxy_class_constants_code, enum_code, NIL); + else + Printv(module_class_constants_code, enum_code, NIL); + } + + Delete(enum_code); + enum_code = NULL; + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * enumvalueDeclaration() + * ---------------------------------------------------------------------- */ + + virtual int enumvalueDeclaration(Node *n) { + if (getCurrentClass() && (cplus_mode != PUBLIC)) + return SWIG_NOWRAP; + + Swig_require("enumvalueDeclaration", n, "*name", "?value", NIL); + String *symname = Getattr(n, "sym:name"); + String *value = Getattr(n, "value"); + String *name = Getattr(n, "name"); + String *tmpValue; + + // Strange hack from parent method + if (value) + tmpValue = NewString(value); + else + tmpValue = NewString(name); + // Note that this is used in enumValue() amongst other places + Setattr(n, "value", tmpValue); + + { + EnumFeature enum_feature = decodeEnumFeature(parentNode(n)); + + if ((enum_feature == ProperEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymous) C/C++ enum with a proper C# enum + // Emit the enum item. + if (!GetFlag(n, "firstenumitem")) + Printf(enum_code, ",\n"); + Printf(enum_code, " %s", symname); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + // Note that the enum value must be a true constant and cannot be set from a PINVOKE call, thus no support for %csconst(0) + value = value ? value : Getattr(n, "enumvalue"); + if (value) { + Printf(enum_code, " = %s", value); + } + } else { + // Wrap C/C++ enums with constant integers or use the typesafe enum pattern + const String *parent_name = Getattr(parentNode(n), "name"); + String *typemap_lookup_type = parent_name ? Copy(parent_name) : NewString("int"); + const String *tm = typemapLookup(n, "cstype", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF); + String *return_type = Copy(tm); + Delete(typemap_lookup_type); + typemap_lookup_type = NULL; + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + if ((enum_feature == TypesafeEnum) && Getattr(parentNode(n), "sym:name") && !Getattr(parentNode(n), "unnamedinstance")) { + // Wrap (non-anonymouse) enum using the typesafe enum pattern + if (Getattr(n, "enumvalue")) { + String *value = enumValue(n); + Printf(enum_code, " %s static readonly %s %s = new %s(\"%s\", %s);\n", methodmods, return_type, symname, return_type, symname, value); + Delete(value); + } else { + Printf(enum_code, " %s static readonly %s %s = new %s(\"%s\");\n", methodmods, return_type, symname, return_type, symname); + } + } else { + // Simple integer constants + // Note these are always generated for anonymous enums, no matter what enum_feature is specified + // Code generated is the same for SimpleEnum and TypeunsafeEnum -> the class it is generated into is determined later + const char *const_readonly = const_feature_flag ? "const" : "static readonly"; + String *value = enumValue(n); + Printf(enum_code, " %s %s %s %s = %s;\n", methodmods, const_readonly, return_type, symname, value); + Delete(value); + } + } + + // Add the enum value to the comma separated list being constructed in the enum declaration. + String *enumvalues = Getattr(parentNode(n), "enumvalues"); + if (!enumvalues) + Setattr(parentNode(n), "enumvalues", Copy(symname)); + else + Printv(enumvalues, ", ", symname, NIL); + } + + Delete(tmpValue); + Swig_restore(n); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------- + * constantWrapper() + * Used for wrapping constants - #define or %constant. + * Also for inline initialised const static primitive type member variables (short, int, double, enums etc). + * C# static const variables are generated for these. + * If the %csconst(1) feature is used then the C constant value is used to initialise the C# const variable. + * If not, a PINVOKE method is generated to get the C constant value for initialisation of the C# const variable. + * However, if the %csconstvalue feature is used, it overrides all other ways to generate the initialisation. + * Also note that this method might be called for wrapping enum items (when the enum is using %csconst(0)). + * ------------------------------------------------------------------------ */ + + virtual int constantWrapper(Node *n) { + String *symname = Getattr(n, "sym:name"); + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + String *return_type = NewString(""); + String *constants_code = NewString(""); + + if (!addSymbol(symname, n)) + return SWIG_ERROR; + + bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0); + + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + /* Adjust the enum type for the Swig_typemap_lookup. + * We want the same jstype typemap for all the enum items so we use the enum type (parent node). */ + if (is_enum_item) { + t = Getattr(parentNode(n), "enumtype"); + Setattr(n, "type", t); + } + + /* Attach the non-standard typemaps to the parameter list. */ + Swig_typemap_attach_parms("cstype", l, NULL); + + /* Get C# return types */ + bool classname_substituted_flag = false; + + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + classname_substituted_flag = substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + // Add the stripped quotes back in + String *new_value = NewString(""); + Swig_save("constantWrapper", n, "value", NIL); + if (SwigType_type(t) == T_STRING) { + Printf(new_value, "\"%s\"", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } else if (SwigType_type(t) == T_CHAR) { + Printf(new_value, "\'%s\'", Copy(Getattr(n, "value"))); + Setattr(n, "value", new_value); + } + + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(constants_code, " %s\n", outattributes); + const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname; + + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + Printf(constants_code, " %s %s %s %s = ", methodmods, (const_feature_flag ? "const" : "static readonly"), return_type, itemname); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + if (value) { + Printf(constants_code, "%s;\n", value); + } else if (!const_feature_flag) { + // Default enum and constant handling will work with any type of C constant and initialises the C# variable from C through a PINVOKE call. + + if (classname_substituted_flag) { + if (SwigType_isenum(t)) { + // This handles wrapping of inline initialised const enum static member variables (not when wrapping enum items - ignored later on) + Printf(constants_code, "(%s)%s.%s();\n", return_type, imclass_name, Swig_name_get(symname)); + } else { + // This handles function pointers using the %constant directive + Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, imclass_name, Swig_name_get(symname)); + } + } else + Printf(constants_code, "%s.%s();\n", imclass_name, Swig_name_get(symname)); + + // Each constant and enum value is wrapped with a separate PInvoke function call + SetFlag(n, "feature:immutable"); + enum_constant_flag = true; + variableWrapper(n); + enum_constant_flag = false; + } else { + // Alternative constant handling will use the C syntax to make a true C# constant and hope that it compiles as C# code + Printf(constants_code, "%s;\n", Getattr(n, "value")); + } + + // Emit the generated code to appropriate place + // Enums only emit the intermediate and PINVOKE methods, so no proxy or module class wrapper methods needed + if (!is_enum_item) { + if (proxy_flag && wrapping_member_flag) + Printv(proxy_class_constants_code, constants_code, NIL); + else + Printv(module_class_constants_code, constants_code, NIL); + } + // Cleanup + Swig_restore(n); + Delete(new_value); + Delete(return_type); + Delete(constants_code); + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * insertDirective() + * ----------------------------------------------------------------------------- */ + + virtual int insertDirective(Node *n) { + String *code = Getattr(n, "code"); + Replaceall(code, "$module", module_class_name); + Replaceall(code, "$imclassname", imclass_name); + Replaceall(code, "$dllimport", dllimport); + return Language::insertDirective(n); + } + + /* ----------------------------------------------------------------------------- + * pragmaDirective() + * + * Valid Pragmas: + * imclassbase - base (extends) for the intermediary class + * imclassclassmodifiers - class modifiers for the intermediary class + * imclasscode - text (C# code) is copied verbatim to the intermediary class + * imclassimports - import statements for the intermediary class + * imclassinterfaces - interface (implements) for the intermediary class + * + * modulebase - base (extends) for the module class + * moduleclassmodifiers - class modifiers for the module class + * modulecode - text (C# code) is copied verbatim to the module class + * moduleimports - import statements for the module class + * moduleinterfaces - interface (implements) for the module class + * + * ----------------------------------------------------------------------------- */ + + virtual int pragmaDirective(Node *n) { + if (!ImportMode) { + String *lang = Getattr(n, "lang"); + String *code = Getattr(n, "name"); + String *value = Getattr(n, "value"); + + if (Strcmp(lang, "csharp") == 0) { + + String *strvalue = NewString(value); + Replaceall(strvalue, "\\\"", "\""); + + if (Strcmp(code, "imclassbase") == 0) { + Delete(imclass_baseclass); + imclass_baseclass = Copy(strvalue); + } else if (Strcmp(code, "imclassclassmodifiers") == 0) { + Delete(imclass_class_modifiers); + imclass_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "imclasscode") == 0) { + Printf(imclass_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "imclassimports") == 0) { + Delete(imclass_imports); + imclass_imports = Copy(strvalue); + } else if (Strcmp(code, "imclassinterfaces") == 0) { + Delete(imclass_interfaces); + imclass_interfaces = Copy(strvalue); + } else if (Strcmp(code, "modulebase") == 0) { + Delete(module_baseclass); + module_baseclass = Copy(strvalue); + } else if (Strcmp(code, "moduleclassmodifiers") == 0) { + Delete(module_class_modifiers); + module_class_modifiers = Copy(strvalue); + } else if (Strcmp(code, "modulecode") == 0) { + Printf(module_class_code, "%s\n", strvalue); + } else if (Strcmp(code, "moduleimports") == 0) { + Delete(module_imports); + module_imports = Copy(strvalue); + } else if (Strcmp(code, "moduleinterfaces") == 0) { + Delete(module_interfaces); + module_interfaces = Copy(strvalue); + } else { + Printf(stderr, "%s : Line %d. Unrecognized pragma.\n", input_file, line_number); + } + Delete(strvalue); + } + } + return Language::pragmaDirective(n); + } + + /* ----------------------------------------------------------------------------- + * emitProxyClassDefAndCPPCasts() + * ----------------------------------------------------------------------------- */ + + void emitProxyClassDefAndCPPCasts(Node *n) { + String *c_classname = SwigType_namestr(Getattr(n, "name")); + String *c_baseclass = NULL; + String *baseclass = NULL; + String *c_baseclassname = NULL; + SwigType *typemap_lookup_type = Getattr(n, "classtypeobj"); + bool feature_director = Swig_directorclass(n) ? true : false; + + // Inheritance from pure C# classes + Node *attributes = NewHash(); + const String *pure_baseclass = typemapLookup(n, "csbase", typemap_lookup_type, WARN_NONE, attributes); + bool purebase_replace = GetFlag(attributes, "tmap:csbase:replace") ? true : false; + bool purebase_notderived = GetFlag(attributes, "tmap:csbase:notderived") ? true : false; + Delete(attributes); + + // C++ inheritance + if (!purebase_replace) { + List *baselist = Getattr(n, "bases"); + if (baselist) { + Iterator base = First(baselist); + while (base.item && GetFlag(base.item, "feature:ignore")) { + base = Next(base); + } + if (base.item) { + c_baseclassname = Getattr(base.item, "name"); + baseclass = Copy(getProxyName(c_baseclassname)); + if (baseclass) + c_baseclass = SwigType_namestr(Getattr(base.item, "name")); + base = Next(base); + /* Warn about multiple inheritance for additional base class(es) */ + while (base.item) { + if (GetFlag(base.item, "feature:ignore")) { + base = Next(base); + continue; + } + String *proxyclassname = SwigType_str(Getattr(n, "classtypeobj"), 0); + String *baseclassname = SwigType_str(Getattr(base.item, "name"), 0); + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#.\n", proxyclassname, baseclassname); + base = Next(base); + } + } + } + } + + bool derived = baseclass && getProxyName(c_baseclassname); + if (derived && purebase_notderived) + pure_baseclass = empty_string; + const String *wanted_base = baseclass ? baseclass : pure_baseclass; + + if (purebase_replace) { + wanted_base = pure_baseclass; + derived = false; + Delete(baseclass); + baseclass = NULL; + if (purebase_notderived) + Swig_error(input_file, line_number, "The csbase typemap for proxy %s must contain just one of the 'replace' or 'notderived' attributes.\n", typemap_lookup_type); + } else if (Len(pure_baseclass) > 0 && Len(baseclass) > 0) { + Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, input_file, line_number, + "Warning for %s proxy: Base %s ignored. Multiple inheritance is not supported in C#. " + "Perhaps you need one of the 'replace' or 'notderived' attributes in the csbase typemap?\n", typemap_lookup_type, pure_baseclass); + } + + // Pure C# interfaces + const String *pure_interfaces = typemapLookup(n, derived ? "csinterfaces_derived" : "csinterfaces", typemap_lookup_type, WARN_NONE); + // Start writing the proxy class + Printv(proxy_class_def, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements + "\n", NIL); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", typemap_lookup_type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(proxy_class_def, "%s\n", csattributes); + + Printv(proxy_class_def, typemapLookup(n, "csclassmodifiers", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $csclassname", // Class name and base class + (*Char(wanted_base) || *Char(pure_interfaces)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {", derived ? typemapLookup(n, "csbody_derived", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF) : // main body of class + typemapLookup(n, "csbody", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + NIL); + + // C++ destructor is wrapped by the Dispose method + // Note that the method name is specified in a typemap attribute called methodname + String *destruct = NewString(""); + const String *tm = NULL; + attributes = NewHash(); + String *destruct_methodname = NULL; + String *destruct_methodmodifiers = NULL; + if (derived) { + tm = typemapLookup(n, "csdestruct_derived", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdestruct_derived:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdestruct_derived:methodmodifiers"); + } else { + tm = typemapLookup(n, "csdestruct", typemap_lookup_type, WARN_NONE, attributes); + destruct_methodname = Getattr(attributes, "tmap:csdestruct:methodname"); + destruct_methodmodifiers = Getattr(attributes, "tmap:csdestruct:methodmodifiers"); + } + if (tm && *Char(tm)) { + if (!destruct_methodname) { + Swig_error(input_file, line_number, "No methodname attribute defined in csdestruct%s typemap for %s\n", (derived ? "_derived" : ""), proxy_class_name); + } + if (!destruct_methodmodifiers) { + Swig_error(input_file, line_number, + "No methodmodifiers attribute defined in csdestruct%s typemap for %s.\n", (derived ? "_derived" : ""), proxy_class_name); + } + } + // Emit the Finalize and Dispose methods + if (tm) { + // Finalize method + if (*Char(destructor_call)) { + Printv(proxy_class_def, typemapLookup(n, "csfinalize", typemap_lookup_type, WARN_NONE), NIL); + } + // Dispose method + Printv(destruct, tm, NIL); + if (*Char(destructor_call)) + Replaceall(destruct, "$imcall", destructor_call); + else + Replaceall(destruct, "$imcall", "throw new MethodAccessException(\"C++ destructor does not have public access\")"); + if (*Char(destruct)) + Printv(proxy_class_def, "\n ", destruct_methodmodifiers, " ", derived ? "override" : "virtual", " void ", destruct_methodname, "() ", destruct, "\n", + NIL); + } + + if (feature_director) { + // Generate director connect method + // put this in classDirectorEnd ??? + Printf(proxy_class_code, " private void SwigDirectorConnect() {\n"); + + int i; + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *method = Getattr(udata, "method"); + String *methid = Getattr(udata, "class_methodidx"); + String *overname = Getattr(udata, "overname"); + Printf(proxy_class_code, " if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s))\n", method, methid); + Printf(proxy_class_code, " swigDelegate%s = new SwigDelegate%s_%s(SwigDirector%s);\n", methid, proxy_class_name, methid, overname); + } + Printf(proxy_class_code, " %s.%s_director_connect(swigCPtr", imclass_name, proxy_class_name); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + Printf(proxy_class_code, ", swigDelegate%s", methid); + } + Printf(proxy_class_code, ");\n"); + Printf(proxy_class_code, " }\n"); + + if (first_class_dmethod < curr_class_dmethod) { + // Only emit if there is at least one director method + Printf(proxy_class_code, "\n"); + Printf(proxy_class_code, " private bool SwigDerivedClassHasMethod(string methodName, Type[] methodTypes) {\n"); + Printf(proxy_class_code, + " System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance, null, methodTypes, null);\n"); + Printf(proxy_class_code, " bool hasDerivedMethod = methodInfo.DeclaringType.IsSubclassOf(typeof(%s));\n", proxy_class_name); + /* Could add this code to cover corner case where the GetMethod() returns a method which allows type + * promotion, eg it will return foo(double), if looking for foo(int). + if (hasDerivedMethod) { + hasDerivedMethod = false; + if (methodInfo != null) + { + hasDerivedMethod = true; + ParameterInfo[] parameterArray1 = methodInfo.GetParameters(); + for (int i=0; i<methodTypes.Length; i++) + { + if (parameterArray1[0].ParameterType != methodTypes[0]) + { + hasDerivedMethod = false; + break; + } + } + } + } + */ + Printf(proxy_class_code, " return hasDerivedMethod;\n"); + Printf(proxy_class_code, " }\n"); + } + + if (Len(director_delegate_callback) > 0) + Printv(proxy_class_code, director_delegate_callback, NIL); + if (Len(director_delegate_definitions) > 0) + Printv(proxy_class_code, "\n", director_delegate_definitions, NIL); + if (Len(director_delegate_instances) > 0) + Printv(proxy_class_code, "\n", director_delegate_instances, NIL); + if (Len(director_method_types) > 0) + Printv(proxy_class_code, "\n", director_method_types, NIL); + + Delete(director_callback_typedefs); + director_callback_typedefs = NULL; + Delete(director_callbacks); + director_callbacks = NULL; + Delete(director_delegate_callback); + director_delegate_callback = NULL; + Delete(director_delegate_definitions); + director_delegate_definitions = NULL; + Delete(director_delegate_instances); + director_delegate_instances = NULL; + Delete(director_method_types); + director_method_types = NULL; + Delete(director_connect_parms); + director_connect_parms = NULL; + } + + Delete(attributes); + Delete(destruct); + + // Emit extra user code + Printv(proxy_class_def, typemapLookup(n, "cscode", typemap_lookup_type, WARN_NONE), // extra C# code + "\n", NIL); + + // Substitute various strings into the above template + Replaceall(proxy_class_code, "$csclassname", proxy_class_name); + Replaceall(proxy_class_def, "$csclassname", proxy_class_name); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + + // Add code to do C++ casting to base class (only for classes in an inheritance hierarchy) + if (derived) { + Printv(imclass_cppcasts_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", proxy_class_name, "Upcast", "\")]\n", NIL); + Printf(imclass_cppcasts_code, " public static extern IntPtr $csclassnameUpcast(IntPtr objectRef);\n"); + + Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name); + + Printv(upcasts_code, + "SWIGEXPORT $cbaseclass * SWIGSTDCALL CSharp_$imclazznameUpcast", + "($cclass *objectRef) {\n", " return ($cbaseclass *)objectRef;\n" "}\n", "\n", NIL); + + Replaceall(upcasts_code, "$cbaseclass", c_baseclass); + Replaceall(upcasts_code, "$imclazzname", proxy_class_name); + Replaceall(upcasts_code, "$cclass", c_classname); + } + Delete(baseclass); + } + + /* ---------------------------------------------------------------------- + * classHandler() + * ---------------------------------------------------------------------- */ + + virtual int classHandler(Node *n) { + + File *f_proxy = NULL; + if (proxy_flag) { + proxy_class_name = NewString(Getattr(n, "sym:name")); + + if (!addSymbol(proxy_class_name, n)) + return SWIG_ERROR; + + if (Cmp(proxy_class_name, imclass_name) == 0) { + Printf(stderr, "Class name cannot be equal to intermediary class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + if (Cmp(proxy_class_name, module_class_name) == 0) { + Printf(stderr, "Class name cannot be equal to module class name: %s\n", proxy_class_name); + SWIG_exit(EXIT_FAILURE); + } + + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), proxy_class_name); + f_proxy = NewFile(filen, "w", SWIG_output_files()); + if (!f_proxy) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the proxy class file + emitBanner(f_proxy); + + addOpenNamespace(namespce, f_proxy); + + Clear(proxy_class_def); + Clear(proxy_class_code); + + destructor_call = NewString(""); + proxy_class_constants_code = NewString(""); + } + + Language::classHandler(n); + + if (proxy_flag) { + + emitProxyClassDefAndCPPCasts(n); + + Replaceall(proxy_class_def, "$module", module_class_name); + Replaceall(proxy_class_code, "$module", module_class_name); + Replaceall(proxy_class_constants_code, "$module", module_class_name); + Replaceall(proxy_class_def, "$imclassname", imclass_name); + Replaceall(proxy_class_code, "$imclassname", imclass_name); + Replaceall(proxy_class_constants_code, "$imclassname", imclass_name); + Replaceall(proxy_class_def, "$dllimport", dllimport); + Replaceall(proxy_class_code, "$dllimport", dllimport); + Replaceall(proxy_class_constants_code, "$dllimport", dllimport); + + Printv(f_proxy, proxy_class_def, proxy_class_code, NIL); + + // Write out all the constants + if (Len(proxy_class_constants_code) != 0) + Printv(f_proxy, proxy_class_constants_code, NIL); + + Printf(f_proxy, "}\n"); + addCloseNamespace(namespce, f_proxy); + Close(f_proxy); + f_proxy = NULL; + + /* Output the downcast method, if necessary. Note: There's no other really + good place to put this code, since Abstract Base Classes (ABCs) can and should have + downcasts, making the constructorHandler() a bad place (because ABCs don't get to + have constructors emitted.) */ + if (GetFlag(n, "feature:javadowncast")) { + String *norm_name = SwigType_namestr(Getattr(n, "name")); + + Printf(imclass_class_code, " public final static native %s downcast%s(long cPtrBase, boolean cMemoryOwn);\n", proxy_class_name, proxy_class_name); + + Wrapper *dcast_wrap = NewWrapper(); + + Printf(dcast_wrap->def, "SWIGEXPORT jobject SWIGSTDCALL CSharp_downcast%s(JNIEnv *jenv, jclass jcls, jlong jCPtrBase, jboolean cMemoryOwn) {", + proxy_class_name); + Printf(dcast_wrap->code, " Swig::Director *director = (Swig::Director *) 0;\n"); + Printf(dcast_wrap->code, " jobject jresult = (jobject) 0;\n"); + Printf(dcast_wrap->code, " %s *obj = *((%s **)&jCPtrBase);\n", norm_name, norm_name); + Printf(dcast_wrap->code, " if (obj) director = dynamic_cast<Swig::Director *>(obj);\n"); + Printf(dcast_wrap->code, " if (director) jresult = director->swig_get_self(jenv);\n"); + Printf(dcast_wrap->code, " return jresult;\n"); + Printf(dcast_wrap->code, "}\n"); + + Wrapper_print(dcast_wrap, f_wrappers); + DelWrapper(dcast_wrap); + } + + emitDirectorExtraMethods(n); + + Delete(proxy_class_name); + proxy_class_name = NULL; + Delete(destructor_call); + destructor_call = NULL; + Delete(proxy_class_constants_code); + proxy_class_constants_code = NULL; + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberfunctionHandler(Node *n) { + Language::memberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmemberfunctionHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmemberfunctionHandler(Node *n) { + + static_flag = true; + Language::staticmemberfunctionHandler(n); + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *intermediary_function_name = Swig_name_member(proxy_class_name, overloaded_name); + Setattr(n, "proxyfuncname", Getattr(n, "sym:name")); + Setattr(n, "imfuncname", intermediary_function_name); + proxyClassFunctionHandler(n); + Delete(overloaded_name); + } + static_flag = false; + + return SWIG_OK; + } + + + /* ----------------------------------------------------------------------------- + * proxyClassFunctionHandler() + * + * Function called for creating a C# wrapper function around a c++ function in the + * proxy class. Used for both static and non-static C++ class functions. + * C++ class static functions map to C# static functions. + * Two extra attributes in the Node must be available. These are "proxyfuncname" - + * the name of the C# class proxy function, which in turn will call "imfuncname" - + * the intermediary (PInvoke) function name in the intermediary class. + * ----------------------------------------------------------------------------- */ + + void proxyClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *intermediary_function_name = Getattr(n, "imfuncname"); + String *proxy_function_name = Getattr(n, "proxyfuncname"); + String *tm; + Parm *p; + Parm *last_parm = 0; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + if (!proxy_flag) + return; + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "overload:ignore")) + return; + + // Don't generate proxy method for additional explicitcall method used in directors + if (GetFlag(n, "explicitcall")) + return; + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + // Note that in the case of polymorphic (covariant) return types, the method's return type is changed to be the base of the C++ return type + SwigType *covariant = Getattr(n, "covariant"); + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(covariant ? covariant : t, tm); + Printf(return_type, "%s", tm); + if (covariant) + Swig_warning(WARN_CSHARP_COVARIANT_RET, input_file, line_number, + "Covariant return types not supported in C#. Proxy method will return %s.\n", SwigType_str(covariant, 0)); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // Properties + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(Swig_name_member(proxy_class_name, variable_name))) == 0); + if (setter_flag) + Swig_typemap_attach_parms("csvarin", l, NULL); + } + + /* Start generating the proxy function */ + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(function_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (methodmods) { + if (is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. + String *mmods = Copy(methodmods); + Replaceall(mmods, "override", ""); + Replaceall(mmods, "virtual", ""); + Replaceall(mmods, "new", ""); + Chop(mmods); // remove trailing whitespace + Printf(function_code, " %s ", mmods); + Delete(mmods); + } else { + Printf(function_code, " %s ", methodmods); + } + } else { + methodmods = (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s ", methodmods); + if (!is_smart_pointer()) { + // Smart pointer classes do not mirror the inheritance hierarchy of the underlying pointer type, so no virtual/override/new required. + if (Getattr(n, "override")) + Printf(function_code, "override "); + else if (checkAttribute(n, "storage", "virtual")) + Printf(function_code, "virtual "); + if (Getattr(n, "hides")) + Printf(function_code, "new "); + } + } + if (static_flag) + Printf(function_code, "static "); + Printf(function_code, "%s %s(", return_type, proxy_function_name); + + Printv(imcall, imclass_name, ".$imfuncname(", NIL); + if (!static_flag) + Printf(imcall, "swigCPtr"); + + emit_mark_varargs(l); + + int gencomma = !static_flag; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + /* Ignore the 'this' argument for variable wrappers */ + if (!(variable_wrapper_flag && i == 0)) { + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + if (setter_flag) + last_parm = p; + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, setter_flag); + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + Delete(arg); + Delete(param_type); + } + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in proxy class) + if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { + excodeSubstitute(n, tm, "csout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + + // For director methods: generate code to selectively make a normal polymorphic call or + // an explicit method call - needed to prevent infinite recursion calls in director methods. + Node *explicit_n = Getattr(n, "explicitcallnode"); + if (explicit_n) { + String *ex_overloaded_name = getOverloadedName(explicit_n); + String *ex_intermediary_function_name = Swig_name_member(proxy_class_name, ex_overloaded_name); + + String *ex_imcall = Copy(imcall); + Replaceall(ex_imcall, "$imfuncname", ex_intermediary_function_name); + Replaceall(imcall, "$imfuncname", intermediary_function_name); + + String *excode = NewString(""); + if (!Cmp(return_type, "void")) + Printf(excode, "if (this.GetType() == typeof(%s)) %s; else %s", proxy_class_name, imcall, ex_imcall); + else + Printf(excode, "((this.GetType() == typeof(%s)) ? %s : %s)", proxy_class_name, imcall, ex_imcall); + + Clear(imcall); + Printv(imcall, excode, NIL); + Delete(ex_overloaded_name); + Delete(excode); + } else { + Replaceall(imcall, "$imfuncname", intermediary_function_name); + } + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (wrapping_member_flag && !enum_constant_flag) { + // Properties + if (generate_property_declaration_flag) { // Ensure the declaration is generated just once should the property contain both a set and get + // Get the C# variable type - obtained differently depending on whether a setter is required. + String *variable_type = return_type; + if (setter_flag) { + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + String *cstypeout = Getattr(p, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + variable_type = cstypeout ? cstypeout : tm; + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(proxy_class_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (!methodmods) + methodmods = (is_public(n) ? public_string : protected_string); + Printf(proxy_class_code, " %s %s%s %s {", methodmods, static_flag ? "static " : "", variable_type, variable_name); + } + generate_property_declaration_flag = false; + + if (setter_flag) { + // Setter method + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:csvarin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", p); + Printf(proxy_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + // Getter method + if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarout", n); + Printf(proxy_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); + } + } + } else { + // Normal function call + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(proxy_class_code, function_code, NIL); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + } + + /* ---------------------------------------------------------------------- + * constructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int constructorHandler(Node *n) { + + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + int i; + String *function_code = NewString(""); + String *helper_code = NewString(""); // Holds code for the constructor helper method generated only when the csin typemap has code in the pre or post attributes + String *helper_args = NewString(""); + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + String *im_return_type = NewString(""); + bool feature_director = (parentNode(n) && Swig_directorclass(n)); + + Language::constructorHandler(n); + + // Wrappers not wanted for some methods where the parameters cannot be overloaded in C# + if (Getattr(n, "overload:ignore")) + return SWIG_OK; + + if (proxy_flag) { + String *overloaded_name = getOverloadedName(n); + String *mangled_overname = Swig_name_construct(overloaded_name); + String *imcall = NewString(""); + + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) { + Printf(function_code, " %s\n", csattributes); + Printf(helper_code, " %s\n", csattributes); + } + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + + tm = Getattr(n, "tmap:imtype"); // typemaps were attached earlier to the node + String *imtypeout = Getattr(n, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + Printf(im_return_type, "%s", tm); + + Printf(function_code, " %s %s(", methodmods, proxy_class_name); + Printf(helper_code, " static private %s SwigConstruct%s(", im_return_type, proxy_class_name); + + Printv(imcall, imclass_name, ".", mangled_overname, "(", NIL); + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("in", l, NULL); + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + emit_mark_varargs(l); + + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; p; i++) { + + /* Ignored varargs */ + if (checkAttribute(p, "varargs:ignore", "1")) { + p = nextSibling(p); + continue; + } + + /* Ignored parameters */ + if (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + continue; + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, false); + String *cshin = 0; + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + cshin = Getattr(p, "tmap:csin:cshin"); + if (cshin) + Replaceall(cshin, "$csinput", arg); + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to proxy function */ + if (gencomma) { + Printf(function_code, ", "); + Printf(helper_code, ", "); + Printf(helper_args, ", "); + } + Printf(function_code, "%s %s", param_type, arg); + Printf(helper_code, "%s %s", param_type, arg); + Printf(helper_args, "%s", cshin ? cshin : arg); + ++gencomma; + + Delete(cshin); + Delete(arg); + Delete(param_type); + p = Getattr(p, "tmap:in:next"); + } + + Printf(imcall, ")"); + + Printf(function_code, ")"); + Printf(helper_code, ")"); + + /* Insert the csconstruct typemap, doing the replacement for $directorconnect, as needed */ + Hash *attributes = NewHash(); + String *construct_tm = Copy(typemapLookup(n, "csconstruct", Getattr(n, "name"), + WARN_CSHARP_TYPEMAP_CSCONSTRUCT_UNDEF, attributes)); + if (construct_tm) { + if (!feature_director) { + Replaceall(construct_tm, "$directorconnect", ""); + } else { + String *connect_attr = Getattr(attributes, "tmap:csconstruct:directorconnect"); + + if (connect_attr) { + Replaceall(construct_tm, "$directorconnect", connect_attr); + } else { + Swig_warning(WARN_CSHARP_NO_DIRECTORCONNECT_ATTR, input_file, line_number, "\"directorconnect\" attribute missing in %s \"csconstruct\" typemap.\n", + Getattr(n, "name")); + Replaceall(construct_tm, "$directorconnect", ""); + } + } + + Printv(function_code, " ", construct_tm, NIL); + } + + excodeSubstitute(n, function_code, "csconstruct", attributes); + + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Printf(helper_code, " {\n"); + if (is_pre_code) { + Printv(helper_code, pre_code, "\n", NIL); + } + if (is_post_code) { + Printf(helper_code, " try {\n"); + Printv(helper_code, " return ", imcall, ";\n", NIL); + Printv(helper_code, " } finally {\n", post_code, "\n }", NIL); + } else { + Printv(helper_code, " return ", imcall, ";", NIL); + } + if (is_terminator_code) { + Printv(helper_code, "\n", terminator_code, NIL); + } + Printf(helper_code, "\n }\n"); + String *helper_name = NewStringf("%s.SwigConstruct%s(%s)", proxy_class_name, proxy_class_name, helper_args); + String *im_outattributes = Getattr(n, "tmap:imtype:outattributes"); + if (im_outattributes) + Printf(proxy_class_code, " %s\n", im_outattributes); + Printv(proxy_class_code, helper_code, "\n", NIL); + Replaceall(function_code, "$imcall", helper_name); + Delete(helper_name); + } else { + Replaceall(function_code, "$imcall", imcall); + } + + Printv(proxy_class_code, function_code, "\n", NIL); + + Delete(helper_args); + Delete(im_return_type); + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(construct_tm); + Delete(attributes); + Delete(overloaded_name); + Delete(imcall); + } + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * destructorHandler() + * ---------------------------------------------------------------------- */ + + virtual int destructorHandler(Node *n) { + Language::destructorHandler(n); + String *symname = Getattr(n, "sym:name"); + + if (proxy_flag) { + Printv(destructor_call, imclass_name, ".", Swig_name_destroy(symname), "(swigCPtr)", NIL); + } + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * membervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int membervariableHandler(Node *n) { + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + variable_wrapper_flag = true; + Language::membervariableHandler(n); + wrapping_member_flag = false; + variable_wrapper_flag = false; + generate_property_declaration_flag = false; + + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * staticmembervariableHandler() + * ---------------------------------------------------------------------- */ + + virtual int staticmembervariableHandler(Node *n) { + + bool static_const_member_flag = (Getattr(n, "value") == 0); + + generate_property_declaration_flag = true; + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + static_flag = true; + Language::staticmembervariableHandler(n); + wrapping_member_flag = false; + static_flag = false; + generate_property_declaration_flag = false; + + if (static_const_member_flag) + Printf(proxy_class_code, "\n }\n\n"); + + return SWIG_OK; + } + + /* ---------------------------------------------------------------------- + * memberconstantHandler() + * ---------------------------------------------------------------------- */ + + virtual int memberconstantHandler(Node *n) { + variable_name = Getattr(n, "sym:name"); + wrapping_member_flag = true; + Language::memberconstantHandler(n); + wrapping_member_flag = false; + return SWIG_OK; + } + + /* ----------------------------------------------------------------------------- + * getOverloadedName() + * ----------------------------------------------------------------------------- */ + + String *getOverloadedName(Node *n) { + + /* A C# HandleRef is used for all classes in the SWIG intermediary class. + * The intermediary class methods are thus mangled when overloaded to give + * a unique name. */ + String *overloaded_name = NewStringf("%s", Getattr(n, "sym:name")); + + if (Getattr(n, "sym:overloaded")) { + Printv(overloaded_name, Getattr(n, "sym:overname"), NIL); + } + + return overloaded_name; + } + + /* ----------------------------------------------------------------------------- + * moduleClassFunctionHandler() + * ----------------------------------------------------------------------------- */ + + void moduleClassFunctionHandler(Node *n) { + SwigType *t = Getattr(n, "type"); + ParmList *l = Getattr(n, "parms"); + String *tm; + Parm *p; + Parm *last_parm = 0; + int i; + String *imcall = NewString(""); + String *return_type = NewString(""); + String *function_code = NewString(""); + int num_arguments = 0; + int num_required = 0; + String *overloaded_name = getOverloadedName(n); + String *func_name = NULL; + bool setter_flag = false; + String *pre_code = NewString(""); + String *post_code = NewString(""); + String *terminator_code = NewString(""); + + if (l) { + if (SwigType_type(Getattr(l, "type")) == T_VOID) { + l = nextSibling(l); + } + } + + /* Attach the non-standard typemaps to the parameter list */ + Swig_typemap_attach_parms("cstype", l, NULL); + Swig_typemap_attach_parms("csin", l, NULL); + + /* Get return types */ + if ((tm = Swig_typemap_lookup("cstype", n, "", 0))) { + String *cstypeout = Getattr(n, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + if (cstypeout) + tm = cstypeout; + substituteClassname(t, tm); + Printf(return_type, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(t, 0)); + } + + /* Change function name for global variables */ + if (proxy_flag && global_variable_flag) { + // Capitalize the first letter in the variable to create the getter/setter function name + func_name = NewString(""); + setter_flag = (Cmp(Getattr(n, "sym:name"), Swig_name_set(variable_name)) == 0); + if (setter_flag) + Printf(func_name, "set"); + else + Printf(func_name, "get"); + Putc(toupper((int) *Char(variable_name)), func_name); + Printf(func_name, "%s", Char(variable_name) + 1); + if (setter_flag) + Swig_typemap_attach_parms("csvarin", l, NULL); + } else { + func_name = Copy(Getattr(n, "sym:name")); + } + + /* Start generating the function */ + const String *outattributes = Getattr(n, "tmap:cstype:outattributes"); + if (outattributes) + Printf(function_code, " %s\n", outattributes); + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(function_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string); + Printf(function_code, " %s static %s %s(", methodmods, return_type, func_name); + Printv(imcall, imclass_name, ".", overloaded_name, "(", NIL); + + /* Get number of required and total arguments */ + num_arguments = emit_num_arguments(l); + num_required = emit_num_required(l); + + bool global_or_member_variable = global_variable_flag || (wrapping_member_flag && !enum_constant_flag); + int gencomma = 0; + + /* Output each parameter */ + for (i = 0, p = l; i < num_arguments; i++) { + + /* Ignored parameters */ + while (checkAttribute(p, "tmap:in:numinputs", "0")) { + p = Getattr(p, "tmap:in:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *param_type = NewString(""); + last_parm = p; + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + const String *inattributes = Getattr(p, "tmap:cstype:inattributes"); + Printf(param_type, "%s%s", inattributes ? inattributes : empty_string, tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + + if (gencomma) + Printf(imcall, ", "); + + String *arg = makeParameterName(n, p, i, global_or_member_variable); + + // Use typemaps to transform type used in C# wrapper function (in proxy class) to type used in PInvoke function (in intermediary class) + if ((tm = Getattr(p, "tmap:csin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", arg); + String *pre = Getattr(p, "tmap:csin:pre"); + if (pre) { + substituteClassname(pt, pre); + Replaceall(pre, "$csinput", arg); + if (Len(pre_code) > 0) + Printf(pre_code, "\n"); + Printv(pre_code, pre, NIL); + } + String *post = Getattr(p, "tmap:csin:post"); + if (post) { + substituteClassname(pt, post); + Replaceall(post, "$csinput", arg); + if (Len(post_code) > 0) + Printf(post_code, "\n"); + Printv(post_code, post, NIL); + } + String *terminator = Getattr(p, "tmap:csin:terminator"); + if (terminator) { + substituteClassname(pt, terminator); + Replaceall(terminator, "$csinput", arg); + if (Len(terminator_code) > 0) + Insert(terminator_code, 0, "\n"); + Insert(terminator_code, 0, terminator); + } + Printv(imcall, tm, NIL); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSIN_UNDEF, input_file, line_number, "No csin typemap defined for %s\n", SwigType_str(pt, 0)); + } + + /* Add parameter to module class function */ + if (gencomma >= 2) + Printf(function_code, ", "); + gencomma = 2; + Printf(function_code, "%s %s", param_type, arg); + + p = Getattr(p, "tmap:in:next"); + Delete(arg); + Delete(param_type); + } + + Printf(imcall, ")"); + Printf(function_code, ")"); + + // Transform return type used in PInvoke function (in intermediary class) to type used in C# wrapper function (in module class) + if ((tm = Swig_typemap_lookup("csout", n, "", 0))) { + excodeSubstitute(n, tm, "csout", n); + bool is_pre_code = Len(pre_code) > 0; + bool is_post_code = Len(post_code) > 0; + bool is_terminator_code = Len(terminator_code) > 0; + if (is_pre_code || is_post_code || is_terminator_code) { + Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap + if (is_post_code) { + Insert(tm, 0, "\n try "); + Printv(tm, " finally {\n", post_code, "\n }", NIL); + } else { + Insert(tm, 0, "\n "); + } + if (is_pre_code) { + Insert(tm, 0, pre_code); + Insert(tm, 0, "\n"); + } + if (is_terminator_code) { + Printv(tm, "\n", terminator_code, NIL); + } + Insert(tm, 0, "{"); + Printf(tm, "\n }"); + } + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csout typemap defined for %s\n", SwigType_str(t, 0)); + } + + if (proxy_flag && global_variable_flag) { + // Properties + if (generate_property_declaration_flag) { // Ensure the declaration is generated just once should the property contain both a set and get + // Get the C# variable type - obtained differently depending on whether a setter is required. + String *variable_type = return_type; + if (setter_flag) { + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + String *cstypeout = Getattr(p, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap + variable_type = cstypeout ? cstypeout : tm; + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } + const String *csattributes = Getattr(n, "feature:cs:attributes"); + if (csattributes) + Printf(module_class_code, " %s\n", csattributes); + const String *methodmods = Getattr(n, "feature:cs:methodmodifiers"); + if (!methodmods) + methodmods = (is_public(n) ? public_string : protected_string); + Printf(module_class_code, " %s static %s %s {", methodmods, variable_type, variable_name); + } + generate_property_declaration_flag = false; + + if (setter_flag) { + // Setter method + p = last_parm; // (last parameter is the only parameter for properties) + SwigType *pt = Getattr(p, "type"); + if ((tm = Getattr(p, "tmap:csvarin"))) { + substituteClassname(pt, tm); + Replaceall(tm, "$csinput", "value"); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarin", p); + Printf(module_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarin typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + // Getter method + if ((tm = Swig_typemap_lookup("csvarout", n, "", 0))) { + if (GetFlag(n, "feature:new")) + Replaceall(tm, "$owner", "true"); + else + Replaceall(tm, "$owner", "false"); + substituteClassname(t, tm); + Replaceall(tm, "$imcall", imcall); + excodeSubstitute(n, tm, "csvarout", n); + Printf(module_class_code, "%s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No csvarout typemap defined for %s\n", SwigType_str(t, 0)); + } + } + } else { + // Normal function call + Printf(function_code, " %s\n\n", tm ? (const String *) tm : empty_string); + Printv(module_class_code, function_code, NIL); + } + + Delete(pre_code); + Delete(post_code); + Delete(terminator_code); + Delete(function_code); + Delete(return_type); + Delete(imcall); + Delete(func_name); + } + + /*---------------------------------------------------------------------- + * replaceSpecialVariables() + *--------------------------------------------------------------------*/ + + virtual void replaceSpecialVariables(String *method, String *tm, Parm *parm) { + (void)method; + SwigType *type = Getattr(parm, "type"); + substituteClassname(type, tm); + } + + /*---------------------------------------------------------------------- + * decodeEnumFeature() + * Decode the possible enum features, which are one of: + * %csenum(simple) + * %csenum(typeunsafe) - default + * %csenum(typesafe) + * %csenum(proper) + *--------------------------------------------------------------------*/ + + EnumFeature decodeEnumFeature(Node *n) { + EnumFeature enum_feature = TypeunsafeEnum; + String *feature = Getattr(n, "feature:cs:enum"); + if (feature) { + if (Cmp(feature, "simple") == 0) + enum_feature = SimpleEnum; + else if (Cmp(feature, "typesafe") == 0) + enum_feature = TypesafeEnum; + else if (Cmp(feature, "proper") == 0) + enum_feature = ProperEnum; + } + return enum_feature; + } + + /* ----------------------------------------------------------------------- + * enumValue() + * This method will return a string with an enum value to use in C# generated + * code. If the %csconst feature is not used, the string will contain the intermediary + * class call to obtain the enum value. The intermediary class and PINVOKE methods to obtain + * the enum value will be generated. Otherwise the C/C++ enum value will be used if there + * is one and hopefully it will compile as C# code - e.g. 20 as in: enum E{e=20}; + * The %csconstvalue feature overrides all other ways to generate the constant value. + * The caller must delete memory allocated for the returned string. + * ------------------------------------------------------------------------ */ + + String *enumValue(Node *n) { + String *symname = Getattr(n, "sym:name"); + + // Check for the %csconstvalue feature + String *value = Getattr(n, "feature:cs:constvalue"); + + if (!value) { + // The %csconst feature determines how the constant value is obtained + int const_feature_flag = GetFlag(n, "feature:cs:const"); + + if (const_feature_flag) { + // Use the C syntax to make a true C# constant and hope that it compiles as C# code + value = Getattr(n, "enumvalue") ? Copy(Getattr(n, "enumvalue")) : Copy(Getattr(n, "enumvalueex")); + } else { + // Get the enumvalue from a PINVOKE call + if (!getCurrentClass() || !cparse_cplusplus || !proxy_flag) { + // Strange hack to change the name + Setattr(n, "name", Getattr(n, "value")); /* for wrapping of enums in a namespace when emit_action is used */ + constantWrapper(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(symname)); + } else { + memberconstantHandler(n); + value = NewStringf("%s.%s()", imclass_name, Swig_name_get(Swig_name_member(proxy_class_name, symname))); + } + } + } + return value; + } + + /* ----------------------------------------------------------------------------- + * getEnumName() + * ----------------------------------------------------------------------------- */ + + String *getEnumName(SwigType *t) { + Node *enum_name = NULL; + Node *n = enumLookup(t); + if (n) { + String *symname = Getattr(n, "sym:name"); + if (symname) { + // Add in class scope when referencing enum if not a global enum + String *scopename_prefix = Swig_scopename_prefix(Getattr(n, "name")); + String *proxyname = 0; + if (scopename_prefix) { + proxyname = getProxyName(scopename_prefix); + } + if (proxyname) + enum_name = NewStringf("%s.%s", proxyname, symname); + else + enum_name = NewStringf("%s", symname); + Delete(scopename_prefix); + } + } + + return enum_name; + } + + /* ----------------------------------------------------------------------------- + * substituteClassname() + * + * Substitute the special variable $csclassname with the proxy class name for classes/structs/unions + * that SWIG knows about. Also substitutes enums with enum name. + * Otherwise use the $descriptor name for the C# class name. Note that the $&csclassname substitution + * is the same as a $&descriptor substitution, ie one pointer added to descriptor name. + * Inputs: + * pt - parameter type + * tm - typemap contents that might contain the special variable to be replaced + * Outputs: + * tm - typemap contents complete with the special variable substitution + * Return: + * substitution_performed - flag indicating if a substitution was performed + * ----------------------------------------------------------------------------- */ + + bool substituteClassname(SwigType *pt, String *tm) { + bool substitution_performed = false; + SwigType *type = Copy(SwigType_typedef_resolve_all(pt)); + SwigType *strippedtype = SwigType_strip_qualifiers(type); + + if (Strstr(tm, "$csclassname")) { + SwigType *classnametype = Copy(strippedtype); + substituteClassnameSpecialVariable(classnametype, tm, "$csclassname"); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$*csclassname")) { + SwigType *classnametype = Copy(strippedtype); + Delete(SwigType_pop(classnametype)); + substituteClassnameSpecialVariable(classnametype, tm, "$*csclassname"); + substitution_performed = true; + Delete(classnametype); + } + if (Strstr(tm, "$&csclassname")) { + SwigType *classnametype = Copy(strippedtype); + SwigType_add_pointer(classnametype); + substituteClassnameSpecialVariable(classnametype, tm, "$&csclassname"); + substitution_performed = true; + Delete(classnametype); + } + + Delete(strippedtype); + Delete(type); + + return substitution_performed; + } + + /* ----------------------------------------------------------------------------- + * substituteClassnameSpecialVariable() + * ----------------------------------------------------------------------------- */ + + void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) { + if (SwigType_isenum(classnametype)) { + String *enumname = getEnumName(classnametype); + if (enumname) + Replaceall(tm, classnamespecialvariable, enumname); + else + Replaceall(tm, classnamespecialvariable, NewStringf("int")); + } else { + String *classname = getProxyName(classnametype); + if (classname) { + Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too + } else { // use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved. + String *descriptor = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype)); + Replaceall(tm, classnamespecialvariable, descriptor); + + // Add to hash table so that the type wrapper classes can be created later + Setattr(swig_types_hash, descriptor, classnametype); + Delete(descriptor); + } + } + } + + /* ----------------------------------------------------------------------------- + * makeParameterName() + * + * Inputs: + * n - Node + * p - parameter node + * arg_num - parameter argument number + * setter - set this flag when wrapping variables + * Return: + * arg - a unique parameter name + * ----------------------------------------------------------------------------- */ + + String *makeParameterName(Node *n, Parm *p, int arg_num, bool setter) { + + String *arg = 0; + String *pn = Getattr(p, "name"); + + // Use C parameter name unless it is a duplicate or an empty parameter name + int count = 0; + ParmList *plist = Getattr(n, "parms"); + while (plist) { + if ((Cmp(pn, Getattr(plist, "name")) == 0)) + count++; + plist = nextSibling(plist); + } + String *wrn = pn ? Swig_name_warning(p, 0, pn, 0) : 0; + arg = (!pn || (count > 1) || wrn) ? NewStringf("arg%d", arg_num) : Copy(pn); + + if (setter && Cmp(arg, "self") != 0) { + // Note that in C# properties, the input variable name is always called 'value' + Delete(arg); + arg = NewString("value"); + } + + return arg; + } + + /* ----------------------------------------------------------------------------- + * emitTypeWrapperClass() + * ----------------------------------------------------------------------------- */ + + void emitTypeWrapperClass(String *classname, SwigType *type) { + Node *n = NewHash(); + Setfile(n, input_file); + Setline(n, line_number); + + String *swigtype = NewString(""); + String *filen = NewStringf("%s%s.cs", SWIG_output_directory(), classname); + File *f_swigtype = NewFile(filen, "w", SWIG_output_files()); + if (!f_swigtype) { + FileErrorDisplay(filen); + SWIG_exit(EXIT_FAILURE); + } + Append(filenames_list, Copy(filen)); + Delete(filen); + filen = NULL; + + // Start writing out the type wrapper class file + emitBanner(f_swigtype); + + addOpenNamespace(namespce, f_swigtype); + + // Pure C# baseclass and interfaces + const String *pure_baseclass = typemapLookup(n, "csbase", type, WARN_NONE); + const String *pure_interfaces = typemapLookup(n, "csinterfaces", type, WARN_NONE); + + // Emit the class + Printv(swigtype, typemapLookup(n, "csimports", type, WARN_NONE), // Import statements + "\n", NIL); + + // Class attributes + const String *csattributes = typemapLookup(n, "csattributes", type, WARN_NONE); + if (csattributes && *Char(csattributes)) + Printf(swigtype, "%s\n", csattributes); + + Printv(swigtype, typemapLookup(n, "csclassmodifiers", type, WARN_CSHARP_TYPEMAP_CLASSMOD_UNDEF), // Class modifiers + " $csclassname", // Class name and base class + (*Char(pure_baseclass) || *Char(pure_interfaces)) ? " : " : "", pure_baseclass, ((*Char(pure_baseclass)) && *Char(pure_interfaces)) ? // Interfaces + ", " : "", pure_interfaces, " {", typemapLookup(n, "csbody", type, WARN_CSHARP_TYPEMAP_CSBODY_UNDEF), // main body of class + typemapLookup(n, "cscode", type, WARN_NONE), // extra C# code + "}\n", NIL); + + Replaceall(swigtype, "$csclassname", classname); + Replaceall(swigtype, "$module", module_class_name); + Replaceall(swigtype, "$imclassname", imclass_name); + Replaceall(swigtype, "$dllimport", dllimport); + + Printv(f_swigtype, swigtype, NIL); + + addCloseNamespace(namespce, f_swigtype); + + Close(f_swigtype); + Delete(swigtype); + Delete(n); + } + + /* ----------------------------------------------------------------------------- + * typemapLookup() + * n - for input only and must contain info for Getfile(n) and Getline(n) to work + * tmap_method - typemap method name + * type - typemap type to lookup + * warning - warning number to issue if no typemaps found + * typemap_attributes - the typemap attributes are attached to this node and will + * also be used for temporary storage if non null + * return is never NULL, unlike Swig_typemap_lookup() + * ----------------------------------------------------------------------------- */ + + const String *typemapLookup(Node *n, const_String_or_char_ptr tmap_method, SwigType *type, int warning, Node *typemap_attributes = 0) { + Node *node = !typemap_attributes ? NewHash() : typemap_attributes; + Setattr(node, "type", type); + Setfile(node, Getfile(n)); + Setline(node, Getline(n)); + const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0); + if (!tm) { + tm = empty_string; + if (warning != WARN_NONE) + Swig_warning(warning, Getfile(n), Getline(n), "No %s typemap defined for %s\n", tmap_method, SwigType_str(type, 0)); + } + if (!typemap_attributes) + Delete(node); + return tm; + } + + /* ----------------------------------------------------------------------------- + * canThrow() + * Determine whether the code in the typemap can throw a C# exception. + * If so, note it for later when excodeSubstitute() is called. + * ----------------------------------------------------------------------------- */ + + void canThrow(Node *n, const String *typemap, Node *parameter) { + String *canthrow_attribute = NewStringf("tmap:%s:canthrow", typemap); + String *canthrow = Getattr(parameter, canthrow_attribute); + if (canthrow) + Setattr(n, "csharp:canthrow", "1"); + Delete(canthrow_attribute); + } + + /* ----------------------------------------------------------------------------- + * excodeSubstitute() + * If a method can throw a C# exception, additional exception code is added to + * check for the pending exception so that it can then throw the exception. The + * $excode special variable is replaced by the exception code in the excode + * typemap attribute. + * ----------------------------------------------------------------------------- */ + + void excodeSubstitute(Node *n, String *code, const String *typemap, Node *parameter) { + String *excode_attribute = NewStringf("tmap:%s:excode", typemap); + String *excode = Getattr(parameter, excode_attribute); + if (Getattr(n, "csharp:canthrow")) { + int count = Replaceall(code, "$excode", excode); + if (count < 1 || !excode) { + Swig_warning(WARN_CSHARP_EXCODE, input_file, line_number, + "C# exception may not be thrown - no $excode or excode attribute in '%s' typemap.\n", typemap); + } + } else { + Replaceall(code, "$excode", empty_string); + } + Delete(excode_attribute); + } + + /* ----------------------------------------------------------------------------- + * addOpenNamespace() + * ----------------------------------------------------------------------------- */ + + void addOpenNamespace(String *namspace, File *file) { + if (namspace) + if (Len(namspace) > 0) + Printf(file, "namespace %s {\n", namspace); + } + + /* ----------------------------------------------------------------------------- + * addCloseNamespace() + * ----------------------------------------------------------------------------- */ + + void addCloseNamespace(String *namspace, File *file) { + if (namspace) + if (Len(namspace) > 0) + Printf(file, "\n}\n"); + } + + /*---------------------------------------------------------------------- + * Start of director methods + *--------------------------------------------------------------------*/ + +#if 0 + /*---------------------------------------------------------------------- + * emitDirectorUpcalls() + *--------------------------------------------------------------------*/ + + void emitDirectorUpcalls() { + if (n_dmethods) { + Wrapper *w = NewWrapper(); + String *dmethod_data = NewString(""); + int n_methods = 0; + Iterator udata_iter; + + udata_iter = First(dmethods_seq); + while (udata_iter.item) { + UpcallData *udata = udata_iter.item; + Printf(dmethod_data, " { \"%s\", \"%s\" }", Getattr(udata, "imclass_method"), Getattr(udata, "imclass_fdesc")); + ++n_methods; + + udata_iter = Next(udata_iter); + + if (udata_iter.item) + Putc(',', dmethod_data); + Putc('\n', dmethod_data); + } + + + Wrapper_print(w, f_wrappers); + Delete(dmethod_data); + Delete(swig_module_init); + DelWrapper(w); + } + } +#endif + + /*---------------------------------------------------------------------- + * emitDirectorExtraMethods() + * + * This is where the director connect method is + * generated. + *--------------------------------------------------------------------*/ + void emitDirectorExtraMethods(Node *n) { + if (!Swig_directorclass(n)) + return; + + // Output the director connect method: + String *norm_name = SwigType_namestr(Getattr(n, "name")); + String *swig_director_connect = NewStringf("%s_director_connect", proxy_class_name); + String *sym_name = Getattr(n, "sym:name"); + Wrapper *code_wrap; + + Printv(imclass_class_code, "\n [DllImport(\"", dllimport, "\", EntryPoint=\"CSharp_", swig_director_connect, "\")]\n", NIL); + Printf(imclass_class_code, " public static extern void %s(HandleRef jarg1", swig_director_connect); + + code_wrap = NewWrapper(); + Printf(code_wrap->def, "SWIGEXPORT void SWIGSTDCALL CSharp_%s(void *objarg", swig_director_connect); + + Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", norm_name, norm_name); + Printf(code_wrap->code, " SwigDirector_%s *director = dynamic_cast<SwigDirector_%s *>(obj);\n", sym_name, sym_name); + // TODO: if statement not needed?? - Java too + Printf(code_wrap->code, " if (director) {\n"); + Printf(code_wrap->code, " director->swig_connect_director("); + + for (int i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + + Printf(code_wrap->def, ", "); + if (i != first_class_dmethod) + Printf(code_wrap->code, ", "); + Printf(code_wrap->def, "SwigDirector_%s::SWIG_Callback%s_t callback%s", sym_name, methid, methid); + Printf(code_wrap->code, "callback%s", methid); + Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", sym_name, sym_name, methid, methid); + } + + Printf(code_wrap->def, ") {\n"); + Printf(code_wrap->code, ");\n"); + Printf(imclass_class_code, ");\n"); + Printf(code_wrap->code, " }\n"); + Printf(code_wrap->code, "}\n"); + + Wrapper_print(code_wrap, f_wrappers); + DelWrapper(code_wrap); + + Delete(swig_director_connect); + } + + /* --------------------------------------------------------------- + * classDirectorMethod() + * + * Emit a virtual director method to pass a method call on to the + * underlying Java object. + * + * --------------------------------------------------------------- */ + + int classDirectorMethod(Node *n, Node *parent, String *super) { + String *empty_str = NewString(""); + String *classname = Getattr(parent, "sym:name"); + String *c_classname = Getattr(parent, "name"); + String *name = Getattr(n, "name"); + String *symname = Getattr(n, "sym:name"); + SwigType *type = Getattr(n, "type"); + SwigType *returntype = Getattr(n, "returntype"); + String *overloaded_name = getOverloadedName(n); + String *storage = Getattr(n, "storage"); + String *value = Getattr(n, "value"); + String *decl = Getattr(n, "decl"); + String *declaration = NewString(""); + String *tm; + Parm *p; + int i; + Wrapper *w = NewWrapper(); + ParmList *l = Getattr(n, "parms"); + bool is_void = !(Cmp(returntype, "void")); + String *qualified_return = NewString(""); + bool pure_virtual = (!(Cmp(storage, "virtual")) && !(Cmp(value, "0"))); + int status = SWIG_OK; + bool output_director = true; + String *dirclassname = directorClassName(parent); + String *qualified_name = NewStringf("%s::%s", dirclassname, name); + SwigType *c_ret_type = NULL; + String *jupcall_args = NewString(""); + String *imclass_dmethod; + String *callback_typedef_parms = NewString(""); + String *delegate_parms = NewString(""); + String *proxy_method_types = NewString(""); + String *callback_def = NewString(""); + String *callback_code = NewString(""); + String *imcall_args = NewString(""); + int gencomma = 0; + bool ignored_method = GetFlag(n, "feature:ignore") ? true : false; + + // Kludge Alert: functionWrapper sets sym:overload properly, but it + // isn't at this point, so we have to manufacture it ourselves. At least + // we're consistent with the sym:overload name in functionWrapper. (?? when + // does the overloaded method name get set?) + + imclass_dmethod = NewStringf("SwigDirector_%s", Swig_name_member(classname, overloaded_name)); + + if (returntype) { + + qualified_return = SwigType_rcaststr(returntype, "c_result"); + + if (!is_void && !ignored_method) { + if (!SwigType_isclass(returntype)) { + if (!(SwigType_ispointer(returntype) || SwigType_isreference(returntype))) { + String *construct_result = NewStringf("= SwigValueInit< %s >()", SwigType_lstr(returntype, 0)); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), construct_result, NIL); + Delete(construct_result); + } else { + String *base_typename = SwigType_base(returntype); + String *resolved_typename = SwigType_typedef_resolve_all(base_typename); + Symtab *symtab = Getattr(n, "sym:symtab"); + Node *typenode = Swig_symbol_clookup(resolved_typename, symtab); + + if (SwigType_ispointer(returntype) || (typenode && Getattr(typenode, "abstract"))) { + /* initialize pointers to something sane. Same for abstract + classes when a reference is returned. */ + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= 0", NIL); + } else { + /* If returning a reference, initialize the pointer to a sane + default - if a C# exception occurs, then the pointer returns + something other than a NULL-initialized reference. */ + String *non_ref_type = Copy(returntype); + + /* Remove reference and const qualifiers */ + Replaceall(non_ref_type, "r.", ""); + Replaceall(non_ref_type, "q(const).", ""); + Wrapper_add_localv(w, "result_default", "static", SwigType_str(non_ref_type, "result_default"), "=", SwigType_str(non_ref_type, "()"), NIL); + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), "= &result_default", NIL); + + Delete(non_ref_type); + } + + Delete(base_typename); + Delete(resolved_typename); + } + } else { + SwigType *vt; + + vt = cplus_value_type(returntype); + if (!vt) { + Wrapper_add_localv(w, "c_result", SwigType_lstr(returntype, "c_result"), NIL); + } else { + Wrapper_add_localv(w, "c_result", SwigType_lstr(vt, "c_result"), NIL); + Delete(vt); + } + } + } + + /* Create the intermediate class wrapper */ + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + tm = Swig_typemap_lookup("imtype", tp, "", 0); + if (tm) { + String *imtypeout = Getattr(tp, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + const String *im_directoroutattributes = Getattr(tp, "tmap:imtype:directoroutattributes"); + if (im_directoroutattributes) { + Printf(callback_def, " %s\n", im_directoroutattributes); + Printf(director_delegate_definitions, " %s\n", im_directoroutattributes); + } + + Printf(callback_def, " private %s SwigDirector%s(", tm, overloaded_name); + if (!ignored_method) + Printf(director_delegate_definitions, " public delegate %s", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(returntype, 0)); + } + + Parm *retpm = NewParmFromNode(returntype, empty_str, n); + + if ((c_ret_type = Swig_typemap_lookup("ctype", retpm, "", 0))) { + + if (!is_void && !ignored_method) { + String *jretval_decl = NewStringf("%s jresult", c_ret_type); + Wrapper_add_localv(w, "jresult", jretval_decl, "= 0", NIL); + Delete(jretval_decl); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(retpm); + } + + /* Go through argument list, attach lnames for arguments */ + for (i = 0, p = l; p; p = nextSibling(p), ++i) { + String *arg = Getattr(p, "name"); + String *lname = NewString(""); + + if (!arg && Cmp(Getattr(p, "type"), "void")) { + lname = NewStringf("arg%d", i); + Setattr(p, "name", lname); + } else + lname = arg; + + Setattr(p, "lname", lname); + } + + /* Attach the standard typemaps */ + Swig_typemap_attach_parms("out", l, 0); + Swig_typemap_attach_parms("ctype", l, 0); + Swig_typemap_attach_parms("imtype", l, 0); + Swig_typemap_attach_parms("cstype", l, 0); + Swig_typemap_attach_parms("directorin", l, 0); + Swig_typemap_attach_parms("csdirectorin", l, 0); + + /* Preamble code */ + if (!ignored_method) + Printf(w->code, "if (!swig_callback%s) {\n", overloaded_name); + + if (!pure_virtual) { + String *super_call = Swig_method_call(super, l); + if (is_void) { + Printf(w->code, "%s;\n", super_call); + if (!ignored_method) + Printf(w->code, "return;\n"); + } else { + Printf(w->code, "return %s;\n", super_call); + } + Delete(super_call); + } else { + Printf(w->code, " throw Swig::DirectorPureVirtualException(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name)); + } + + if (!ignored_method) + Printf(w->code, "} else {\n"); + + /* Go through argument list, convert from native to Java */ + for (p = l; p; /* empty */ ) { + /* Is this superfluous? */ + while (checkAttribute(p, "tmap:directorin:numinputs", "0")) { + p = Getattr(p, "tmap:directorin:next"); + } + + SwigType *pt = Getattr(p, "type"); + String *ln = Copy(Getattr(p, "name")); + String *c_param_type = NULL; + String *c_decl = NewString(""); + String *arg = NewString(""); + + Printf(arg, "j%s", ln); + + /* And add to the upcall args */ + if (gencomma > 0) + Printf(jupcall_args, ", "); + Printf(jupcall_args, "%s", arg); + + /* Get parameter's intermediary C type */ + if ((c_param_type = Getattr(p, "tmap:ctype"))) { + String *ctypeout = Getattr(p, "tmap:ctype:out"); // the type in the ctype typemap's out attribute overrides the type in the typemap + if (ctypeout) + c_param_type = ctypeout; + + Parm *tp = NewParmFromNode(c_param_type, empty_str, n); + String *desc_tm = NULL; + + /* Add to local variables */ + Printf(c_decl, "%s %s", c_param_type, arg); + if (!ignored_method) + Wrapper_add_localv(w, arg, c_decl, (!(SwigType_ispointer(pt) || SwigType_isreference(pt)) ? "" : "= 0"), NIL); + + /* Add input marshalling code */ + if ((desc_tm = Swig_typemap_lookup("directorin", tp, "", 0)) + && (tm = Getattr(p, "tmap:directorin"))) { + + Replaceall(tm, "$input", arg); + Replaceall(tm, "$owner", "0"); + + if (Len(tm)) + if (!ignored_method) + Printf(w->code, "%s\n", tm); + + Delete(tm); + + /* Add C type to callback typedef */ + if (gencomma > 0) + Printf(callback_typedef_parms, ", "); + Printf(callback_typedef_parms, "%s", c_param_type); + + /* Add parameter to the intermediate class code if generating the + * intermediate's upcall code */ + if ((tm = Getattr(p, "tmap:imtype"))) { + + String *imtypeout = Getattr(p, "tmap:imtype:out"); // the type in the imtype typemap's out attribute overrides the type in the typemap + if (imtypeout) + tm = imtypeout; + const String *im_directorinattributes = Getattr(p, "tmap:imtype:directorinattributes"); + + String *din = Copy(Getattr(p, "tmap:csdirectorin")); + + if (din) { + Replaceall(din, "$module", module_class_name); + Replaceall(din, "$imclassname", imclass_name); + substituteClassname(pt, din); + Replaceall(din, "$iminput", ln); + + if (gencomma > 0) { + Printf(delegate_parms, ", "); + Printf(proxy_method_types, ", "); + Printf(imcall_args, ", "); + } + Printf(delegate_parms, "%s%s %s", im_directorinattributes ? im_directorinattributes : empty_string, tm, ln); + + if (Cmp(din, ln)) { + Printv(imcall_args, din, NIL); + } else + Printv(imcall_args, ln, NIL); + + /* Get the C# parameter type */ + if ((tm = Getattr(p, "tmap:cstype"))) { + substituteClassname(pt, tm); + Printf(proxy_method_types, "typeof(%s)", tm); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(pt, 0)); + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, "No csdirectorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + p = Getattr(p, "tmap:directorin:next"); + + Delete(desc_tm); + } else { + if (!desc_tm) { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(c_param_type, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } else if (!tm) { + Swig_warning(WARN_CSHARP_TYPEMAP_CSDIRECTORIN_UNDEF, input_file, line_number, + "No or improper directorin typemap defined for argument %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + p = nextSibling(p); + } + + output_director = false; + } + + Delete(tp); + } else { + Swig_warning(WARN_CSHARP_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s for use in %s::%s (skipping director method)\n", + SwigType_str(pt, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + p = nextSibling(p); + } + + gencomma++; + Delete(arg); + Delete(c_decl); + Delete(c_param_type); + } + + /* header declaration, start wrapper definition */ + String *target; + SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : type; + target = Swig_method_decl(rtype, decl, qualified_name, l, 0, 0); + Printf(w->def, "%s", target); + Delete(qualified_name); + Delete(target); + target = Swig_method_decl(rtype, decl, name, l, 0, 1); + Printf(declaration, " virtual %s", target); + Delete(target); + + // Add any exception specifications to the methods in the director class + ParmList *throw_parm_list = NULL; + if ((throw_parm_list = Getattr(n, "throws")) || Getattr(n, "throw")) { + int gencomma = 0; + + Append(w->def, " throw("); + Append(declaration, " throw("); + + if (throw_parm_list) + Swig_typemap_attach_parms("throws", throw_parm_list, 0); + for (p = throw_parm_list; p; p = nextSibling(p)) { + if ((tm = Getattr(p, "tmap:throws"))) { + if (gencomma++) { + Append(w->def, ", "); + Append(declaration, ", "); + } + Printf(w->def, "%s", SwigType_str(Getattr(p, "type"), 0)); + Printf(declaration, "%s", SwigType_str(Getattr(p, "type"), 0)); + } + } + + Append(w->def, ")"); + Append(declaration, ")"); + } + + Append(w->def, " {"); + Append(declaration, ";\n"); + + /* Finish off the inherited upcall's definition */ + + Printf(callback_def, "%s)", delegate_parms); + Printf(callback_def, " {\n"); + + /* Emit the intermediate class's upcall to the actual class */ + + String *upcall = NewStringf("%s(%s)", symname, imcall_args); + + if (!is_void) { + Parm *tp = NewParmFromNode(returntype, empty_str, n); + + if ((tm = Swig_typemap_lookup("csdirectorout", tp, "", 0))) { + substituteClassname(returntype, tm); + Replaceall(tm, "$cscall", upcall); + + Printf(callback_code, " return %s;\n", tm); + } + + Delete(tm); + Delete(tp); + } else + Printf(callback_code, " %s;\n", upcall); + + Printf(callback_code, " }\n"); + Delete(upcall); + + if (!ignored_method) { + if (!is_void) + Printf(w->code, "jresult = (%s) ", c_ret_type); + + Printf(w->code, "swig_callback%s(%s);\n", overloaded_name, jupcall_args); + + if (!is_void) { + String *jresult_str = NewString("jresult"); + String *result_str = NewString("c_result"); + Parm *tp = NewParmFromNode(returntype, result_str, n); + + /* Copy jresult into c_result... */ + if ((tm = Swig_typemap_lookup("directorout", tp, result_str, w))) { + Replaceall(tm, "$input", jresult_str); + Replaceall(tm, "$result", result_str); + Printf(w->code, "%s\n", tm); + } else { + Swig_warning(WARN_TYPEMAP_DIRECTOROUT_UNDEF, input_file, line_number, + "Unable to use return type %s used in %s::%s (skipping director method)\n", + SwigType_str(returntype, 0), SwigType_namestr(c_classname), SwigType_namestr(name)); + output_director = false; + } + + Delete(tp); + Delete(jresult_str); + Delete(result_str); + } + + /* Terminate wrapper code */ + Printf(w->code, "}\n"); + if (!is_void) + Printf(w->code, "return %s;", qualified_return); + } + + Printf(w->code, "}"); + + // We expose virtual protected methods via an extra public inline method which makes a straight call to the wrapped class' method + String *inline_extra_method = NewString(""); + if (dirprot_mode() && !is_public(n) && !pure_virtual) { + Printv(inline_extra_method, declaration, NIL); + String *extra_method_name = NewStringf("%sSwigPublic", name); + Replaceall(inline_extra_method, name, extra_method_name); + Replaceall(inline_extra_method, ";\n", " {\n "); + if (!is_void) + Printf(inline_extra_method, "return "); + String *methodcall = Swig_method_call(super, l); + Printv(inline_extra_method, methodcall, ";\n }\n", NIL); + Delete(methodcall); + Delete(extra_method_name); + } + + /* emit code */ + if (status == SWIG_OK && output_director) { + if (!is_void) { + Replaceall(w->code, "$null", qualified_return); + } else { + Replaceall(w->code, "$null", ""); + } + if (!ignored_method) + Printv(director_delegate_callback, "\n", callback_def, callback_code, NIL); + if (!Getattr(n, "defaultargs")) { + Wrapper_print(w, f_directors); + Printv(f_directors_h, declaration, NIL); + Printv(f_directors_h, inline_extra_method, NIL); + } + } + + if (!ignored_method) { + /* Emit the actual upcall through */ + UpcallData *udata = addUpcallMethod(imclass_dmethod, symname, decl, overloaded_name); + String *methid = Getattr(udata, "class_methodidx"); + + Printf(director_callback_typedefs, " typedef %s (SWIGSTDCALL* SWIG_Callback%s_t)(", c_ret_type, methid); + Printf(director_callback_typedefs, "%s);\n", callback_typedef_parms); + Printf(director_callbacks, " SWIG_Callback%s_t swig_callback%s;\n", methid, overloaded_name); + + Printf(director_delegate_definitions, " SwigDelegate%s_%s(%s);\n", classname, methid, delegate_parms); + Printf(director_delegate_instances, " private SwigDelegate%s_%s swigDelegate%s;\n", classname, methid, methid); + Printf(director_method_types, " private static Type[] swigMethodTypes%s = new Type[] { %s };\n", methid, proxy_method_types); + Printf(director_connect_parms, "SwigDirector%s%s delegate%s", classname, methid, methid); + } + + Delete(qualified_return); + Delete(c_ret_type); + Delete(declaration); + Delete(callback_typedef_parms); + Delete(delegate_parms); + Delete(proxy_method_types); + Delete(callback_def); + Delete(callback_code); + DelWrapper(w); + + return status; + } + + /* ------------------------------------------------------------ + * classDirectorConstructor() + * ------------------------------------------------------------ */ + + int classDirectorConstructor(Node *n) { + Node *parent = parentNode(n); + String *decl = Getattr(n, "decl");; + String *supername = Swig_class_name(parent); + String *classname = directorClassName(parent); + String *sub = NewString(""); + Parm *p; + ParmList *superparms = Getattr(n, "parms"); + ParmList *parms; + int argidx = 0; + + /* Assign arguments to superclass's parameters, if not already done */ + for (p = superparms; p; p = nextSibling(p)) { + String *pname = Getattr(p, "name"); + + if (!pname) { + pname = NewStringf("arg%d", argidx++); + Setattr(p, "name", pname); + } + } + + // TODO: Is this copy needed? + parms = CopyParmList(superparms); + + if (!Getattr(n, "defaultargs")) { + /* constructor */ + { + String *basetype = Getattr(parent, "classtype"); + String *target = Swig_method_decl(0, decl, classname, parms, 0, 0); + String *call = Swig_csuperclass_call(0, basetype, superparms); + String *classtype = SwigType_namestr(Getattr(n, "name")); + + Printf(f_directors, "%s::%s : %s, %s {\n", classname, target, call, Getattr(parent, "director:ctor")); + Printf(f_directors, " swig_init_callbacks();\n"); + Printf(f_directors, "}\n\n"); + + Delete(classtype); + Delete(target); + Delete(call); + } + + /* constructor header */ + { + String *target = Swig_method_decl(0, decl, classname, parms, 0, 1); + Printf(f_directors_h, " %s;\n", target); + Delete(target); + } + } + + Delete(sub); + Delete(supername); + Delete(parms); + return Language::classDirectorConstructor(n); + } + + /* ------------------------------------------------------------ + * classDirectorDefaultConstructor() + * ------------------------------------------------------------ */ + + int classDirectorDefaultConstructor(Node *n) { + String *classname = Swig_class_name(n); + String *classtype = SwigType_namestr(Getattr(n, "name")); + Wrapper *w = NewWrapper(); + + Printf(w->def, "SwigDirector_%s::SwigDirector_%s() : %s {", classname, classname, Getattr(n, "director:ctor")); + Printf(w->code, "}\n"); + Wrapper_print(w, f_directors); + + Printf(f_directors_h, " SwigDirector_%s();\n", classname); + DelWrapper(w); + Delete(classtype); + Delete(classname); + return Language::classDirectorDefaultConstructor(n); + } + + + /* ------------------------------------------------------------ + * classDirectorInit() + * ------------------------------------------------------------ */ + + int classDirectorInit(Node *n) { + Delete(none_comparison); + none_comparison = NewString(""); // not used + + Delete(director_ctor_code); + director_ctor_code = NewString("$director_new"); + + Java_director_declaration(n); + + Printf(f_directors_h, "%s {\n", Getattr(n, "director:decl")); + Printf(f_directors_h, "\npublic:\n"); + + /* Keep track of the director methods for this class */ + first_class_dmethod = curr_class_dmethod = n_dmethods; + + director_callback_typedefs = NewString(""); + director_callbacks = NewString(""); + director_delegate_callback = NewString(""); + director_delegate_definitions = NewString(""); + director_delegate_instances = NewString(""); + director_method_types = NewString(""); + director_connect_parms = NewString(""); + + return Language::classDirectorInit(n); + } + + /* ---------------------------------------------------------------------- + * classDirectorDestructor() + * ---------------------------------------------------------------------- */ + + int classDirectorDestructor(Node *n) { + Node *current_class = getCurrentClass(); + String *full_classname = Getattr(current_class, "name"); + String *classname = Swig_class_name(current_class); + Wrapper *w = NewWrapper(); + + if (Getattr(n, "throw")) { + Printf(f_directors_h, " virtual ~SwigDirector_%s() throw ();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() throw () {\n", classname, classname); + } else { + Printf(f_directors_h, " virtual ~SwigDirector_%s();\n", classname); + Printf(w->def, "SwigDirector_%s::~SwigDirector_%s() {\n", classname, classname); + } + + /* Ensure that correct directordisconnect typemap's method name is called + * here: */ + + const String *disconn_tm = NULL; + Node *disconn_attr = NewHash(); + String *disconn_methodname = NULL; + + disconn_tm = typemapLookup(n, "directordisconnect", full_classname, WARN_NONE, disconn_attr); + disconn_methodname = Getattr(disconn_attr, "tmap:directordisconnect:methodname"); + + Printv(w->code, "}\n", NIL); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + Delete(disconn_attr); + Delete(classname); + return SWIG_OK; + } + + /* ------------------------------------------------------------ + * classDirectorEnd() + * ------------------------------------------------------------ */ + + int classDirectorEnd(Node *n) { + int i; + String *director_classname = directorClassName(n); + + Wrapper *w = NewWrapper(); + + if (Len(director_callback_typedefs) > 0) { + Printf(f_directors_h, "\n%s", director_callback_typedefs); + } + + Printf(f_directors_h, " void swig_connect_director("); + + Printf(w->def, "void %s::swig_connect_director(", director_classname); + + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *methid = Getattr(udata, "class_methodidx"); + String *overname = Getattr(udata, "overname"); + + Printf(f_directors_h, "SWIG_Callback%s_t callback%s", methid, overname); + Printf(w->def, "SWIG_Callback%s_t callback%s", methid, overname); + Printf(w->code, "swig_callback%s = callback%s;\n", overname, overname); + if (i != curr_class_dmethod - 1) { + Printf(f_directors_h, ", "); + Printf(w->def, ", "); + } + } + + Printf(f_directors_h, ");\n"); + Printf(w->def, ") {"); + + + if (Len(director_callback_typedefs) > 0) { + Printf(f_directors_h, "\nprivate:\n%s", director_callbacks); + } + Printf(f_directors_h, " void swig_init_callbacks();\n"); + Printf(f_directors_h, "};\n\n"); + Printf(w->code, "}\n\n"); + + Printf(w->code, "void %s::swig_init_callbacks() {\n", director_classname); + for (i = first_class_dmethod; i < curr_class_dmethod; ++i) { + UpcallData *udata = Getitem(dmethods_seq, i); + String *overname = Getattr(udata, "overname"); + Printf(w->code, "swig_callback%s = 0;\n", overname); + } + Printf(w->code, "}"); + + Wrapper_print(w, f_directors); + + DelWrapper(w); + + return Language::classDirectorEnd(n); + } + + /* -------------------------------------------------------------------- + * classDirectorDisown() + * ------------------------------------------------------------------*/ + virtual int classDirectorDisown(Node *n) { + (void) n; + return SWIG_OK; + } + + /*---------------------------------------------------------------------- + * extraDirectorProtectedCPPMethodsRequired() + *--------------------------------------------------------------------*/ + + bool extraDirectorProtectedCPPMethodsRequired() const { + return false; + } + + /*---------------------------------------------------------------------- + * Java_director_declaration() + * + * Generate the director class's declaration + * e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {" + *--------------------------------------------------------------------*/ + + void Java_director_declaration(Node *n) { + + String *base = Getattr(n, "classtype"); + String *class_ctor = NewString("Swig::Director()"); + + String *classname = Swig_class_name(n); + String *directorname = NewStringf("SwigDirector_%s", classname); + String *declaration = Swig_class_declaration(n, directorname); + + Printf(declaration, " : public %s, public Swig::Director", base); + + // Stash stuff for later. + Setattr(n, "director:decl", declaration); + Setattr(n, "director:ctor", class_ctor); + } + +}; /* class CSHARP */ + +/* ----------------------------------------------------------------------------- + * swig_csharp() - Instantiate module + * ----------------------------------------------------------------------------- */ + +static Language *new_swig_csharp() { + return new CSHARP(); +} +extern "C" Language *swig_csharp(void) { + return new_swig_csharp(); +} + +/* ----------------------------------------------------------------------------- + * Static member variables + * ----------------------------------------------------------------------------- */ + +const char *CSHARP::usage = (char *) "\ +C# Options (available with -csharp)\n\ + -dllimport <dl> - Override DllImport attribute name to <dl>\n\ + -namespace <nm> - Generate wrappers into C# namespace <nm>\n\ + -noproxy - Generate the low-level functional interface instead\n\ + of proxy classes\n\ + -oldvarnames - old intermediary method names for variable wrappers\n\ +\n"; |
