The only remaining use of this attribute is to test for whether we're wrapping a ctor and it is simpler and more clear to just check the node type directly in this case. This attribute was pretty confusing as it was used for parameters and entire declarations, so removing it makes things more clear and simpler.
1718 lines
58 KiB
C++
1718 lines
58 KiB
C++
/* -----------------------------------------------------------------------------
|
|
* See the LICENSE file for information on copyright, usage and redistribution
|
|
* of SWIG, and the README file for authors - http://www.swig.org/release.html.
|
|
*
|
|
* c.cxx
|
|
*
|
|
* C language module for SWIG.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
#include <ctype.h>
|
|
#include "swigmod.h"
|
|
|
|
#ifdef IS_SET_TO_ONE
|
|
#undef IS_SET_TO_ONE
|
|
#endif
|
|
#define IS_SET_TO_ONE(n, var) \
|
|
(Cmp(Getattr(n, var), "1") == 0)
|
|
|
|
int SwigType_isbuiltin(SwigType *t) {
|
|
const char* builtins[] = { "void", "short", "int", "long", "char", "float", "double", "bool", 0 };
|
|
int i = 0;
|
|
char *c = Char(t);
|
|
if (!t)
|
|
return 0;
|
|
while (builtins[i]) {
|
|
if (strcmp(c, builtins[i]) == 0)
|
|
return 1;
|
|
i++;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
// Private helpers, could be made public and reused from other language modules in the future.
|
|
namespace
|
|
{
|
|
|
|
// Delete a DOH object on scope exit.
|
|
class scoped_dohptr
|
|
{
|
|
public:
|
|
explicit scoped_dohptr(DOH* obj) : obj_(obj) {}
|
|
~scoped_dohptr() { Delete(obj_); }
|
|
|
|
// This is an std::auto_ptr<>-like "destructive" copy ctor which allows to return objects of this type from functions.
|
|
scoped_dohptr(scoped_dohptr const& tmp) : obj_(tmp.release()) {}
|
|
|
|
DOH* get() const { return obj_; }
|
|
|
|
DOH* release() const /* not really */ {
|
|
DOH* obj = obj_;
|
|
const_cast<DOH*&>(const_cast<scoped_dohptr*>(this)->obj_) = NULL;
|
|
return obj;
|
|
}
|
|
|
|
operator DOH*() const { return obj_; }
|
|
|
|
private:
|
|
scoped_dohptr& operator=(scoped_dohptr const&);
|
|
|
|
DOH* const obj_;
|
|
};
|
|
|
|
// Helper class to output "begin" fragment in the ctor and "end" in the dtor.
|
|
class begin_end_output_guard
|
|
{
|
|
public:
|
|
begin_end_output_guard(File* f, const_String_or_char_ptr begin, const_String_or_char_ptr end)
|
|
: f_(f),
|
|
end_(NewString(end))
|
|
{
|
|
String* const s = NewString(begin);
|
|
Dump(s, f_);
|
|
Delete(s);
|
|
}
|
|
|
|
~begin_end_output_guard()
|
|
{
|
|
Dump(end_, f_);
|
|
Delete(end_);
|
|
}
|
|
|
|
private:
|
|
// Non copyable.
|
|
begin_end_output_guard(const begin_end_output_guard&);
|
|
begin_end_output_guard& operator=(const begin_end_output_guard&);
|
|
|
|
File* const f_;
|
|
String* const end_;
|
|
};
|
|
|
|
// Subclass to output extern "C" guards when compiling as C++.
|
|
class cplusplus_output_guard : private begin_end_output_guard
|
|
{
|
|
public:
|
|
explicit cplusplus_output_guard(File* f)
|
|
: begin_end_output_guard(
|
|
f,
|
|
"#ifdef __cplusplus\n"
|
|
"extern \"C\" {\n"
|
|
"#endif\n\n",
|
|
"#ifdef __cplusplus\n"
|
|
"}\n"
|
|
"#endif\n\n"
|
|
)
|
|
{
|
|
}
|
|
};
|
|
|
|
// String containing one indentation level for the generated code.
|
|
const char* const cindent = " ";
|
|
|
|
} // anonymous namespace
|
|
|
|
class C:public Language {
|
|
static const char *usage;
|
|
|
|
File *f_begin;
|
|
File *f_runtime;
|
|
File *f_header;
|
|
File *f_wrappers;
|
|
File *f_wrappers_cxx;
|
|
File *f_wrappers_types;
|
|
File *f_wrappers_decl;
|
|
File *f_wrappers_aliases;
|
|
File *f_init;
|
|
|
|
String *empty_string;
|
|
String *int_string;
|
|
String *tl_namespace; // optional top level namespace
|
|
|
|
// Contains fully expanded names of the classes for which we have already specialized SWIG_derives_from<>.
|
|
Hash *already_specialized_derives_from;
|
|
|
|
// If non-null, contains wrap:action code to be used in the next functionWrapper() call.
|
|
String *special_wrap_action;
|
|
|
|
// Used only while generating wrappers for an enum, initially true and reset to false as soon as we see any enum elements.
|
|
bool enum_is_empty;
|
|
|
|
bool except_flag;
|
|
|
|
// Selects between the wrappers (public) declarations and (private) definitions.
|
|
enum output_target {
|
|
output_wrapper_decl,
|
|
output_wrapper_def
|
|
};
|
|
|
|
public:
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* C()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
C() :
|
|
empty_string(NewString("")),
|
|
int_string(NewString("int")),
|
|
tl_namespace(NULL),
|
|
already_specialized_derives_from(NULL),
|
|
special_wrap_action(NULL),
|
|
except_flag(true) {
|
|
}
|
|
|
|
|
|
String *getNamespacedName(Node *n)
|
|
{
|
|
if (!n)
|
|
return 0;
|
|
|
|
String *proxyname = NULL;
|
|
if ((proxyname = Getattr(n, "proxyname")))
|
|
return Copy(proxyname);
|
|
|
|
String *symname = Getattr(n, "sym:name");
|
|
String *nspace = Getattr(n, "sym:nspace");
|
|
|
|
if (nspace) {
|
|
// FIXME: using namespace as class name is a hack.
|
|
proxyname = Swig_name_member(tl_namespace, nspace, symname);
|
|
} else {
|
|
proxyname = symname;
|
|
}
|
|
Setattr(n, "proxyname", proxyname);
|
|
Delete(proxyname);
|
|
|
|
return Copy(proxyname);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* 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
|
|
* top level namespace name if the nspace feature is used.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *getProxyName(SwigType *t) {
|
|
Node *n = classLookup(t);
|
|
|
|
return n ? getNamespacedName(n) : NULL;
|
|
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* getEnumName()
|
|
*
|
|
* Return the name to use for the enum in the generated code.
|
|
* Also caches it in the node for subsequent access.
|
|
* Returns NULL if the node doesn't correspond to an enum.
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
String *getEnumName(Node *n) {
|
|
String *enumname = NULL;
|
|
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 *proxyname = 0;
|
|
if (String *name = Getattr(n, "name")) {
|
|
if (String *scopename_prefix = Swig_scopename_prefix(name)) {
|
|
proxyname = getProxyName(scopename_prefix);
|
|
Delete(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 (tl_namespace)
|
|
enumname = NewStringf("%s_%s_%s", tl_namespace, nspace, symname);
|
|
else
|
|
enumname = NewStringf("%s_%s", nspace, symname);
|
|
} else {
|
|
enumname = Copy(symname);
|
|
}
|
|
}
|
|
Setattr(n, "enumname", enumname);
|
|
Delete(enumname);
|
|
}
|
|
}
|
|
}
|
|
|
|
return enumname;
|
|
}
|
|
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* substituteResolvedTypeSpecialVariable()
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
void substituteResolvedTypeSpecialVariable(output_target target, SwigType *classnametype, String *tm, const char *classnamespecialvariable) {
|
|
if (!CPlusPlus) {
|
|
// Just use the original C type when not using C++, we know that this type can be used in the wrappers.
|
|
Clear(tm);
|
|
String* const s = SwigType_str(classnametype, 0);
|
|
Append(tm, s);
|
|
Delete(s);
|
|
return;
|
|
}
|
|
|
|
if (SwigType_isenum(classnametype)) {
|
|
String *enumname = getEnumName(enumLookup(classnametype));
|
|
if (enumname)
|
|
Replaceall(tm, classnamespecialvariable, enumname);
|
|
else
|
|
Replaceall(tm, classnamespecialvariable, NewStringf("int"));
|
|
} else {
|
|
scoped_dohptr btype(SwigType_base(classnametype));
|
|
String* typestr = NIL;
|
|
if (target == output_wrapper_def || Cmp(btype, "SwigObj") == 0) {
|
|
// Special case, just leave it unchanged.
|
|
typestr = NewString("SwigObj");
|
|
} else {
|
|
typestr = getProxyName(classnametype);
|
|
if (!typestr) {
|
|
if (SwigType_isbuiltin(btype)) {
|
|
// This should work just as well in C without any changes.
|
|
typestr = SwigType_str(classnametype, 0);
|
|
} else {
|
|
// Swig doesn't know anything about this type, use descriptor for it.
|
|
typestr = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
|
|
|
|
// And make sure it is declared before it is used.
|
|
Printf(f_wrappers_types, "typedef struct %s %s;\n\n", typestr, typestr);
|
|
}
|
|
}
|
|
}
|
|
|
|
Replaceall(tm, classnamespecialvariable, typestr);
|
|
Delete(typestr);
|
|
}
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* substituteResolvedType()
|
|
*
|
|
* 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 substituteResolvedType(output_target target, 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, "$resolved_type")) {
|
|
SwigType *classnametype = Copy(strippedtype);
|
|
substituteResolvedTypeSpecialVariable(target, classnametype, tm, "$resolved_type");
|
|
substitution_performed = true;
|
|
Delete(classnametype);
|
|
}
|
|
if (Strstr(tm, "$*resolved_type")) {
|
|
SwigType *classnametype = Copy(strippedtype);
|
|
Delete(SwigType_pop(classnametype));
|
|
if (Len(classnametype) > 0) {
|
|
substituteResolvedTypeSpecialVariable(target, classnametype, tm, "$*resolved_type");
|
|
substitution_performed = true;
|
|
}
|
|
Delete(classnametype);
|
|
}
|
|
if (Strstr(tm, "$&resolved_type")) {
|
|
SwigType *classnametype = Copy(strippedtype);
|
|
SwigType_add_pointer(classnametype);
|
|
substituteResolvedTypeSpecialVariable(target, classnametype, tm, "$&resolved_type");
|
|
substitution_performed = true;
|
|
Delete(classnametype);
|
|
}
|
|
|
|
Delete(strippedtype);
|
|
Delete(type);
|
|
|
|
return substitution_performed;
|
|
}
|
|
|
|
/* ------------------------------------------------------------
|
|
* main()
|
|
* ------------------------------------------------------------ */
|
|
|
|
virtual void main(int argc, char *argv[]) {
|
|
|
|
// look for certain command line options
|
|
for (int i = 1; i < argc; i++) {
|
|
if (argv[i]) {
|
|
if (strcmp(argv[i], "-help") == 0) {
|
|
Printf(stdout, "%s\n", usage);
|
|
} else if (strcmp(argv[i], "-noexcept") == 0) {
|
|
except_flag = false;
|
|
Swig_mark_arg(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!CPlusPlus)
|
|
except_flag = false;
|
|
|
|
// add a symbol to the parser for conditional compilation
|
|
Preprocessor_define("SWIGC 1", 0);
|
|
if (except_flag)
|
|
Preprocessor_define("SWIG_C_EXCEPT 1", 0);
|
|
if (CPlusPlus)
|
|
Preprocessor_define("SWIG_CPPMODE 1", 0);
|
|
|
|
SWIG_library_directory("c");
|
|
|
|
// add typemap definitions
|
|
SWIG_typemap_lang("c");
|
|
SWIG_config_file("c.swg");
|
|
|
|
allow_overloading();
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* top()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int top(Node *n) {
|
|
String *module = Getattr(n, "name");
|
|
String *outfile = Getattr(n, "outfile");
|
|
|
|
// initialize I/O
|
|
f_begin = NewFile(outfile, "w", SWIG_output_files());
|
|
if (!f_begin) {
|
|
FileErrorDisplay(outfile);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
f_runtime = NewString("");
|
|
f_init = NewString("");
|
|
f_header = NewString("");
|
|
f_wrappers = NewString("");
|
|
f_wrappers_cxx = NewString("");
|
|
|
|
Swig_banner(f_begin);
|
|
|
|
// Open the file where all wrapper declarations will be written to in the end.
|
|
String* const outfile_h = Getattr(n, "outfile_h");
|
|
File* const f_wrappers_h = NewFile(outfile_h, "w", SWIG_output_files());
|
|
if (!f_wrappers_h) {
|
|
FileErrorDisplay(outfile_h);
|
|
SWIG_exit(EXIT_FAILURE);
|
|
}
|
|
|
|
Swig_banner(f_wrappers_h);
|
|
|
|
Swig_register_filebyname("begin", f_begin);
|
|
Swig_register_filebyname("header", f_header);
|
|
Swig_register_filebyname("wrapper", f_wrappers);
|
|
Swig_register_filebyname("runtime", f_runtime);
|
|
Swig_register_filebyname("init", f_init);
|
|
Swig_register_filebyname("cheader", f_wrappers_h);
|
|
|
|
{
|
|
String* const include_guard_name = NewStringf("SWIG_%s_WRAP_H_", Char(module));
|
|
String* const include_guard_begin = NewStringf(
|
|
"#ifndef %s\n"
|
|
"#define %s\n\n",
|
|
include_guard_name,
|
|
include_guard_name
|
|
);
|
|
String* const include_guard_end = NewStringf(
|
|
"\n"
|
|
"#endif /* %s */\n",
|
|
include_guard_name
|
|
);
|
|
|
|
begin_end_output_guard
|
|
include_guard_wrappers_h(f_wrappers_h, include_guard_begin, include_guard_end);
|
|
|
|
// All the struct types used by the functions go to f_wrappers_types so that they're certain to be defined before they're used by any functions. All the
|
|
// functions declarations go directly to f_wrappers_decl and f_wrappers_h_body combines both of them.
|
|
String* const f_wrappers_h_body = NewString("");
|
|
f_wrappers_types = NewString("");
|
|
f_wrappers_decl = NewString("");
|
|
|
|
// We also define aliases for the global wrapper functions to allow calling them using their original names, but as this can result in problems (as usual
|
|
// when using the preprocessor), we provide a way to disable this by defining SWIG_NO_WRAPPER_ALIASES when compiling the generated code and so we use a
|
|
// separate section for this too.
|
|
f_wrappers_aliases = NIL;
|
|
|
|
{
|
|
|
|
cplusplus_output_guard
|
|
cplusplus_guard_wrappers(f_wrappers),
|
|
cplusplus_guard_wrappers_h(f_wrappers_h_body);
|
|
|
|
// emit code for children
|
|
Language::top(n);
|
|
|
|
Dump(f_wrappers_types, f_wrappers_h_body);
|
|
Delete(f_wrappers_types);
|
|
|
|
Dump(f_wrappers_decl, f_wrappers_h_body);
|
|
Delete(f_wrappers_decl);
|
|
} // close extern "C" guards
|
|
|
|
Dump(f_wrappers_h_body, f_wrappers_h);
|
|
Delete(f_wrappers_h_body);
|
|
|
|
if (f_wrappers_aliases) {
|
|
Dump(f_wrappers_aliases, f_wrappers_h);
|
|
Delete(f_wrappers_aliases);
|
|
|
|
Printv(f_wrappers_h, "#endif /* SWIG_NO_WRAPPER_ALIASES */\n", NIL);
|
|
}
|
|
} // close wrapper header guard
|
|
|
|
// write all to the file
|
|
Dump(f_header, f_runtime);
|
|
Dump(f_wrappers_cxx, f_runtime);
|
|
Wrapper_pretty_print(f_wrappers, f_runtime);
|
|
Dump(f_init, f_runtime);
|
|
Dump(f_runtime, f_begin);
|
|
|
|
// cleanup
|
|
Delete(f_begin);
|
|
Delete(f_header);
|
|
Delete(f_wrappers);
|
|
Delete(f_wrappers_cxx);
|
|
Delete(f_wrappers_h);
|
|
Delete(f_init);
|
|
Delete(f_runtime);
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* globalvariableHandler()
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
virtual int globalvariableHandler(Node *n) {
|
|
// We can't export variables defined inside namespaces to C directly, whatever their type.
|
|
String* const scope = Swig_scopename_prefix(Getattr(n, "name"));
|
|
if (!scope) {
|
|
// If we can export the variable directly, do it, this will be more convenient to use from C code than accessor functions.
|
|
if (String* const var_decl = make_c_var_decl(n)) {
|
|
Printv(f_wrappers_decl, "SWIGIMPORT ", var_decl, ";\n\n", NIL);
|
|
Delete(var_decl);
|
|
return SWIG_OK;
|
|
}
|
|
} else {
|
|
Delete(scope);
|
|
}
|
|
|
|
// Otherwise, e.g. if it's of a C++-only type, or a reference, generate accessor functions for it.
|
|
return Language::globalvariableHandler(n);
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------
|
|
* globalfunctionHandler()
|
|
* ------------------------------------------------------------------------ */
|
|
|
|
virtual int globalfunctionHandler(Node *n) {
|
|
SwigType *type = Getattr(n, "type");
|
|
ParmList *parms = Getattr(n, "parms");
|
|
String *arg_list = NewString("");
|
|
String *call = empty_string;
|
|
String *cres = empty_string;
|
|
|
|
call = Swig_cfunction_call(Getattr(n, "name"), parms);
|
|
cres = Swig_cresult(type, "result", call);
|
|
Setattr(n, "wrap:action", cres);
|
|
Setattr(n, "c:globalfun", "1");
|
|
|
|
if (!SwigType_ispointer(type) && !SwigType_isreference(type))
|
|
Setattr(n, "c:retval", "1");
|
|
|
|
functionWrapper(n);
|
|
|
|
Delete(cres);
|
|
Delete(call);
|
|
Delete(arg_list);
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* prepend_feature()
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
String* prepend_feature(Node *n) {
|
|
String *prepend_str = Getattr(n, "feature:prepend");
|
|
if (prepend_str) {
|
|
char *t = Char(prepend_str);
|
|
if (*t == '{') {
|
|
Delitem(prepend_str, 0);
|
|
Delitem(prepend_str, DOH_END);
|
|
}
|
|
}
|
|
return (prepend_str ? prepend_str : empty_string);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* append_feature()
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
String* append_feature(Node *n) {
|
|
String *append_str = Getattr(n, "feature:append");
|
|
if (append_str) {
|
|
char *t = Char(append_str);
|
|
if (*t == '{') {
|
|
Delitem(append_str, 0);
|
|
Delitem(append_str, DOH_END);
|
|
}
|
|
}
|
|
return (append_str ? append_str : empty_string);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* get_mangled_type()
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
String *get_mangled_type(SwigType *type_arg) {
|
|
String *result = NewString("");
|
|
SwigType *prefix = 0;
|
|
SwigType *type = 0;
|
|
SwigType *tdtype = SwigType_typedef_resolve_all(type_arg);
|
|
if (tdtype)
|
|
type = tdtype;
|
|
else
|
|
type = Copy(type_arg);
|
|
|
|
// special cases for ptr to function as an argument
|
|
if (SwigType_ismemberpointer(type)) {
|
|
SwigType_del_memberpointer(type);
|
|
SwigType_add_pointer(type);
|
|
}
|
|
if (SwigType_ispointer(type)) {
|
|
SwigType_del_pointer(type);
|
|
if (SwigType_isfunction(type)) {
|
|
Printf(result, "f");
|
|
goto ready;
|
|
}
|
|
Delete(type);
|
|
type = Copy(type_arg);
|
|
}
|
|
|
|
prefix = SwigType_prefix(type);
|
|
Replaceall(prefix, ".", "");
|
|
Replaceall(prefix, "const", "c");
|
|
Replaceall(prefix, "volatile", "v");
|
|
Replaceall(prefix, "a(", "a");
|
|
Replaceall(prefix, "m(", "m");
|
|
Replaceall(prefix, "q(", "");
|
|
Replaceall(prefix, ")", "");
|
|
Replaceall(prefix, " ", "");
|
|
Printf(result, "%s", prefix);
|
|
|
|
type = SwigType_base(type);
|
|
if (SwigType_isbuiltin(type))
|
|
Printf(result, "%c", *Char(SwigType_base(type)));
|
|
else if (SwigType_isenum(type))
|
|
Printf(result, "e%s", Swig_scopename_last(type));
|
|
else
|
|
Printf(result, "%s", Char(Swig_name_mangle(SwigType_base(type))));
|
|
|
|
ready:
|
|
if (prefix)
|
|
Delete(prefix);
|
|
if (type)
|
|
Delete(type);
|
|
|
|
return result;
|
|
}
|
|
|
|
virtual void functionWrapperCSpecific(Node *n)
|
|
{
|
|
// this is C function, we don't apply typemaps to it
|
|
String *name = Getattr(n, "sym:name");
|
|
String *wname = Swig_name_wrapper(name);
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *return_type = NULL;
|
|
String *arg_names = NULL;
|
|
ParmList *parms = Getattr(n, "parms");
|
|
Parm *p;
|
|
String *proto = NewString("");
|
|
int gencomma = 0;
|
|
bool is_void_return = (SwigType_type(type) == T_VOID);
|
|
|
|
// create new function wrapper object
|
|
Wrapper *wrapper = NewWrapper();
|
|
|
|
// create new wrapper name
|
|
Setattr(n, "wrap:name", wname); //Necessary to set this attribute? Apparently, it's never read!
|
|
|
|
// create function call
|
|
arg_names = Swig_cfunction_call(empty_string, parms);
|
|
if (arg_names) {
|
|
Delitem(arg_names, 0);
|
|
Delitem(arg_names, DOH_END);
|
|
}
|
|
return_type = SwigType_str(type, 0);
|
|
|
|
// emit wrapper prototype and code
|
|
for (p = parms, gencomma = 0; p; p = nextSibling(p)) {
|
|
Printv(proto, gencomma ? ", " : "", SwigType_str(Getattr(p, "type"), 0), " ", Getattr(p, "lname"), NIL);
|
|
gencomma = 1;
|
|
}
|
|
Printv(wrapper->def, return_type, " ", wname, "(", proto, ") {\n", NIL);
|
|
|
|
// attach 'check' typemaps
|
|
Swig_typemap_attach_parms("check", parms, wrapper);
|
|
|
|
// insert constraint checking
|
|
for (p = parms; p; ) {
|
|
String *tm;
|
|
if ((tm = Getattr(p, "tmap:check"))) {
|
|
Replaceall(tm, "$target", Getattr(p, "lname"));
|
|
Replaceall(tm, "$name", name);
|
|
Printv(wrapper->code, tm, "\n", NIL);
|
|
p = Getattr(p, "tmap:check:next");
|
|
}
|
|
else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
Append(wrapper->code, prepend_feature(n));
|
|
if (!is_void_return) {
|
|
Printv(wrapper->code, return_type, " result;\n", NIL);
|
|
Printf(wrapper->code, "result = ");
|
|
}
|
|
Printv(wrapper->code, name, "(", arg_names, ");\n", NIL);
|
|
Append(wrapper->code, append_feature(n));
|
|
if (!is_void_return)
|
|
Printf(wrapper->code, "return result;\n");
|
|
Printf(wrapper->code, "}");
|
|
|
|
Wrapper_print(wrapper, f_wrappers);
|
|
|
|
emit_wrapper_func_decl(n, name);
|
|
|
|
// cleanup
|
|
Delete(proto);
|
|
Delete(arg_names);
|
|
Delete(wname);
|
|
Delete(return_type);
|
|
DelWrapper(wrapper);
|
|
}
|
|
|
|
static void functionWrapperPrepareArgs(const ParmList *parms)
|
|
{
|
|
Parm *p;
|
|
int index = 1;
|
|
String *lname = 0;
|
|
|
|
for (p = (Parm*)parms, index = 1; p; (p = nextSibling(p)), index++) {
|
|
if(!(lname = Getattr(p, "lname"))) {
|
|
lname = NewStringf("arg%d", index);
|
|
Setattr(p, "lname", lname);
|
|
}
|
|
}
|
|
}
|
|
|
|
virtual void functionWrapperAppendOverloaded(String *name, Parm* first_param)
|
|
{
|
|
String *over_suffix = NewString("");
|
|
Parm *p;
|
|
String *mangled;
|
|
|
|
for (p = first_param; p; p = nextSibling(p)) {
|
|
mangled = get_mangled_type(Getattr(p, "type"));
|
|
Printv(over_suffix, "_", mangled, NIL);
|
|
}
|
|
Append(name, over_suffix);
|
|
Delete(over_suffix);
|
|
}
|
|
|
|
static void functionWrapperAddCPPResult(Wrapper *wrapper, const SwigType *type, const String *tm)
|
|
{
|
|
SwigType *cpptype;
|
|
SwigType *tdtype = SwigType_typedef_resolve_all(tm);
|
|
if (tdtype)
|
|
cpptype = tdtype;
|
|
else
|
|
cpptype = (SwigType*)tm;
|
|
if (SwigType_ismemberpointer(type))
|
|
Wrapper_add_local(wrapper, "cppresult", SwigType_str(type, "cppresult"));
|
|
else
|
|
Wrapper_add_local(wrapper, "cppresult", SwigType_str(cpptype, "cppresult"));
|
|
}
|
|
|
|
String *get_wrapper_func_return_type(output_target target, Node *n)
|
|
{
|
|
SwigType *type = Getattr(n, "type");
|
|
String *return_type = NewString("");
|
|
String *tm;
|
|
|
|
if ((tm = Swig_typemap_lookup("ctype", n, "", 0))) {
|
|
// handle simple typemap cases
|
|
String *ctypeout = Getattr(n, "tmap:ctype:out");
|
|
if (ctypeout)
|
|
{
|
|
return_type = ctypeout;
|
|
Printf(stdout, "Obscure ctype:out found! O.o\n");
|
|
}
|
|
else
|
|
{
|
|
substituteResolvedType(target, type, tm);
|
|
return_type = tm;
|
|
}
|
|
}
|
|
else {
|
|
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(type, 0));
|
|
}
|
|
|
|
Replaceall(return_type, "::", "_");
|
|
|
|
return return_type;
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* get_wrapper_func_proto()
|
|
*
|
|
* Return the function signature, i.e. the comma-separated list of argument types and names surrounded by parentheses.
|
|
* If a non-null wrapper is specified, it is used to emit typemap-defined code in it and it also determines whether we're generating the prototype for the
|
|
* declarations or the definitions, which changes the type used for the C++ objects.
|
|
* ---------------------------------------------------------------------- */
|
|
scoped_dohptr get_wrapper_func_proto(Node *n, Wrapper* wrapper = NULL)
|
|
{
|
|
ParmList *parms = Getattr(n, "parms");
|
|
|
|
Parm *p;
|
|
String *proto = NewString("(");
|
|
int gencomma = 0;
|
|
|
|
// attach the standard typemaps
|
|
if (wrapper) {
|
|
emit_attach_parmmaps(parms, wrapper);
|
|
} else {
|
|
// We can't call emit_attach_parmmaps() without a wrapper, it would just crash.
|
|
// Attach "in" manually, we need it for tmap:in:numinputs below.
|
|
Swig_typemap_attach_parms("in", parms, 0);
|
|
}
|
|
Setattr(n, "wrap:parms", parms); //never read again?!
|
|
|
|
// attach 'ctype' typemaps
|
|
Swig_typemap_attach_parms("ctype", parms, 0);
|
|
|
|
|
|
// prepare function definition
|
|
for (p = parms, gencomma = 0; p; ) {
|
|
String *tm;
|
|
SwigType *type = NULL;
|
|
|
|
while (p && checkAttribute(p, "tmap:in:numinputs", "0")) {
|
|
p = Getattr(p, "tmap:in:next");
|
|
}
|
|
if (!p) break;
|
|
|
|
type = Getattr(p, "type");
|
|
if (SwigType_type(type) == T_VOID) {
|
|
p = nextSibling(p);
|
|
continue;
|
|
}
|
|
String *lname = Getattr(p, "lname");
|
|
String *c_parm_type = 0;
|
|
String *arg_name = NewString("");
|
|
|
|
SwigType *tdtype = SwigType_typedef_resolve_all(type);
|
|
if (tdtype)
|
|
type = tdtype;
|
|
|
|
Printf(arg_name, "c%s", lname);
|
|
|
|
if ((tm = Getattr(p, "tmap:ctype"))) { // set the appropriate type for parameter
|
|
c_parm_type = Copy(tm);
|
|
substituteResolvedType(wrapper ? output_wrapper_def : output_wrapper_decl, type, c_parm_type);
|
|
|
|
// template handling
|
|
Replaceall(c_parm_type, "$tt", SwigType_lstr(type, 0));
|
|
}
|
|
else {
|
|
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(type, 0));
|
|
}
|
|
|
|
Printv(proto, gencomma ? ", " : "", c_parm_type, " ", arg_name, NIL);
|
|
gencomma = 1;
|
|
|
|
// apply typemaps for input parameter
|
|
if (Cmp(nodeType(n), "destructor") == 0) {
|
|
p = Getattr(p, "tmap:in:next");
|
|
}
|
|
else if ((tm = Getattr(p, "tmap:in"))) {
|
|
Replaceall(tm, "$input", arg_name);
|
|
if (wrapper) {
|
|
Setattr(p, "emit:input", arg_name);
|
|
Printf(wrapper->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(type, 0));
|
|
p = nextSibling(p);
|
|
}
|
|
|
|
Delete(arg_name);
|
|
Delete(c_parm_type);
|
|
}
|
|
|
|
Printv(proto, ")", NIL);
|
|
return scoped_dohptr(proto);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* emit_wrapper_func_decl()
|
|
*
|
|
* Declares the wrapper function, using the C types used for it, in the header.
|
|
* Also emits a define allowing to use the function without the "_wrap_" prefix.
|
|
* The node here is a function declaration.
|
|
* ---------------------------------------------------------------------- */
|
|
void emit_wrapper_func_decl(Node *n, String *name)
|
|
{
|
|
// C++ function wrapper proxy code
|
|
bool const is_global = IS_SET_TO_ONE(n, "c:globalfun");
|
|
String *wname = is_global ? Swig_name_wrapper(name) : Copy(name);
|
|
String *preturn_type = get_wrapper_func_return_type(output_wrapper_decl, n);
|
|
String *wrapper_call = NewString("");
|
|
|
|
// add function declaration to the proxy header file
|
|
Printv(f_wrappers_decl, preturn_type, " ", wname, get_wrapper_func_proto(n).get(), ";\n\n", NIL);
|
|
|
|
if (is_global) {
|
|
if (!f_wrappers_aliases) {
|
|
// Allocate it on demand.
|
|
f_wrappers_aliases = NewStringEmpty();
|
|
Printv(f_wrappers_aliases, "#ifndef SWIG_NO_WRAPPER_ALIASES\n", NIL);
|
|
}
|
|
|
|
Printf(f_wrappers_aliases, "#define %s %s\n", name, wname);
|
|
}
|
|
|
|
// cleanup
|
|
Delete(wname);
|
|
Delete(wrapper_call);
|
|
Delete(preturn_type);
|
|
}
|
|
|
|
|
|
virtual void functionWrapperCPPSpecificWrapper(Node *n, String *name)
|
|
{
|
|
// C++ function wrapper
|
|
String *storage = Getattr(n, "storage");
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *otype = Copy(type);
|
|
SwigType *return_type = get_wrapper_func_return_type(output_wrapper_def, n);
|
|
String *wname = IS_SET_TO_ONE(n, "c:globalfun") ? Swig_name_wrapper(name) : Copy(name);
|
|
ParmList *parms = Getattr(n, "parms");
|
|
Parm *p;
|
|
bool const is_ctor = Cmp(nodeType(n), "constructor") == 0;
|
|
bool is_void_return = (SwigType_type(type) == T_VOID);
|
|
bool return_object = false;
|
|
// create new function wrapper object
|
|
Wrapper *wrapper = NewWrapper();
|
|
|
|
// create new wrapper name
|
|
Setattr(n, "wrap:name", wname);
|
|
|
|
// add variable for holding result of original function 'cppresult'
|
|
if (!is_void_return && !is_ctor) {
|
|
String *tm;
|
|
if ((tm = Swig_typemap_lookup("cppouttype", n, "", 0))) {
|
|
functionWrapperAddCPPResult(wrapper, type, tm);
|
|
return_object = checkAttribute(n, "tmap:cppouttype:retobj", "1");
|
|
}
|
|
else {
|
|
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No cppouttype typemap defined for %s\n", SwigType_str(type, 0));
|
|
}
|
|
}
|
|
|
|
// create wrapper function prototype
|
|
Printv(wrapper->def, "SWIGEXPORTC ", return_type, " ", wname, NIL);
|
|
|
|
Printv(wrapper->def, get_wrapper_func_proto(n, wrapper).get(), NIL);
|
|
Printv(wrapper->def, " {", NIL);
|
|
|
|
bool const is_dtor = Cmp(nodeType(n), "destructor") == 0;
|
|
if (!is_dtor) {
|
|
// emit variables for holding parameters
|
|
emit_parameter_variables(parms, wrapper);
|
|
|
|
// emit variable for holding function return value
|
|
emit_return_variable(n, return_type, wrapper);
|
|
}
|
|
|
|
// insert constraint checking
|
|
for (p = parms; p; ) {
|
|
String *tm;
|
|
if ((tm = Getattr(p, "tmap:check"))) {
|
|
Replaceall(tm, "$target", Getattr(p, "lname"));
|
|
Replaceall(tm, "$name", name);
|
|
Printv(wrapper->code, tm, "\n", NIL);
|
|
p = Getattr(p, "tmap:check:next");
|
|
}
|
|
else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
// create action code
|
|
String *action = Getattr(n, "wrap:action");
|
|
if (!action)
|
|
action = NewString("");
|
|
|
|
String *cbase_name = Getattr(n, "c:base_name");
|
|
if (cbase_name) {
|
|
Replaceall(action, "arg1)->", NewStringf("(%s*)arg1)->", Getattr(n, "c:inherited_from")));
|
|
Replaceall(action, Getattr(n, "name"), cbase_name);
|
|
}
|
|
|
|
// handle special cases of cpp return result
|
|
if (!is_ctor) {
|
|
if (SwigType_isenum(SwigType_base(type))){
|
|
if (return_object)
|
|
Replaceall(action, "result =", "cppresult = (int)");
|
|
else Replaceall(action, "result =", "cppresult = (int*)");
|
|
}
|
|
else if (return_object && Getattr(n, "c:retval") && !SwigType_isarray(type)
|
|
&& (Cmp(storage, "static") != 0)) {
|
|
// returning object by value
|
|
String *str = SwigType_str(SwigType_add_reference(SwigType_base(type)), "_result_ref");
|
|
String *lstr = SwigType_lstr(type, 0);
|
|
if (Cmp(Getattr(n, "kind"), "variable") == 0) {
|
|
Delete(action);
|
|
action = NewStringf("{const %s = %s;", str, Swig_cmemberget_call(Getattr(n, "name"), type, 0, 0));
|
|
}
|
|
else {
|
|
String *call_str = NewStringf("{const %s = %s", str,
|
|
SwigType_ispointer(SwigType_typedef_resolve_all(otype)) ? "*" : "");
|
|
Replaceall(action, "result =", call_str);
|
|
Delete(call_str);
|
|
}
|
|
if (Getattr(n, "nested"))
|
|
Replaceall(action, "=", NewStringf("= *(%s)(void*) &", SwigType_str(otype, 0)));
|
|
Printf(action, "cppresult = (%s*) &_result_ref;}", lstr);
|
|
Delete(str);
|
|
Delete(lstr);
|
|
}
|
|
else
|
|
Replaceall(action, "result =", "cppresult = ");
|
|
}
|
|
|
|
// prepare action code to use, e.g. insert try-catch blocks
|
|
|
|
// We don't take extension ctors and dtors into account currently (objects are always created using hardcoded new in constructorHandler() and destroyed
|
|
// using SWIG_destroy_object()) and generating them is at best useless and can be harmful when it results in a clash of names between an extension ctor
|
|
// new_Foo() and the ctor wrapper which has exactly the same name. So for now just drop them completely, which is certainly not right, but not worse than
|
|
// before.
|
|
//
|
|
// TODO-C: Implement proper extension ctors/dtor support.
|
|
if (is_ctor || is_dtor) {
|
|
Delattr(n, "wrap:code");
|
|
}
|
|
|
|
action = emit_action(n);
|
|
|
|
// emit output typemap if needed
|
|
if (!is_void_return && !is_ctor) {
|
|
String *tm;
|
|
if ((tm = Swig_typemap_lookup_out("out", n, "cppresult", wrapper, action))) {
|
|
Replaceall(tm, "$result", "result");
|
|
Printf(wrapper->code, "%s", tm);
|
|
if (Len(tm))
|
|
Printf(wrapper->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(type, 0), Getattr(n, "name"));
|
|
}
|
|
}
|
|
else {
|
|
Append(wrapper->code, action);
|
|
}
|
|
|
|
String *except = Getattr(n, "feature:except");
|
|
if (Getattr(n, "throws") || except) {
|
|
if (!except || (Cmp(except, "0") != 0))
|
|
Printf(wrapper->code, "if (SWIG_exc.handled) {\nSWIG_rt_stack_pop();\nlongjmp(SWIG_rt_env, 1);\n}\n");
|
|
}
|
|
|
|
// insert cleanup code
|
|
for (p = parms; p; ) {
|
|
String *tm;
|
|
if ((tm = Getattr(p, "tmap:freearg"))) {
|
|
if (tm && (Len(tm) != 0)) {
|
|
String *input = NewStringf("c%s", Getattr(p, "lname"));
|
|
Replaceall(tm, "$source", Getattr(p, "lname"));
|
|
Replaceall(tm, "$input", input);
|
|
Delete(input);
|
|
Printv(wrapper->code, tm, "\n", NIL);
|
|
}
|
|
p = Getattr(p, "tmap:freearg:next");
|
|
}
|
|
else {
|
|
p = nextSibling(p);
|
|
}
|
|
}
|
|
|
|
if (!is_void_return)
|
|
Append(wrapper->code, "return result;\n");
|
|
|
|
Append(wrapper->code, "}\n");
|
|
|
|
Wrapper_print(wrapper, f_wrappers);
|
|
|
|
// cleanup
|
|
Delete(wname);
|
|
Delete(return_type);
|
|
Delete(otype);
|
|
DelWrapper(wrapper);
|
|
}
|
|
|
|
virtual void functionWrapperCPPSpecific(Node *n)
|
|
{
|
|
// Use special actions for special methods if set up.
|
|
if (special_wrap_action) {
|
|
Setattr(n, "wrap:action", special_wrap_action);
|
|
Delete(special_wrap_action);
|
|
special_wrap_action = NULL;
|
|
}
|
|
|
|
ParmList *parms = Getattr(n, "parms");
|
|
String *name = Copy(Getattr(n, "sym:name"));
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *tdtype = NULL;
|
|
|
|
// mangle name if function is overloaded
|
|
if (Getattr(n, "sym:overloaded")) {
|
|
if (!Getattr(n, "copy_constructor")) {
|
|
Parm* first_param = (Parm*)parms;
|
|
if (first_param) {
|
|
// Skip the first "this" parameter of the wrapped methods, it doesn't participate in overload resolution and would just result in extra long
|
|
// and ugly names.
|
|
//
|
|
// The check for c:globalfun is needed to avoid dropping the first argument of static methods which don't have "this" pointer neither, in
|
|
// spite of being members. Of course, the constructors don't have it neither.
|
|
if (!Checkattr(n, "nodeType", "constructor") &&
|
|
Checkattr(n, "ismember", "1") &&
|
|
!Checkattr(n, "c:globalfun", "1")) {
|
|
first_param = nextSibling(first_param);
|
|
|
|
// A special case of overloading on const/non-const "this" pointer only, we still need to distinguish between those.
|
|
if (SwigType_isconst(Getattr(n, "decl"))) {
|
|
const char * const nonconst = Char(Getattr(n, "decl")) + 9 /* strlen("q(const).") */;
|
|
for (Node* nover = Getattr(n, "sym:overloaded"); nover; nover = Getattr(nover, "sym:nextSibling")) {
|
|
if (nover == n)
|
|
continue;
|
|
|
|
if (Cmp(Getattr(nover, "decl"), nonconst) == 0) {
|
|
// We have an overload differing by const only, disambiguate.
|
|
Append(name, "_const");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
functionWrapperAppendOverloaded(name, first_param);
|
|
}
|
|
}
|
|
}
|
|
|
|
// resolve correct type
|
|
if((tdtype = SwigType_typedef_resolve_all(type)))
|
|
Setattr(n, "type", tdtype);
|
|
|
|
// make sure lnames are set
|
|
functionWrapperPrepareArgs(parms);
|
|
|
|
// C++ function wrapper
|
|
functionWrapperCPPSpecificWrapper(n, name);
|
|
emit_wrapper_func_decl(n, name);
|
|
|
|
Delete(name);
|
|
}
|
|
|
|
/* ----------------------------------------------------------------------
|
|
* functionWrapper()
|
|
* ---------------------------------------------------------------------- */
|
|
|
|
virtual int functionWrapper(Node *n) {
|
|
|
|
if (CPlusPlus) {
|
|
functionWrapperCPPSpecific(n);
|
|
}
|
|
else {
|
|
functionWrapperCSpecific(n);
|
|
}
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* copy_node()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
Node *copy_node(Node *node) {
|
|
Node *new_node = NewHash();
|
|
Setattr(new_node, "name", Copy(Getattr(node, "name")));
|
|
Setattr(new_node, "ismember", Copy(Getattr(node, "ismember")));
|
|
Setattr(new_node, "view", Copy(Getattr(node, "view")));
|
|
Setattr(new_node, "kind", Copy(Getattr(node, "kind")));
|
|
Setattr(new_node, "access", Copy(Getattr(node, "access")));
|
|
Setattr(new_node, "parms", Copy(Getattr(node, "parms")));
|
|
Setattr(new_node, "type", Copy(Getattr(node, "type")));
|
|
Setattr(new_node, "decl", Copy(Getattr(node, "decl")));
|
|
String *cif = Getattr(node, "c:inherited_from");
|
|
if (cif)
|
|
Setattr(new_node, "c:inherited_from", Copy(cif));
|
|
return new_node;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* is_in()
|
|
*
|
|
* tests if given name already exists in one of child nodes of n
|
|
* --------------------------------------------------------------------- */
|
|
|
|
Hash *is_in(String *name, Node *n) {
|
|
Hash *h;
|
|
for (h = firstChild(n); h; h = nextSibling(h)) {
|
|
if (Cmp(name, Getattr(h, "name")) == 0)
|
|
return h;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* make_c_var_decl()
|
|
*
|
|
* Return the C declaration for the given node of "variable" kind.
|
|
*
|
|
* If the variable has a type not representable in C, returns NULL, the caller must check for this!
|
|
*
|
|
* This function accounts for two special cases:
|
|
* 1. If the type is an anonymous enum, "int" is used instead.
|
|
* 2. If the type is an array, its bounds are stripped.
|
|
* --------------------------------------------------------------------- */
|
|
String *make_c_var_decl(Node *n) {
|
|
String *name = Getattr(n, "name");
|
|
SwigType *type = Getattr(n, "type");
|
|
String *type_str = SwigType_str(type, 0);
|
|
|
|
if (Getattr(n, "unnamedinstance")) {
|
|
// If this is an anonymous enum, we can declare the variable as int even though we can't reference this type.
|
|
if (Strncmp(type_str, "enum $", 6) != 0) {
|
|
// Otherwise we're out of luck, with the current approach of exposing the variables directly we simply can't do it, we would need to use accessor
|
|
// functions instead to support this.
|
|
Swig_error(Getfile(n), Getline(n), "Variables of anonymous non-enum types are not supported.\n");
|
|
return SWIG_ERROR;
|
|
}
|
|
|
|
const char * const unnamed_end = strchr(Char(type_str) + 6, '$');
|
|
if (!unnamed_end) {
|
|
Swig_error(Getfile(n), Getline(n), "Unsupported anonymous enum type \"%s\".\n", type_str);
|
|
return SWIG_ERROR;
|
|
}
|
|
|
|
String* const int_type_str = NewStringf("int%s", unnamed_end + 1);
|
|
Delete(type_str);
|
|
type_str = int_type_str;
|
|
} else {
|
|
scoped_dohptr btype(SwigType_base(type));
|
|
if (SwigType_isenum(btype)) {
|
|
// Enums are special as they can be unknown, i.e. not wrapped by SWIG. In this case we just use int instead.
|
|
if (!enumLookup(btype)) {
|
|
Replaceall(type_str, btype, "int");
|
|
}
|
|
} else {
|
|
// Don't bother with checking if type is representable in C if we're wrapping C and not C++ anyhow: of course it is.
|
|
if (CPlusPlus) {
|
|
if (SwigType_isreference(type))
|
|
return NIL;
|
|
|
|
if (!SwigType_isbuiltin(btype))
|
|
return NIL;
|
|
}
|
|
}
|
|
}
|
|
|
|
String* const var_decl = NewStringEmpty();
|
|
if (SwigType_isarray(type)) {
|
|
String *dims = Strchr(type_str, '[');
|
|
char *c = Char(type_str);
|
|
c[Len(type_str) - Len(dims) - 1] = '\0';
|
|
Printv(var_decl, c, " ", name, "[]", NIL);
|
|
} else {
|
|
Printv(var_decl, type_str, " ", name, NIL);
|
|
}
|
|
|
|
Delete(type_str);
|
|
|
|
return var_decl;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* emit_c_struct_def()
|
|
*
|
|
* Append the declarations of C struct members to the given string.
|
|
* Notice that this function has a side effect of outputting all enum declarations inside the struct into f_wrappers_types directly.
|
|
* This is done to avoid gcc warnings "declaration does not declare anything" given for the anonymous enums inside the structs.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
void emit_c_struct_def(String* out, Node *n) {
|
|
for ( Node* node = firstChild(n); node; node = nextSibling(node)) {
|
|
String* const ntype = nodeType(node);
|
|
if (Cmp(ntype, "cdecl") == 0) {
|
|
String* const var_decl = make_c_var_decl(node);
|
|
Printv(out, cindent, var_decl, ";\n", NIL);
|
|
Delete(var_decl);
|
|
} else if (Cmp(ntype, "enum") == 0) {
|
|
// This goes directly into f_wrappers_types, before this struct declaration.
|
|
emit_one(node);
|
|
} else {
|
|
// WARNING: proxy declaration can be different than original code
|
|
if (Cmp(nodeType(node), "extend") == 0)
|
|
emit_c_struct_def(out, node);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* classHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int classHandler(Node *n) {
|
|
String *name = getNamespacedName(n);
|
|
|
|
if (CPlusPlus) {
|
|
// inheritance support: attach all members from base classes to this class
|
|
if (List *baselist = Getattr(n, "bases")) {
|
|
// We may need to specialize SWIG_derives_from<> for this class: its unique check() method will return true iff it's given the name of any subclasses of
|
|
// this class. Notice that it may happen that all our base classes are ignored, in which case we don't do anything.
|
|
int specialize_derives_from = -1;
|
|
|
|
Iterator i;
|
|
for (i = First(baselist); i.item; i = Next(i)) {
|
|
// look for member variables and functions
|
|
Node *node;
|
|
for (node = firstChild(i.item); node; node = nextSibling(node)) {
|
|
if ((Cmp(Getattr(node, "kind"), "variable") == 0)
|
|
|| (Cmp(Getattr(node, "kind"), "function") == 0)) {
|
|
if ((Cmp(Getattr(node, "access"), "public") == 0)
|
|
&& (Cmp(Getattr(node, "storage"), "static") != 0)) {
|
|
Node *new_node = copy_node(node);
|
|
String *parent_name = Getattr(parentNode(node), "name");
|
|
Hash *dupl_name_node = is_in(Getattr(node, "name"), n);
|
|
// if there's a duplicate inherited name, due to the C++ multiple
|
|
// inheritance, change both names to avoid ambiguity
|
|
if (dupl_name_node) {
|
|
String *cif = Getattr(dupl_name_node, "c:inherited_from");
|
|
String *old_name = Getattr(dupl_name_node, "name");
|
|
if (cif && parent_name && (Cmp(cif, parent_name) != 0)) {
|
|
Setattr(dupl_name_node, "name", NewStringf("%s%s", cif ? cif : "", old_name));
|
|
Setattr(dupl_name_node, "c:base_name", old_name);
|
|
Setattr(new_node, "name", NewStringf("%s%s", parent_name, old_name));
|
|
Setattr(new_node, "c:base_name", old_name);
|
|
Setattr(new_node, "c:inherited_from", parent_name);
|
|
Setattr(new_node, "sym:name", Getattr(new_node, "name"));
|
|
Setattr(new_node, "sym:symtab", Getattr(n, "symtab"));
|
|
set_nodeType(new_node, "cdecl");
|
|
appendChild(n, new_node);
|
|
}
|
|
}
|
|
else {
|
|
Setattr(new_node, "c:inherited_from", parent_name);
|
|
Setattr(new_node, "sym:name", Getattr(new_node, "name"));
|
|
Setattr(new_node, "sym:symtab", Getattr(n, "symtab"));
|
|
set_nodeType(new_node, "cdecl");
|
|
appendChild(n, new_node);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Account for this base class in the RTTI checks.
|
|
String* const name = Getattr(i.item, "sym:name");
|
|
if (name) {
|
|
if (specialize_derives_from == -1) {
|
|
// Check if we hadn't specialized it already. Somewhat surprisingly, this can happen for an instantiation of a template with default parameter(s)
|
|
// if it appears both without them and with the default values explicitly given as it happens in e.g. template_default2 unit test.
|
|
SwigType* const fulltype = Swig_symbol_template_deftype(Getattr(n, "name"), NULL);
|
|
String* const fulltype_str = SwigType_str(fulltype, NULL);
|
|
Delete(fulltype);
|
|
|
|
if (!already_specialized_derives_from || !Getattr(already_specialized_derives_from, fulltype_str)) {
|
|
if (!already_specialized_derives_from) {
|
|
already_specialized_derives_from = NewHash();
|
|
}
|
|
|
|
Setattr(already_specialized_derives_from, fulltype_str, "1");
|
|
|
|
Printv(f_wrappers_cxx,
|
|
"template<> struct SWIG_derives_from< ", fulltype_str, " > {\n",
|
|
cindent, "static bool check(const char* type) {\n",
|
|
cindent, cindent, "return ",
|
|
NIL);
|
|
|
|
specialize_derives_from = true;
|
|
} else {
|
|
specialize_derives_from = false;
|
|
}
|
|
|
|
Delete(fulltype_str);
|
|
}
|
|
else if (specialize_derives_from) {
|
|
// Continue the already started specialization.
|
|
Printv(f_wrappers_cxx, " ||\n", cindent, cindent, NIL);
|
|
}
|
|
|
|
if (specialize_derives_from) {
|
|
Printv(f_wrappers_cxx, "strcmp(type, \"", name, "\") == 0", NIL);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (specialize_derives_from == true) {
|
|
// End SWIG_derives_from specialization.
|
|
Printv(f_wrappers_cxx, ";\n }\n};\n\n", NIL);
|
|
}
|
|
}
|
|
|
|
// declare type for specific class in the proxy header
|
|
Printv(f_wrappers_types, "typedef struct SwigObj_", name, " ", name, ";\n\n", NIL);
|
|
|
|
Delete(name);
|
|
return Language::classHandler(n);
|
|
} else {
|
|
// this is C struct, just declare it in the proxy
|
|
String* struct_def = NewStringEmpty();
|
|
String* const tdname = Getattr(n, "tdname");
|
|
if (tdname)
|
|
Append(struct_def, "typedef struct {\n");
|
|
else
|
|
Printv(struct_def, "struct ", name, " {\n", NIL);
|
|
emit_c_struct_def(struct_def, n);
|
|
if (tdname)
|
|
Printv(struct_def, "} ", tdname, ";\n\n", NIL);
|
|
else
|
|
Append(struct_def, "};\n\n");
|
|
|
|
Printv(f_wrappers_types, struct_def, NIL);
|
|
Delete(struct_def);
|
|
|
|
Delete(name);
|
|
}
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* staticmemberfunctionHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int staticmemberfunctionHandler(Node *n) {
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *tdtype;
|
|
tdtype = SwigType_typedef_resolve_all(type);
|
|
if (tdtype)
|
|
type = tdtype;
|
|
if (type) {
|
|
if (!SwigType_ispointer(type) && !SwigType_isreference(type))
|
|
Setattr(n, "c:retval", "1");
|
|
}
|
|
return Language::staticmemberfunctionHandler(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* memberfunctionHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int memberfunctionHandler(Node *n) {
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *tdtype;
|
|
tdtype = SwigType_typedef_resolve_all(type);
|
|
if (tdtype)
|
|
type = tdtype;
|
|
if (type) {
|
|
if (!SwigType_ispointer(type) && !SwigType_isreference(type))
|
|
Setattr(n, "c:retval", "1");
|
|
}
|
|
return Language::memberfunctionHandler(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* staticmembervariableHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int staticmembervariableHandler(Node *n) {
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *tdtype = SwigType_typedef_resolve_all(type);
|
|
if (tdtype) {
|
|
type = tdtype;
|
|
Setattr(n, "type", type);
|
|
}
|
|
SwigType *btype = SwigType_base(type);
|
|
if (SwigType_isarray(type) && !SwigType_isbuiltin(btype)) {
|
|
// this hack applies to member objects array (not ptrs.)
|
|
SwigType_add_pointer(btype);
|
|
SwigType_add_array(btype, NewStringf("%s", SwigType_array_getdim(type, 0)));
|
|
Setattr(n, "type", btype);
|
|
}
|
|
if (type) {
|
|
if (!SwigType_ispointer(type) && !SwigType_isreference(type))
|
|
Setattr(n, "c:retval", "1");
|
|
}
|
|
Delete(type);
|
|
Delete(btype);
|
|
return Language::staticmembervariableHandler(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* membervariableHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int membervariableHandler(Node *n) {
|
|
SwigType *type = Getattr(n, "type");
|
|
SwigType *tdtype = SwigType_typedef_resolve_all(type);
|
|
if (tdtype) {
|
|
type = tdtype;
|
|
Setattr(n, "type", type);
|
|
}
|
|
SwigType *btype = SwigType_base(type);
|
|
if (SwigType_isarray(type) && !SwigType_isbuiltin(btype)) {
|
|
// this hack applies to member objects array (not ptrs.)
|
|
SwigType_add_pointer(btype);
|
|
SwigType_add_array(btype, NewStringf("%s", SwigType_array_getdim(type, 0)));
|
|
Setattr(n, "type", btype);
|
|
}
|
|
if (type) {
|
|
if (!SwigType_ispointer(type) && !SwigType_isreference(type))
|
|
Setattr(n, "c:retval", "1");
|
|
}
|
|
Delete(type);
|
|
Delete(btype);
|
|
return Language::membervariableHandler(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* constructorHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int constructorHandler(Node *n) {
|
|
Node *klass = Swig_methodclass(n);
|
|
String *classname = Getattr(klass, "classtype");
|
|
String *newclassname = Getattr(klass, "sym:name");
|
|
|
|
bool const is_copy_ctor = Getattr(n, "copy_constructor");
|
|
String *arg_lnames;
|
|
if (is_copy_ctor) {
|
|
arg_lnames = NewStringf("((%s const &)*arg1)", classname);
|
|
} else {
|
|
ParmList *parms = Getattr(n, "parms");
|
|
arg_lnames = Swig_cfunction_call(empty_string, parms);
|
|
}
|
|
|
|
// TODO-C: We need to call the extension ctor here instead of hard-coding "new classname".
|
|
special_wrap_action = NewStringf(
|
|
"result = SWIG_create_object(new %s%s, \"%s\");",
|
|
classname,
|
|
arg_lnames,
|
|
newclassname
|
|
);
|
|
|
|
Delete(arg_lnames);
|
|
|
|
return is_copy_ctor ? Language::copyconstructorHandler(n) : Language::constructorHandler(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* destructorHandler()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int destructorHandler(Node *n) {
|
|
Node *klass = Swig_methodclass(n);
|
|
|
|
// TODO-C: We need to use the extension dtor here if one is defined.
|
|
special_wrap_action = NewStringf(
|
|
"SWIG_destroy_object< %s >(carg1);", Getattr(klass, "classtype")
|
|
);
|
|
|
|
return Language::destructorHandler(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* enumDeclaration()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int enumDeclaration(Node *n) {
|
|
if (ImportMode)
|
|
return SWIG_OK;
|
|
|
|
if (getCurrentClass() && (cplus_mode != PUBLIC))
|
|
return SWIG_NOWRAP;
|
|
|
|
// Preserve the typedef if we have it in the input.
|
|
String* const tdname = Getattr(n, "tdname");
|
|
if (tdname) {
|
|
Printv(f_wrappers_types, "typedef ", NIL);
|
|
}
|
|
Printv(f_wrappers_types, "enum", NIL);
|
|
|
|
if (String* const name = Getattr(n, "name")) {
|
|
String* const enumname = Swig_name_mangle(name);
|
|
Printv(f_wrappers_types, " ", enumname, NIL);
|
|
Delete(enumname);
|
|
}
|
|
|
|
// We don't know here if we're going to have any non-ignored enum elements, so let enumvalueDeclaration() itself reset this flag if it does get called, this
|
|
// is simpler than trying to determine it here, even if it's a bit ugly because we generate the opening brace there, but the closing one here.
|
|
enum_is_empty = true;
|
|
|
|
// Emit each enum item.
|
|
Language::enumDeclaration(n);
|
|
|
|
if (!enum_is_empty) {
|
|
Printv(f_wrappers_types, "\n}", NIL);
|
|
}
|
|
|
|
if (tdname) {
|
|
String* const enumname = Swig_name_mangle(tdname);
|
|
Printv(f_wrappers_types, " ", enumname, NIL);
|
|
Delete(enumname);
|
|
}
|
|
Printv(f_wrappers_types, ";\n\n", NIL);
|
|
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* enumvalueDeclaration()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int enumvalueDeclaration(Node *n) {
|
|
if (Cmp(Getattr(n, "ismember"), "1") == 0 && Cmp(Getattr(n, "access"), "public") != 0)
|
|
return SWIG_NOWRAP;
|
|
Swig_require("enumvalueDeclaration", n, "*value", "?enumvalueex", "?enumvalue", NIL);
|
|
|
|
enum_is_empty = false;
|
|
|
|
if (GetFlag(n, "firstenumitem"))
|
|
Printv(f_wrappers_types, " {\n", NIL);
|
|
else
|
|
Printv(f_wrappers_types, ",\n", NIL);
|
|
|
|
String* const enumitemname = Getattr(n, "value");
|
|
Printv(f_wrappers_types, cindent, Swig_name_mangle(enumitemname), NIL);
|
|
|
|
// We only use "enumvalue", which comes from the input, and not "enumvalueex" synthesized by SWIG itself because C should use the correct value for the enum
|
|
// items without an explicit one anyhow (and "enumvalueex" can't be always used as is in C code for enum elements inside a class or even a namespace).
|
|
String *value = Getattr(n, "enumvalue");
|
|
if (value) {
|
|
String* const cvalue = Copy(value);
|
|
|
|
// Due to what seems to be a bug in SWIG parser, char values for enum elements lose their quotes, i.e.
|
|
//
|
|
// enum { x = 'a', y = '\x62' };
|
|
//
|
|
// in input results in value being just "a" or "\x62". Try to repair this brokenness.
|
|
if (*Char(value) == '\\') {
|
|
Push(cvalue, "'");
|
|
Append(cvalue, "'");
|
|
} else if (Len(value) == 1 && !Swig_symbol_clookup(enumitemname, NULL)) {
|
|
Push(cvalue, "'");
|
|
Append(cvalue, "'");
|
|
}
|
|
|
|
// Boolean constants can't appear in C code neither, so replace them with their values in the simplest possible case. This is not exhaustive, of course,
|
|
// but better than nothing and doing the right thing is not simple at all as we'd need to really parse the expression, just textual substitution wouldn't
|
|
// be enough (consider e.g. an enum element called "very_true" and another one using it as its value).
|
|
if (Cmp(value, "true") == 0) {
|
|
Clear(cvalue);
|
|
Append(cvalue, "1");
|
|
} else if (Cmp(value, "false") == 0) {
|
|
Clear(cvalue);
|
|
Append(cvalue, "0");
|
|
}
|
|
|
|
Printv(f_wrappers_types, " = ", cvalue, NIL);
|
|
|
|
Delete(cvalue);
|
|
}
|
|
|
|
Swig_restore(n);
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* constantWrapper()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int constantWrapper(Node *n) {
|
|
String *name = Getattr(n, "sym:name");
|
|
String *value = Getattr(n, "value");
|
|
Printv(f_wrappers_decl, "#define ", name, " ", value, "\n", NIL);
|
|
return SWIG_OK;
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* classDeclaration()
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int classDeclaration(Node *n) {
|
|
String *name = NewString("");
|
|
String *classtype = Getattr(n, "classtype");
|
|
String *prefix = 0;
|
|
if (classtype) {
|
|
prefix = Swig_scopename_prefix(classtype);
|
|
if (prefix)
|
|
Printf(name, "%s_", Swig_name_mangle(prefix));
|
|
}
|
|
Append(name, Swig_name_mangle(Getattr(n, "sym:name")));
|
|
Setattr(n, "sym:name", name);
|
|
return Language::classDeclaration(n);
|
|
}
|
|
|
|
/* ---------------------------------------------------------------------
|
|
* extendDirective()
|
|
*
|
|
* The idea is to extend the class with additional variables, using
|
|
* SwigObj structs. This is not implemented yet.
|
|
* --------------------------------------------------------------------- */
|
|
|
|
virtual int extendDirective(Node *n) {
|
|
return Language::extendDirective(n);
|
|
}
|
|
|
|
}; /* class C */
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* swig_c() - Instantiate module
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
static Language *new_swig_c() {
|
|
return new C();
|
|
}
|
|
|
|
extern "C" Language *swig_c(void) {
|
|
return new_swig_c();
|
|
}
|
|
|
|
/* -----------------------------------------------------------------------------
|
|
* Static member variables
|
|
* ----------------------------------------------------------------------------- */
|
|
|
|
const char *C::usage = (char *) "\
|
|
C Options (available with -c)\n\
|
|
-noexcept - do not generate exception handling code\n\
|
|
\n";
|
|
|