blob: 27cc65b32453d6b86d860e0a02575bfcc594bdf9 [file] [log] [blame]
/* -----------------------------------------------------------------------------
* This file is part of SWIG, which is licensed as a whole under version 3
* (or any later version) of the GNU General Public License. Some additional
* terms also apply to certain portions of SWIG. The full details of the SWIG
* license and copyrights can be found in the LICENSE and COPYRIGHT files
* included with the SWIG source code as distributed by the SWIG developers
* and at http://www.swig.org/legal.html.
*
* csharp.cxx
*
* C# language module for SWIG.
* ----------------------------------------------------------------------------- */
#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;
File *f_single_out;
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 *interface_class_code; // if %feature("interface") was declared for a class, here goes the interface declaration
String *module_class_code;
String *proxy_class_name; // proxy class name
String *full_imclass_name; // fully qualified intermediary class name when using nspace feature, otherwise same as imclass_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 overridden by %pragma
String *module_class_modifiers; //class modifiers for module class overridden 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
String *output_file; // File name for single file mode. If set all generated code will be written to this file
// Director method stuff:
List *dmethods_seq;
Hash *dmethods_table;
int n_dmethods;
int n_directors;
int first_class_dmethod;
int curr_class_dmethod;
int nesting_depth;
enum EnumFeature { SimpleEnum, TypeunsafeEnum, TypesafeEnum, ProperEnum };
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),
f_single_out(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),
interface_class_code(NULL),
module_class_code(NULL),
proxy_class_name(NULL),
full_imclass_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),
output_file(NULL),
dmethods_seq(NULL),
dmethods_table(NULL),
n_dmethods(0),
n_directors(0),
first_class_dmethod(0),
curr_class_dmethod(0),
nesting_depth(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, fully qualified with
* a namespace if the nspace feature is used.
* ----------------------------------------------------------------------------- */
String *getProxyName(SwigType *t) {
String *proxyname = NULL;
if (proxy_flag) {
Node *n = classLookup(t);
if (n) {
proxyname = Getattr(n, "proxyname");
if (!proxyname) {
String *nspace = Getattr(n, "sym:nspace");
String *symname = Copy(Getattr(n, "sym:name"));
if (symname && !GetFlag(n, "feature:flatnested")) {
for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) {
if (String* name = Getattr(outer_class, "sym:name")) {
Push(symname, ".");
Push(symname, name);
}
else
return NULL;
}
}
if (nspace) {
if (namespce)
proxyname = NewStringf("%s.%s.%s", namespce, nspace, symname);
else
proxyname = NewStringf("%s.%s", nspace, symname);
} else {
proxyname = Copy(symname);
}
Setattr(n, "proxyname", proxyname);
Delete(proxyname);
Delete(symname);
}
}
}
return proxyname;
}
/* ------------------------------------------------------------
* 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]);
if (Len(namespce) == 0) {
Delete(namespce);
namespce = 0;
}
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], "-outfile") == 0) {
if (argv[i + 1]) {
output_file = NewString("");
Printf(output_file, argv[i + 1]);
Swig_mark_arg(i);
Swig_mark_arg(i + 1);
i++;
} else {
Swig_arg_error();
}
} 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();
Swig_interface_feature_enable();
}
/* ---------------------------------------------------------------------
* 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"));
}
// module class and intermediary classes are always created
if (!addSymbol(imclass_name, n))
return SWIG_ERROR;
if (!addSymbol(module_class_name, n))
return SWIG_ERROR;
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 (!dllimport)
dllimport = Copy(module_class_name);
Swig_banner(f_begin);
Printf(f_runtime, "\n\n#ifndef SWIGCSHARP\n#define SWIGCSHARP\n#endif\n\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) {
String *filename = Swig_file_filename(outfile_h);
Printf(f_directors, "#include \"%s\"\n\n", filename);
Delete(filename);
}
}
Printf(f_runtime, "\n");
if (namespce) {
String *wrapper_name = NewStringf("");
Printf(wrapper_name, "CSharp_%s_%%f", namespce);
Swig_name_register("wrapper", wrapper_name);
Delete(wrapper_name);
}
else {
Swig_name_register("wrapper", "CSharp_%f");
}
if (old_variable_names) {
Swig_name_register("set", "set_%n%v");
Swig_name_register("get", "get_%n%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_common.swg", f_runtime);
Swig_insert_file("director.swg", f_runtime);
}
// Generate the intermediary class
{
File *f_im = getOutputFile(SWIG_output_directory(), imclass_name);
addOpenNamespace(0, 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(0, f_im);
if (f_im != f_single_out)
Delete(f_im);
f_im = NULL;
}
// Generate the C# module class
{
File *f_module = getOutputFile(SWIG_output_directory(), module_class_name);
addOpenNamespace(0, 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(0, f_module);
if (f_module != f_single_out)
Delete(f_module);
f_module = NULL;
}
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");
Delete(f_runtime_h);
f_runtime_h = NULL;
Delete(f_directors);
f_directors = NULL;
Delete(f_directors_h);
f_directors_h = NULL;
}
if (f_single_out) {
Dump(f_single_out, f_begin);
Delete(f_single_out);
f_single_out = NULL;
}
Dump(f_wrappers, f_begin);
Wrapper_pretty_print(f_init, f_begin);
Delete(f_header);
Delete(f_wrappers);
Delete(f_init);
Delete(f_runtime);
Delete(f_begin);
return SWIG_OK;
}
/* -----------------------------------------------------------------------------
* emitBanner()
* ----------------------------------------------------------------------------- */
void emitBanner(File *f) {
Printf(f, "//------------------------------------------------------------------------------\n");
Printf(f, "// <auto-generated />\n");
Printf(f, "//\n");
Swig_banner_target_lang(f, "//");
Printf(f, "//------------------------------------------------------------------------------\n\n");
}
/* -----------------------------------------------------------------------------
* getOutputFile()
*
* Prepares a File object by creating the file in the file system and
* writing the banner for auto-generated files to it (emitBanner).
* If '-outfile' is provided (single file mode) the supplied parameters will
* be ignored and the returned file will always be:
* <outdir>/<outfile>
* Otherwise the file will be:
* <dir>/<name>.cs
* ----------------------------------------------------------------------------- */
File *getOutputFile(const String *dir, const String *name) {
if (output_file) {
if (!f_single_out) {
String *filen = NewStringf("%s%s", SWIG_output_directory(), output_file);
f_single_out = NewFile(filen, "w", SWIG_output_files());
if (!f_single_out) {
FileErrorDisplay(filen);
SWIG_exit(EXIT_FAILURE);
}
Append(filenames_list, Copy(filen));
Delete(filen);
filen = NULL;
emitBanner(f_single_out);
}
return f_single_out;
} else {
String *filen = NewStringf("%s%s.cs", dir, name);
File *f = NewFile(filen, "w", SWIG_output_files());
if (!f) {
FileErrorDisplay(filen);
SWIG_exit(EXIT_FAILURE);
}
Append(filenames_list, Copy(filen));
Delete(filen);
filen = NULL;
emitBanner(f);
return f;
}
}
/*-----------------------------------------------------------------------
* Add new director upcall signature
*----------------------------------------------------------------------*/
UpcallData *addUpcallMethod(String *imclass_method, String *class_method, String *decl, String *overloaded_name) {
String *key = NewStringf("%s|%s", imclass_method, decl);
++curr_class_dmethod;
String *class_methodidx = NewStringf("%d", n_dmethods - first_class_dmethod);
n_dmethods++;
Hash *new_udata = NewHash();
Append(dmethods_seq, new_udata);
Setattr(dmethods_table, key, new_udata);
Setattr(new_udata, "method", Copy(class_method));
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, imclass_name))
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 {
Swig_error(input_file, line_number, "No return type for %%native method %s.\n", 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;
bool is_void_return;
String *overloaded_name = getOverloadedName(n);
if (!Getattr(n, "sym:overloaded")) {
if (!addSymbol(symname, n, imclass_name))
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")) {
DelWrapper(f);
return SWIG_OK;
}
}
Printv(imclass_class_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\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);
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 (Getattr(p, "tmap:throws")) {
canThrow(n, "throws", p);
}
}
}
String *null_attribute = 0;
// Now write code to make the function call
if (!native_function_flag) {
Swig_director_emit_dynamic_cast(n, f);
String *actioncode = emit_action(n);
/* Return value if necessary */
if ((tm = Swig_typemap_lookup_out("out", n, Swig_cresult_name(), f, actioncode))) {
canThrow(n, "out", n);
Replaceall(tm, "$source", Swig_cresult_name()); /* 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, Swig_cresult_name(), 0))) {
canThrow(n, "newfree", n);
Replaceall(tm, "$source", Swig_cresult_name()); /* 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, Swig_cresult_name(), 0))) {
canThrow(n, "ret", n);
Replaceall(tm, "$source", Swig_cresult_name()); /* 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(getNSpace(), Swig_name_member(0, getClassPrefix(), 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;
}
String *getCurrentScopeName(String *nspace) {
String *scope = 0;
if (nspace || getCurrentClass()) {
scope = NewString("");
if (nspace)
Printf(scope, "%s", nspace);
if (Node *cls = getCurrentClass()) {
if (Node *outer = Getattr(cls, "nested:outer")) {
String *outerClassesPrefix = Copy(Getattr(outer, "sym:name"));
for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) {
Push(outerClassesPrefix, ".");
Push(outerClassesPrefix, Getattr(outer, "sym:name"));
}
Printv(scope, nspace ? "." : "", outerClassesPrefix, ".", proxy_class_name, NIL);
Delete(outerClassesPrefix);
} else
Printv(scope, nspace ? "." : "", proxy_class_name, NIL);
}
}
return scope;
}
/* ----------------------------------------------------------------------
* 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;
String *nspace = Getattr(n, "sym:nspace"); // NSpace/getNSpace() only works during Language::enumDeclaration call
if (proxy_flag && !is_wrapping_class()) {
// Global enums / enums in a namespace
assert(!full_imclass_name);
if (!nspace) {
full_imclass_name = NewStringf("%s", imclass_name);
} else {
if (namespce) {
full_imclass_name = NewStringf("%s.%s", namespce, imclass_name);
} else {
full_imclass_name = NewStringf("%s", imclass_name);
}
}
}
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
String *scope = getCurrentScopeName(nspace);
if (!addSymbol(symname, n, scope))
return SWIG_ERROR;
// 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);
Delete(scope);
} 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 *output_directory = outputDirectory(nspace);
File *f_enum = getOutputFile(output_directory, symname);
addOpenNamespace(nspace, f_enum);
Printv(f_enum, typemapLookup(n, "csimports", typemap_lookup_type, WARN_NONE), // Import statements
"\n", enum_code, "\n", NIL);
addCloseNamespace(nspace, f_enum);
if (f_enum != f_single_out)
Delete(f_enum);
f_enum = NULL;
Delete(output_directory);
}
} 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;
if (proxy_flag && !is_wrapping_class()) {
Delete(full_imclass_name);
full_imclass_name = 0;
}
}
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");
Node *parent = parentNode(n);
int unnamedinstance = GetFlag(parent, "unnamedinstance");
String *parent_name = Getattr(parent, "name");
String *nspace = getNSpace();
String *newsymname = 0;
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);
// Deal with enum values that are not int
int swigtype = SwigType_type(Getattr(n, "type"));
if (swigtype == T_BOOL) {
const char *val = Equal(Getattr(n, "enumvalue"), "true") ? "1" : "0";
Setattr(n, "enumvalue", val);
} else if (swigtype == T_CHAR) {
String *val = NewStringf("'%(hexescape)s'", Getattr(n, "enumvalue"));
Setattr(n, "enumvalue", val);
Delete(val);
}
{
EnumFeature enum_feature = decodeEnumFeature(parent);
if ((enum_feature == SimpleEnum) && GetFlag(parent, "scopedenum")) {
newsymname = Swig_name_member(0, Getattr(parent, "sym:name"), symname);
symname = newsymname;
}
// Add to language symbol table
String *scope = 0;
if (unnamedinstance || !parent_name || enum_feature == SimpleEnum) {
String *enumClassPrefix = getEnumClassPrefix();
if (enumClassPrefix) {
scope = NewString("");
if (nspace)
Printf(scope, "%s.", nspace);
Printf(scope, "%s", enumClassPrefix);
} else {
scope = Copy(module_class_name);
}
} else {
scope = getCurrentScopeName(nspace);
if (!scope)
scope = Copy(Getattr(parent, "sym:name"));
else
Printf(scope, ".%s", Getattr(parent, "sym:name"));
}
if (!addSymbol(symname, n, scope))
return SWIG_ERROR;
const String *csattributes = Getattr(n, "feature:cs:attributes");
if ((enum_feature == ProperEnum) && parent_name && !unnamedinstance) {
// Wrap (non-anonymous) C/C++ enum with a proper C# enum
// Emit the enum item.
if (!GetFlag(n, "firstenumitem"))
Printf(enum_code, ",\n");
if (csattributes)
Printf(enum_code, " %s\n", csattributes);
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
SwigType *typemap_lookup_type = parent_name ? parent_name : NewString("enum ");
Setattr(n, "type", typemap_lookup_type);
const String *tm = typemapLookup(n, "cstype", typemap_lookup_type, WARN_CSHARP_TYPEMAP_CSWTYPE_UNDEF);
String *return_type = Copy(tm);
substituteClassname(typemap_lookup_type, return_type);
const String *methodmods = Getattr(n, "feature:cs:methodmodifiers");
methodmods = methodmods ? methodmods : (is_public(n) ? public_string : protected_string);
if (csattributes)
Printf(enum_code, " %s\n", csattributes);
if ((enum_feature == TypesafeEnum) && parent_name && !unnamedinstance) {
// Wrap (non-anonymous) 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
// The %csconst feature determines how the constant value is obtained
int const_feature_flag = GetFlag(n, "feature:cs:const");
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);
}
Delete(return_type);
}
// Add the enum value to the comma separated list being constructed in the enum declaration.
String *enumvalues = Getattr(parent, "enumvalues");
if (!enumvalues)
Setattr(parent, "enumvalues", Copy(symname));
else
Printv(enumvalues, ", ", symname, NIL);
Delete(scope);
}
Delete(newsymname);
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");
SwigType *valuetype = Getattr(n, "valuetype");
ParmList *l = Getattr(n, "parms");
String *tm;
String *return_type = NewString("");
String *constants_code = NewString("");
Swig_save("constantWrapper", n, "value", NIL);
Swig_save("constantWrapper", n, "tmap:ctype:out", "tmap:imtype:out", "tmap:cstype:out", "tmap:out:null", "tmap:imtype:outattributes", "tmap:cstype:outattributes", NIL);
bool is_enum_item = (Cmp(nodeType(n), "enumitem") == 0);
const String *itemname = (proxy_flag && wrapping_member_flag) ? variable_name : symname;
if (!is_enum_item) {
String *scope = 0;
if (proxy_class_name) {
String *nspace = getNSpace();
scope = NewString("");
if (nspace)
Printf(scope, "%s.", nspace);
Printf(scope, "%s", proxy_class_name);
} else {
scope = Copy(module_class_name);
}
if (!addSymbol(itemname, n, scope))
return SWIG_ERROR;
Delete(scope);
}
// 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));
}
// Default (octal) escaping is no good - change to hex escaped value
String *hexescaped_value = Getattr(n, "rawvalue") ? NewStringf("%(hexescape)s", Getattr(n, "rawvalue")) : 0;
// Add the stripped quotes back in
String *new_value = NewString("");
if (SwigType_type(t) == T_STRING) {
Printf(new_value, "\"%s\"", hexescaped_value ? hexescaped_value : Copy(Getattr(n, "value")));
Setattr(n, "value", new_value);
} else if (SwigType_type(t) == T_CHAR) {
Printf(new_value, "\'%s\'", hexescaped_value ? hexescaped_value : 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 *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, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname));
} else {
// This handles function pointers using the %constant directive
Printf(constants_code, "new %s(%s.%s(), false);\n", return_type, full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname));
}
} else {
Printf(constants_code, "%s.%s();\n", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), 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
if (Getattr(n, "wrappedasconstant")) {
if (SwigType_type(t) == T_CHAR) {
if (SwigType_type(valuetype) == T_CHAR)
Printf(constants_code, "\'%(hexescape)s\';\n", Getattr(n, "staticmembervariableHandler:value"));
else
Printf(constants_code, "(char)%s;\n", Getattr(n, "staticmembervariableHandler:value"));
} else {
Printf(constants_code, "%s;\n", Getattr(n, "staticmembervariableHandler:value"));
}
} else {
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) {
int ret = SWIG_OK;
String *code = Getattr(n, "code");
String *section = Getattr(n, "section");
Replaceall(code, "$module", module_class_name);
Replaceall(code, "$imclassname", imclass_name);
Replaceall(code, "$dllimport", dllimport);
if (!ImportMode && (Cmp(section, "proxycode") == 0)) {
if (proxy_class_code) {
Swig_typemap_replace_embedded_typemap(code, n);
int offset = Len(code) > 0 && *Char(code) == '\n' ? 1 : 0;
Printv(proxy_class_code, Char(code) + offset, "\n", NIL);
}
} else {
ret = Language::insertDirective(n);
}
return ret;
}
/* -----------------------------------------------------------------------------
* 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 {
Swig_error(input_file, line_number, "Unrecognized pragma.\n");
}
Delete(strvalue);
}
}
return Language::pragmaDirective(n);
}
/* -----------------------------------------------------------------------------
* getQualifiedInterfaceName()
* ----------------------------------------------------------------------------- */
String *getQualifiedInterfaceName(Node *n) {
String *ret = Getattr(n, "interface:qname");
if (!ret) {
String *nspace = Getattr(n, "sym:nspace");
String *interface_name = Getattr(n, "interface:name");
if (nspace) {
if (namespce)
ret = NewStringf("%s.%s.%s", namespce, nspace, interface_name);
else
ret = NewStringf("%s.%s", nspace, interface_name);
} else {
ret = Copy(interface_name);
}
Setattr(n, "interface:qname", ret);
}
return ret;
}
/* -----------------------------------------------------------------------------
* getInterfaceName()
* ----------------------------------------------------------------------------- */
String *getInterfaceName(SwigType *t, bool qualified) {
String *interface_name = NULL;
if (proxy_flag) {
Node *n = classLookup(t);
if (n && Getattr(n, "interface:name"))
interface_name = qualified ? getQualifiedInterfaceName(n) : Getattr(n, "interface:name");
}
return interface_name;
}
/* -----------------------------------------------------------------------------
* addInterfaceNameAndUpcasts()
* ----------------------------------------------------------------------------- */
void addInterfaceNameAndUpcasts(SwigType *smart, String *interface_list, String *interface_upcasts, Hash *base_list, SwigType *c_classname) {
List *keys = Keys(base_list);
for (Iterator it = First(keys); it.item; it = Next(it)) {
Node *base = Getattr(base_list, it.item);
SwigType *c_baseclassname = Getattr(base, "name");
String *interface_name = Getattr(base, "interface:name");
if (Len(interface_list))
Append(interface_list, ", ");
Append(interface_list, interface_name);
Node *attributes = NewHash();
String *interface_code = Copy(typemapLookup(base, "csinterfacecode", Getattr(base, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACECODE_UNDEF, attributes));
String *cptr_method_name = 0;
if (interface_code) {
Replaceall(interface_code, "$interfacename", interface_name);
Printv(interface_upcasts, interface_code, NIL);
cptr_method_name = Copy(Getattr(attributes, "tmap:csinterfacecode:cptrmethod"));
}
if (!cptr_method_name)
cptr_method_name = NewStringf("%s_GetInterfaceCPtr", interface_name);
Replaceall(cptr_method_name, ".", "_");
Replaceall(cptr_method_name, "$interfacename", interface_name);
String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), cptr_method_name);
upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname);
Delete(upcast_method_name);
Delete(cptr_method_name);
Delete(interface_code);
}
Delete(keys);
}
/* -----------------------------------------------------------------------------
* upcastsCode()
*
* Add code for C++ casting to base class
* ----------------------------------------------------------------------------- */
void upcastsCode(SwigType *smart, String *upcast_method_name, SwigType *c_classname, SwigType *c_baseclassname) {
String *wname = Swig_name_wrapper(upcast_method_name);
Printv(imclass_cppcasts_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL);
Printf(imclass_cppcasts_code, " public static extern global::System.IntPtr %s(global::System.IntPtr jarg1);\n", upcast_method_name);
Replaceall(imclass_cppcasts_code, "$csclassname", proxy_class_name);
String *classname = SwigType_namestr(c_classname);
String *baseclassname = SwigType_namestr(c_baseclassname);
if (smart) {
String *smartnamestr = SwigType_namestr(smart);
String *bsmartnamestr = SwigType_namestr(smart);
// TODO: SwigType_typedef_resolve_all on a String instead of SwigType is incorrect for templates
SwigType *rclassname = SwigType_typedef_resolve_all(classname);
SwigType *rbaseclassname = SwigType_typedef_resolve_all(baseclassname);
Replaceall(bsmartnamestr, rclassname, rbaseclassname);
Printv(upcasts_code,
"SWIGEXPORT ", bsmartnamestr, " * SWIGSTDCALL ", wname, "(", smartnamestr, " *jarg1) {\n",
" return jarg1 ? new ", bsmartnamestr, "(*jarg1) : 0;\n"
"}\n", "\n", NIL);
Delete(rbaseclassname);
Delete(rclassname);
Delete(bsmartnamestr);
Delete(smartnamestr);
} else {
Printv(upcasts_code,
"SWIGEXPORT ", baseclassname, " * SWIGSTDCALL ", wname, "(", classname, " *jarg1) {\n",
" return (", baseclassname, " *)jarg1;\n"
"}\n", "\n", NIL);
}
Delete(baseclassname);
Delete(classname);
Delete(wname);
}
/* -----------------------------------------------------------------------------
* emitProxyClassDefAndCPPCasts()
* ----------------------------------------------------------------------------- */
void emitProxyClassDefAndCPPCasts(Node *n) {
SwigType *c_classname = Getattr(n, "name");
SwigType *c_baseclassname = NULL;
String *baseclass = NULL;
String *interface_list = NewStringEmpty();
String *interface_upcasts = NewStringEmpty();
SwigType *typemap_lookup_type = Getattr(n, "classtypeobj");
bool feature_director = Swig_directorclass(n) ? true : false;
bool has_outerclass = Getattr(n, "nested:outer") != 0 && !GetFlag(n, "feature:flatnested");
SwigType *smart = Swig_cparse_smartptr(n);
// 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) {
if (!(GetFlag(base.item, "feature:ignore") || Getattr(base.item, "feature:interface"))) {
SwigType *baseclassname = Getattr(base.item, "name");
if (!c_baseclassname) {
String *name = getProxyName(baseclassname);
if (name) {
c_baseclassname = baseclassname;
baseclass = name;
}
} else {
/* Warn about multiple inheritance for additional base class(es) */
String *proxyclassname = Getattr(n, "classtypeobj");
Swig_warning(WARN_CSHARP_MULTIPLE_INHERITANCE, Getfile(n), Getline(n),
"Warning for %s, base %s ignored. Multiple inheritance is not supported in C#.\n", SwigType_namestr(proxyclassname), SwigType_namestr(baseclassname));
}
}
base = Next(base);
}
}
}
Hash *interface_bases = Getattr(n, "interface:bases");
if (interface_bases)
addInterfaceNameAndUpcasts(smart, interface_list, interface_upcasts, interface_bases, c_classname);
bool derived = baseclass != 0;
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;
baseclass = NULL;
if (purebase_notderived)
Swig_error(Getfile(n), Getline(n), "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, Getfile(n), Getline(n),
"Warning for %s, 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);
if (*Char(interface_list) && *Char(pure_interfaces))
Append(interface_list, ", ");
Append(interface_list, pure_interfaces);
// Start writing the proxy class
if (!has_outerclass)
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(interface_list)) ? " : " : "", wanted_base, (*Char(wanted_base) && *Char(interface_list)) ? // Interfaces
", " : "", interface_list, " {", 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 Finalize and Dispose methods
const char *tmap_method = derived ? "csdestruct_derived" : "csdestruct";
const String *tm = typemapExists(n, tmap_method, typemap_lookup_type);
if (tm) {
Swig_error(Getfile(tm), Getline(tm),
"A deprecated %s typemap was found for %s, please remove it and replace all csdestruct, csdestruct_derived and csfinalize typemaps by the csdispose, csdispose_derived, csdisposing and csdisposing_derived typemaps.\n",
tmap_method, proxy_class_name);
}
tmap_method = "csfinalize";
tm = typemapExists(n, tmap_method, typemap_lookup_type);
if (tm) {
Swig_error(Getfile(tm), Getline(tm),
"A deprecated %s typemap was found for %s, please remove it and replace all csdestruct, csdestruct_derived and csfinalize typemaps by the csdispose, csdispose_derived, csdisposing and csdisposing_derived typemaps.\n",
tmap_method, proxy_class_name);
}
tmap_method = derived ? "csdisposing_derived" : "csdisposing";
String *destruct = NewString("");
attributes = NewHash();
const String *destruct_methodname = NULL;
const String *destruct_methodmodifiers = NULL;
const String *destruct_parameters = NULL;
if (derived) {
tm = typemapLookup(n, "csdisposing_derived", typemap_lookup_type, WARN_NONE, attributes);
destruct_methodname = Getattr(attributes, "tmap:csdisposing_derived:methodname");
destruct_methodmodifiers = Getattr(attributes, "tmap:csdisposing_derived:methodmodifiers");
destruct_parameters = Getattr(attributes, "tmap:csdisposing_derived:parameters");
} else {
tm = typemapLookup(n, "csdisposing", typemap_lookup_type, WARN_NONE, attributes);
destruct_methodname = Getattr(attributes, "tmap:csdisposing:methodname");
destruct_methodmodifiers = Getattr(attributes, "tmap:csdisposing:methodmodifiers");
destruct_parameters = Getattr(attributes, "tmap:csdisposing:parameters");
}
if (tm && *Char(tm)) {
if (!destruct_methodname) {
Swig_error(Getfile(n), Getline(n), "No methodname attribute defined in %s typemap for %s\n", tmap_method, proxy_class_name);
}
if (!destruct_methodmodifiers) {
Swig_error(Getfile(n), Getline(n),
"No methodmodifiers attribute defined in %s typemap for %s.\n", tmap_method, proxy_class_name);
}
if (!destruct_parameters)
destruct_parameters = empty_string;
}
// Emit the Finalize and Dispose methods
if (tm) {
// Finalize and Dispose methods
Printv(proxy_class_def, typemapLookup(n, derived ? "csdispose_derived" : "csdispose", typemap_lookup_type, WARN_NONE), NIL);
// Dispose(bool disposing) method
Printv(destruct, tm, NIL);
if (*Char(destructor_call))
Replaceall(destruct, "$imcall", destructor_call);
else
Replaceall(destruct, "$imcall", "throw new global::System.MethodAccessException(\"C++ destructor does not have public access\")");
if (*Char(destruct)) {
Printv(proxy_class_def, "\n ", NIL);
const String *methodmods = Getattr(n, "destructmethodmodifiers");
if (methodmods)
Printv(proxy_class_def, methodmods, NIL);
else
Printv(proxy_class_def, destruct_methodmodifiers, " ", derived ? "override" : "virtual", NIL);
Printv(proxy_class_def, " void ", destruct_methodname, "(", destruct_parameters, ") ", destruct, "\n", NIL);
}
}
if (*Char(interface_upcasts))
Printv(proxy_class_def, interface_upcasts, 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(SwigDirectorMethod%s);\n", methid, proxy_class_name, methid, overname);
}
String *director_connect_method_name = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect");
Printf(proxy_class_code, " %s.%s(swigCPtr", imclass_name, director_connect_method_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, global::System.Type[] methodTypes) {\n");
Printf(proxy_class_code,
" global::System.Reflection.MethodInfo methodInfo = this.GetType().GetMethod(methodName, global::System.Reflection.BindingFlags.Public | global::System.Reflection.BindingFlags.NonPublic | global::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(director_connect_method_name);
}
Delete(interface_upcasts);
Delete(interface_list);
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);
if (derived) {
String *upcast_method_name = Swig_name_member(getNSpace(), getClassPrefix(), smart != 0 ? "SWIGSmartPtrUpcast" : "SWIGUpcast");
upcastsCode(smart, upcast_method_name, c_classname, c_baseclassname);
Delete(upcast_method_name);
}
Delete(smart);
}
/* ----------------------------------------------------------------------
* emitInterfaceDeclaration()
* ---------------------------------------------------------------------- */
void emitInterfaceDeclaration(Node *n, String *interface_name, File *f_interface) {
Printv(f_interface, typemapLookup(n, "csimports", Getattr(n, "classtypeobj"), WARN_NONE), "\n", NIL);
Printf(f_interface, "public interface %s", interface_name);
if (List *baselist = Getattr(n, "bases")) {
String *bases = 0;
for (Iterator base = First(baselist); base.item; base = Next(base)) {
if (GetFlag(base.item, "feature:ignore") || !Getattr(base.item, "feature:interface"))
continue; // TODO: warn about skipped non-interface bases
String *base_iname = Getattr(base.item, "interface:name");
if (!bases)
bases = NewStringf(" : %s", base_iname);
else {
Append(bases, ", ");
Append(bases, base_iname);
}
}
if (bases) {
Printv(f_interface, bases, NIL);
Delete(bases);
}
}
Printf(f_interface, " {\n");
Node *attributes = NewHash();
String *interface_code = Copy(typemapLookup(n, "csinterfacecode", Getattr(n, "classtypeobj"), WARN_CSHARP_TYPEMAP_INTERFACECODE_UNDEF, attributes));
if (interface_code) {
String *interface_declaration = Copy(Getattr(attributes, "tmap:csinterfacecode:declaration"));
if (interface_declaration) {
Replaceall(interface_declaration, "$interfacename", interface_name);
Printv(f_interface, interface_declaration, NIL);
Delete(interface_declaration);
}
Delete(interface_code);
}
}
/* ----------------------------------------------------------------------
* classHandler()
* ---------------------------------------------------------------------- */
virtual int classHandler(Node *n) {
String *nspace = getNSpace();
File *f_proxy = NULL;
File *f_interface = NULL;
// save class local variables
String *old_proxy_class_name = proxy_class_name;
String *old_full_imclass_name = full_imclass_name;
String *old_destructor_call = destructor_call;
String *old_proxy_class_constants_code = proxy_class_constants_code;
String *old_proxy_class_def = proxy_class_def;
String *old_proxy_class_code = proxy_class_code;
bool has_outerclass = Getattr(n, "nested:outer") && !GetFlag(n, "feature:flatnested");
String *old_interface_class_code = interface_class_code;
interface_class_code = 0;
if (proxy_flag) {
proxy_class_name = NewString(Getattr(n, "sym:name"));
String *interface_name = Getattr(n, "feature:interface") ? Getattr(n, "interface:name") : 0;
if (Node *outer = Getattr(n, "nested:outer")) {
String *outerClassesPrefix = Copy(Getattr(outer, "sym:name"));
for (outer = Getattr(outer, "nested:outer"); outer != 0; outer = Getattr(outer, "nested:outer")) {
Push(outerClassesPrefix, ".");
Push(outerClassesPrefix, Getattr(outer, "sym:name"));
}
String *fnspace = nspace ? NewStringf("%s.%s", nspace, outerClassesPrefix) : outerClassesPrefix;
if (!addSymbol(proxy_class_name, n, fnspace))
return SWIG_ERROR;
if (interface_name && !addInterfaceSymbol(interface_name, n, fnspace))
return SWIG_ERROR;
if (nspace)
Delete(fnspace);
Delete(outerClassesPrefix);
} else {
if (!addSymbol(proxy_class_name, n, nspace))
return SWIG_ERROR;
if (interface_name && !addInterfaceSymbol(interface_name, n, nspace))
return SWIG_ERROR;
}
if (!nspace) {
full_imclass_name = NewStringf("%s", imclass_name);
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);
}
} else {
if (namespce) {
full_imclass_name = NewStringf("%s.%s", namespce, imclass_name);
} else {
full_imclass_name = NewStringf("%s", imclass_name);
}
}
if (!has_outerclass) {
String *output_directory = outputDirectory(nspace);
f_proxy = getOutputFile(output_directory, proxy_class_name);
addOpenNamespace(nspace, f_proxy);
Delete(output_directory);
}
else
++nesting_depth;
proxy_class_def = NewString("");
proxy_class_code = NewString("");
destructor_call = NewString("");
proxy_class_constants_code = NewString("");
if (Getattr(n, "feature:interface")) {
interface_class_code = NewString("");
String *output_directory = outputDirectory(nspace);
f_interface = getOutputFile(output_directory, interface_name);
addOpenNamespace(nspace, f_interface);
emitInterfaceDeclaration(n, interface_name, interface_class_code);
Delete(output_directory);
}
}
Language::classHandler(n);
if (proxy_flag) {
emitProxyClassDefAndCPPCasts(n);
String *csclazzname = Swig_name_member(getNSpace(), getClassPrefix(), ""); // mangled full proxy class name
Replaceall(proxy_class_def, "$csclassname", proxy_class_name);
Replaceall(proxy_class_code, "$csclassname", proxy_class_name);
Replaceall(proxy_class_constants_code, "$csclassname", proxy_class_name);
Replaceall(interface_class_code, "$csclassname", proxy_class_name);
Replaceall(proxy_class_def, "$csclazzname", csclazzname);
Replaceall(proxy_class_code, "$csclazzname", csclazzname);
Replaceall(proxy_class_constants_code, "$csclazzname", csclazzname);
Replaceall(interface_class_code, "$csclazzname", csclazzname);
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(interface_class_code, "$module", module_class_name);
Replaceall(proxy_class_def, "$imclassname", full_imclass_name);
Replaceall(proxy_class_code, "$imclassname", full_imclass_name);
Replaceall(proxy_class_constants_code, "$imclassname", full_imclass_name);
Replaceall(interface_class_code, "$imclassname", full_imclass_name);
Replaceall(proxy_class_def, "$dllimport", dllimport);
Replaceall(proxy_class_code, "$dllimport", dllimport);
Replaceall(proxy_class_constants_code, "$dllimport", dllimport);
Replaceall(interface_class_code, "$dllimport", dllimport);
if (!has_outerclass)
Printv(f_proxy, proxy_class_def, proxy_class_code, NIL);
else {
Swig_offset_string(proxy_class_def, nesting_depth);
Append(old_proxy_class_code, proxy_class_def);
Swig_offset_string(proxy_class_code, nesting_depth);
Append(old_proxy_class_code, proxy_class_code);
}
// Write out all the constants
if (Len(proxy_class_constants_code) != 0) {
if (!has_outerclass)
Printv(f_proxy, proxy_class_constants_code, NIL);
else {
Swig_offset_string(proxy_class_constants_code, nesting_depth);
Append(old_proxy_class_code, proxy_class_constants_code);
}
}
if (!has_outerclass) {
Printf(f_proxy, "}\n");
addCloseNamespace(nspace, f_proxy);
if (f_proxy != f_single_out)
Delete(f_proxy);
f_proxy = NULL;
} else {
for (int i = 0; i < nesting_depth; ++i)
Append(old_proxy_class_code, " ");
Append(old_proxy_class_code, "}\n\n");
--nesting_depth;
}
if (f_interface) {
Printv(f_interface, interface_class_code, "}\n", NIL);
addCloseNamespace(nspace, f_interface);
if (f_interface != f_single_out)
Delete(f_interface);
f_interface = 0;
}
emitDirectorExtraMethods(n);
Delete(interface_class_code);
interface_class_code = old_interface_class_code;
Delete(csclazzname);
Delete(proxy_class_name);
proxy_class_name = old_proxy_class_name;
Delete(full_imclass_name);
full_imclass_name = old_full_imclass_name;
Delete(destructor_call);
destructor_call = old_destructor_call;
Delete(proxy_class_constants_code);
proxy_class_constants_code = old_proxy_class_constants_code;
Delete(proxy_class_def);
proxy_class_def = old_proxy_class_def;
Delete(proxy_class_code);
proxy_class_code = old_proxy_class_code;
}
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(getNSpace(), getClassPrefix(), 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(getNSpace(), getClassPrefix(), 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("");
bool is_interface = Getattr(parentNode(n), "feature:interface") != 0
&& !static_flag && Getattr(n, "interface:owner") == 0;
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(getNSpace(), Swig_name_member(0, getClassPrefix(), 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);
if (is_interface)
Printf(interface_class_code, " %s %s(", return_type, proxy_function_name);
Printv(imcall, full_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, ", ");
if (is_interface)
Printf(interface_class_code, ", ");
}
gencomma = 2;
Printf(function_code, "%s %s", param_type, arg);
if (is_interface)
Printf(interface_class_code, "%s %s", param_type, arg);
Delete(arg);
Delete(param_type);
}
p = Getattr(p, "tmap:in:next");
}
Printf(imcall, ")");
Printf(function_code, ")");
if (is_interface)
Printf(interface_class_code, ");\n");
// 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(getNSpace(), getClassPrefix(), 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("");
Node *directorNode = Getattr(n, "directorNode");
if (directorNode) {
UpcallData *udata = Getattr(directorNode, "upcalldata");
String *methid = Getattr(udata, "class_methodidx");
if (!Cmp(return_type, "void"))
Printf(excode, "if (SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s)) %s; else %s", proxy_function_name, methid, ex_imcall, imcall);
else
Printf(excode, "(SwigDerivedClassHasMethod(\"%s\", swigMethodTypes%s) ? %s : %s)", proxy_function_name, methid, ex_imcall, imcall);
Clear(imcall);
Printv(imcall, excode, NIL);
} else {
// probably an ignored method or nodirector
}
Delete(excode);
Delete(ex_overloaded_name);
} 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) {
assert(last_parm); // (last parameter is the only parameter for properties)
/* Get variable type - ensure the variable name is fully resolved during typemap lookup via the symbol table set in NewParmNode */
SwigType *cvariable_type = Getattr(last_parm, "type");
Parm *variable_parm = NewParmNode(cvariable_type, n);
if ((tm = Swig_typemap_lookup("cstype", variable_parm, "", 0))) {
String *cstypeout = Getattr(variable_parm, "tmap:cstype:out"); // the type in the cstype typemap's out attribute overrides the type in the typemap
if (cstypeout)
tm = cstypeout;
substituteClassname(cvariable_type, tm);
variable_type = tm;
} else {
Swig_warning(WARN_CSHARP_TYPEMAP_CSOUT_UNDEF, input_file, line_number, "No cstype typemap defined for %s\n", SwigType_str(cvariable_type, 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
assert(last_parm); // (last parameter is the only parameter for properties)
SwigType *cvariable_type = Getattr(last_parm, "type");
Parm *variable_parm = NewParmNode(cvariable_type, n);
if ((tm = Swig_typemap_lookup("csvarin", variable_parm, "", 0))) {
substituteClassname(cvariable_type, tm);
Replaceall(tm, "$csinput", "value");
Replaceall(tm, "$imcall", imcall);
excodeSubstitute(n, tm, "csvarin", variable_parm);
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(cvariable_type, 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(getNSpace(), 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, full_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 *typemap_lookup_type = Getattr(getCurrentClass(), "classtypeobj");
String *construct_tm = Copy(typemapLookup(n, "csconstruct", typemap_lookup_type,
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, full_imclass_name, ".", Swig_name_destroy(getNSpace(), symname), "(swigCPtr)", NIL);
const String *methodmods = Getattr(n, "feature:cs:methodmodifiers");
if (methodmods)
Setattr(getCurrentClass(), "destructmethodmodifiers", methodmods);
}
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;
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(getNSpace(), 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);
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 {
String *newsymname = 0;
if (!getCurrentClass() || !proxy_flag) {
String *enumClassPrefix = getEnumClassPrefix();
if (enumClassPrefix) {
// A global scoped enum
newsymname = Swig_name_member(0, enumClassPrefix, symname);
symname = newsymname;
}
}
// 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()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), symname));
} else {
memberconstantHandler(n);
value = NewStringf("%s.%s()", full_imclass_name ? full_imclass_name : imclass_name, Swig_name_get(getNSpace(), Swig_name_member(0, getEnumClassPrefix(), symname)));
}
}
}
return value;
}
/* -----------------------------------------------------------------------------
* getEnumName()
* ----------------------------------------------------------------------------- */
String *getEnumName(SwigType *t) {
Node *enumname = NULL;
Node *n = enumLookup(t);
if (n) {
enumname = Getattr(n, "enumname");
if (!enumname) {
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) {
enumname = NewStringf("%s.%s", proxyname, symname);
} else {
// global enum or enum in a namespace
String *nspace = Getattr(n, "sym:nspace");
if (nspace) {
if (namespce)
enumname = NewStringf("%s.%s.%s", namespce, nspace, symname);
else
enumname = NewStringf("%s.%s", nspace, symname);
} else {
enumname = Copy(symname);
}
}
Setattr(n, "enumname", enumname);
Delete(enumname);
Delete(scopename_prefix);
}
}
}
return enumname;
}
/* -----------------------------------------------------------------------------
* 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));
if (Len(classnametype) > 0) {
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);
}
if (Strstr(tm, "$csinterfacename")) {
SwigType *interfacenametype = Copy(strippedtype);
substituteInterfacenameSpecialVariable(interfacenametype, tm, "$csinterfacename", true);
substitution_performed = true;
Delete(interfacenametype);
}
if (Strstr(tm, "$*csinterfacename")) {
SwigType *interfacenametype = Copy(strippedtype);
Delete(SwigType_pop(interfacenametype));
if (Len(interfacenametype) > 0) {
substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*csinterfacename", true);
substitution_performed = true;
}
Delete(interfacenametype);
}
if (Strstr(tm, "$&csinterfacename")) {
SwigType *interfacenametype = Copy(strippedtype);
SwigType_add_pointer(interfacenametype);
substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&csinterfacename", true);
substitution_performed = true;
Delete(interfacenametype);
}
if (Strstr(tm, "$interfacename")) {
SwigType *interfacenametype = Copy(strippedtype);
substituteInterfacenameSpecialVariable(interfacenametype, tm, "$interfacename", false);
substitution_performed = true;
Delete(interfacenametype);
}
if (Strstr(tm, "$*interfacename")) {
SwigType *interfacenametype = Copy(strippedtype);
Delete(SwigType_pop(interfacenametype));
if (Len(interfacenametype) > 0) {
substituteInterfacenameSpecialVariable(interfacenametype, tm, "$*interfacename", false);
substitution_performed = true;
}
Delete(interfacenametype);
}
if (Strstr(tm, "$&interfacename")) {
SwigType *interfacenametype = Copy(strippedtype);
SwigType_add_pointer(interfacenametype);
substituteInterfacenameSpecialVariable(interfacenametype, tm, "$&interfacename", false);
substitution_performed = true;
Delete(interfacenametype);
}
Delete(strippedtype);
Delete(type);
return substitution_performed;
}
/* -----------------------------------------------------------------------------
* substituteClassnameSpecialVariable()
* ----------------------------------------------------------------------------- */
void substituteClassnameSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) {
String *replacementname;
if (SwigType_isenum(classnametype)) {
String *enumname = getEnumName(classnametype);
if (enumname) {
replacementname = Copy(enumname);
} else {
bool anonymous_enum = (Cmp(classnametype, "enum ") == 0);
if (anonymous_enum) {
replacementname = NewString("int");
} else {
// An unknown enum - one that has not been parsed (neither a C enum forward reference nor a definition) or an ignored enum
replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
Replace(replacementname, "enum ", "", DOH_REPLACE_ANY);
Setattr(swig_types_hash, replacementname, classnametype);
}
}
} else {
String *classname = getProxyName(classnametype); // getProxyName() works for pointers to classes too
if (classname) {
replacementname = Copy(classname);
} else {
// use $descriptor if SWIG does not know anything about this type. Note that any typedefs are resolved.
replacementname = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
// Add to hash table so that the type wrapper classes can be created later
Setattr(swig_types_hash, replacementname, classnametype);
}
}
Replaceall(tm, classnamespecialvariable, replacementname);
Delete(replacementname);
}
/* -----------------------------------------------------------------------------
* substituteInterfacenameSpecialVariable()
* ----------------------------------------------------------------------------- */
void substituteInterfacenameSpecialVariable(SwigType *interfacenametype, String *tm, const char *interfacenamespecialvariable, bool qualified) {
String *interfacename = getInterfaceName(interfacenametype, qualified);
if (interfacename) {
String *replacementname = Copy(interfacename);
Replaceall(tm, interfacenamespecialvariable, replacementname);
Delete(replacementname);
}
}
/* -----------------------------------------------------------------------------
* emitTypeWrapperClass()
* ----------------------------------------------------------------------------- */
void emitTypeWrapperClass(String *classname, SwigType *type) {
Node *n = NewHash();
Setfile(n, input_file);
Setline(n, line_number);
String *swigtype = NewString("");
File *f_swigtype = getOutputFile(SWIG_output_directory(), classname);
addOpenNamespace(0, 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);
// For unknown enums
Replaceall(swigtype, "$enumvalues", "");
Printv(f_swigtype, swigtype, NIL);
addCloseNamespace(0, f_swigtype);
if (f_swigtype != f_single_out)
Delete(f_swigtype);
f_swigtype = NULL;
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;
}
/* -----------------------------------------------------------------------------
* typemapExists()
* 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
* returns found typemap or NULL if not found
* ----------------------------------------------------------------------------- */
const String *typemapExists(Node *n, const_String_or_char_ptr tmap_method, SwigType *type) {
Node *node = NewHash();
Setattr(node, "type", type);
Setfile(node, Getfile(n));
Setline(node, Getline(n));
const String *tm = Swig_typemap_lookup(tmap_method, node, "", 0);
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(const String *nspace, File *file) {
if (namespce || nspace) {
Printf(file, "namespace ");
if (namespce)
Printv(file, namespce, nspace ? "." : "", NIL);
if (nspace)
Printv(file, nspace, NIL);
Printf(file, " {\n");
}
}
/* -----------------------------------------------------------------------------
* addCloseNamespace()
* ----------------------------------------------------------------------------- */
void addCloseNamespace(const String *nspace, File *file) {
if (namespce || nspace)
Printf(file, "\n}\n");
}
/* -----------------------------------------------------------------------------
* outputDirectory()
*
* Return the directory to use for generating C# classes/enums and create the
* subdirectory (does not create if language specific outdir does not exist).
* ----------------------------------------------------------------------------- */
String *outputDirectory(String *nspace) {
String *output_directory = Copy(SWIG_output_directory());
if (nspace) {
String *nspace_subdirectory = Copy(nspace);
Replaceall(nspace_subdirectory, ".", SWIG_FILE_DELIMITER);
String *newdir_error = Swig_new_subdirectory(output_directory, nspace_subdirectory);
if (newdir_error) {
Printf(stderr, "%s\n", newdir_error);
Delete(newdir_error);
SWIG_exit(EXIT_FAILURE);
}
Printv(output_directory, nspace_subdirectory, SWIG_FILE_DELIMITER, 0);
Delete(nspace_subdirectory);
}
return output_directory;
}
/*----------------------------------------------------------------------
* 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 *dirclassname = directorClassName(n);
String *swig_director_connect = Swig_name_member(getNSpace(), getClassPrefix(), "director_connect");
String *wname = Swig_name_wrapper(swig_director_connect);
String *sym_name = Getattr(n, "sym:name");
String *qualified_classname = Copy(sym_name);
String *nspace = getNSpace();
String *dirClassName = directorClassName(n);
String *smartptr = Getattr(n, "feature:smartptr");
if (!GetFlag(n, "feature:flatnested")) {
for (Node *outer_class = Getattr(n, "nested:outer"); outer_class; outer_class = Getattr(outer_class, "nested:outer")) {
Push(qualified_classname, ".");
Push(qualified_classname, Getattr(outer_class, "sym:name"));
}
}
if (nspace)
Insert(qualified_classname, 0, NewStringf("%s.", nspace));
Printv(imclass_class_code, "\n [global::System.Runtime.InteropServices.DllImport(\"", dllimport, "\", EntryPoint=\"", wname, "\")]\n", NIL);
Printf(imclass_class_code, " public static extern void %s(global::System.Runtime.InteropServices.HandleRef jarg1", swig_director_connect);
Wrapper *code_wrap = NewWrapper();
Printf(code_wrap->def, "SWIGEXPORT void SWIGSTDCALL %s(void *objarg", wname);
if (smartptr) {
Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", smartptr, smartptr);
Printf(code_wrap->code, " // Keep a local instance of the smart pointer around while we are using the raw pointer\n");
Printf(code_wrap->code, " // Avoids using smart pointer specific API.\n");
Printf(code_wrap->code, " %s *director = static_cast<%s *>(obj->operator->());\n", dirClassName, dirClassName);
} else {
Printf(code_wrap->code, " %s *obj = (%s *)objarg;\n", norm_name, norm_name);
Printf(code_wrap->code, " %s *director = static_cast<%s *>(obj);\n", dirClassName, dirClassName);
}
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, "%s::SWIG_Callback%s_t callback%s", dirclassname, methid, methid);
Printf(code_wrap->code, "callback%s", methid);
Printf(imclass_class_code, ", %s.SwigDelegate%s_%s delegate%s", qualified_classname, sym_name, methid, methid);
}
Printf(code_wrap->def, ") {\n");
Printf(code_wrap->code, ");\n");
Printf(imclass_class_code, ");\n");
Printf(code_wrap->code, "}\n");
Wrapper_print(code_wrap, f_wrappers);
DelWrapper(code_wrap);
Delete(wname);
Delete(swig_director_connect);
Delete(qualified_classname);
Delete(dirclassname);
}
/* ---------------------------------------------------------------
* classDirectorMethod()
*
* Emit a virtual director method to pass a method call on to the
* underlying C# object.
*
* --------------------------------------------------------------- */
int classDirectorMethod(Node *n, Node *parent, String *super) {
String *classname = Getattr(parent, "sym:name");
String *c_classname = Getattr(parent, "name");
String *name = Getattr(n, "name");
String *symname = Getattr(n, "sym:name");
SwigType *returntype = Getattr(n, "type");
String *overloaded_name = getOverloadedName(n);
String *storage = Getattr(n, "storage");
String *value = Getattr(n, "value");
String *decl = Getattr(n, "decl");
String *declaration = NewString("");
String *pre_code = NewString("");
String *post_code = NewString("");
String *terminator_code = NewString("");
String *tm;
Parm *p;
int i;
Wrapper *w = NewWrapper();
ParmList *l = Getattr(n, "parms");
bool is_void = !(Cmp(returntype, "void"));
String *qualified_return = 0;
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("");
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(getNSpace(), getClassPrefix(), overloaded_name));
qualified_return = SwigType_rcaststr(returntype, "c_result");
if (!is_void && (!ignored_method || pure_virtual)) {
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, "abstracts"))) {
/* 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. */
SwigType *noref_type = SwigType_del_reference(Copy(returntype));
String *noref_ltype = SwigType_lstr(noref_type, 0);
String *return_ltype = SwigType_lstr(returntype, 0);
Wrapper_add_localv(w, "result_default", "static", noref_ltype, "result_default", NIL);
Wrapper_add_localv(w, "c_result", return_ltype, "c_result", NIL);
Printf(w->code, "result_default = SwigValueInit< %s >();\n", noref_ltype);
Printf(w->code, "c_result = &result_default;\n");
Delete(return_ltype);
Delete(noref_ltype);
Delete(noref_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 */
tm = Swig_typemap_lookup("imtype", n, "", 0);
if (tm) {
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;
const String *im_directoroutattributes = Getattr(n, "tmap:imtype:directoroutattributes");
if (im_directoroutattributes) {
Printf(callback_def, " %s\n", im_directoroutattributes);
if (!ignored_method)
Printf(director_delegate_definitions, " %s\n", im_directoroutattributes);
}
Printf(callback_def, " private %s SwigDirectorMethod%s(", tm, overloaded_name);
if (!ignored_method) {
const String *csdirectordelegatemodifiers = Getattr(n, "feature:csdirectordelegatemodifiers");
String *modifiers = (csdirectordelegatemodifiers ? NewStringf("%s%s", csdirectordelegatemodifiers, Len(csdirectordelegatemodifiers) > 0 ? " " : "") : NewStringf("public "));
Printf(director_delegate_definitions, " %sdelegate %s", modifiers, tm);
Delete(modifiers);
}
} else {
Swig_warning(WARN_CSHARP_TYPEMAP_CSTYPE_UNDEF, input_file, line_number, "No imtype typemap defined for %s\n", SwigType_str(returntype, 0));
}
if ((c_ret_type = Swig_typemap_lookup("ctype", n, "", 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;
}
Swig_director_parms_fixup(l);
/* 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, w);
Swig_typemap_attach_parms("csdirectorin", l, 0);
Swig_typemap_attach_parms("directorargout", l, w);
/* 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, "Swig::DirectorPureVirtualException::raise(\"%s::%s\");\n", SwigType_namestr(c_classname), SwigType_namestr(name));
if (!is_void)
Printf(w->code, "return %s;", qualified_return);
else if (!ignored_method)
Printf(w->code, "return;\n");
}
if (!ignored_method)
Printf(w->code, "} else {\n");
/* Go through argument list, convert from native to C# */
for (i = 0, p = l; p; ++i) {
/* Is this superfluous? */
while (checkAttribute(p, "tmap:directorin:numinputs", "0")) {
p = Getattr(p, "tmap:directorin:next");
}
SwigType *pt = Getattr(p, "type");
String *ln = makeParameterName(n, p, i, false);
String *c_param_type = NULL;
String *c_decl = NewString("");
String *arg = NewString("");
Printf(arg, "j%s", ln);
/* And add to the upcall args */
if (i > 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;
/* 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 ((tm = Getattr(p, "tmap:directorin"))) {
Setattr(p, "emit:directorinput", arg);
Replaceall(tm, "$input", arg);
Replaceall(tm, "$owner", "0");
if (Len(tm))
if (!ignored_method)
Printf(w->code, "%s\n", tm);
/* Add C type to callback typedef */
if (i > 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);
// pre and post attribute support
String *pre = Getattr(p, "tmap:csdirectorin:pre");
if (pre) {
substituteClassname(pt, pre);
Replaceall(pre, "$iminput", ln);
if (Len(pre_code) > 0)
Printf(pre_code, "\n");
Printv(pre_code, pre, NIL);
}
String *post = Getattr(p, "tmap:csdirectorin:post");
if (post) {
substituteClassname(pt, post);
Replaceall(post, "$iminput", ln);
if (Len(post_code) > 0)
Printf(post_code, "\n");
Printv(post_code, post, NIL);
}
String *terminator = Getattr(p, "tmap:csdirectorin:terminator");
if (terminator) {
substituteClassname(pt, terminator);
Replaceall(terminator, "$iminput", ln);
if (Len(terminator_code) > 0)
Insert(terminator_code, 0, "\n");
Insert(terminator_code, 0, terminator);
}
if (i > 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);
int flags = DOH_REPLACE_FIRST | DOH_REPLACE_ID_BEGIN | DOH_REPLACE_NOCOMMENT;
if (Replace(tm, "ref ", "", flags) || Replace(tm, "ref\t", "", flags)) {
Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm);
} else if (Replace(tm, "out ", "", flags) || Replace(tm, "out\t", "", flags)) {
Printf(proxy_method_types, "typeof(%s).MakeByRefType()", tm);
} else {
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");
} else {
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;
}
} 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);
}
Delete(ln);
Delete(arg);
Delete(c_decl);
}
/* header declaration, start wrapper definition */
String *target;
SwigType *rtype = Getattr(n, "conversion_operator") ? 0 : Getattr(n, "classDirectorMethods:type");
target = Swig_method_decl(rtype, decl, qualified_name, l, 0);
Printf(w->def, "%s", target);
Delete(qualified_name);
Delete(target);
target = Swig_method_decl(rtype, decl, name, l, 1);
Printf(declaration, " virtual %s", target);
Delete(target);
// Add any exception specifications to the methods in the director class
if (Getattr(n, "noexcept")) {
Append(w->def, " noexcept");
Append(declaration, " noexcept");
}
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 (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 ((tm = Swig_typemap_lookup("csdirectorout", n, "", 0))) {
substituteClassname(returntype, tm);
Replaceall(tm, "$cscall", upcall);
if (!is_void)
Insert(tm, 0, "return ");
Replaceall(tm, "\n ", "\n "); // add extra indentation to code in typemap
// pre and post attribute support
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)
Printf(callback_code, "%s\n try {\n %s;\n } finally {\n%s\n }\n", pre_code, tm, post_code);
else if (is_pre_code)
Printf(callback_code, "%s\n %s;\n", pre_code, tm);
else if (is_post_code)
Printf(callback_code, " try {\n %s;\n } finally {\n%s\n }\n", tm, post_code);
else
Printf(callback_code, " %s;\n", tm);
if (is_terminator_code)
Printv(callback_code, "\n", terminator_code, NIL);
}
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");
/* Copy jresult into c_result... */
if ((tm = Swig_typemap_lookup("directorout", n, 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(jresult_str);
Delete(result_str);
}
/* Marshal outputs */
for (p = l; p;) {
if ((tm = Getattr(p, "tmap:directorargout"))) {
canThrow(n, "directorargout", p);
Replaceall(tm, "$result", "jresult");
Replaceall(tm, "$input", Getattr(p, "emit:directorinput"));
Printv(w->code, tm, "\n", NIL);
p = Getattr(p, "tmap:directorargout:next");
} else {
p = nextSibling(p);
}
}
/* 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 the director method */
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")) {
Replaceall(w->code, "$symname", symname);
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");
Setattr(n, "upcalldata", udata);
/*
Printf(stdout, "setting upcalldata, nodeType: %s %s::%s %p\n", nodeType(n), classname, Getattr(n, "name"), n);
*/
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 global::System.Type[] swigMethodTypes%s = new global::System.Type[] { %s };\n", methid, proxy_method_types);
Printf(director_connect_parms, "SwigDirector%s%s delegate%s", classname, methid, methid);
}
Delete(pre_code);
Delete(post_code);
Delete(terminator_code);
Delete(qualified_return);
Delete(declaration);
Delete(callback_typedef_parms);
Delete(delegate_parms);
Delete(proxy_method_types);
Delete(callback_def);
Delete(callback_code);
Delete(dirclassname);
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 *dirclassname = 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, dirclassname, parms, 0);
String *call = Swig_csuperclass_call(0, basetype, superparms);
Printf(f_directors, "%s::%s : %s, %s {\n", dirclassname, target, call, Getattr(parent, "director:ctor"));
Printf(f_directors, " swig_init_callbacks();\n");
Printf(f_directors, "}\n\n");
Delete(target);
Delete(call);
}
/* constructor header */
{
String *target = Swig_method_decl(0, decl, dirclassname, parms, 1);
Printf(f_directors_h, " %s;\n", target);
Delete(target);
}
}
Delete(sub);
Delete(supername);
Delete(parms);
Delete(dirclassname);
return Language::classDirectorConstructor(n);
}
/* ------------------------------------------------------------
* classDirectorDefaultConstructor()
* ------------------------------------------------------------ */
int classDirectorDefaultConstructor(Node *n) {
String *dirclassname = directorClassName(n);
String *classtype = SwigType_namestr(Getattr(n, "name"));
Wrapper *w = NewWrapper();
Printf(w->def, "%s::%s() : %s {", dirclassname, dirclassname, Getattr(n, "director:ctor"));
Printf(w->code, "}\n");
Wrapper_print(w, f_directors);
Printf(f_directors_h, " %s();\n", dirclassname);
DelWrapper(w);
Delete(classtype);
Delete(dirclassname);
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");
directorDeclaration(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);
}
int classDeclaration(Node *n) {
String *old_director_callback_typedefs = director_callback_typedefs;
String *old_director_callbacks = director_callbacks;
String *old_director_delegate_callback = director_delegate_callback;
String *old_director_delegate_definitions = director_delegate_definitions;
String *old_director_delegate_instances = director_delegate_instances;
String *old_director_method_types = director_method_types;
String *old_director_connect_parms = director_connect_parms;
int ret = Language::classDeclaration(n);
// these variables are deleted in emitProxyClassDefAndCPPCasts, hence no Delete here
director_callback_typedefs = old_director_callback_typedefs;
director_callbacks = old_director_callbacks;
director_delegate_callback = old_director_delegate_callback;
director_delegate_definitions = old_director_delegate_definitions;
director_delegate_instances = old_director_delegate_instances;
director_method_types = old_director_method_types;
director_connect_parms = old_director_connect_parms;
return ret;
}
/* ----------------------------------------------------------------------
* classDirectorDestructor()
* ---------------------------------------------------------------------- */
int classDirectorDestructor(Node *n) {
Node *current_class = getCurrentClass();
String *dirclassname = directorClassName(current_class);
Wrapper *w = NewWrapper();
if (Getattr(n, "noexcept")) {
Printf(f_directors_h, " virtual ~%s() noexcept;\n", dirclassname);
Printf(w->def, "%s::~%s() noexcept {\n", dirclassname, dirclassname);
} else if (Getattr(n, "throw")) {
Printf(f_directors_h, " virtual ~%s() throw();\n", dirclassname);
Printf(w->def, "%s::~%s() throw() {\n", dirclassname, dirclassname);
} else {
Printf(f_directors_h, " virtual ~%s();\n", dirclassname);
Printf(w->def, "%s::~%s() {\n", dirclassname, dirclassname);
}
Printv(w->code, "}\n", NIL);
Wrapper_print(w, f_directors);
DelWrapper(w);
Delete(dirclassname);
return SWIG_OK;
}
/* ------------------------------------------------------------
* classDirectorEnd()
* ------------------------------------------------------------ */
int classDirectorEnd(Node *n) {
int i;
String *dirclassname = 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(", dirclassname);
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_callbacks) > 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", dirclassname);
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);
Delete(dirclassname);
return Language::classDirectorEnd(n);
}
/* --------------------------------------------------------------------
* classDirectorDisown()
* ------------------------------------------------------------------*/
virtual int classDirectorDisown(Node *n) {
(void) n;
return SWIG_OK;
}
/*----------------------------------------------------------------------
* extraDirectorProtectedCPPMethodsRequired()
*--------------------------------------------------------------------*/
bool extraDirectorProtectedCPPMethodsRequired() const {
return false;
}
/*----------------------------------------------------------------------
* directorDeclaration()
*
* Generate the director class's declaration
* e.g. "class SwigDirector_myclass : public myclass, public Swig::Director {"
*--------------------------------------------------------------------*/
void directorDeclaration(Node *n) {
String *base = Getattr(n, "classtype");
String *class_ctor = NewString("Swig::Director()");
String *dirclassname = directorClassName(n);
String *declaration = Swig_class_declaration(n, dirclassname);
Printf(declaration, " : public %s, public Swig::Director", base);
// Stash stuff for later.
Setattr(n, "director:decl", declaration);
Setattr(n, "director:ctor", class_ctor);
Delete(dirclassname);
}
/*----------------------------------------------------------------------
* nestedClassesSupport()
*--------------------------------------------------------------------*/
NestedClassSupport nestedClassesSupport() const {
return NCS_Full;
}
}; /* 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 = "\
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\
-outfile <file> - Write all C# into a single <file> located in the output directory\n\
\n";