diff options
author | vitalyisaev <vitalyisaev@ydb.tech> | 2023-11-30 13:26:22 +0300 |
---|---|---|
committer | vitalyisaev <vitalyisaev@ydb.tech> | 2023-11-30 15:44:45 +0300 |
commit | 0a98fece5a9b54f16afeb3a94b3eb3105e9c3962 (patch) | |
tree | 291d72dbd7e9865399f668c84d11ed86fb190bbf /contrib/tools/swig/Source/Swig | |
parent | cb2c8d75065e5b3c47094067cb4aa407d4813298 (diff) | |
download | ydb-0a98fece5a9b54f16afeb3a94b3eb3105e9c3962.tar.gz |
YQ Connector:Use docker-compose in integrational tests
Diffstat (limited to 'contrib/tools/swig/Source/Swig')
25 files changed, 19570 insertions, 0 deletions
diff --git a/contrib/tools/swig/Source/Swig/cwrap.c b/contrib/tools/swig/Source/Swig/cwrap.c new file mode 100644 index 0000000000..b7d01bc117 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/cwrap.c @@ -0,0 +1,1661 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * cwrap.c + * + * This file defines a variety of wrapping rules for C/C++ handling including + * the naming of local variables, calling conventions, and so forth. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" + +extern int UseWrapperSuffix; + +static const char *cresult_variable_name = "result"; + +static Parm *nonvoid_parms(Parm *p) { + if (p) { + SwigType *t = Getattr(p, "type"); + if (SwigType_type(t) == T_VOID) + return 0; + } + return p; +} + +/* ----------------------------------------------------------------------------- + * Swig_cresult_name_set() + * + * Change the name of the variable used to hold the return value from C/C++ wrapper functions + * from the default "result". + * ----------------------------------------------------------------------------- */ + +void Swig_cresult_name_set(const char *new_name) { + cresult_variable_name = new_name; +} + +/* ----------------------------------------------------------------------------- + * Swig_cresult_name() + * + * Get the name of the variable used to hold the return value from C/C++ wrapper functions + * ----------------------------------------------------------------------------- */ + +const char *Swig_cresult_name(void) { + return cresult_variable_name; +} + +/* ----------------------------------------------------------------------------- + * Swig_cparm_name() + * + * Generates a name for the ith argument in an argument list + * ----------------------------------------------------------------------------- */ + +String *Swig_cparm_name(Parm *p, int i) { + String *name = NewStringf("arg%d", i + 1); + if (p) { + Setattr(p, "lname", name); + } + + return name; +} + +/* ----------------------------------------------------------------------------- + * Swig_clocal() + * + * Creates a string that declares a C local variable type. Converts references + * and user defined types to pointers. + * ----------------------------------------------------------------------------- */ + +static String *Swig_clocal(SwigType *t, const_String_or_char_ptr name, const_String_or_char_ptr value) { + String *decl; + + decl = NewStringEmpty(); + + switch (SwigType_type(t)) { + case T_REFERENCE: + if (value) { + String *lstrname = SwigType_lstr(t, name); + String *lstr = SwigType_lstr(t, 0); + Printf(decl, "%s = (%s) &%s_defvalue", lstrname, lstr, name); + Delete(lstrname); + Delete(lstr); + } else { + String *lstrname = SwigType_lstr(t, name); + Printf(decl, "%s = 0", lstrname); + Delete(lstrname); + } + break; + case T_RVALUE_REFERENCE: + if (value) { + String *lstrname = SwigType_lstr(t, name); + String *lstr = SwigType_lstr(t, 0); + Printf(decl, "%s = (%s) &%s_defrvalue", lstrname, lstr, name); + Delete(lstrname); + Delete(lstr); + } else { + String *lstrname = SwigType_lstr(t, name); + Printf(decl, "%s = 0", lstrname); + Delete(lstrname); + } + break; + case T_VOID: + break; + case T_VARARGS: + Printf(decl, "void *%s = 0", name); + break; + + default: + if (value) { + String *lcaststr = SwigType_lcaststr(t, value); + String *lstr = SwigType_lstr(t, 0); + String *lstrn = SwigType_lstr(t, name); + Printf(decl, "%s = (%s) %s", lstrn, lstr, lcaststr); + Delete(lcaststr); + Delete(lstr); + Delete(lstrn); + } else { + String *lstrname = SwigType_lstr(t, name); + Append(decl, lstrname); + Delete(lstrname); + } + } + return decl; +} + +/* ----------------------------------------------------------------------------- + * Swig_wrapped_var_convert() + * + * Converts a member variable for use in the get and set wrapper methods. + * This function only converts user defined types to pointers. + * ----------------------------------------------------------------------------- */ + +String *Swig_wrapped_var_type(SwigType *t, int varcref) { + SwigType *ty; + + if (!Strstr(t, "enum $unnamed")) { + ty = Copy(t); + } else { + /* Change the type for unnamed enum instance variables */ + ty = NewString("int"); + } + + if (SwigType_isclass(t)) { + if (varcref) { + if (cparse_cplusplus) { + if (!SwigType_isconst(ty)) + SwigType_add_qualifier(ty, "const"); + SwigType_add_reference(ty); + } else { + return Copy(ty); + } + } else { + SwigType_add_pointer(ty); + } + } + return ty; +} + +String *Swig_wrapped_member_var_type(SwigType *t, int varcref) { + SwigType *ty; + + if (!Strstr(t, "enum $unnamed")) { + ty = Copy(t); + } else { + /* Change the type for unnamed enum instance variables */ + ty = NewString("int"); + } + if (SwigType_isclass(t)) { + if (varcref) { + if (cparse_cplusplus) { + if (!SwigType_isconst(ty)) + SwigType_add_qualifier(ty, "const"); + SwigType_add_reference(ty); + } else { + return Copy(ty); + } + } else { + SwigType_add_pointer(ty); + } + } + return ty; +} + + +static String *Swig_wrapped_var_deref(SwigType *t, const_String_or_char_ptr name, int varcref) { + if (SwigType_isclass(t)) { + if (varcref) { + if (cparse_cplusplus) { + return NewStringf("*%s", name); + } else { + return NewStringf("%s", name); + } + } else { + return NewStringf("*%s", name); + } + } else { + return SwigType_rcaststr(t, name); + } +} + +static String *Swig_wrapped_var_assign(SwigType *t, const_String_or_char_ptr name, int varcref) { + if (SwigType_isclass(t)) { + if (varcref) { + return NewStringf("%s", name); + } else { + return NewStringf("&%s", name); + } + } else { + return SwigType_lcaststr(t, name); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_cargs() + * + * Emit all of the local variables for a list of parameters. Returns the + * number of parameters. + * Default values for the local variables are only emitted if the compact default + * argument behaviour is required. + * ----------------------------------------------------------------------------- */ +int Swig_cargs(Wrapper *w, ParmList *p) { + int i = 0; + int compactdefargs = ParmList_is_compactdefargs(p); + + while (p != 0) { + String *lname = Swig_cparm_name(p, i); + SwigType *pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *local = 0; + String *type = Getattr(p, "type"); + /* default values only emitted if in compact default args mode */ + String *pvalue = (compactdefargs) ? Getattr(p, "value") : 0; + + /* When using compactdefaultargs, the code generated initialises a variable via a constructor call that accepts the + * default value as a parameter. The default constructor is not called and therefore SwigValueWrapper is not needed. */ + SwigType *altty = pvalue ? 0 : SwigType_alttype(type, 0); + + int tycode = SwigType_type(type); + if (tycode == T_REFERENCE) { + if (pvalue) { + SwigType *tvalue; + String *defname, *defvalue, *rvalue, *qvalue; + rvalue = SwigType_typedef_resolve_all(pvalue); + qvalue = SwigType_typedef_qualified(rvalue); + defname = NewStringf("%s_defvalue", lname); + tvalue = Copy(type); + SwigType_del_reference(tvalue); + tycode = SwigType_type(tvalue); + if (tycode != T_USER) { + /* plain primitive type, we copy the def value */ + String *lstr = SwigType_lstr(tvalue, defname); + defvalue = NewStringf("%s = %s", lstr, qvalue); + Delete(lstr); + } else { + /* user type, we copy the reference value */ + String *str = SwigType_str(type, defname); + defvalue = NewStringf("%s = %s", str, qvalue); + Delete(str); + } + Wrapper_add_localv(w, defname, defvalue, NIL); + Delete(tvalue); + Delete(rvalue); + Delete(qvalue); + Delete(defname); + Delete(defvalue); + } + } else if (tycode == T_RVALUE_REFERENCE) { + if (pvalue) { + SwigType *tvalue; + String *defname, *defvalue, *rvalue, *qvalue; + rvalue = SwigType_typedef_resolve_all(pvalue); + qvalue = SwigType_typedef_qualified(rvalue); + defname = NewStringf("%s_defrvalue", lname); + tvalue = Copy(type); + SwigType_del_rvalue_reference(tvalue); + tycode = SwigType_type(tvalue); + if (tycode != T_USER) { + /* plain primitive type, we copy the def value */ + String *lstr = SwigType_lstr(tvalue, defname); + defvalue = NewStringf("%s = %s", lstr, qvalue); + Delete(lstr); + } else { + /* user type, we copy the reference value */ + String *str = SwigType_str(type, defname); + defvalue = NewStringf("%s = %s", str, qvalue); + Delete(str); + } + Wrapper_add_localv(w, defname, defvalue, NIL); + Delete(tvalue); + Delete(rvalue); + Delete(qvalue); + Delete(defname); + Delete(defvalue); + } + } else if (!pvalue && ((tycode == T_POINTER) || (tycode == T_STRING) || (tycode == T_WSTRING))) { + pvalue = (String *) "0"; + } + if (!altty) { + local = Swig_clocal(pt, lname, pvalue); + } else { + local = Swig_clocal(altty, lname, pvalue); + Delete(altty); + } + Wrapper_add_localv(w, lname, local, NIL); + Delete(local); + i++; + } + Delete(lname); + p = nextSibling(p); + } + return (i); +} + +/* ----------------------------------------------------------------------------- + * Swig_cresult() + * + * This function generates the C code needed to set the result of a C + * function call. + * ----------------------------------------------------------------------------- */ + +String *Swig_cresult(SwigType *t, const_String_or_char_ptr name, const_String_or_char_ptr decl) { + String *fcall; + + fcall = NewStringEmpty(); + switch (SwigType_type(t)) { + case T_VOID: + break; + case T_REFERENCE: + { + String *lstr = SwigType_lstr(t, 0); + Printf(fcall, "%s = (%s) &", name, lstr); + Delete(lstr); + } + break; + case T_RVALUE_REFERENCE: + { + String *const_lvalue_str; + String *lstr = SwigType_lstr(t, 0); + SwigType *tt = Copy(t); + SwigType_del_rvalue_reference(tt); + SwigType_add_qualifier(tt, "const"); + SwigType_add_reference(tt); + const_lvalue_str = SwigType_rcaststr(tt, 0); + + Printf(fcall, "%s = (%s) &%s", name, lstr, const_lvalue_str); + + Delete(const_lvalue_str); + Delete(tt); + Delete(lstr); + } + break; + case T_USER: + Printf(fcall, "%s = ", name); + break; + + default: + /* Normal return value */ + { + String *lstr = SwigType_lstr(t, 0); + Printf(fcall, "%s = (%s)", name, lstr); + Delete(lstr); + } + break; + } + + /* Now print out function call */ + Append(fcall, decl); + + /* A sick hack */ + { + char *c = Char(decl) + Len(decl) - 1; + if (!((*c == ';') || (*c == '}'))) + Append(fcall, ";"); + } + + return fcall; +} + +/* ----------------------------------------------------------------------------- + * Swig_cfunction_call() + * + * Creates a string that calls a C function using the local variable rules + * defined above. + * + * name(arg0, arg1, arg2, ... argn) + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cfunction_call(const_String_or_char_ptr name, ParmList *parms) { + String *func; + int i = 0; + int comma = 0; + Parm *p = parms; + String *nname; + + func = NewStringEmpty(); + nname = SwigType_namestr(name); + + /* + SWIGTEMPLATEDISAMBIGUATOR is compiler dependent (swiglabels.swg), + - SUN Studio 9 requires 'template', + - gcc-3.4 forbids the use of 'template'. + the rest seems not caring very much, + */ + if (SwigType_istemplate(name)) { + String *prefix = Swig_scopename_prefix(nname); + if (!prefix || Len(prefix) == 0) { + Printf(func, "%s(", nname); + } else { + String *last = Swig_scopename_last(nname); + Printf(func, "%s::SWIGTEMPLATEDISAMBIGUATOR %s(", prefix, last); + Delete(last); + } + Delete(prefix); + } else { + Printf(func, "%s(", nname); + } + Delete(nname); + + while (p) { + SwigType *pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + SwigType *rpt = SwigType_typedef_resolve_all(pt); + String *pname = Swig_cparm_name(p, i); + String *rcaststr = SwigType_rcaststr(rpt, pname); + + if (comma) { + Append(func, ","); + } + + if (cparse_cplusplus && SwigType_type(rpt) == T_USER) + Printv(func, "SWIG_STD_MOVE(", rcaststr, ")", NIL); + else + Printv(func, rcaststr, NIL); + + Delete(rpt); + Delete(pname); + Delete(rcaststr); + comma = 1; + i++; + } + p = nextSibling(p); + } + Append(func, ")"); + return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_cmethod_call() + * + * Generates a string that calls a C++ method from a list of parameters. + * + * arg0->name(arg1, arg2, arg3, ..., argn) + * + * self is an argument that defines how to handle the first argument. Normally, + * it should be set to "this->". With C++ proxy classes enabled, it could be + * set to "(*this)->" or some similar sequence. + * ----------------------------------------------------------------------------- */ + +static String *Swig_cmethod_call(const_String_or_char_ptr name, ParmList *parms, const_String_or_char_ptr self, String *explicit_qualifier, SwigType *director_type) { + String *func, *nname; + int i = 0; + Parm *p = parms; + SwigType *pt; + int comma = 0; + + func = NewStringEmpty(); + if (!p) + return func; + + if (!self) + self = "(this)->"; + Append(func, self); + + if (SwigType_istemplate(name) && (strncmp(Char(name), "operator ", 9) == 0)) { + /* fix for template + operators and compilers like gcc 3.3.5 */ + String *tprefix = SwigType_templateprefix(name); + nname = tprefix; + } else { + nname = SwigType_namestr(name); + } + + if (director_type) { + const char *pname = "darg"; + String *rcaststr = SwigType_rcaststr(director_type, pname); + Replaceall(func, "this", rcaststr); + Delete(rcaststr); + } else { + pt = Getattr(p, "type"); + + /* If the method is invoked through a dereferenced pointer, we don't add any casts + (needed for smart pointers). Otherwise, we cast to the appropriate type */ + + if (Strstr(func, "*this")) { + String *pname = Swig_cparm_name(p, 0); + Replaceall(func, "this", pname); + Delete(pname); + } else { + String *pname = Swig_cparm_name(p, 0); + String *rcaststr = SwigType_rcaststr(pt, pname); + Replaceall(func, "this", rcaststr); + Delete(rcaststr); + Delete(pname); + } + + /* + SWIGTEMPLATEDESIMBUAGATOR is compiler dependent (swiglabels.swg), + - SUN Studio 9 requires 'template', + - gcc-3.4 forbids the use of 'template' (correctly implementing the ISO C++ standard) + the others don't seem to care, + */ + if (SwigType_istemplate(name)) + Printf(func, "SWIGTEMPLATEDISAMBIGUATOR "); + + if (explicit_qualifier) { + Printv(func, explicit_qualifier, "::", NIL); + } + } + + Printf(func, "%s(", nname); + + i++; + p = nextSibling(p); + while (p) { + pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *pname = Swig_cparm_name(p, i); + String *rcaststr = SwigType_rcaststr(pt, pname); + if (comma) + Append(func, ","); + Append(func, rcaststr); + Delete(rcaststr); + Delete(pname); + comma = 1; + i++; + } + p = nextSibling(p); + } + Append(func, ")"); + Delete(nname); + return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_cconstructor_call() + * + * Creates a string that calls a C constructor function. + * + * calloc(1,sizeof(name)); + * ----------------------------------------------------------------------------- */ + +String *Swig_cconstructor_call(const_String_or_char_ptr name) { + DOH *func; + + func = NewStringEmpty(); + Printf(func, "calloc(1, sizeof(%s))", name); + return func; +} + + +/* ----------------------------------------------------------------------------- + * Swig_cppconstructor_call() + * + * Creates a string that calls a C function using the local variable rules + * defined above. + * + * name(arg0, arg1, arg2, ... argn) + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cppconstructor_base_call(const_String_or_char_ptr name, ParmList *parms, int skip_self) { + String *func; + String *nname; + int i = 0; + int comma = 0; + Parm *p = parms; + SwigType *pt; + if (skip_self) { + if (p) + p = nextSibling(p); + i++; + } + nname = SwigType_namestr(name); + func = NewStringEmpty(); + Printf(func, "new %s(", nname); + while (p) { + pt = Getattr(p, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *rcaststr = 0; + String *pname = 0; + if (comma) + Append(func, ","); + if (!Getattr(p, "arg:byname")) { + pname = Swig_cparm_name(p, i); + i++; + } else { + pname = Getattr(p, "value"); + if (pname) + pname = Copy(pname); + else + pname = Copy(Getattr(p, "name")); + } + rcaststr = SwigType_rcaststr(pt, pname); + Append(func, rcaststr); + Delete(rcaststr); + comma = 1; + Delete(pname); + } + p = nextSibling(p); + } + Append(func, ")"); + Delete(nname); + return func; +} + +String *Swig_cppconstructor_call(const_String_or_char_ptr name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 0); +} + +String *Swig_cppconstructor_nodirector_call(const_String_or_char_ptr name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 1); +} + +String *Swig_cppconstructor_director_call(const_String_or_char_ptr name, ParmList *parms) { + return Swig_cppconstructor_base_call(name, parms, 0); +} + +/* ----------------------------------------------------------------------------- + * recursive_flag_search() + * + * This function searches for the class attribute 'attr' in the class + * 'n' or recursively in its bases. + * + * If you define SWIG_FAST_REC_SEARCH, the method will set the found + * 'attr' in the target class 'n'. If not, the method will set the + * 'noattr' one. This prevents of having to navigate the entire + * hierarchy tree every time, so, it is an O(1) method... or something + * like that. However, it populates all the parsed classes with the + * 'attr' and/or 'noattr' attributes. + * + * If you undefine the SWIG_FAST_REC_SEARCH no attribute will be set + * while searching. This could be slower for large projects with very + * large hierarchy trees... or maybe not. But it will be cleaner. + * + * Maybe later a swig option can be added to switch at runtime. + * + * ----------------------------------------------------------------------------- */ + +/* #define SWIG_FAST_REC_SEARCH 1 */ +static String *recursive_flag_search(Node *n, const String *attr, const String *noattr) { + String *f = 0; + n = Swig_methodclass(n); + if (GetFlag(n, noattr)) { + return 0; + } + f = GetFlagAttr(n, attr); + if (f) { + return f; + } else { + List *bl = Getattr(n, "bases"); + if (bl) { + Iterator bi; + for (bi = First(bl); bi.item; bi = Next(bi)) { + f = recursive_flag_search(bi.item, attr, noattr); + if (f) { +#ifdef SWIG_FAST_REC_SEARCH + SetFlagAttr(n, attr, f); +#endif + return f; + } + } + } + } +#ifdef SWIG_FAST_REC_SEARCH + SetFlag(n, noattr); +#endif + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_unref_call() + * + * Find the "feature:unref" call, if any. + * ----------------------------------------------------------------------------- */ + +String *Swig_unref_call(Node *n) { + String *unref = recursive_flag_search(n, "feature:unref", "feature:nounref"); + if (unref) { + String *pname = Swig_cparm_name(0, 0); + unref = NewString(unref); + Replaceall(unref, "$this", pname); + Replaceall(unref, "$self", pname); + Delete(pname); + } + return unref; +} + +/* ----------------------------------------------------------------------------- + * Swig_ref_call() + * + * Find the "feature:ref" call, if any. + * ----------------------------------------------------------------------------- */ + +String *Swig_ref_call(Node *n, const String *lname) { + String *ref = recursive_flag_search(n, "feature:ref", "feature:noref"); + if (ref) { + ref = NewString(ref); + Replaceall(ref, "$this", lname); + Replaceall(ref, "$self", lname); + } + return ref; +} + +/* ----------------------------------------------------------------------------- + * Swig_cdestructor_call() + * + * Creates a string that calls a C destructor function. + * + * free((char *) arg0); + * ----------------------------------------------------------------------------- */ + +String *Swig_cdestructor_call(Node *n) { + Node *cn = Swig_methodclass(n); + String *unref = Swig_unref_call(cn); + + if (unref) { + return unref; + } else { + String *pname = Swig_cparm_name(0, 0); + String *call = NewStringf("free((char *) %s);", pname); + Delete(pname); + return call; + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_cppdestructor_call() + * + * Creates a string that calls a C destructor function. + * + * delete arg1; + * ----------------------------------------------------------------------------- */ + +String *Swig_cppdestructor_call(Node *n) { + Node *cn = Swig_methodclass(n); + String *unref = Swig_unref_call(cn); + if (unref) { + return unref; + } else { + String *pname = Swig_cparm_name(0, 0); + String *call = NewStringf("delete %s;", pname); + Delete(pname); + return call; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_cmemberset_call() + * + * Generates a string that sets the name of a member in a C++ class or C struct. + * + * arg0->name = arg1 + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cmemberset_call(const_String_or_char_ptr name, SwigType *type, String *self, int varcref) { + String *func; + String *pname0 = Swig_cparm_name(0, 0); + String *pname1 = Swig_cparm_name(0, 1); + func = NewStringEmpty(); + if (!self) + self = NewString("(this)->"); + else + self = NewString(self); + Replaceall(self, "this", pname0); + if (SwigType_type(type) != T_ARRAY) { + if (!Strstr(type, "enum $unnamed")) { + String *dref = Swig_wrapped_var_deref(type, pname1, varcref); + int extra_cast = 0; + if (cparse_cplusplusout) { + /* Required for C nested structs compiled as C++ as a duplicate of the nested struct is put into the global namespace. + * We could improve this by adding the extra casts just for nested structs rather than all structs. */ + String *base = SwigType_base(type); + extra_cast = SwigType_isclass(base); + Delete(base); + } + if (extra_cast) { + String *lstr; + SwigType *ptype = Copy(type); + SwigType_add_pointer(ptype); + lstr = SwigType_lstr(ptype, 0); + Printf(func, "if (%s) *(%s)&%s%s = %s", pname0, lstr, self, name, dref); + Delete(lstr); + Delete(ptype); + } else { + Printf(func, "if (%s) %s%s = %s", pname0, self, name, dref); + } + Delete(dref); + } else { + Printf(func, "if (%s && sizeof(int) == sizeof(%s%s)) *(int*)(void*)&(%s%s) = %s", pname0, self, name, self, name, pname1); + } + } + Delete(self); + Delete(pname0); + Delete(pname1); + return (func); +} + + +/* ----------------------------------------------------------------------------- + * Swig_cmemberget_call() + * + * Generates a string that sets the name of a member in a C++ class or C struct. + * + * arg0->name + * + * ----------------------------------------------------------------------------- */ + +String *Swig_cmemberget_call(const_String_or_char_ptr name, SwigType *t, String *self, int varcref) { + String *func; + String *call; + String *pname0 = Swig_cparm_name(0, 0); + if (!self) + self = NewString("(this)->"); + else + self = NewString(self); + Replaceall(self, "this", pname0); + func = NewStringEmpty(); + call = Swig_wrapped_var_assign(t, "", varcref); + Printf(func, "%s (%s%s)", call, self, name); + Delete(self); + Delete(call); + Delete(pname0); + return func; +} + +/* ----------------------------------------------------------------------------- + * Swig_replace_special_variables() + * + * Replaces special variables with a value from the supplied node + * ----------------------------------------------------------------------------- */ +void Swig_replace_special_variables(Node *n, Node *parentnode, String *code) { + Node *parentclass = parentnode; + String *overloaded = Getattr(n, "sym:overloaded"); + Replaceall(code, "$name", Getattr(n, "name")); + Replaceall(code, "$symname", Getattr(n, "sym:name")); + Replaceall(code, "$wrapname", Getattr(n, "wrap:name")); + Replaceall(code, "$overname", overloaded ? Char(Getattr(n, "sym:overname")) : ""); + + if (Strstr(code, "$decl")) { + String *decl = Swig_name_decl(n); + Replaceall(code, "$decl", decl); + Delete(decl); + } + if (Strstr(code, "$fulldecl")) { + String *fulldecl = Swig_name_fulldecl(n); + Replaceall(code, "$fulldecl", fulldecl); + Delete(fulldecl); + } + + if (parentclass && !Equal(nodeType(parentclass), "class")) + parentclass = 0; + if (Strstr(code, "$parentclasssymname")) { + String *parentclasssymname = 0; + if (parentclass) + parentclasssymname = Getattr(parentclass, "sym:name"); + Replaceall(code, "$parentclasssymname", parentclasssymname ? parentclasssymname : ""); + } + if (Strstr(code, "$parentclassname")) { + String *parentclassname = 0; + if (parentclass) + parentclassname = Getattr(parentclass, "name"); + Replaceall(code, "$parentclassname", parentclassname ? SwigType_str(parentclassname, "") : ""); + } +} + +/* ----------------------------------------------------------------------------- + * extension_code() + * + * Generates an extension function (a function defined in %extend) + * + * return_type function_name(parms) code + * + * ----------------------------------------------------------------------------- */ +static String *extension_code(Node *n, const String *function_name, ParmList *parms, SwigType *return_type, const String *code, int cplusplus, const String *self) { + String *parms_str = cplusplus ? ParmList_str_defaultargs(parms) : ParmList_str(parms); + String *sig = NewStringf("%s(%s)", function_name, (cplusplus || Len(parms_str)) ? parms_str : "void"); + String *rt_sig = SwigType_str(return_type, sig); + String *body = NewStringf("SWIGINTERN %s", rt_sig); + Printv(body, code, "\n", NIL); + if (Strstr(body, "$")) { + Swig_replace_special_variables(n, parentNode(parentNode(n)), body); + if (self) + Replaceall(body, "$self", self); + } + Delete(parms_str); + Delete(sig); + Delete(rt_sig); + return body; +} + +/* ----------------------------------------------------------------------------- + * Swig_add_extension_code() + * + * Generates an extension function (a function defined in %extend) and + * adds it to the "wrap:code" attribute of a node + * + * See also extension_code() + * + * ----------------------------------------------------------------------------- */ +int Swig_add_extension_code(Node *n, const String *function_name, ParmList *parms, SwigType *return_type, const String *code, int cplusplus, const String *self) { + String *body = extension_code(n, function_name, parms, return_type, code, cplusplus, self); + Setattr(n, "wrap:code", body); + Delete(body); + return SWIG_OK; +} + + +/* ----------------------------------------------------------------------------- + * Swig_MethodToFunction(Node *n) + * + * Converts a C++ method node to a function accessor function. + * ----------------------------------------------------------------------------- */ + +int Swig_MethodToFunction(Node *n, const_String_or_char_ptr nspace, String *classname, int flags, SwigType *director_type, int is_director) { + String *name; + ParmList *parms; + SwigType *type; + Parm *p; + String *self = 0; + int is_smart_pointer_overload = 0; + String *qualifier = Getattr(n, "qualifier"); + String *directorScope = NewString(nspace); + + Replace(directorScope, NSPACE_SEPARATOR, "_", DOH_REPLACE_ANY); + + /* If smart pointer without const overload or mutable method, change self dereferencing */ + if (flags & CWRAP_SMART_POINTER) { + if (flags & CWRAP_SMART_POINTER_OVERLOAD) { + if (qualifier && strncmp(Char(qualifier), "q(const)", 8) == 0) { + self = NewString("(*(this))->"); + is_smart_pointer_overload = 1; + } + else if (Swig_storage_isstatic(n)) { + String *cname = Getattr(n, "extendsmartclassname") ? Getattr(n, "extendsmartclassname") : classname; + String *ctname = SwigType_namestr(cname); + self = NewStringf("(*(%s const *)this)->", ctname); + is_smart_pointer_overload = 1; + Delete(ctname); + } + else { + self = NewString("(*this)->"); + } + } else { + self = NewString("(*this)->"); + } + } + + /* If node is a member template expansion, we don't allow added code */ + if (Getattr(n, "templatetype")) + flags &= ~(CWRAP_EXTEND); + + name = Getattr(n, "name"); + parms = CopyParmList(nonvoid_parms(Getattr(n, "parms"))); + + type = NewString(classname); + if (qualifier) { + SwigType_push(type, qualifier); + } + SwigType_add_pointer(type); + p = NewParm(type, "self", n); + Setattr(p, "self", "1"); + Setattr(p, "hidden","1"); + /* + Disable the 'this' ownership in 'self' to manage inplace + operations like: + + A& A::operator+=(int i) { ...; return *this;} + + Here the 'self' parameter ownership needs to be disabled since + there could be two objects sharing the same 'this' pointer: the + input and the result one. And worse, the pointer could be deleted + in one of the objects (input), leaving the other (output) with + just a seg. fault to happen. + + To avoid the previous problem, use + + %feature("self:disown") *::operator+=; + %feature("new") *::operator+=; + + These two lines just transfer the ownership of the 'this' pointer + from the input to the output wrapping object. + + This happens in python, but may also happen in other target + languages. + */ + if (GetFlag(n, "feature:self:disown")) { + Setattr(p, "wrap:disown", "1"); + } + set_nextSibling(p, parms); + Delete(type); + + /* Generate action code for the access */ + if (!(flags & CWRAP_EXTEND)) { + String *explicit_qualifier = 0; + String *call = 0; + String *cres = 0; + String *explicitcall_name = 0; + int pure_virtual = !(Cmp(Getattr(n, "storage"), "virtual")) && !(Cmp(Getattr(n, "value"), "0")); + + /* Call the explicit method rather than allow for a polymorphic call */ + if ((flags & CWRAP_DIRECTOR_TWO_CALLS) || (flags & CWRAP_DIRECTOR_ONE_CALL)) { + String *access = Getattr(n, "access"); + if (access && (Cmp(access, "protected") == 0)) { + /* If protected access (can only be if a director method) then call the extra public accessor method (language module must provide this) */ + String *explicit_qualifier_tmp = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), "qname")); + explicitcall_name = NewStringf("%sSwigPublic", name); + if (Len(directorScope) > 0) + explicit_qualifier = NewStringf("SwigDirector_%s_%s", directorScope, explicit_qualifier_tmp); + else + explicit_qualifier = NewStringf("SwigDirector_%s", explicit_qualifier_tmp); + Delete(explicit_qualifier_tmp); + } else { + explicit_qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), "qname")); + } + } + + if (!self && SwigType_isrvalue_reference(Getattr(n, "refqualifier"))) { + String *memory_header = NewString("<memory>"); + Setfile(memory_header, Getfile(n)); + Setline(memory_header, Getline(n)); + Swig_fragment_emit(memory_header); + self = NewString("std::move(*this)."); + Delete(memory_header); + } + + call = Swig_cmethod_call(explicitcall_name ? explicitcall_name : name, p, self, explicit_qualifier, director_type); + cres = Swig_cresult(Getattr(n, "type"), Swig_cresult_name(), call); + + if (pure_virtual && is_director && (flags & CWRAP_DIRECTOR_TWO_CALLS)) { + String *qualifier = SwigType_namestr(Getattr(Getattr(parentNode(n), "typescope"), "qname")); + Delete(cres); + cres = NewStringf("Swig::DirectorPureVirtualException::raise(\"%s::%s\");", qualifier, name); + Delete(qualifier); + } + + if (flags & CWRAP_DIRECTOR_TWO_CALLS) { + /* Create two method calls, one to call the explicit method, the other a normal polymorphic function call */ + String *cres_both_calls = NewStringf(""); + String *call_extra = Swig_cmethod_call(name, p, self, 0, director_type); + String *cres_extra = Swig_cresult(Getattr(n, "type"), Swig_cresult_name(), call_extra); + Printv(cres_both_calls, "if (upcall) {\n", cres, "\n", "} else {", cres_extra, "\n}", NIL); + Setattr(n, "wrap:action", cres_both_calls); + Delete(cres_extra); + Delete(call_extra); + Delete(cres_both_calls); + } else { + Setattr(n, "wrap:action", cres); + } + + Delete(explicitcall_name); + Delete(call); + Delete(cres); + Delete(explicit_qualifier); + } else { + /* Methods with default arguments are wrapped with additional methods for each default argument, + * however, only one extra %extend method is generated. */ + + String *defaultargs = Getattr(n, "defaultargs"); + String *code = Getattr(n, "code"); + String *cname = Getattr(n, "extendsmartclassname") ? Getattr(n, "extendsmartclassname") : classname; + String *membername = Swig_name_member(nspace, cname, name); + String *mangled = Swig_name_mangle(membername); + int is_smart_pointer = flags & CWRAP_SMART_POINTER; + + type = Getattr(n, "type"); + + /* Check if the method is overloaded. If so, and it has code attached, we append an extra suffix + to avoid a name-clash in the generated wrappers. This allows overloaded methods to be defined + in C. + + But when not using the suffix used for overloaded functions, we still need to ensure that the + wrapper name doesn't conflict with any wrapper functions for some languages, so optionally make + it sufficiently unique by appending a suffix similar to the one used for overloaded functions to it. + */ + if (code) { + if (Getattr(n, "sym:overloaded")) { + Append(mangled, Getattr(defaultargs ? defaultargs : n, "sym:overname")); + } else if (UseWrapperSuffix) { + Append(mangled, "__SWIG"); + } + } + + /* See if there is any code that we need to emit */ + if (!defaultargs && code && !is_smart_pointer) { + Swig_add_extension_code(n, mangled, p, type, code, cparse_cplusplus, "self"); + } + if (is_smart_pointer) { + int i = 0; + Parm *pp = p; + String *func = NewStringf("%s(", mangled); + String *cres; + + if (!Swig_storage_isstatic(n)) { + String *pname = Swig_cparm_name(pp, i); + String *ctname = SwigType_namestr(cname); + String *fadd = 0; + if (is_smart_pointer_overload) { + String *nclassname = SwigType_namestr(classname); + fadd = NewStringf("(%s const *)((%s const *)%s)->operator ->()", ctname, nclassname, pname); + Delete(nclassname); + } + else { + fadd = NewStringf("(%s*)(%s)->operator ->()", ctname, pname); + } + Append(func, fadd); + Delete(ctname); + Delete(fadd); + Delete(pname); + pp = nextSibling(pp); + if (pp) + Append(func, ","); + } else { + pp = nextSibling(pp); + } + ++i; + while (pp) { + SwigType *pt = Getattr(pp, "type"); + if ((SwigType_type(pt) != T_VOID)) { + String *pname = Swig_cparm_name(pp, i++); + String *rcaststr = SwigType_rcaststr(pt, pname); + Append(func, rcaststr); + Delete(rcaststr); + Delete(pname); + pp = nextSibling(pp); + if (pp) + Append(func, ","); + } + } + Append(func, ")"); + cres = Swig_cresult(Getattr(n, "type"), Swig_cresult_name(), func); + Setattr(n, "wrap:action", cres); + Delete(cres); + } else { + String *call = Swig_cfunction_call(mangled, p); + String *cres = Swig_cresult(Getattr(n, "type"), Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + + Delete(membername); + Delete(mangled); + } + Setattr(n, "parms", p); + Delete(p); + Delete(self); + Delete(parms); + Delete(directorScope); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_methodclass() + * + * This function returns the class node for a given method or class. + * ----------------------------------------------------------------------------- */ + +Node *Swig_methodclass(Node *n) { + Node *nodetype = nodeType(n); + if (Cmp(nodetype, "class") == 0) + return n; + return GetFlag(n, "feature:extend") ? parentNode(parentNode(n)) : parentNode(n); +} + +int Swig_directorclass(Node *n) { + Node *classNode = Swig_methodclass(n); + assert(classNode != 0); + return (Getattr(classNode, "vtable") != 0); +} + +Node *Swig_directormap(Node *module, String *type) { + int is_void = !Cmp(type, "void"); + if (!is_void && module) { + /* ?? follow the inheritance hierarchy? */ + + String *base = SwigType_base(type); + + Node *directormap = Getattr(module, "wrap:directormap"); + if (directormap) + return Getattr(directormap, base); + } + return 0; +} + + +/* ----------------------------------------------------------------------------- + * Swig_ConstructorToFunction() + * + * This function creates a C wrapper for a C constructor function. + * ----------------------------------------------------------------------------- */ + +int Swig_ConstructorToFunction(Node *n, const_String_or_char_ptr nspace, String *classname, String *none_comparison, String *director_ctor, int cplus, int flags, String *directorname) { + Parm *p; + ParmList *directorparms; + SwigType *type; + int use_director = Swig_directorclass(n); + ParmList *parms = CopyParmList(nonvoid_parms(Getattr(n, "parms"))); + /* Prepend the list of prefix_args (if any) */ + Parm *prefix_args = Getattr(n, "director:prefix_args"); + if (prefix_args != NIL) { + Parm *p2, *p3; + + directorparms = CopyParmList(prefix_args); + for (p = directorparms; nextSibling(p); p = nextSibling(p)); + for (p2 = parms; p2; p2 = nextSibling(p2)) { + p3 = CopyParm(p2); + set_nextSibling(p, p3); + Delete(p3); + p = p3; + } + } else + directorparms = parms; + + type = NewString(classname); + SwigType_add_pointer(type); + + if (flags & CWRAP_EXTEND) { + /* Constructors with default arguments are wrapped with additional constructor methods for each default argument, + * however, only one extra %extend method is generated. */ + String *call; + String *cres; + String *defaultargs = Getattr(n, "defaultargs"); + String *code = Getattr(n, "code"); + String *membername = Swig_name_construct(nspace, classname); + String *mangled = Swig_name_mangle(membername); + + /* Check if the constructor is overloaded. If so, and it has code attached, we append an extra suffix + to avoid a name-clash in the generated wrappers. This allows overloaded constructors to be defined + in C. */ + if (Getattr(n, "sym:overloaded") && code) { + Append(mangled, Getattr(defaultargs ? defaultargs : n, "sym:overname")); + } + + /* See if there is any code that we need to emit */ + if (!defaultargs && code) { + Swig_add_extension_code(n, mangled, parms, type, code, cparse_cplusplus, "self"); + } + + call = Swig_cfunction_call(mangled, parms); + cres = Swig_cresult(type, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + Delete(membername); + Delete(mangled); + } else { + if (cplus) { + /* if a C++ director class exists, create it rather than the original class */ + if (use_director) { + Node *parent = Swig_methodclass(n); + int abstract = Getattr(parent, "abstracts") != 0; + String *action = NewStringEmpty(); + String *tmp_none_comparison = Copy(none_comparison); + String *director_call; + String *nodirector_call; + + Replaceall(tmp_none_comparison, "$arg", "arg1"); + + director_call = Swig_cppconstructor_director_call(directorname, directorparms); + nodirector_call = Swig_cppconstructor_nodirector_call(classname, parms); + + if (abstract) { + /* whether or not the abstract class has been subclassed in python, + * create a director instance (there's no way to create a normal + * instance). if any of the pure virtual methods haven't been + * implemented in the target language, calls to those methods will + * generate Swig::DirectorPureVirtualException exceptions. + */ + String *cres = Swig_cresult(type, Swig_cresult_name(), director_call); + Append(action, cres); + Delete(cres); + } else { + /* (scottm): The code for creating a new director is now a string + template that gets passed in via the director_ctor argument. + + $comparison : an 'if' comparison from none_comparison + $director_new: Call new for director class + $nondirector_new: Call new for non-director class + */ + String *cres; + Append(action, director_ctor); + Replaceall(action, "$comparison", tmp_none_comparison); + + cres = Swig_cresult(type, Swig_cresult_name(), director_call); + Replaceall(action, "$director_new", cres); + Delete(cres); + + cres = Swig_cresult(type, Swig_cresult_name(), nodirector_call); + Replaceall(action, "$nondirector_new", cres); + Delete(cres); + } + Setattr(n, "wrap:action", action); + Delete(tmp_none_comparison); + Delete(action); + } else { + String *call = Swig_cppconstructor_call(classname, parms); + String *cres = Swig_cresult(type, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + } + } else { + String *call = Swig_cconstructor_call(classname); + String *cres = Swig_cresult(type, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + } + } + Setattr(n, "type", type); + Setattr(n, "parms", parms); + Delete(type); + if (directorparms != parms) + Delete(directorparms); + Delete(parms); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_DestructorToFunction() + * + * This function creates a C wrapper for a destructor function. + * ----------------------------------------------------------------------------- */ + +int Swig_DestructorToFunction(Node *n, const_String_or_char_ptr nspace, String *classname, int cplus, int flags) { + SwigType *type; + Parm *p; + + type = NewString(classname); + SwigType_add_pointer(type); + p = NewParm(type, "self", n); + Setattr(p, "self", "1"); + Setattr(p, "hidden", "1"); + Setattr(p, "wrap:disown", "1"); + Delete(type); + type = NewString("void"); + + if (flags & CWRAP_EXTEND) { + String *cres; + String *call; + String *membername, *mangled, *code; + membername = Swig_name_destroy(nspace, classname); + mangled = Swig_name_mangle(membername); + code = Getattr(n, "code"); + if (code) { + Swig_add_extension_code(n, mangled, p, type, code, cparse_cplusplus, "self"); + } + call = Swig_cfunction_call(mangled, p); + cres = NewStringf("%s;", call); + Setattr(n, "wrap:action", cres); + Delete(membername); + Delete(mangled); + Delete(call); + Delete(cres); + } else { + if (cplus) { + String *call = Swig_cppdestructor_call(n); + String *cres = NewStringf("%s", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } else { + String *call = Swig_cdestructor_call(n); + String *cres = NewStringf("%s", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + } + Setattr(n, "type", type); + Setattr(n, "parms", p); + Delete(type); + Delete(p); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_MembersetToFunction() + * + * This function creates a C wrapper for setting a structure member. + * ----------------------------------------------------------------------------- */ + +int Swig_MembersetToFunction(Node *n, String *classname, int flags) { + String *name; + ParmList *parms; + Parm *p; + SwigType *t; + SwigType *ty; + SwigType *type; + SwigType *void_type = NewString("void"); + String *self = 0; + + int varcref = flags & CWRAP_NATURAL_VAR; + + if (flags & CWRAP_SMART_POINTER) { + self = NewString("(*this)->"); + } + if (flags & CWRAP_ALL_PROTECTED_ACCESS) { + self = NewStringf("darg->"); + } + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + + t = NewString(classname); + SwigType_add_pointer(t); + parms = NewParm(t, "self", n); + Setattr(parms, "self", "1"); + Setattr(parms, "hidden","1"); + Delete(t); + + ty = Swig_wrapped_member_var_type(type, varcref); + p = NewParm(ty, name, n); + Setattr(parms, "hidden", "1"); + set_nextSibling(parms, p); + + /* If the type is a pointer or reference. We mark it with a special wrap:disown attribute */ + if (SwigType_check_decl(type, "p.")) { + Setattr(p, "wrap:disown", "1"); + } + Delete(p); + + if (flags & CWRAP_EXTEND) { + String *call; + String *cres; + String *code = Getattr(n, "code"); + + String *sname = Swig_name_set(0, name); + String *membername = Swig_name_member(0, classname, sname); + String *mangled = Swig_name_mangle(membername); + + if (code) { + /* I don't think this ever gets run - WSF */ + Swig_add_extension_code(n, mangled, parms, void_type, code, cparse_cplusplus, "self"); + } + call = Swig_cfunction_call(mangled, parms); + cres = NewStringf("%s;", call); + Setattr(n, "wrap:action", cres); + + Delete(cres); + Delete(call); + Delete(mangled); + Delete(membername); + Delete(sname); + } else { + String *call = Swig_cmemberset_call(name, type, self, varcref); + String *cres = NewStringf("%s;", call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + Setattr(n, "type", void_type); + Setattr(n, "parms", parms); + Delete(parms); + Delete(ty); + Delete(void_type); + Delete(self); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_MembergetToFunction() + * + * This function creates a C wrapper for getting a structure member. + * ----------------------------------------------------------------------------- */ + +int Swig_MembergetToFunction(Node *n, String *classname, int flags) { + String *name; + ParmList *parms; + SwigType *t; + SwigType *ty; + SwigType *type; + String *self = 0; + + int varcref = flags & CWRAP_NATURAL_VAR; + + if (flags & CWRAP_SMART_POINTER) { + if (Swig_storage_isstatic(n)) { + Node *sn = Getattr(n, "cplus:staticbase"); + String *base = Getattr(sn, "name"); + self = NewStringf("%s::", base); + } else if (flags & CWRAP_SMART_POINTER_OVERLOAD) { + String *nclassname = SwigType_namestr(classname); + self = NewStringf("(*(%s const *)this)->", nclassname); + Delete(nclassname); + } else { + self = NewString("(*this)->"); + } + } + if (flags & CWRAP_ALL_PROTECTED_ACCESS) { + self = NewStringf("darg->"); + } + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + + t = NewString(classname); + SwigType_add_pointer(t); + parms = NewParm(t, "self", n); + Setattr(parms, "self", "1"); + Setattr(parms, "hidden","1"); + Delete(t); + + ty = Swig_wrapped_member_var_type(type, varcref); + if (flags & CWRAP_EXTEND) { + String *call; + String *cres; + String *code = Getattr(n, "code"); + + String *gname = Swig_name_get(0, name); + String *membername = Swig_name_member(0, classname, gname); + String *mangled = Swig_name_mangle(membername); + + if (code) { + /* I don't think this ever gets run - WSF */ + Swig_add_extension_code(n, mangled, parms, ty, code, cparse_cplusplus, "self"); + } + call = Swig_cfunction_call(mangled, parms); + cres = Swig_cresult(ty, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + + Delete(cres); + Delete(call); + Delete(mangled); + Delete(membername); + Delete(gname); + } else { + String *call = Swig_cmemberget_call(name, type, self, varcref); + String *cres = Swig_cresult(ty, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(call); + Delete(cres); + } + Setattr(n, "type", ty); + Setattr(n, "parms", parms); + Delete(parms); + Delete(ty); + + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_VarsetToFunction() + * + * This function creates a C wrapper for setting a global variable or static member + * variable. + * ----------------------------------------------------------------------------- */ + +int Swig_VarsetToFunction(Node *n, int flags) { + String *name, *nname; + ParmList *parms; + SwigType *type, *ty; + + int varcref = flags & CWRAP_NATURAL_VAR; + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + nname = SwigType_namestr(name); + ty = Swig_wrapped_var_type(type, varcref); + parms = NewParm(ty, name, n); + + if (flags & CWRAP_EXTEND) { + String *sname = Swig_name_set(0, name); + String *mangled = Swig_name_mangle(sname); + String *call = Swig_cfunction_call(mangled, parms); + String *cres = NewStringf("%s;", call); + Setattr(n, "wrap:action", cres); + Delete(cres); + Delete(call); + Delete(mangled); + Delete(sname); + } else { + if (!Strstr(type, "enum $unnamed")) { + String *pname = Swig_cparm_name(0, 0); + String *dref = Swig_wrapped_var_deref(type, pname, varcref); + String *call = NewStringf("%s = %s;", nname, dref); + Setattr(n, "wrap:action", call); + Delete(call); + Delete(dref); + Delete(pname); + } else { + String *pname = Swig_cparm_name(0, 0); + String *call = NewStringf("if (sizeof(int) == sizeof(%s)) *(int*)(void*)&(%s) = %s;", nname, nname, pname); + Setattr(n, "wrap:action", call); + Delete(pname); + Delete(call); + } + } + Setattr(n, "type", "void"); + Setattr(n, "parms", parms); + Delete(parms); + Delete(ty); + Delete(nname); + return SWIG_OK; +} + +/* ----------------------------------------------------------------------------- + * Swig_VargetToFunction() + * + * This function creates a C wrapper for getting a global variable or static member + * variable. + * ----------------------------------------------------------------------------- */ + +int Swig_VargetToFunction(Node *n, int flags) { + String *cres, *call; + String *name; + SwigType *type; + SwigType *ty = 0; + + int varcref = flags & CWRAP_NATURAL_VAR; + + name = Getattr(n, "name"); + type = Getattr(n, "type"); + ty = Swig_wrapped_var_type(type, varcref); + + if (flags & CWRAP_EXTEND) { + String *sname = Swig_name_get(0, name); + String *mangled = Swig_name_mangle(sname); + call = Swig_cfunction_call(mangled, 0); + cres = Swig_cresult(ty, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(mangled); + Delete(sname); + } else { + String *nname = 0; + if (Equal(nodeType(n), "constant")) { + String *rawval = Getattr(n, "rawval"); + String *value = rawval ? rawval : Getattr(n, "value"); + nname = NewStringf("(%s)", value); + } else { + nname = SwigType_namestr(name); + } + call = Swig_wrapped_var_assign(type, nname, varcref); + cres = Swig_cresult(ty, Swig_cresult_name(), call); + Setattr(n, "wrap:action", cres); + Delete(nname); + } + + Setattr(n, "type", ty); + Delattr(n, "parms"); + Delete(cres); + Delete(call); + Delete(ty); + return SWIG_OK; +} diff --git a/contrib/tools/swig/Source/Swig/deprecate.c b/contrib/tools/swig/Source/Swig/deprecate.c new file mode 100644 index 0000000000..5783455e59 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/deprecate.c @@ -0,0 +1,107 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * deprecate.c + * + * The functions in this file are SWIG core functions that are deprecated + * or which do not fit in nicely with everything else. Generally this means + * that the function and/or API needs to be changed in some future release. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" + +/* --------------------------------------------------------------------- + * ParmList_is_compactdefargs() + * + * Returns 1 if the parameter list passed in is marked for compact argument + * handling (by the "compactdefargs" attribute). Otherwise returns 0. + * ---------------------------------------------------------------------- */ + +/* Discussion: + + "compactdefargs" is a property set by the Parser to indicate special + handling of default arguments. This property seems to be something that + is associated with functions and methods rather than low-level ParmList + objects. Therefore, I don't like the fact that this special purpose + feature is bolted onto the side of ParmList objects. + + Proposed solution: + + 1. "compactdefargs" should be a feature set on function/method nodes + instead of ParmList objects. For example, if you have a function, + you would check the function node to see if the parameters are + to be handled in this way. + + + Difficulties: + + 1. This is used by functions in cwrap.c and emit.cxx, none of which + are passed information about the function/method node. We might + have to change the API of those functions to make this work correctly. + For example: + + int emit_num_required(ParmList *parms) + + might become + + int emit_num_required(ParmList *parms, int compactargs) + +*/ + +int ParmList_is_compactdefargs(ParmList *p) { + int compactdefargs = 0; + + if (p) { + compactdefargs = Getattr(p, "compactdefargs") ? 1 : 0; + + /* The "compactdefargs" attribute should only be set on the first parameter in the list. + * However, sometimes an extra parameter is inserted at the beginning of the parameter list, + * so we check the 2nd parameter too. */ + if (!compactdefargs) { + Parm *nextparm = nextSibling(p); + compactdefargs = (nextparm && Getattr(nextparm, "compactdefargs")) ? 1 : 0; + } + } + + return compactdefargs; +} + +/* --------------------------------------------------------------------- + * ParmList_errorstr() + * + * Generate a prototype string suitable for use in error/warning messages. + * Similar to ParmList_protostr() but is also aware of hidden parameters. + * ---------------------------------------------------------------------- */ + +/* Discussion. This function is used to generate error messages, but take + into account that there might be a hidden parameter. Although this involves + parameter lists, it really isn't a core feature of swigparm.h or parms.c. + This is because the "hidden" attribute of parameters is added elsewhere (cwrap.c). + + For now, this function is placed here because it doesn't really seem to fit in + with the parms.c interface. + +*/ + +String *ParmList_errorstr(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + if (Getattr(p,"hidden")) { + p = nextSibling(p); + } else { + String *pstr = SwigType_str(Getattr(p, "type"), 0); + Append(out, pstr); + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + } + return out; +} diff --git a/contrib/tools/swig/Source/Swig/error.c b/contrib/tools/swig/Source/Swig/error.c new file mode 100644 index 0000000000..efd644f9a8 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/error.c @@ -0,0 +1,351 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * error.c + * + * Error handling functions. These are used to issue warnings and + * error messages. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include <stdarg.h> +#include <ctype.h> + +/* ----------------------------------------------------------------------------- + * Commentary on the warning filter. + * + * The warning filter is a string of numbers prefaced by (-) or (+) to + * indicate whether or not a warning message is displayed. For example: + * + * "-304-201-140+210+201" + * + * The filter string is scanned left to right and the first occurrence + * of a warning number is used to determine printing behavior. + * + * The same number may appear more than once in the string. For example, in the + * above string, "201" appears twice. This simply means that warning 201 + * was disabled after it was previously enabled. This may only be temporary + * setting--the first number may be removed later in which case the warning + * is reenabled. + * ----------------------------------------------------------------------------- */ + +#if defined(_WIN32) +# define DEFAULT_ERROR_MSG_FORMAT EMF_MICROSOFT +#else +# define DEFAULT_ERROR_MSG_FORMAT EMF_STANDARD +#endif +static ErrorMessageFormat msg_format = DEFAULT_ERROR_MSG_FORMAT; +static int silence = 0; /* Silent operation */ +static String *filter = 0; /* Warning filter */ +static int warnall = 0; +static int nwarning = 0; +static int nerrors = 0; + +static int init_fmt = 0; +static char wrn_wnum_fmt[64]; +static char wrn_nnum_fmt[64]; +static char err_line_fmt[64]; +static char err_eof_fmt[64]; +static char diag_line_fmt[64]; +static char diag_eof_fmt[64]; + +static String *format_filename(const_String_or_char_ptr filename); + +/* ----------------------------------------------------------------------------- + * Swig_warning() + * + * Issue a warning message on stderr. + * ----------------------------------------------------------------------------- */ + +void Swig_warning(int wnum, const_String_or_char_ptr filename, int line, const char *fmt, ...) { + String *out; + char *msg; + int wrn = 1; + va_list ap; + if (silence) + return; + if (!init_fmt) + Swig_error_msg_format(DEFAULT_ERROR_MSG_FORMAT); + + va_start(ap, fmt); + + out = NewStringEmpty(); + vPrintf(out, fmt, ap); + + msg = Char(out); + if (isdigit((unsigned char) *msg)) { + unsigned long result = strtoul(msg, &msg, 10); + if (msg != Char(out)) { + msg++; + wnum = result; + } + } + + /* Check in the warning filter */ + if (filter) { + char temp[32]; + char *c; + char *f = Char(filter); + sprintf(temp, "%d", wnum); + while (*f != '\0' && (c = strstr(f, temp))) { + if (*(c - 1) == '-') { + wrn = 0; /* Warning disabled */ + break; + } + if (*(c - 1) == '+') { + wrn = 1; /* Warning enabled */ + break; + } + f += strlen(temp); + } + } + if (warnall || wrn) { + String *formatted_filename = format_filename(filename); + String *full_message = NewString(""); + if (wnum) { + Printf(full_message, wrn_wnum_fmt, formatted_filename, line, wnum); + } else { + Printf(full_message, wrn_nnum_fmt, formatted_filename, line); + } + Printf(full_message, "%s", msg); + Printv(stderr, full_message, NIL); + nwarning++; + Delete(full_message); + Delete(formatted_filename); + } + Delete(out); + va_end(ap); +} + +/* ----------------------------------------------------------------------------- + * Swig_error() + * + * Issue an error message on stderr. + * ----------------------------------------------------------------------------- */ + +void Swig_error(const_String_or_char_ptr filename, int line, const char *fmt, ...) { + va_list ap; + String *formatted_filename = NULL; + String *full_message = NULL; + + if (silence) + return; + if (!init_fmt) + Swig_error_msg_format(DEFAULT_ERROR_MSG_FORMAT); + + va_start(ap, fmt); + formatted_filename = format_filename(filename); + full_message = NewString(""); + if (line > 0) { + Printf(full_message, err_line_fmt, formatted_filename, line); + } else { + Printf(full_message, err_eof_fmt, formatted_filename); + } + vPrintf(full_message, fmt, ap); + Printv(stderr, full_message, NIL); + va_end(ap); + nerrors++; + Delete(full_message); + Delete(formatted_filename); +} + +/* ----------------------------------------------------------------------------- + * Swig_error_count() + * + * Returns number of errors received. + * ----------------------------------------------------------------------------- */ + +int Swig_error_count(void) { + return nerrors; +} + +/* ----------------------------------------------------------------------------- + * Swig_error_silent() + * + * Set silent flag + * ----------------------------------------------------------------------------- */ + +void Swig_error_silent(int s) { + silence = s; +} + + +/* ----------------------------------------------------------------------------- + * Swig_warnfilter() + * + * Takes a comma separate list of warning numbers and puts in the filter. + * ----------------------------------------------------------------------------- */ + +void Swig_warnfilter(const_String_or_char_ptr wlist, int add) { + char *c; + char *cw; + String *s; + if (!filter) + filter = NewStringEmpty(); + + s = NewString(""); + Clear(s); + cw = Char(wlist); + while (*cw != '\0') { + if (*cw != ' ') { + Putc(*cw, s); + } + ++cw; + } + c = Char(s); + c = strtok(c, ", "); + while (c) { + if (isdigit((int) *c) || (*c == '+') || (*c == '-')) { + /* Even if c is a digit, the rest of the string might not be, eg in the case of typemap + * warnings (a bit odd really), eg: %warnfilter(SWIGWARN_TYPEMAP_CHARLEAK_MSG) */ + if (add) { + Insert(filter, 0, c); + if (isdigit((int) *c)) { + Insert(filter, 0, "-"); + } + } else { + char *temp = (char *)Malloc(sizeof(char)*strlen(c) + 2); + if (isdigit((int) *c)) { + sprintf(temp, "-%s", c); + } else { + strcpy(temp, c); + } + Replace(filter, temp, "", DOH_REPLACE_FIRST); + Free(temp); + } + } + c = strtok(NULL, ", "); + } + Delete(s); +} + +void Swig_warnall(void) { + warnall = 1; +} + + +/* ----------------------------------------------------------------------------- + * Swig_warn_count() + * + * Return the number of warnings + * ----------------------------------------------------------------------------- */ + +int Swig_warn_count(void) { + return nwarning; +} + +/* ----------------------------------------------------------------------------- + * Swig_error_msg_format() + * + * Set the type of error/warning message display + * ----------------------------------------------------------------------------- */ + +void Swig_error_msg_format(ErrorMessageFormat format) { + const char *error = "Error"; + const char *warning = "Warning"; + + const char *fmt_eof = 0; + const char *fmt_line = 0; + + /* here 'format' could be directly a string instead of an enum, but + by now a switch is used to translated into one. */ + switch (format) { + case EMF_MICROSOFT: + fmt_line = "%s(%d) "; + fmt_eof = "%s(999999) "; /* Is there a special character for EOF? Just use a large number. */ + break; + case EMF_STANDARD: + default: + fmt_line = "%s:%d"; + fmt_eof = "%s:EOF"; + } + + sprintf(wrn_wnum_fmt, "%s: %s %%d: ", fmt_line, warning); + sprintf(wrn_nnum_fmt, "%s: %s: ", fmt_line, warning); + sprintf(err_line_fmt, "%s: %s: ", fmt_line, error); + sprintf(err_eof_fmt, "%s: %s: ", fmt_eof, error); + sprintf(diag_line_fmt, "%s: ", fmt_line); + sprintf(diag_eof_fmt, "%s: ", fmt_eof); + + msg_format = format; + init_fmt = 1; +} + +/* ----------------------------------------------------------------------------- + * format_filename() + * + * Remove double backslashes in Windows filename paths for display + * ----------------------------------------------------------------------------- */ +static String *format_filename(const_String_or_char_ptr filename) { + String *formatted_filename = NewString(filename); +#if defined(_WIN32) + Replaceall(formatted_filename, "\\\\", "\\"); +#endif + return formatted_filename; +} + +/* ----------------------------------------------------------------------------- + * Swig_stringify_with_location() + * + * Return a string representation of any DOH object with line and file location + * information in the appropriate error message format. The string representation + * is enclosed within [] brackets after the line and file information. + * ----------------------------------------------------------------------------- */ + +String *Swig_stringify_with_location(DOH *object) { + String *str = NewStringEmpty(); + + if (!init_fmt) + Swig_error_msg_format(DEFAULT_ERROR_MSG_FORMAT); + + if (object) { + int line = Getline(object); + String *formatted_filename = format_filename(Getfile(object)); + if (line > 0) { + Printf(str, diag_line_fmt, formatted_filename, line); + } else { + Printf(str, diag_eof_fmt, formatted_filename); + } + if (Len(object) == 0) { + Printf(str, "[EMPTY]"); + } else { + Printf(str, "[%s]", object); + } + Delete(formatted_filename); + } else { + Printf(str, "[NULL]"); + } + + return str; +} + +/* ----------------------------------------------------------------------------- + * Swig_diagnostic() + * + * Issue a diagnostic message on stdout. + * ----------------------------------------------------------------------------- */ + +void Swig_diagnostic(const_String_or_char_ptr filename, int line, const char *fmt, ...) { + va_list ap; + String *formatted_filename = NULL; + + if (!init_fmt) + Swig_error_msg_format(DEFAULT_ERROR_MSG_FORMAT); + + va_start(ap, fmt); + formatted_filename = format_filename(filename); + if (line > 0) { + Printf(stdout, diag_line_fmt, formatted_filename, line); + } else { + Printf(stdout, diag_eof_fmt, formatted_filename); + } + vPrintf(stdout, fmt, ap); + va_end(ap); + Delete(formatted_filename); +} + diff --git a/contrib/tools/swig/Source/Swig/extend.c b/contrib/tools/swig/Source/Swig/extend.c new file mode 100644 index 0000000000..23660c0ad8 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/extend.c @@ -0,0 +1,141 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * extend.c + * + * Extensions support (%extend) + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" + +static Hash *extendhash = 0; /* Hash table of added methods */ + +/* ----------------------------------------------------------------------------- + * Swig_extend_hash() + * + * Access the extend hash + * ----------------------------------------------------------------------------- */ +Hash *Swig_extend_hash(void) { + if (!extendhash) + extendhash = NewHash(); + return extendhash; +} + +/* ----------------------------------------------------------------------------- + * Swig_extend_merge() + * + * Extension merge. This function is used to handle the %extend directive + * when it appears before a class definition. To handle this, the %extend + * actually needs to take precedence. Therefore, we will selectively nuke symbols + * from the current symbol table, replacing them with the added methods. + * ----------------------------------------------------------------------------- */ + +void Swig_extend_merge(Node *cls, Node *am) { + Node *n; + Node *csym; + + n = firstChild(am); + while (n) { + String *symname; + if (Strcmp(nodeType(n),"constructor") == 0) { + symname = Getattr(n,"sym:name"); + if (symname) { + if (Strcmp(symname,Getattr(n,"name")) == 0) { + /* If the name and the sym:name of a constructor are the same, + then it hasn't been renamed. However---the name of the class + itself might have been renamed so we need to do a consistency + check here */ + if (Getattr(cls,"sym:name")) { + Setattr(n,"sym:name", Getattr(cls,"sym:name")); + } + } + } + } + + symname = Getattr(n,"sym:name"); + DohIncref(symname); + if ((symname) && (!Getattr(n,"error"))) { + /* Remove node from its symbol table */ + Swig_symbol_remove(n); + csym = Swig_symbol_add(symname,n); + if (csym != n) { + /* Conflict with previous definition. Nuke previous definition */ + String *e = NewStringEmpty(); + String *en = NewStringEmpty(); + String *ec = NewStringEmpty(); + Printf(ec,"Identifier '%s' redefined by %%extend (ignored),",symname); + Printf(en,"%%extend definition of '%s'.",symname); + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(csym),Getline(csym),"%s\n",ec); + Swig_warning(WARN_PARSE_REDEFINED,Getfile(n),Getline(n),"%s\n",en); + SWIG_WARN_NODE_END(n); + Printf(e,"%s:%d:%s\n%s:%d:%s\n",Getfile(csym),Getline(csym),ec, + Getfile(n),Getline(n),en); + Setattr(csym,"error",e); + Delete(e); + Delete(en); + Delete(ec); + Swig_symbol_remove(csym); /* Remove class definition */ + Swig_symbol_add(symname,n); /* Insert extend definition */ + } + } + n = nextSibling(n); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_extend_append_previous() + * ----------------------------------------------------------------------------- */ + +void Swig_extend_append_previous(Node *cls, Node *am) { + Node *n, *ne; + Node *pe = 0; + Node *ae = 0; + + if (!am) return; + + n = firstChild(am); + while (n) { + ne = nextSibling(n); + set_nextSibling(n,0); + /* typemaps and fragments need to be prepended */ + if (((Cmp(nodeType(n),"typemap") == 0) || (Cmp(nodeType(n),"fragment") == 0))) { + if (!pe) pe = Swig_cparse_new_node("extend"); + appendChild(pe, n); + } else { + if (!ae) ae = Swig_cparse_new_node("extend"); + appendChild(ae, n); + } + n = ne; + } + if (pe) prependChild(cls,pe); + if (ae) appendChild(cls,ae); +} + + +/* ----------------------------------------------------------------------------- + * Swig_extend_unused_check() + * + * Check for unused %extend. Special case, don't report unused + * extensions for templates + * ----------------------------------------------------------------------------- */ + +void Swig_extend_unused_check(void) { + Iterator ki; + + if (!extendhash) return; + for (ki = First(extendhash); ki.key; ki = Next(ki)) { + if (!Strchr(ki.key,'<')) { + SWIG_WARN_NODE_BEGIN(ki.item); + Swig_warning(WARN_PARSE_EXTEND_UNDEF,Getfile(ki.item), Getline(ki.item), "%%extend defined for an undeclared class %s.\n", SwigType_namestr(ki.key)); + SWIG_WARN_NODE_END(ki.item); + } + } +} + diff --git a/contrib/tools/swig/Source/Swig/fragment.c b/contrib/tools/swig/Source/Swig/fragment.c new file mode 100644 index 0000000000..03b231fa13 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/fragment.c @@ -0,0 +1,188 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * fragment.c + * + * This file manages named code fragments. Code fragments are typically + * used to hold helper-code that may or may not be included in the wrapper + * file (depending on what features are actually used in the interface). + * + * By using fragments, it's possible to greatly reduce the amount of + * wrapper code and to generate cleaner wrapper files. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "swigwarn.h" +#include "cparse.h" + +static Hash *fragments = 0; +static Hash *looking_fragments = 0; +static int debug = 0; + + +/* ----------------------------------------------------------------------------- + * Swig_fragment_register() + * + * Add a fragment. Use the original Node*, so, if something needs to be + * changed, lang.cxx doesn't need to be touched again. + * ----------------------------------------------------------------------------- */ + +void Swig_fragment_register(Node *fragment) { + if (Getattr(fragment, "emitonly")) { + Swig_fragment_emit(fragment); + return; + } else { + String *name = Copy(Getattr(fragment, "value")); + String *type = Getattr(fragment, "type"); + if (type) { + SwigType *rtype = SwigType_typedef_resolve_all(type); + String *mangle = Swig_string_mangle(type); + Append(name, mangle); + Delete(mangle); + Delete(rtype); + if (debug) + Printf(stdout, "register fragment %s %s\n", name, type); + } + if (!fragments) { + fragments = NewHash(); + } + if (!Getattr(fragments, name)) { + String *section = Copy(Getattr(fragment, "section")); + String *ccode = Copy(Getattr(fragment, "code")); + Hash *kwargs = Getattr(fragment, "kwargs"); + Setmeta(ccode, "section", section); + if (kwargs) { + Setmeta(ccode, "kwargs", kwargs); + } + Setfile(ccode, Getfile(fragment)); + Setline(ccode, Getline(fragment)); + /* Replace $descriptor() macros */ + Swig_cparse_replace_descriptor(ccode); + Setattr(fragments, name, ccode); + if (debug) + Printf(stdout, "registering fragment %s %s\n", name, section); + Delete(section); + Delete(ccode); + } + Delete(name); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_fragment_emit() + * + * Emit a fragment + * ----------------------------------------------------------------------------- */ + +static +char *char_index(char *str, char c) { + while (*str && (c != *str)) + ++str; + return (c == *str) ? str : 0; +} + +void Swig_fragment_emit(Node *n) { + String *code; + char *pc, *tok; + String *t; + String *mangle = 0; + String *name = 0; + String *type = 0; + + name = Getattr(n, "value"); + if (!name) { + name = n; + } + + if (!fragments) { + Swig_warning(WARN_FRAGMENT_NOT_FOUND, Getfile(n), Getline(n), "Fragment '%s' not found.\n", name); + return; + } + + type = Getattr(n, "type"); + if (type) { + mangle = Swig_string_mangle(type); + } + + if (debug) + Printf(stdout, "looking fragment %s %s\n", name, type); + t = Copy(name); + tok = Char(t); + pc = char_index(tok, ','); + if (pc) + *pc = 0; + while (tok) { + String *name = NewString(tok); + if (mangle) + Append(name, mangle); + if (looking_fragments && Getattr(looking_fragments, name)) { + return; + } + code = Getattr(fragments, name); + if (debug) + Printf(stdout, "looking subfragment %s\n", name); + if (code && (Strcmp(code, "ignore") != 0)) { + String *section = Getmeta(code, "section"); + Hash *nn = Getmeta(code, "kwargs"); + if (!looking_fragments) + looking_fragments = NewHash(); + Setattr(looking_fragments, name, "1"); + while (nn) { + if (Equal(Getattr(nn, "name"), "fragment")) { + if (debug) + Printf(stdout, "emitting fragment %s %s\n", nn, type); + Setfile(nn, Getfile(n)); + Setline(nn, Getline(n)); + Swig_fragment_emit(nn); + } + nn = nextSibling(nn); + } + if (section) { + File *f = Swig_filebyname(section); + if (!f) { + Swig_error(Getfile(code), Getline(code), "Bad section '%s' in %%fragment declaration for code fragment '%s'\n", section, name); + } else { + if (debug) + Printf(stdout, "emitting subfragment %s %s\n", name, section); + if (debug) + Printf(f, "/* begin fragment %s */\n", name); + Printf(f, "%s\n", code); + if (debug) + Printf(f, "/* end fragment %s */\n\n", name); + Setattr(fragments, name, "ignore"); + Delattr(looking_fragments, name); + } + } + } else if (!code && type) { + SwigType *rtype = SwigType_typedef_resolve_all(type); + if (!Equal(type, rtype)) { + String *name = Copy(Getattr(n, "value")); + String *mangle = Swig_string_mangle(type); + Append(name, mangle); + Setfile(name, Getfile(n)); + Setline(name, Getline(n)); + Swig_fragment_emit(name); + Delete(mangle); + Delete(name); + } + Delete(rtype); + } + + if (!code) { + Swig_warning(WARN_FRAGMENT_NOT_FOUND, Getfile(n), Getline(n), "Fragment '%s' not found.\n", name); + } + tok = pc ? pc + 1 : 0; + if (tok) { + pc = char_index(tok, ','); + if (pc) + *pc = 0; + } + Delete(name); + } + Delete(t); +} diff --git a/contrib/tools/swig/Source/Swig/getopt.c b/contrib/tools/swig/Source/Swig/getopt.c new file mode 100644 index 0000000000..7791d13f72 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/getopt.c @@ -0,0 +1,104 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * getopt.c + * + * Handles the parsing of command line options. This is particularly nasty + * compared to other utilities given that command line options can potentially + * be read by many different modules within SWIG. Thus, in order to make sure + * there are no unrecognized options, each module is required to "mark" + * the options that it uses. Afterwards, we can make a quick scan to make + * sure there are no unmarked options. + * + * TODO: + * Should have cleaner error handling in general. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" + +static char **args; +static int numargs; +static int *marked; + +/* ----------------------------------------------------------------------------- + * Swig_init_args() + * + * Initialize the argument list handler. + * ----------------------------------------------------------------------------- */ + +void Swig_init_args(int argc, char **argv) { + assert(argc > 0); + assert(argv); + + numargs = argc; + args = argv; + marked = (int *) Calloc(numargs, sizeof(int)); + marked[0] = 1; +} + +/* ----------------------------------------------------------------------------- + * Swig_mark_arg() + * + * Marks an argument as being parsed. + * ----------------------------------------------------------------------------- */ + +void Swig_mark_arg(int n) { + assert(marked); + assert((n >= 0) && (n < numargs)); + marked[n] = 1; +} + +/* ----------------------------------------------------------------------------- + * Swig_check_marked() + * + * Checks to see if argument has been picked up. + * ----------------------------------------------------------------------------- */ + +int Swig_check_marked(int n) { + assert((n >= 0) && (n < numargs)); + return marked[n]; +} + +/* ----------------------------------------------------------------------------- + * Swig_check_options() + * + * Checkers for unprocessed command line options and errors. + * ----------------------------------------------------------------------------- */ + +void Swig_check_options(int check_input) { + int error = 0; + int i; + int max = check_input ? numargs - 1 : numargs; + assert(marked); + for (i = 1; i < max; i++) { + if (!marked[i]) { + Printf(stderr, "swig error : Unrecognized option %s\n", args[i]); + error = 1; + } + } + if (error) { + Printf(stderr, "Use 'swig -help' for available options.\n"); + Exit(EXIT_FAILURE); + } + if (check_input && marked[numargs - 1]) { + Printf(stderr, "Must specify an input file. Use -help for available options.\n"); + Exit(EXIT_FAILURE); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_arg_error() + * + * Generates a generic error message and exits. + * ----------------------------------------------------------------------------- */ + +void Swig_arg_error(void) { + Printf(stderr, "SWIG : Unable to parse command line options.\n"); + Printf(stderr, "Use 'swig -help' for available options.\n"); + Exit(EXIT_FAILURE); +} diff --git a/contrib/tools/swig/Source/Swig/include.c b/contrib/tools/swig/Source/Swig/include.c new file mode 100644 index 0000000000..c153ac9b7a --- /dev/null +++ b/contrib/tools/swig/Source/Swig/include.c @@ -0,0 +1,377 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * include.c + * + * The functions in this file are used to manage files in the SWIG library. + * General purpose functions for opening, including, and retrieving pathnames + * are provided. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" + +static List *directories = 0; /* List of include directories */ +static String *lastpath = 0; /* Last file that was included */ +static List *pdirectories = 0; /* List of pushed directories */ +static int dopush = 1; /* Whether to push directories */ +static int file_debug = 0; + +/* This functions determine whether to push/pop dirs in the preprocessor */ +void Swig_set_push_dir(int push) { + dopush = push; +} + +int Swig_get_push_dir(void) { + return dopush; +} + +/* ----------------------------------------------------------------------------- + * Swig_add_directory() + * + * Adds a directory to the SWIG search path. + * ----------------------------------------------------------------------------- */ + +List *Swig_add_directory(const_String_or_char_ptr dirname) { + String *adirname; + if (!directories) + directories = NewList(); + assert(directories); + if (dirname) { + adirname = NewString(dirname); + Append(directories,adirname); + Delete(adirname); + } + return directories; +} + +/* ----------------------------------------------------------------------------- + * Swig_push_directory() + * + * Inserts a directory at the front of the SWIG search path. This is used by + * the preprocessor to grab files in the same directory as other included files. + * ----------------------------------------------------------------------------- */ + +void Swig_push_directory(const_String_or_char_ptr dirname) { + String *pdirname; + if (!Swig_get_push_dir()) + return; + if (!pdirectories) + pdirectories = NewList(); + assert(pdirectories); + pdirname = NewString(dirname); + assert(pdirname); + Insert(pdirectories,0,pdirname); + Delete(pdirname); +} + +/* ----------------------------------------------------------------------------- + * Swig_pop_directory() + * + * Pops a directory off the front of the SWIG search path. This is used by + * the preprocessor. + * ----------------------------------------------------------------------------- */ + +void Swig_pop_directory(void) { + if (!Swig_get_push_dir()) + return; + if (!pdirectories) + return; + Delitem(pdirectories, 0); +} + +/* ----------------------------------------------------------------------------- + * Swig_last_file() + * + * Returns the full pathname of the last file opened. + * ----------------------------------------------------------------------------- */ + +String *Swig_last_file(void) { + assert(lastpath); + return lastpath; +} + +/* ----------------------------------------------------------------------------- + * Swig_search_path_any() + * + * Returns a list of the current search paths. + * ----------------------------------------------------------------------------- */ + +static List *Swig_search_path_any(int syspath) { + String *filename; + List *slist; + int i, ilen; + + slist = NewList(); + assert(slist); + filename = NewStringEmpty(); + assert(filename); + Printf(filename, ".%s", SWIG_FILE_DELIMITER); + Append(slist, filename); + Delete(filename); + + /* If there are any pushed directories. Add them first */ + if (pdirectories) { + ilen = Len(pdirectories); + for (i = 0; i < ilen; i++) { + filename = NewString(Getitem(pdirectories,i)); + Append(filename,SWIG_FILE_DELIMITER); + Append(slist,filename); + Delete(filename); + } + } + /* Add system directories next */ + ilen = Len(directories); + for (i = 0; i < ilen; i++) { + filename = NewString(Getitem(directories,i)); + Append(filename,SWIG_FILE_DELIMITER); + if (syspath) { + /* If doing a system include, put the system directories first */ + Insert(slist,i,filename); + } else { + /* Otherwise, just put the system directories after the pushed directories (if any) */ + Append(slist,filename); + } + Delete(filename); + } + return slist; +} + +List *Swig_search_path(void) { + return Swig_search_path_any(0); +} + + + +/* ----------------------------------------------------------------------------- + * Swig_open() + * + * open a file, optionally looking for it in the include path. Returns an open + * FILE * on success. + * ----------------------------------------------------------------------------- */ + +static FILE *Swig_open_file(const_String_or_char_ptr name, int sysfile, int use_include_path) { + FILE *f; + String *filename; + List *spath = 0; + char *cname; + int i, ilen, nbytes; + char bom[3]; + + if (!directories) + directories = NewList(); + assert(directories); + + cname = Char(name); + filename = NewString(cname); + assert(filename); + if (file_debug) { + Printf(stdout, " Open: %s\n", filename); + } + f = fopen(Char(filename), "r"); + if (!f && use_include_path) { + spath = Swig_search_path_any(sysfile); + ilen = Len(spath); + for (i = 0; i < ilen; i++) { + Clear(filename); + Printf(filename, "%s%s", Getitem(spath, i), cname); + f = fopen(Char(filename), "r"); + if (f) + break; + } + Delete(spath); + } + if (f) { + Delete(lastpath); + lastpath = filename; + + /* Skip the UTF-8 BOM if it's present */ + nbytes = (int)fread(bom, 1, 3, f); + if (nbytes == 3 && bom[0] == (char)0xEF && bom[1] == (char)0xBB && bom[2] == (char)0xBF) { + /* skip */ + } else { + fseek(f, 0, SEEK_SET); + } + } + return f; +} + +/* Open a file - searching the include paths to find it */ +FILE *Swig_include_open(const_String_or_char_ptr name) { + return Swig_open_file(name, 0, 1); +} + +/* Open a file - does not use include paths to find it */ +FILE *Swig_open(const_String_or_char_ptr name) { + return Swig_open_file(name, 0, 0); +} + + + +/* ----------------------------------------------------------------------------- + * Swig_read_file() + * + * Reads data from an open FILE * and returns it as a string. + * ----------------------------------------------------------------------------- */ + +String *Swig_read_file(FILE *f) { + int len; + char buffer[4096]; + String *str = NewStringEmpty(); + + assert(str); + while (fgets(buffer, 4095, f)) { + Append(str, buffer); + } + len = Len(str); + /* Add a newline if not present on last line -- the preprocessor seems to + * rely on \n and not EOF terminating lines */ + if (len) { + char *cstr = Char(str); + if (cstr[len - 1] != '\n') { + Append(str, "\n"); + } + } + return str; +} + +/* ----------------------------------------------------------------------------- + * Swig_include() + * + * Opens a file and returns it as a string. + * ----------------------------------------------------------------------------- */ + +static String *Swig_include_any(const_String_or_char_ptr name, int sysfile) { + FILE *f; + String *str; + String *file; + + f = Swig_open_file(name, sysfile, 1); + if (!f) + return 0; + str = Swig_read_file(f); + fclose(f); + Seek(str, 0, SEEK_SET); + file = Copy(Swig_last_file()); + Setfile(str, file); + Delete(file); + Setline(str, 1); + return str; +} + +String *Swig_include(const_String_or_char_ptr name) { + return Swig_include_any(name, 0); +} + +String *Swig_include_sys(const_String_or_char_ptr name) { + return Swig_include_any(name, 1); +} + +/* ----------------------------------------------------------------------------- + * Swig_insert_file() + * + * Copies the contents of a file into another file + * ----------------------------------------------------------------------------- */ + +int Swig_insert_file(const_String_or_char_ptr filename, File *outfile) { + char buffer[4096]; + int nbytes; + FILE *f = Swig_include_open(filename); + + if (!f) + return -1; + while ((nbytes = Read(f, buffer, 4096)) > 0) { + Write(outfile, buffer, nbytes); + } + fclose(f); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_register_filebyname() + * + * Register a "named" file with the core. Named files can become targets + * for %insert directives and other SWIG operations. This function takes + * the place of the f_header, f_wrapper, f_init, and other global variables + * in SWIG1.1 + * ----------------------------------------------------------------------------- */ + +static Hash *named_files = 0; + +void Swig_register_filebyname(const_String_or_char_ptr filename, File *outfile) { + if (!named_files) + named_files = NewHash(); + Setattr(named_files, filename, outfile); +} + +/* ----------------------------------------------------------------------------- + * Swig_filebyname() + * + * Get a named file + * ----------------------------------------------------------------------------- */ + +File *Swig_filebyname(const_String_or_char_ptr filename) { + if (!named_files) + return 0; + return Getattr(named_files, filename); +} + +/* ----------------------------------------------------------------------------- + * Swig_file_extension() + * + * Returns the extension of a file + * ----------------------------------------------------------------------------- */ + +String *Swig_file_extension(const_String_or_char_ptr filename) { + String *name = Swig_file_filename(filename); + const char *c = strrchr(Char(name), '.'); + String *extension = c ? NewString(c) : NewString(""); + Delete(name); + return extension; +} + +/* ----------------------------------------------------------------------------- + * Swig_file_basename() + * + * Returns the filename with the extension removed. + * ----------------------------------------------------------------------------- */ + +String *Swig_file_basename(const_String_or_char_ptr filename) { + String *extension = Swig_file_extension(filename); + String *basename = NewStringWithSize(filename, Len(filename) - Len(extension)); + Delete(extension); + return basename; +} + +/* ----------------------------------------------------------------------------- + * Swig_file_filename() + * + * Return the file name with any leading path stripped off + * ----------------------------------------------------------------------------- */ +String *Swig_file_filename(const_String_or_char_ptr filename) { + const char *delim = SWIG_FILE_DELIMITER; + const char *c = strrchr(Char(filename), *delim); + return c ? NewString(c + 1) : NewString(filename); +} + +/* ----------------------------------------------------------------------------- + * Swig_file_dirname() + * + * Return the name of the directory associated with a file + * ----------------------------------------------------------------------------- */ +String *Swig_file_dirname(const_String_or_char_ptr filename) { + const char *delim = SWIG_FILE_DELIMITER; + const char *c = strrchr(Char(filename), *delim); + return c ? NewStringWithSize(filename, (int)(c - Char(filename) + 1)) : NewString(""); +} + +/* + * Swig_file_debug() + */ +void Swig_file_debug_set(void) { + file_debug = 1; +} diff --git a/contrib/tools/swig/Source/Swig/misc.c b/contrib/tools/swig/Source/Swig/misc.c new file mode 100644 index 0000000000..7d1119c5e2 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/misc.c @@ -0,0 +1,1569 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * misc.c + * + * Miscellaneous functions that don't really fit anywhere else. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include <errno.h> +#include <ctype.h> +#include <limits.h> +#include <sys/types.h> +#include <sys/stat.h> + +#ifdef _WIN32 +#include <direct.h> +#ifndef S_ISDIR +#define S_ISDIR(mode) (((mode) & S_IFDIR) == S_IFDIR) +#endif +#endif + +static char *fake_version = 0; + +/* ----------------------------------------------------------------------------- + * Swig_copy_string() + * + * Duplicate a NULL-terminate string given as a char *. + * ----------------------------------------------------------------------------- */ + +char *Swig_copy_string(const char *s) { + char *c = 0; + if (s) { + c = (char *) Malloc(strlen(s) + 1); + strcpy(c, s); + } + return c; +} + +/* ----------------------------------------------------------------------------- + * Swig_set_fakeversion() + * + * Version string override + * ----------------------------------------------------------------------------- */ + +void Swig_set_fakeversion(const char *version) { + fake_version = Swig_copy_string(version); +} + +/* ----------------------------------------------------------------------------- + * Swig_package_version() + * + * Return the package string containing the version number + * ----------------------------------------------------------------------------- */ + +const char *Swig_package_version(void) { + return fake_version ? fake_version : PACKAGE_VERSION; +} + +/* ----------------------------------------------------------------------------- + * Swig_package_version_hex() + * + * Return the package version in hex format "0xAABBCC" such as "0x040200" for 4.2.0 + * ----------------------------------------------------------------------------- */ + +String *Swig_package_version_hex(void) { + String *package_version = NewString(Swig_package_version()); + char *token = strtok(Char(package_version), "."); + String *vers = NewString("SWIG_VERSION 0x"); + int count = 0; + while (token) { + int len = (int)strlen(token); + assert(len == 1 || len == 2); + Printf(vers, "%s%s", (len == 1) ? "0" : "", token); + token = strtok(NULL, "."); + count++; + } + Delete(package_version); + assert(count == 3); /* Check version format is correct */ + return vers; +} + +/* ----------------------------------------------------------------------------- + * Swig_obligatory_macros() + * + * Generates the SWIG_VERSION and SWIGXXX macros where XXX is the target language + * name (must be provided uppercase). + * ----------------------------------------------------------------------------- */ + +void Swig_obligatory_macros(String *f_runtime, const char *language) { + String *version_hex = Swig_package_version_hex(); + Printf(f_runtime, "\n\n"); + Printf(f_runtime, "#define %s\n", version_hex); + Printf(f_runtime, "#define SWIG%s\n", language); + Delete(version_hex); +} + +/* ----------------------------------------------------------------------------- + * Swig_banner() + * + * Emits the SWIG identifying banner for the C/C++ wrapper file. + * ----------------------------------------------------------------------------- */ + +void Swig_banner(File *f) { + Printf(f, "/* ----------------------------------------------------------------------------\n"); + Swig_banner_target_lang(f, " *"); + Printf(f, " * ----------------------------------------------------------------------------- */\n"); + +} + +/* ----------------------------------------------------------------------------- + * Swig_banner_target_lang() + * + * Emits a SWIG identifying banner in the target language + * ----------------------------------------------------------------------------- */ + +void Swig_banner_target_lang(File *f, const_String_or_char_ptr commentchar) { + Printf(f, "%s This file was automatically generated by SWIG (https://www.swig.org).\n", commentchar); + Printf(f, "%s Version %s\n", commentchar, Swig_package_version()); + Printf(f, "%s\n", commentchar); + Printf(f, "%s Do not make changes to this file unless you know what you are doing - modify\n", commentchar); + Printf(f, "%s the SWIG interface file instead.\n", commentchar); +} + +/* ----------------------------------------------------------------------------- + * Swig_strip_c_comments() + * + * Return a new string with C comments stripped from the input string. NULL is + * returned if there aren't any comments. + * ----------------------------------------------------------------------------- */ + +String *Swig_strip_c_comments(const String *s) { + const char *c = Char(s); + const char *comment_begin = 0; + const char *comment_end = 0; + String *stripped = 0; + + while (*c) { + if (!comment_begin && *c == '/') { + ++c; + if (!*c) + break; + if (*c == '*') + comment_begin = c-1; + } else if (comment_begin && !comment_end && *c == '*') { + ++c; + if (*c == '/') { + comment_end = c; + break; + } + } + ++c; + } + + if (comment_begin && comment_end) { + int size = (int)(comment_begin - Char(s)); + String *stripmore = 0; + stripped = NewStringWithSize(s, size); + Printv(stripped, comment_end + 1, NIL); + do { + stripmore = Swig_strip_c_comments(stripped); + if (stripmore) { + Delete(stripped); + stripped = stripmore; + } + } while (stripmore); + } + return stripped; +} + +/* ----------------------------------------------------------------------------- + * is_directory() + * ----------------------------------------------------------------------------- */ +static int is_directory(String *directory) { + int last = Len(directory) - 1; + int statres; + struct stat st; + char *dir = Char(directory); + if (dir[last] == SWIG_FILE_DELIMITER[0]) { + /* remove trailing slash - can cause S_ISDIR to fail on Windows, at least */ + dir[last] = 0; + statres = stat(dir, &st); + dir[last] = SWIG_FILE_DELIMITER[0]; + } else { + statres = stat(dir, &st); + } + return (statres == 0 && S_ISDIR(st.st_mode)); +} + +/* ----------------------------------------------------------------------------- + * Swig_new_subdirectory() + * + * Create the subdirectory only if the basedirectory already exists as a directory. + * basedirectory can be empty to indicate current directory but not NULL. + * ----------------------------------------------------------------------------- */ + +String *Swig_new_subdirectory(String *basedirectory, String *subdirectory) { + String *error = 0; + int current_directory = Len(basedirectory) == 0; + + if (current_directory || is_directory(basedirectory)) { + Iterator it; + String *dir = NewString(basedirectory); + List *subdirs = Split(subdirectory, SWIG_FILE_DELIMITER[0], INT_MAX); + + for (it = First(subdirs); it.item; it = Next(it)) { + int result; + String *subdirectory = it.item; + Printf(dir, "%s", subdirectory); +#ifdef _WIN32 + result = _mkdir(Char(dir)); +#else + result = mkdir(Char(dir), 0777); +#endif + if (result != 0 && errno != EEXIST) { + error = NewStringf("Cannot create directory %s: %s", dir, strerror(errno)); + break; + } + if (!is_directory(dir)) { + error = NewStringf("Cannot create directory %s: it may already exist but not be a directory", dir); + break; + } + Printf(dir, SWIG_FILE_DELIMITER); + } + } else { + error = NewStringf("Cannot create subdirectory %s under the base directory %s. Either the base does not exist as a directory or it is not readable.", subdirectory, basedirectory); + } + return error; +} + +/* ----------------------------------------------------------------------------- + * Swig_filename_correct() + * + * Corrects filename paths by removing duplicate delimiters and on non-unix + * systems use the correct delimiter across the whole name. + * ----------------------------------------------------------------------------- */ + +void Swig_filename_correct(String *filename) { + int network_path = 0; + if (Len(filename) >= 2) { + const char *fname = Char(filename); + if (fname[0] == '\\' && fname[1] == '\\') + network_path = 1; + if (fname[0] == '/' && fname[1] == '/') + network_path = 1; + } +#if defined(_WIN32) + /* accept Unix path separator on non-Unix systems */ + Replaceall(filename, "/", SWIG_FILE_DELIMITER); +#endif +#if defined(__CYGWIN__) + /* accept Windows path separator in addition to Unix path separator */ + Replaceall(filename, "\\", SWIG_FILE_DELIMITER); +#endif + /* remove all duplicate file name delimiters */ + while (Replaceall(filename, SWIG_FILE_DELIMITER SWIG_FILE_DELIMITER, SWIG_FILE_DELIMITER)) { + } + /* Network paths can start with a double slash on Windows - unremove the duplicate slash we just removed */ + if (network_path) + Insert(filename, 0, SWIG_FILE_DELIMITER); +} + +/* ----------------------------------------------------------------------------- + * Swig_filename_escape() + * + * Escapes backslashes in filename - for Windows + * ----------------------------------------------------------------------------- */ + +String *Swig_filename_escape(String *filename) { + String *adjusted_filename = Copy(filename); + Swig_filename_correct(adjusted_filename); +#if defined(_WIN32) /* Note not on Cygwin else filename is displayed with double '/' */ + Replaceall(adjusted_filename, "\\", "\\\\"); +#endif + return adjusted_filename; +} + +/* ----------------------------------------------------------------------------- + * Swig_filename_escape() + * + * Escapes spaces in filename - for Makefiles + * ----------------------------------------------------------------------------- */ + +String *Swig_filename_escape_space(String *filename) { + String *adjusted_filename = Copy(filename); + Swig_filename_correct(adjusted_filename); + Replaceall(adjusted_filename, " ", "\\ "); + return adjusted_filename; +} + +/* ----------------------------------------------------------------------------- + * Swig_filename_unescape() + * + * Remove double backslash escaping in filename - for Windows + * ----------------------------------------------------------------------------- */ + +void Swig_filename_unescape(String *filename) { + (void)filename; +#if defined(_WIN32) + Replaceall(filename, "\\\\", "\\"); +#endif +} + +/* ----------------------------------------------------------------------------- + * Swig_storage_isextern() + * + * Determine if the storage class specifier is extern (but not externc) + * ----------------------------------------------------------------------------- */ + +int Swig_storage_isextern(Node *n) { + const String *storage = Getattr(n, "storage"); + return storage ? Strcmp(storage, "extern") == 0 || Strncmp(storage, "extern ", 7) == 0 : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_storage_isexternc() + * + * Determine if the storage class specifier is externc (but not plain extern) + * ----------------------------------------------------------------------------- */ + +int Swig_storage_isexternc(Node *n) { + const String *storage = Getattr(n, "storage"); + return storage ? Strcmp(storage, "externc") == 0 || Strncmp(storage, "externc ", 8) == 0 : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_storage_isstatic_custom() + * + * Determine if the storage class specifier is static + * ----------------------------------------------------------------------------- */ + +int Swig_storage_isstatic_custom(Node *n, const_String_or_char_ptr storage_name) { + const String *storage = Getattr(n, storage_name); + return storage ? Strncmp(storage, "static", 6) == 0 : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_storage_isstatic() + * + * Determine if the storage class specifier is static + * ----------------------------------------------------------------------------- */ + +int Swig_storage_isstatic(Node *n) { + return Swig_storage_isstatic_custom(n, "storage"); +} + +/* ----------------------------------------------------------------------------- + * Swig_string_escape() + * + * Takes a string object and produces a string with escape codes added to it. + * Octal escaping is used. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_escape(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + while ((c = Getc(s)) != EOF) { + if (c == '\n') { + Printf(ns, "\\n"); + } else if (c == '\r') { + Printf(ns, "\\r"); + } else if (c == '\t') { + Printf(ns, "\\t"); + } else if (c == '\\') { + Printf(ns, "\\\\"); + } else if (c == '\'') { + Printf(ns, "\\'"); + } else if (c == '\"') { + Printf(ns, "\\\""); + } else if (c == ' ') { + Putc(c, ns); + } else if (!isgraph(c)) { + if (c < 0) + c += UCHAR_MAX + 1; + Printf(ns, "\\%o", c); + } else { + Putc(c, ns); + } + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_hexescape() + * + * Takes a string object and produces a string with escape codes added to it. + * Hex escaping is used. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_hexescape(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + while ((c = Getc(s)) != EOF) { + if (c == '\n') { + Printf(ns, "\\n"); + } else if (c == '\r') { + Printf(ns, "\\r"); + } else if (c == '\t') { + Printf(ns, "\\t"); + } else if (c == '\\') { + Printf(ns, "\\\\"); + } else if (c == '\'') { + Printf(ns, "\\'"); + } else if (c == '\"') { + Printf(ns, "\\\""); + } else if (c == ' ') { + Putc(c, ns); + } else if (!isgraph(c)) { + if (c < 0) + c += UCHAR_MAX + 1; + Printf(ns, "\\x%X", c); + } else { + Putc(c, ns); + } + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_upper() + * + * Takes a string object and returns a copy that is uppercase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_upper(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + Putc(toupper(c), ns); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_lower() + * + * Takes a string object and returns a copy that is lowercase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_lower(String *s) { + String *ns; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + Putc(tolower(c), ns); + } + return ns; +} + + +/* ----------------------------------------------------------------------------- + * Swig_string_title() + * + * Takes a string object and returns a copy that is lowercase with first letter + * capitalized + * ----------------------------------------------------------------------------- */ + +String *Swig_string_title(String *s) { + String *ns; + int first = 1; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + Putc(first ? toupper(c) : tolower(c), ns); + first = 0; + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_ccase() + * + * Takes a string object and returns a copy that is lowercase with the first + * letter capitalized and the one following '_', which are removed. + * + * camel_case -> CamelCase + * camelCase -> CamelCase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_ccase(String *s) { + String *ns; + int first = 1; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + if (c == '_') { + first = 1; + continue; + } + Putc(first ? toupper(c) : c, ns); + first = 0; + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_lccase() + * + * Takes a string object and returns a copy with the character after + * each '_' capitalised, and the '_' removed. The first character is + * also forced to lowercase. + * + * camel_case -> camelCase + * CamelCase -> camelCase + * ----------------------------------------------------------------------------- */ + +String *Swig_string_lccase(String *s) { + String *ns; + int first = 1; + int after_underscore = 0; + int c; + ns = NewStringEmpty(); + + Seek(s, 0, SEEK_SET); + while ((c = Getc(s)) != EOF) { + if (c == '_') { + after_underscore = 1; + continue; + } + if (first) { + Putc(tolower(c), ns); + first = 0; + } else { + Putc(after_underscore ? toupper(c) : c, ns); + } + after_underscore = 0; + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_ucase() + * + * This is the reverse case of ccase, ie + * + * CamelCase -> camel_case + * get2D -> get_2d + * asFloat2 -> as_float2 + * ----------------------------------------------------------------------------- */ + +String *Swig_string_ucase(String *s) { + String *ns; + int c; + int lastC = 0; + int nextC = 0; + int underscore = 0; + ns = NewStringEmpty(); + + /* We insert a underscore when: + 1. Lower case char followed by upper case char + getFoo > get_foo; getFOo > get_foo; GETFOO > getfoo + 2. Number preceded by char and not end of string + get2D > get_2d; get22D > get_22d; GET2D > get_2d + but: + asFloat2 > as_float2 + */ + + Seek(s, 0, SEEK_SET); + + while ((c = Getc(s)) != EOF) { + nextC = Getc(s); Ungetc(nextC, s); + if (isdigit(c) && isalpha(lastC) && nextC != EOF) + underscore = 1; + else if (isupper(c) && isalpha(lastC) && !isupper(lastC)) + underscore = 1; + + lastC = c; + + if (underscore) { + Putc('_', ns); + underscore = 0; + } + + Putc(tolower(c), ns); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_first_upper() + * + * Make the first character in the string uppercase, leave all the + * rest the same. This is used by the Ruby module to provide backwards + * compatibility with the old way of naming classes and constants. For + * more info see the Ruby documentation. + * + * firstUpper -> FirstUpper + * ----------------------------------------------------------------------------- */ + +String *Swig_string_first_upper(String *s) { + String *ns = NewStringEmpty(); + char *cs = Char(s); + if (cs && cs[0] != 0) { + Putc(toupper((int)cs[0]), ns); + Append(ns, cs + 1); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_first_lower() + * + * Make the first character in the string lowercase, leave all the + * rest the same. This is used by the Ruby module to provide backwards + * compatibility with the old way of naming classes and constants. For + * more info see the Ruby documentation. + * + * firstLower -> FirstLower + * ----------------------------------------------------------------------------- */ + +String *Swig_string_first_lower(String *s) { + String *ns = NewStringEmpty(); + char *cs = Char(s); + if (cs && cs[0] != 0) { + Putc(tolower((int)cs[0]), ns); + Append(ns, cs + 1); + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_schemify() + * + * Replace underscores with dashes, to make identifiers look nice to Schemers. + * + * under_scores -> under-scores + * ----------------------------------------------------------------------------- */ + +String *Swig_string_schemify(String *s) { + String *ns = NewString(s); + Replaceall(ns, "_", "-"); + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_typecode() + * + * Takes a string with possible type-escapes in it and replaces them with + * real C datatypes. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_typecode(String *s) { + String *ns; + int c; + String *tc; + ns = NewStringEmpty(); + while ((c = Getc(s)) != EOF) { + if (c == '`') { + String *str = 0; + tc = NewStringEmpty(); + while ((c = Getc(s)) != EOF) { + if (c == '`') + break; + Putc(c, tc); + } + str = SwigType_str(tc, 0); + Append(ns, str); + Delete(str); + } else { + Putc(c, ns); + if (c == '\'') { + while ((c = Getc(s)) != EOF) { + Putc(c, ns); + if (c == '\'') + break; + if (c == '\\') { + c = Getc(s); + Putc(c, ns); + } + } + } else if (c == '\"') { + while ((c = Getc(s)) != EOF) { + Putc(c, ns); + if (c == '\"') + break; + if (c == '\\') { + c = Getc(s); + Putc(c, ns); + } + } + } + } + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_mangle() + * + * Take a string and mangle it by stripping all non-valid C identifier + * characters. + * + * This routine skips unnecessary blank spaces, therefore mangling + * 'char *' and 'char*', 'std::pair<int, int >' and + * 'std::pair<int,int>', produce the same result. + * + * However, note that 'long long' and 'long_long' produce different + * mangled strings. + * + * The mangling method still is not 'perfect', for example std::pair and + * std_pair return the same mangling. This is just a little better + * than before, but it seems to be enough for most of the purposes. + * + * Having a perfect mangling will break some examples and code which + * assume, for example, that A::get_value will be mangled as + * A_get_value. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_mangle(const String *s) { +#if 0 + /* old mangling, not suitable for using in macros */ + String *t = Copy(s); + char *c = Char(t); + while (*c) { + if (!isalnum(*c)) + *c = '_'; + c++; + } + return t; +#else + String *result = NewStringEmpty(); + int space = 0; + int state = 0; + char *pc, *cb; + String *b = Copy(s); + if (SwigType_istemplate(b)) { + String *st = Swig_symbol_template_deftype(b, 0); + String *sq = Swig_symbol_type_qualify(st, 0); + String *t = SwigType_namestr(sq); + Delete(st); + Delete(sq); + Delete(b); + b = t; + } + pc = cb = Char(b); + while (*pc) { + char c = *pc; + if (isalnum((int) c) || (c == '_')) { + state = 1; + if (space && (space == state)) { + Append(result, "_SS_"); + } + space = 0; + Printf(result, "%c", (int) c); + + } else { + if (isspace((int) c)) { + space = state; + ++pc; + continue; + } else { + state = 3; + space = 0; + } + switch (c) { + case '.': + if ((cb != pc) && (*(pc - 1) == 'p')) { + Append(result, "_"); + ++pc; + continue; + } else { + c = 'f'; + } + break; + case ':': + if (*(pc + 1) == ':') { + Append(result, "_"); + ++pc; + ++pc; + continue; + } + break; + case '*': + c = 'm'; + break; + case '&': + c = 'A'; + break; + case '<': + c = 'l'; + break; + case '>': + c = 'g'; + break; + case '=': + c = 'e'; + break; + case ',': + c = 'c'; + break; + case '(': + c = 'p'; + break; + case ')': + c = 'P'; + break; + case '[': + c = 'b'; + break; + case ']': + c = 'B'; + break; + case '^': + c = 'x'; + break; + case '|': + c = 'o'; + break; + case '~': + c = 'n'; + break; + case '!': + c = 'N'; + break; + case '%': + c = 'M'; + break; + case '?': + c = 'q'; + break; + case '+': + c = 'a'; + break; + case '-': + c = 's'; + break; + case '/': + c = 'd'; + break; + default: + break; + } + if (isalpha((int) c)) { + Printf(result, "_S%c_", (int) c); + } else { + Printf(result, "_S%02X_", (int) c); + } + } + ++pc; + } + Delete(b); + return result; +#endif +} + +String *Swig_string_emangle(String *s) { + return Swig_string_mangle(s); +} + + +/* ----------------------------------------------------------------------------- + * Swig_scopename_split() + * + * Take a qualified name like "A::B::C" and splits off the last name. + * In this case, returns "C" as last and "A::B" as prefix. + * Always returns non NULL for last, but prefix may be NULL if there is no prefix. + * ----------------------------------------------------------------------------- */ + +void Swig_scopename_split(const String *s, String **rprefix, String **rlast) { + char *tmp = Char(s); + char *c = tmp; + char *cc = c; + char *co = 0; + if (!strstr(c, "::")) { + *rprefix = 0; + *rlast = Copy(s); + } + + co = strstr(cc, "operator "); + if (co) { + if (co == cc) { + *rprefix = 0; + *rlast = Copy(s); + return; + } else { + *rprefix = NewStringWithSize(cc, (int)(co - cc - 2)); + *rlast = NewString(co); + return; + } + } + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + cc = c; + c += 2; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + + if (cc != tmp) { + *rprefix = NewStringWithSize(tmp, (int)(cc - tmp)); + *rlast = NewString(cc + 2); + return; + } else { + *rprefix = 0; + *rlast = Copy(s); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_prefix() + * + * Take a qualified name like "A::B::C" and return the scope name. + * In this case, "A::B". Returns NULL if there is no base. + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_prefix(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *cc = c; + char *co = 0; + if (!strstr(c, "::")) + return 0; + co = strstr(cc, "operator "); + + if (co) { + if (co == cc) { + return 0; + } else { + String *prefix = NewStringWithSize(cc, (int)(co - cc - 2)); + return prefix; + } + } + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + cc = c; + c += 2; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + + if (cc != tmp) { + return NewStringWithSize(tmp, (int)(cc - tmp)); + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_last() + * + * Take a qualified name like "A::B::C" and returns the last. In this + * case, "C". + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_last(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *cc = c; + char *co = 0; + if (!strstr(c, "::")) + return NewString(s); + + co = strstr(cc, "operator "); + if (co) { + return NewString(co); + } + + + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + c += 2; + cc = c; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + return NewString(cc); +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_first() + * + * Take a qualified name like "A::B::C" and returns the first scope name. + * In this case, "A". Returns NULL if there is no base. + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_first(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *co = 0; + if (!strstr(c, "::")) + return 0; + + co = strstr(c, "operator "); + if (co) { + if (co == c) { + return 0; + } + } else { + co = c + Len(s); + } + + while (*c && (c != co)) { + if ((*c == ':') && (*(c + 1) == ':')) { + break; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + if (*c && (c != tmp)) { + return NewStringWithSize(tmp, (int)(c - tmp)); + } else { + return 0; + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_scopename_suffix() + * + * Take a qualified name like "A::B::C" and returns the suffix. + * In this case, "B::C". Returns NULL if there is no suffix. + * ----------------------------------------------------------------------------- */ + +String *Swig_scopename_suffix(const String *s) { + char *tmp = Char(s); + char *c = tmp; + char *co = 0; + if (!strstr(c, "::")) + return 0; + + co = strstr(c, "operator "); + if (co) { + if (co == c) + return 0; + } + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + break; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + if (*c && (c != tmp)) { + return NewString(c + 2); + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_tolist() + * + * Take a qualified scope name like "A::B::C" and convert it to a list. + * In this case, return a list of 3 elements "A", "B", "C". + * Returns an empty list if the input is empty. + * ----------------------------------------------------------------------------- */ + +List *Swig_scopename_tolist(const String *s) { + List *scopes = NewList(); + String *name = Len(s) == 0 ? 0 : NewString(s); + + while (name) { + String *last = 0; + String *prefix = 0; + Swig_scopename_split(name, &prefix, &last); + Insert(scopes, 0, last); + Delete(last); + Delete(name); + name = prefix; + } + Delete(name); + return scopes; +} + +/* ----------------------------------------------------------------------------- + * Swig_scopename_check() + * + * Checks to see if a name is qualified with a scope name, examples: + * foo -> 0 + * ::foo -> 1 + * foo::bar -> 1 + * foo< ::bar > -> 0 + * ----------------------------------------------------------------------------- */ + +int Swig_scopename_check(const String *s) { + char *c = Char(s); + char *co = strstr(c, "operator "); + + if (co) { + if (co == c) + return 0; + } + if (!strstr(c, "::")) + return 0; + while (*c) { + if ((*c == ':') && (*(c + 1) == ':')) { + return 1; + } else { + if (*c == '<') { + int level = 1; + c++; + while (*c && level) { + if (*c == '<') + level++; + if (*c == '>') + level--; + c++; + } + } else { + c++; + } + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_command() + * + * Feature removed in SWIG 4.1.0. + * ----------------------------------------------------------------------------- */ + +String *Swig_string_command(String *s) { + Swig_error("SWIG", Getline(s), "Command encoder no longer supported - use regex encoder instead.\n"); + Exit(EXIT_FAILURE); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_strip() + * + * Strip given prefix from identifiers + * + * Printf(stderr,"%(strip:[wx])s","wxHello") -> Hello + * ----------------------------------------------------------------------------- */ + +String *Swig_string_strip(String *s) { + String *ns; + if (!Len(s)) { + ns = NewString(s); + } else { + const char *cs = Char(s); + const char *ce = Strchr(cs, ']'); + if (*cs != '[' || !ce) { + ns = NewString(s); + } else { + String *fmt = NewStringf("%%.%ds", ce-cs-1); + String *prefix = NewStringf(fmt, cs+1); + if (0 == Strncmp(ce+1, prefix, Len(prefix))) { + ns = NewString(ce+1+Len(prefix)); + } else { + ns = NewString(ce+1); + } + } + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_rstrip() + * + * Strip given suffix from identifiers + * + * Printf(stderr,"%(rstrip:[Cls])s","HelloCls") -> Hello + * ----------------------------------------------------------------------------- */ + +String *Swig_string_rstrip(String *s) { + String *ns; + int len = Len(s); + if (!len) { + ns = NewString(s); + } else { + const char *cs = Char(s); + const char *ce = Strchr(cs, ']'); + if (*cs != '[' || !ce) { + ns = NewString(s); + } else { + String *fmt = NewStringf("%%.%ds", ce-cs-1); + String *suffix = NewStringf(fmt, cs+1); + int suffix_len = Len(suffix); + if (0 == Strncmp(cs+len-suffix_len, suffix, suffix_len)) { + int copy_len = len-suffix_len-(int)(ce+1-cs); + ns = NewStringWithSize(ce+1, copy_len); + } else { + ns = NewString(ce+1); + } + } + } + return ns; +} + +/* ----------------------------------------------------------------------------- + * Swig_offset_string() + * + * Insert number tabs before each new line in s + * ----------------------------------------------------------------------------- */ + +void Swig_offset_string(String *s, int number) { + char *res, *p, *end, *start; + /* count a number of lines in s */ + int lines = 1; + int len = Len(s); + if (len == 0) + return; + start = strchr(Char(s), '\n'); + while (start) { + ++lines; + start = strchr(start + 1, '\n'); + } + /* do not count pending new line */ + if ((Char(s))[len-1] == '\n') + --lines; + /* allocate a temporary storage for a padded string */ + res = (char*)Malloc(len + lines * number * 2 + 1); + res[len + lines * number * 2] = 0; + + /* copy lines to res, prepending tabs to each line */ + p = res; /* output pointer */ + start = Char(s); /* start of a current line */ + end = strchr(start, '\n'); /* end of a current line */ + while (end) { + memset(p, ' ', number*2); + p += number*2; + memcpy(p, start, end - start + 1); + p += end - start + 1; + start = end + 1; + end = strchr(start, '\n'); + } + /* process the last line */ + if (*start) { + memset(p, ' ', number*2); + p += number*2; + strcpy(p, start); + } + /* replace 's' contents with 'res' */ + Clear(s); + Append(s, res); + Free(res); +} + + +#ifdef HAVE_PCRE +#define PCRE2_CODE_UNIT_WIDTH 8 +#include <pcre2.h> + +static int split_regex_pattern_subst(String *s, String **pattern, String **subst, const char **input) +{ + const char *pats, *pate; + const char *subs, *sube; + + /* Locate the search pattern */ + const char *p = Char(s); + if (*p++ != '/') goto err_out; + pats = p; + p = strchr(p, '/'); + if (!p) goto err_out; + pate = p; + + /* Locate the substitution string */ + subs = ++p; + p = strchr(p, '/'); + if (!p) goto err_out; + sube = p; + + *pattern = NewStringWithSize(pats, (int)(pate - pats)); + *subst = NewStringWithSize(subs, (int)(sube - subs)); + *input = p + 1; + return 1; + +err_out: + Swig_error("SWIG", Getline(s), "Invalid regex substitution: '%s'.\n", s); + Exit(EXIT_FAILURE); + return 0; +} + +/* This function copies len characters from src to dst, possibly applying case conversions to them: if convertCase is 1, to upper case and if it is -1, to lower + * case. If convertNextOnly is 1, only a single character is converted (and convertCase is reset), otherwise all of them are. */ +static void copy_with_maybe_case_conversion(String *dst, const char *src, int len, int *convertCase, int convertNextOnly) +{ + /* Deal with the trivial cases first. */ + if (!len) + return; + + if (!*convertCase) { + Write(dst, src, len); + return; + } + + /* If we must convert only the first character, do it and write the rest at once. */ + if (convertNextOnly) { + int src_char = *src; + Putc(*convertCase == 1 ? toupper(src_char) : tolower(src_char), dst); + *convertCase = 0; + if (len > 1) { + Write(dst, src + 1, len - 1); + } + } else { + /* We need to convert all characters. */ + int i; + for (i = 0; i < len; i++, src++) { + int src_char = *src; + Putc(*convertCase == 1 ? toupper(src_char) : tolower(src_char), dst); + } + } +} + +String *replace_captures(int num_captures, const char *input, String *subst, size_t captures[], String *pattern, String *s) +{ + int convertCase = 0, convertNextOnly = 0; + String *result = NewStringEmpty(); + const char *p = Char(subst); + + while (*p) { + /* Copy part without substitutions */ + const char *q = strchr(p, '\\'); + if (!q) { + copy_with_maybe_case_conversion(result, p, (int)strlen(p), &convertCase, convertNextOnly); + break; + } + copy_with_maybe_case_conversion(result, p, (int)(q - p), &convertCase, convertNextOnly); + p = q + 1; + + /* Handle substitution */ + if (*p == '\0') { + Putc('\\', result); + } else if (isdigit((unsigned char)*p)) { + int group = *p++ - '0'; + if (group < num_captures) { + int l = (int)captures[group*2], r = (int)captures[group*2 + 1]; + if (l != -1) { + copy_with_maybe_case_conversion(result, input + l, r - l, &convertCase, convertNextOnly); + } + } else { + Swig_error("SWIG", Getline(s), "PCRE capture replacement failed while matching \"%s\" using \"%s\" - request for group %d is greater than the number of captures %d.\n", + Char(pattern), input, group, num_captures-1); + } + } else { + /* Handle Perl-like case conversion escapes. */ + switch (*p) { + case 'u': + convertCase = 1; + convertNextOnly = 1; + break; + case 'U': + convertCase = 1; + convertNextOnly = 0; + break; + case 'l': + convertCase = -1; + convertNextOnly = 1; + break; + case 'L': + convertCase = -1; + convertNextOnly = 0; + break; + case 'E': + convertCase = 0; + break; + default: + Swig_error("SWIG", Getline(s), "Unrecognized escape character '%c' in the replacement string \"%s\".\n", + *p, Char(subst)); + } + p++; + } + } + + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_string_regex() + * + * Executes a regular expression substitution. For example: + * + * Printf(stderr,"gsl%(regex:/GSL_(.*)_/\\1/)s", "GSL_Hello_") -> gslHello + * ----------------------------------------------------------------------------- */ +String *Swig_string_regex(String *s) { + const int pcre_options = 0; + + String *res = 0; + pcre2_code *compiled_pat = 0; + const char *input; + PCRE2_UCHAR pcre_error[256]; + int pcre_errornum; + size_t pcre_errorpos; + String *pattern = 0, *subst = 0; + size_t *captures = 0; + pcre2_match_data *match_data = 0; + if (split_regex_pattern_subst(s, &pattern, &subst, &input)) { + int rc; + + compiled_pat = pcre2_compile( + (PCRE2_SPTR8)Char(pattern), PCRE2_ZERO_TERMINATED, pcre_options, &pcre_errornum, &pcre_errorpos, NULL); + if (!compiled_pat) { + pcre2_get_error_message (pcre_errornum, pcre_error, sizeof pcre_error); + Swig_error("SWIG", Getline(s), "PCRE compilation failed: '%s' in '%s':%i.\n", + pcre_error, Char(pattern), pcre_errorpos); + Exit(EXIT_FAILURE); + } + match_data = pcre2_match_data_create_from_pattern (compiled_pat, NULL); + rc = pcre2_match(compiled_pat, (PCRE2_SPTR8)input, PCRE2_ZERO_TERMINATED, 0, 0, match_data, NULL); + captures = pcre2_get_ovector_pointer (match_data); + if (rc >= 0) { + res = replace_captures(rc, input, subst, captures, pattern, s); + } else if (rc != PCRE2_ERROR_NOMATCH) { + Swig_error("SWIG", Getline(s), "PCRE execution failed: error %d while matching \"%s\" using \"%s\".\n", + rc, Char(pattern), input); + Exit(EXIT_FAILURE); + } + } + + DohDelete(pattern); + DohDelete(subst); + pcre2_code_free(compiled_pat); + pcre2_match_data_free(match_data); + return res ? res : NewStringEmpty(); +} + +String *Swig_pcre_version(void) { + int len = pcre2_config(PCRE2_CONFIG_VERSION, NULL); + char *buf = Malloc(len); + String *result; + pcre2_config(PCRE2_CONFIG_VERSION, buf); + result = NewStringf("PCRE2 Version: %s", buf); + Free(buf); + return result; +} + +#else + +String *Swig_string_regex(String *s) { + Swig_error("SWIG", Getline(s), "PCRE regex support not enabled in this SWIG build.\n"); + Exit(EXIT_FAILURE); + return 0; +} + +String *Swig_pcre_version(void) { + return NewStringf("PCRE not used"); +} + +#endif + +/* ------------------------------------------------------------ + * Swig_is_generated_overload() + * Check if the function is an automatically generated + * overload created because a method has default parameters. + * ------------------------------------------------------------ */ +int Swig_is_generated_overload(Node *n) { + Node *base_method = Getattr(n, "sym:overloaded"); + Node *default_args = Getattr(n, "defaultargs"); + return ((base_method != NULL) && (default_args != NULL) && (base_method == default_args)); +} + +/* ----------------------------------------------------------------------------- + * Swig_init() + * + * Initialize the SWIG core + * ----------------------------------------------------------------------------- */ + +void Swig_init(void) { + /* Set some useful string encoding methods */ + DohEncoding("escape", Swig_string_escape); + DohEncoding("hexescape", Swig_string_hexescape); + DohEncoding("upper", Swig_string_upper); + DohEncoding("lower", Swig_string_lower); + DohEncoding("title", Swig_string_title); + DohEncoding("ctitle", Swig_string_ccase); + DohEncoding("lctitle", Swig_string_lccase); + DohEncoding("utitle", Swig_string_ucase); + DohEncoding("typecode", Swig_string_typecode); + DohEncoding("mangle", Swig_string_emangle); + DohEncoding("command", Swig_string_command); + DohEncoding("schemify", Swig_string_schemify); + DohEncoding("strip", Swig_string_strip); + DohEncoding("rstrip", Swig_string_rstrip); + DohEncoding("regex", Swig_string_regex); + + /* aliases for the case encoders */ + DohEncoding("uppercase", Swig_string_upper); + DohEncoding("lowercase", Swig_string_lower); + DohEncoding("camelcase", Swig_string_ccase); + DohEncoding("lowercamelcase", Swig_string_lccase); + DohEncoding("undercase", Swig_string_ucase); + DohEncoding("firstuppercase", Swig_string_first_upper); + DohEncoding("firstlowercase", Swig_string_first_lower); + + /* Initialize typemaps */ + Swig_typemap_init(); + + /* Initialize symbol table */ + Swig_symbol_init(); + + /* Initialize type system */ + SwigType_typesystem_init(); + + /* Initialize template system */ + SwigType_template_init(); +} diff --git a/contrib/tools/swig/Source/Swig/naming.c b/contrib/tools/swig/Source/Swig/naming.c new file mode 100644 index 0000000000..c4613f6c62 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/naming.c @@ -0,0 +1,1771 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * naming.c + * + * Functions for generating various kinds of names during code generation. + * + * Swig_name_register is used to register a format string for generating names. + * The format string makes use of the following format specifiers: + * + * %c - class name is substituted + * %f - function name is substituted + * %m - member name is substituted + * %n - namespace is substituted + * %v - variable name is substituted + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +/* Hash table containing naming data */ + +static Hash *naming_hash = 0; + +#if 0 +#define SWIG_DEBUG +#endif + +/* ----------------------------------------------------------------------------- + * Swig_name_register() + * + * Register a new naming format. + * ----------------------------------------------------------------------------- */ + +void Swig_name_register(const_String_or_char_ptr method, const_String_or_char_ptr format) { + if (!naming_hash) + naming_hash = NewHash(); + Setattr(naming_hash, method, format); +} + +void Swig_name_unregister(const_String_or_char_ptr method) { + if (naming_hash) { + Delattr(naming_hash, method); + } +} + +/* Return naming format for the specified method or the default format if none was explicitly registered */ +static String* get_naming_format_for(const char *method, const char *def_format) { + String* f = naming_hash ? Getattr(naming_hash, method) : NULL; + + return f ? Copy(f) : NewString(def_format); +} + +static int name_mangle(String *r) { + char *c; + int special; + special = 0; + Replaceall(r, "::", "_"); + c = Char(r); + while (*c) { + if (!isalnum((int) *c) && (*c != '_')) { + special = 1; + switch (*c) { + case '+': + *c = 'a'; + break; + case '-': + *c = 's'; + break; + case '*': + *c = 'm'; + break; + case '/': + *c = 'd'; + break; + case '<': + *c = 'l'; + break; + case '>': + *c = 'g'; + break; + case '=': + *c = 'e'; + break; + case ',': + *c = 'c'; + break; + case '(': + *c = 'p'; + break; + case ')': + *c = 'P'; + break; + case '[': + *c = 'b'; + break; + case ']': + *c = 'B'; + break; + case '^': + *c = 'x'; + break; + case '&': + *c = 'A'; + break; + case '|': + *c = 'o'; + break; + case '~': + *c = 'n'; + break; + case '!': + *c = 'N'; + break; + case '%': + *c = 'M'; + break; + case '.': + *c = 'f'; + break; + case '?': + *c = 'q'; + break; + default: + *c = '_'; + break; + } + } + c++; + } + if (special) + Append(r, "___"); + return special; +} + +/* ----------------------------------------------------------------------------- + * replace_nspace() + * + * Mangles in the namespace from nspace by replacing %n in name if nspace feature required. + * ----------------------------------------------------------------------------- */ + +static void replace_nspace(String *name, const_String_or_char_ptr nspace) { + if (nspace) { + String *namspace = NewStringf("%s_", nspace); + Replaceall(namspace, NSPACE_SEPARATOR, "_"); + Replace(name, "%n", namspace, DOH_REPLACE_ANY); + Delete(namspace); + } else { + Replace(name, "%n", "", DOH_REPLACE_ANY); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_name_mangle() + * + * Converts all of the non-identifier characters of a string to underscores. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_mangle(const_String_or_char_ptr s) { +#if 0 + String *r = NewString(s); + name_mangle(r); + return r; +#else + return Swig_string_mangle(s); +#endif +} + +/* ----------------------------------------------------------------------------- + * Swig_name_wrapper() + * + * Returns the name of a wrapper function. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_wrapper(const_String_or_char_ptr fname) { + String *r = get_naming_format_for("wrapper", "_wrap_%f"); + + Replace(r, "%f", fname, DOH_REPLACE_ANY); + name_mangle(r); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_member() + * + * Returns the name of a class method. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_member(const_String_or_char_ptr nspace, const_String_or_char_ptr classname, const_String_or_char_ptr membername) { + String *r; + String *rclassname; + char *cname; + + rclassname = SwigType_namestr(classname); + r = get_naming_format_for("member", "%n%c_%m"); + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + replace_nspace(r, nspace); + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Replace(r, "%m", membername, DOH_REPLACE_ANY); + /* name_mangle(r); */ + Delete(rclassname); + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_get() + * + * Returns the name of the accessor function used to get a variable. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_get(const_String_or_char_ptr nspace, const_String_or_char_ptr vname) { + String *r = get_naming_format_for("get", "%n%v_get"); + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_get: '%s'\n", vname); +#endif + + replace_nspace(r, nspace); + Replace(r, "%v", vname, DOH_REPLACE_ANY); + /* name_mangle(r); */ + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_set() + * + * Returns the name of the accessor function used to set a variable. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_set(const_String_or_char_ptr nspace, const_String_or_char_ptr vname) { + String *r = get_naming_format_for("set", "%n%v_set"); + + replace_nspace(r, nspace); + Replace(r, "%v", vname, DOH_REPLACE_ANY); + /* name_mangle(r); */ + return r; +} + +/* Common implementation of all Swig_name_<special-method>() functions below. */ +static String *make_full_name_for(const char *method, const char *def_format, const_String_or_char_ptr nspace, const_String_or_char_ptr classname) { + String *r; + String *rclassname; + char *cname; + + rclassname = SwigType_namestr(classname); + r = get_naming_format_for(method, def_format); + + cname = Char(rclassname); + if ((strncmp(cname, "struct ", 7) == 0) || ((strncmp(cname, "class ", 6) == 0)) || ((strncmp(cname, "union ", 6) == 0))) { + cname = strchr(cname, ' ') + 1; + } + + replace_nspace(r, nspace); + Replace(r, "%c", cname, DOH_REPLACE_ANY); + Delete(rclassname); + return r; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_construct() + * + * Returns the name of the accessor function used to create an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_construct(const_String_or_char_ptr nspace, const_String_or_char_ptr classname) { + return make_full_name_for("construct", "new_%n%c", nspace, classname); +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_copyconstructor() + * + * Returns the name of the accessor function used to copy an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_copyconstructor(const_String_or_char_ptr nspace, const_String_or_char_ptr classname) { + return make_full_name_for("copy", "copy_%n%c", nspace, classname); +} + +/* ----------------------------------------------------------------------------- + * Swig_name_destroy() + * + * Returns the name of the accessor function used to destroy an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_destroy(const_String_or_char_ptr nspace, const_String_or_char_ptr classname) { + return make_full_name_for("destroy", "delete_%n%c", nspace, classname); +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_disown() + * + * Returns the name of the accessor function used to disown an object. + * ----------------------------------------------------------------------------- */ + +String *Swig_name_disown(const_String_or_char_ptr nspace, const_String_or_char_ptr classname) { + return make_full_name_for("disown", "disown_%n%c", nspace, classname); +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_object_set() + * + * Sets an object associated with a name and optional declarators. + * ----------------------------------------------------------------------------- */ + +void Swig_name_object_set(Hash *namehash, String *name, SwigType *decl, DOH *object) { + DOH *n; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_object_set: '%s', '%s'\n", name, decl); +#endif + n = Getattr(namehash, name); + if (!n) { + n = NewHash(); + Setattr(namehash, name, n); + Delete(n); + } + /* Add an object based on the declarator value */ + if (!decl) { + Setattr(n, "start", object); + } else { + SwigType *cd = Copy(decl); + Setattr(n, cd, object); + Delete(cd); + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_name_object_get() + * + * Return an object associated with an optional class prefix, name, and + * declarator. This function operates according to name matching rules + * described for the %rename directive in the SWIG manual. + * ----------------------------------------------------------------------------- */ + +static DOH *get_object(Hash *n, String *decl) { + DOH *rn = 0; + if (!n) + return 0; + if (decl) { + rn = Getattr(n, decl); + } else { + rn = Getattr(n, "start"); + } + return rn; +} + +static DOH *name_object_get(Hash *namehash, String *tname, SwigType *decl, SwigType *ncdecl) { + DOH *rn = 0; + Hash *n = Getattr(namehash, tname); + if (n) { + rn = get_object(n, decl); + if ((!rn) && ncdecl) + rn = get_object(n, ncdecl); + if (!rn) + rn = get_object(n, 0); + } + return rn; +} + +DOH *Swig_name_object_get(Hash *namehash, String *prefix, String *name, SwigType *decl) { + String *tname = NewStringEmpty(); + DOH *rn = 0; + char *ncdecl = 0; + + if (!namehash) + return 0; + + /* DB: This removed to more tightly control feature/name matching */ + /* if ((decl) && (SwigType_isqualifier(decl))) { + ncdecl = strchr(Char(decl),'.'); + ncdecl++; + } + */ +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_object_get: '%s' '%s', '%s'\n", prefix, name, decl); +#endif + + + /* Perform a class-based lookup (if class prefix supplied) */ + if (prefix) { + if (Len(prefix)) { + Printf(tname, "%s::%s", prefix, name); + rn = name_object_get(namehash, tname, decl, ncdecl); + if (!rn) { + String *cls = Swig_scopename_last(prefix); + if (!Equal(cls, prefix)) { + Clear(tname); + Printf(tname, "*::%s::%s", cls, name); + rn = name_object_get(namehash, tname, decl, ncdecl); + } + Delete(cls); + } + /* Lookup a name within a templated-based class */ + if (!rn) { + String *t_name = SwigType_istemplate_templateprefix(prefix); + if (t_name) { + Clear(tname); + Printf(tname, "%s::%s", t_name, name); + rn = name_object_get(namehash, tname, decl, ncdecl); + Delete(t_name); + } + } + /* Lookup a template-based name within a class */ + if (!rn) { + String *t_name = SwigType_istemplate_templateprefix(name); + if (t_name) + rn = Swig_name_object_get(namehash, prefix, t_name, decl); + Delete(t_name); + } + } + /* A wildcard-based class lookup */ + if (!rn) { + Clear(tname); + Printf(tname, "*::%s", name); + rn = name_object_get(namehash, tname, decl, ncdecl); + } + } else { + /* Lookup in the global namespace only */ + Clear(tname); + Printf(tname, "::%s", name); + rn = name_object_get(namehash, tname, decl, ncdecl); + } + /* Catch-all */ + if (!rn) { + rn = name_object_get(namehash, name, decl, ncdecl); + } + if (!rn && Swig_scopename_check(name)) { + String *nprefix = 0; + String *nlast = 0; + Swig_scopename_split(name, &nprefix, &nlast); + rn = name_object_get(namehash, nlast, decl, ncdecl); + Delete(nlast); + Delete(nprefix); + } + + Delete(tname); + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_object_get: found %d\n", rn ? 1 : 0); +#endif + + return rn; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_object_inherit() + * + * Implements name-based inheritance scheme. + * ----------------------------------------------------------------------------- */ + +void Swig_name_object_inherit(Hash *namehash, String *base, String *derived) { + Iterator ki; + Hash *derh; + String *bprefix; + String *dprefix; + char *cbprefix; + int plen; + + if (!namehash) + return; + + /* Temporary hash holding all the entries we add while we iterate over + namehash itself as we can't modify the latter while iterating over it. */ + derh = NULL; + bprefix = NewStringf("%s::", base); + dprefix = NewStringf("%s::", derived); + cbprefix = Char(bprefix); + plen = (int)strlen(cbprefix); + for (ki = First(namehash); ki.key; ki = Next(ki)) { + char *k = Char(ki.key); + if (strncmp(k, cbprefix, plen) == 0) { + /* Copy, adjusting name, this element to the derived hash. */ + Iterator oi; + String *nkey = NewStringf("%s%s", dprefix, k + plen); + Hash *n = ki.item; + Hash *newh; + + /* Don't overwrite an existing value for the derived class, if any. */ + newh = Getattr(namehash, nkey); + if (!newh) { + if (!derh) + derh = NewHash(); + + newh = NewHash(); + Setattr(derh, nkey, newh); + Delete(newh); + } + for (oi = First(n); oi.key; oi = Next(oi)) { + if (!Getattr(newh, oi.key)) { + String *ci = Copy(oi.item); + Setattr(newh, oi.key, ci); + Delete(ci); + } + } + Delete(nkey); + } + } + + /* Merge the contents of derived hash into the main hash. */ + if (derh) { + for (ki = First(derh); ki.key; ki = Next(ki)) { + Setattr(namehash, ki.key, ki.item); + } + } + + Delete(bprefix); + Delete(dprefix); + Delete(derh); +} + +/* ----------------------------------------------------------------------------- + * merge_features() + * + * Given a hash, this function merges the features in the hash into the node. + * ----------------------------------------------------------------------------- */ + +static void merge_features(Hash *features, Node *n) { + Iterator ki; + + if (!features) + return; + for (ki = First(features); ki.key; ki = Next(ki)) { + String *ci = Copy(ki.item); + Setattr(n, ki.key, ci); + Delete(ci); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_features_get() + * + * Attaches any features in the features hash to the node that matches + * the declaration, decl. + * ----------------------------------------------------------------------------- */ + +static void features_get(Hash *features, const String *tname, SwigType *decl, SwigType *ncdecl, Node *node) { + Node *n = Getattr(features, tname); +#ifdef SWIG_DEBUG + Printf(stdout, " features_get: %s\n", tname); +#endif + if (n) { + merge_features(get_object(n, 0), node); + if (ncdecl) + merge_features(get_object(n, ncdecl), node); + merge_features(get_object(n, decl), node); + } +} + +void Swig_features_get(Hash *features, String *prefix, String *name, SwigType *decl, Node *node) { + char *ncdecl = 0; + String *rdecl = 0; + String *rname = 0; + if (!features) + return; + + /* MM: This removed to more tightly control feature/name matching */ + /* + if ((decl) && (SwigType_isqualifier(decl))) { + ncdecl = strchr(Char(decl),'.'); + ncdecl++; + } + */ + + /* very specific hack for template constructors/destructors */ + if (name && SwigType_istemplate(name)) { + String *nodetype = nodeType(node); + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + String *nprefix = 0; + String *nlast = 0; + String *tprefix; + Swig_scopename_split(name, &nprefix, &nlast); + tprefix = SwigType_templateprefix(nlast); + Delete(nlast); + if (Len(nprefix)) { + Append(nprefix, "::"); + Append(nprefix, tprefix); + Delete(tprefix); + rname = nprefix; + } else { + rname = tprefix; + Delete(nprefix); + } + rdecl = Copy(decl); + Replaceall(rdecl, name, rname); + decl = rdecl; + name = rname; + } + } + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_features_get: '%s' '%s' '%s'\n", prefix, name, decl); +#endif + + /* Global features */ + features_get(features, "", 0, 0, node); + if (name) { + String *tname = NewStringEmpty(); + /* add features for 'root' template */ + String *dname = SwigType_istemplate_templateprefix(name); + if (dname) { + features_get(features, dname, decl, ncdecl, node); + } + /* Catch-all */ + features_get(features, name, decl, ncdecl, node); + /* Perform a class-based lookup (if class prefix supplied) */ + if (prefix) { + /* A class-generic feature */ + if (Len(prefix)) { + Printf(tname, "%s::", prefix); + features_get(features, tname, decl, ncdecl, node); + } + /* A wildcard-based class lookup */ + Clear(tname); + Printf(tname, "*::%s", name); + features_get(features, tname, decl, ncdecl, node); + /* A specific class lookup */ + if (Len(prefix)) { + /* A template-based class lookup */ + String *tprefix = SwigType_istemplate_templateprefix(prefix); + if (tprefix) { + Clear(tname); + Printf(tname, "%s::%s", tprefix, name); + features_get(features, tname, decl, ncdecl, node); + } + Clear(tname); + Printf(tname, "%s::%s", prefix, name); + features_get(features, tname, decl, ncdecl, node); + Delete(tprefix); + } + } else { + /* Lookup in the global namespace only */ + Clear(tname); + Printf(tname, "::%s", name); + features_get(features, tname, decl, ncdecl, node); + } + Delete(tname); + Delete(dname); + } + if (name && SwigType_istemplate(name)) { + /* add features for complete template type */ + String *dname = Swig_symbol_template_deftype(name, 0); + if (!Equal(dname, name)) { + Swig_features_get(features, prefix, dname, decl, node); + } + Delete(dname); + } + + if (rname) + Delete(rname); + if (rdecl) + Delete(rdecl); +} + + +/* ----------------------------------------------------------------------------- + * Swig_feature_set() + * + * Sets a feature name and value. Also sets optional feature attributes as + * passed in by featureattribs. Optional feature attributes are given a full name + * concatenating the feature name plus ':' plus the attribute name. + * ----------------------------------------------------------------------------- */ + +void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, const_String_or_char_ptr value, Hash *featureattribs) { + Hash *n; + Hash *fhash; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_feature_set: '%s' '%s' '%s' '%s'\n", name, decl, featurename, value); +#endif + + n = Getattr(features, name); + if (!n) { + n = NewHash(); + Setattr(features, name, n); + Delete(n); + } + if (!decl) { + fhash = Getattr(n, "start"); + if (!fhash) { + fhash = NewHash(); + Setattr(n, "start", fhash); + Delete(fhash); + } + } else { + fhash = Getattr(n, decl); + if (!fhash) { + String *cdecl_ = Copy(decl); + fhash = NewHash(); + Setattr(n, cdecl_, fhash); + Delete(cdecl_); + Delete(fhash); + } + } + if (value) { + Setattr(fhash, featurename, value); + } else { + Delattr(fhash, featurename); + } + + { + /* Add in the optional feature attributes */ + Hash *attribs = featureattribs; + while (attribs) { + String *attribname = Getattr(attribs, "name"); + String *featureattribname = NewStringf("%s:%s", featurename, attribname); + if (value) { + String *attribvalue = Getattr(attribs, "value"); + Setattr(fhash, featureattribname, attribvalue); + } else { + Delattr(fhash, featureattribname); + } + attribs = nextSibling(attribs); + Delete(featureattribname); + } + } + + if (name && SwigType_istemplate(name)) { + String *dname = Swig_symbol_template_deftype(name, 0); + if (Strcmp(dname, name)) { + Swig_feature_set(features, dname, decl, featurename, value, featureattribs); + } + Delete(dname); + } +} + +/* ----------------------------------------------------------------------------- + * The rename/namewarn engine + * + * Code below was in parser.y for a while + * ----------------------------------------------------------------------------- */ + +static Hash *namewarn_hash = 0; +static Hash *name_namewarn_hash(void) { + if (!namewarn_hash) + namewarn_hash = NewHash(); + return namewarn_hash; +} + +static Hash *rename_hash = 0; +static Hash *name_rename_hash(void) { + if (!rename_hash) + rename_hash = NewHash(); + return rename_hash; +} + +static List *namewarn_list = 0; +static List *name_namewarn_list(void) { + if (!namewarn_list) + namewarn_list = NewList(); + return namewarn_list; +} + +static List *rename_list = 0; +static List *name_rename_list(void) { + if (!rename_list) + rename_list = NewList(); + return rename_list; +} + +/* ----------------------------------------------------------------------------- + * int need_name_warning(Node *n) + * + * Detects if a node needs name warnings + * + * ----------------------------------------------------------------------------- */ + +static int need_name_warning(Node *n) { + int need = 1; + /* + We don't use name warnings for: + - class forwards, no symbol is generated at the target language. + - template declarations, only for real instances using %template(name). + - typedefs, have no effect at the target language. + - using declarations and using directives, have no effect at the target language. + */ + if (checkAttribute(n, "nodeType", "classforward")) { + need = 0; + } else if (checkAttribute(n, "nodeType", "using")) { + need = 0; + } else if (checkAttribute(n, "storage", "typedef")) { + need = 0; + } else if (Getattr(n, "hidden")) { + need = 0; + } else if (Getattr(n, "ignore")) { + need = 0; + } else if (Getattr(n, "templatetype")) { + need = 0; + } else if (GetFlag(n, "parsing_template_declaration")) { + need = 0; + } + return need; +} + +/* ----------------------------------------------------------------------------- + * int Swig_need_redefined_warn() + * + * Detects when a redefined object needs a warning + * + * ----------------------------------------------------------------------------- */ + +static int nodes_are_equivalent(Node *a, Node *b, int a_inclass) { + /* they must have the same type */ + String *ta = nodeType(a); + String *tb = nodeType(b); + if (!Equal(ta, tb)) { + if (!(Equal(ta, "using") && Equal(tb, "cdecl"))) { + return 0; + } + } + + if (Cmp(ta, "cdecl") == 0) { + /* both cdecl case */ + /* typedef */ + String *a_storage = Getattr(a, "storage"); + String *b_storage = Getattr(b, "storage"); + + if ((Cmp(a_storage, "typedef") == 0) + || (Cmp(b_storage, "typedef") == 0)) { + if (Cmp(a_storage, b_storage) == 0) { + String *a_type = (Getattr(a, "type")); + String *b_type = (Getattr(b, "type")); + if (Cmp(a_type, b_type) == 0) + return 1; + } + return 0; + } + + /* static functions */ + if (Swig_storage_isstatic(a) || Swig_storage_isstatic(b)) { + if (Cmp(a_storage, b_storage) != 0) + return 0; + } + + /* friend methods */ + + if (!a_inclass || (Cmp(a_storage, "friend") == 0)) { + /* check declaration */ + + String *a_decl = (Getattr(a, "decl")); + String *b_decl = (Getattr(b, "decl")); + if (Cmp(a_decl, b_decl) == 0) { + /* check return type */ + String *a_type = (Getattr(a, "type")); + String *b_type = (Getattr(b, "type")); + if (Cmp(a_type, b_type) == 0) { + /* check parameters */ + Parm *ap = (Getattr(a, "parms")); + Parm *bp = (Getattr(b, "parms")); + while (ap && bp) { + SwigType *at = Getattr(ap, "type"); + SwigType *bt = Getattr(bp, "type"); + if (Cmp(at, bt) != 0) + return 0; + ap = nextSibling(ap); + bp = nextSibling(bp); + } + if (ap || bp) { + return 0; + } else { + Node *a_template = Getattr(a, "template"); + Node *b_template = Getattr(b, "template"); + /* Not equivalent if one is a template instantiation (via %template) and the other is a non-templated function */ + if ((a_template && !b_template) || (!a_template && b_template)) + return 0; + } + return 1; + } + } + } + } else if (Equal(ta, "using")) { + /* using and cdecl case */ + String *b_storage = Getattr(b, "storage"); + if (Equal(b_storage, "typedef")) { + String *a_name = Getattr(a, "name"); + String *b_name = Getattr(b, "name"); + if (Equal(a_name, b_name)) + return 1; + } + } else { + /* both %constant case */ + String *a_storage = Getattr(a, "storage"); + String *b_storage = Getattr(b, "storage"); + if ((Cmp(a_storage, "%constant") == 0) + || (Cmp(b_storage, "%constant") == 0)) { + if (Cmp(a_storage, b_storage) == 0) { + String *a_type = (Getattr(a, "type")); + String *b_type = (Getattr(b, "type")); + if ((Cmp(a_type, b_type) == 0) + && (Cmp(Getattr(a, "value"), Getattr(b, "value")) == 0)) + return 1; + } + return 0; + } + if (Equal(ta, "template") && Equal(tb, "template")) { + if (Cmp(a_storage, "friend") == 0 || Cmp(b_storage, "friend") == 0) + return 1; + } + } + return 0; +} + +int Swig_need_redefined_warn(Node *a, Node *b, int InClass) { + String *a_name = Getattr(a, "name"); + String *b_name = Getattr(b, "name"); + String *a_symname = Getattr(a, "sym:name"); + String *b_symname = Getattr(b, "sym:name"); + /* always send a warning if a 'rename' is involved */ + if ((a_symname && !Equal(a_symname, a_name)) + || (b_symname && !Equal(b_symname, b_name))) { + if (!Equal(a_name, b_name)) { + return 1; + } + } + + + return !nodes_are_equivalent(a, b, InClass); +} + + +/* ----------------------------------------------------------------------------- + * int Swig_need_protected(Node* n) + * + * Detects when we need to fully register the protected member. + * This is basically any protected members when the allprotected mode is set. + * Otherwise we take just the protected virtual methods and non-static methods + * (potentially virtual methods) as well as constructors/destructors. + * Also any "using" statements in a class may potentially be virtual. + * ----------------------------------------------------------------------------- */ + +int Swig_need_protected(Node *n) { + String *nodetype = nodeType(n); + if (checkAttribute(n, "access", "protected")) { + if ((Equal(nodetype, "cdecl"))) { + if (Swig_director_mode() && Swig_director_protected_mode() && Swig_all_protected_mode()) { + return 1; + } + if (SwigType_isfunction(Getattr(n, "decl"))) { + String *storage = Getattr(n, "storage"); + /* The function is declared virtual, or it has no storage. This eliminates typedef, static etc. */ + return !storage || Equal(storage, "virtual"); + } + } else if (Equal(nodetype, "constructor") || Equal(nodetype, "destructor")) { + return 1; + } else if (Equal(nodetype, "using") && !Getattr(n, "namespace")) { + return 1; + } + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * void name_nameobj_add() + * + * Add nameobj (rename/namewarn) + * + * ----------------------------------------------------------------------------- */ + +static List *make_attrlist(const char *ckey) { + List *list = NewList(); + const char *cattr = strchr(ckey, '$'); + if (cattr) { + String *nattr; + const char *rattr = strchr(++cattr, '$'); + while (rattr) { + nattr = NewStringWithSize(cattr, (int)(rattr - cattr)); + Append(list, nattr); + Delete(nattr); + cattr = rattr + 1; + rattr = strchr(cattr, '$'); + } + nattr = NewString(cattr); + Append(list, nattr); + Delete(nattr); + } else { + Append(list, "nodeType"); + } + return list; +} + +static void name_object_attach_keys(const char *keys[], Hash *nameobj) { + Node *kw = nextSibling(nameobj); + List *matchlist = 0; + while (kw) { + Node *next = nextSibling(kw); + String *kname = Getattr(kw, "name"); + char *ckey = kname ? Char(kname) : 0; + if (ckey) { + const char **rkey; + int isnotmatch = 0; + int isregexmatch = 0; + if ((strncmp(ckey, "match", 5) == 0) + || (isnotmatch = (strncmp(ckey, "notmatch", 8) == 0)) + || (isregexmatch = (strncmp(ckey, "regexmatch", 10) == 0)) + || (isnotmatch = isregexmatch = (strncmp(ckey, "notregexmatch", 13) == 0))) { + Hash *mi = NewHash(); + List *attrlist = make_attrlist(ckey); + if (!matchlist) + matchlist = NewList(); + Setattr(mi, "value", Getattr(kw, "value")); + Setattr(mi, "attrlist", attrlist); + if (isnotmatch) + SetFlag(mi, "notmatch"); + if (isregexmatch) + SetFlag(mi, "regexmatch"); + Delete(attrlist); + Append(matchlist, mi); + Delete(mi); + removeNode(kw); + } else { + for (rkey = keys; *rkey != 0; ++rkey) { + if (strcmp(ckey, *rkey) == 0) { + Setattr(nameobj, *rkey, Getattr(kw, "value")); + removeNode(kw); + } + } + } + } + kw = next; + } + if (matchlist) { + Setattr(nameobj, "matchlist", matchlist); + Delete(matchlist); + } +} + +static void name_nameobj_add(Hash *name_hash, List *name_list, String *prefix, String *name, SwigType *decl, Hash *nameobj) { + String *nname = 0; + if (name && Len(name)) { + String *target_fmt = Getattr(nameobj, "targetfmt"); + nname = prefix ? NewStringf("%s::%s", prefix, name) : NewString(name); + if (target_fmt) { + String *tmp = NewStringf(target_fmt, nname); + Delete(nname); + nname = tmp; + } + } + + if (!nname || !Len(nname) || Getattr(nameobj, "fullname") || /* any of these options trigger a 'list' nameobj */ + Getattr(nameobj, "sourcefmt") || Getattr(nameobj, "matchlist") || Getattr(nameobj, "regextarget")) { + if (decl) + Setattr(nameobj, "decl", decl); + if (nname && Len(nname)) + Setattr(nameobj, "targetname", nname); + /* put the new nameobj at the beginning of the list, such that the + last inserted rule take precedence */ + Insert(name_list, 0, nameobj); + } else { + /* here we add an old 'hash' nameobj, simple and fast */ + Swig_name_object_set(name_hash, nname, decl, nameobj); + } + Delete(nname); +} + +/* ----------------------------------------------------------------------------- + * int name_match_nameobj() + * + * Apply and check the nameobj's math list to the node + * + * ----------------------------------------------------------------------------- */ + +static DOH *get_lattr(Node *n, List *lattr) { + DOH *res = 0; + int ilen = Len(lattr); + int i; + for (i = 0; n && (i < ilen); ++i) { + String *nattr = Getitem(lattr, i); + res = Getattr(n, nattr); +#ifdef SWIG_DEBUG + if (!res) { + Printf(stdout, "missing %s %s %s\n", nattr, Getattr(n, "name"), Getattr(n, "member")); + } else { + Printf(stdout, "lattr %d %s %s\n", i, nattr, DohIsString(res) ? res : Getattr(res, "name")); + } +#endif + n = res; + } + return res; +} + +#ifdef HAVE_PCRE +#define PCRE2_CODE_UNIT_WIDTH 8 +#include <pcre2.h> + +static int name_regexmatch_value(Node *n, String *pattern, String *s) { + pcre2_code *compiled_pat; + PCRE2_UCHAR err[256]; + int errornum; + size_t errpos; + int rc; + pcre2_match_data *match_data = 0; + + compiled_pat = pcre2_compile((PCRE2_SPTR8)Char(pattern), PCRE2_ZERO_TERMINATED, 0, &errornum, &errpos, NULL); + if (!compiled_pat) { + pcre2_get_error_message (errornum, err, sizeof err); + Swig_error("SWIG", Getline(n), + "Invalid regex \"%s\": compilation failed at %d: %s\n", + Char(pattern), errpos, err); + Exit(EXIT_FAILURE); + } + + match_data = pcre2_match_data_create_from_pattern (compiled_pat, NULL); + rc = pcre2_match(compiled_pat, (PCRE2_SPTR8)Char(s), PCRE2_ZERO_TERMINATED, 0, 0, match_data, 0); + pcre2_code_free(compiled_pat); + pcre2_match_data_free(match_data); + + if (rc == PCRE2_ERROR_NOMATCH) + return 0; + + if (rc < 0 ) { + Swig_error("SWIG", Getline(n), + "Matching \"%s\" against regex \"%s\" failed: %d\n", + Char(s), Char(pattern), rc); + Exit(EXIT_FAILURE); + } + + return 1; +} + +#else /* !HAVE_PCRE */ + +static int name_regexmatch_value(Node *n, String *pattern, String *s) { + (void)pattern; + (void)s; + Swig_error("SWIG", Getline(n), + "PCRE regex matching is not available in this SWIG build.\n"); + Exit(EXIT_FAILURE); + return 0; +} + +#endif /* HAVE_PCRE/!HAVE_PCRE */ + +static int name_match_value(String *mvalue, String *value) { +#if defined(SWIG_USE_SIMPLE_MATCHOR) + int match = 0; + char *cvalue = Char(value); + char *cmvalue = Char(mvalue); + char *sep = strchr(cmvalue, '|'); + while (sep && !match) { + match = strncmp(cvalue, cmvalue, sep - cmvalue) == 0; +#ifdef SWIG_DEBUG + Printf(stdout, "match_value: %s %s %d\n", cvalue, cmvalue, match); +#endif + cmvalue = sep + 1; + sep = strchr(cmvalue, '|'); + } + if (!match) { + match = strcmp(cvalue, cmvalue) == 0; +#ifdef SWIG_DEBUG + Printf(stdout, "match_value: %s %s %d\n", cvalue, cmvalue, match); +#endif + } + return match; +#else + return Equal(mvalue, value); +#endif +} + +static int name_match_nameobj(Hash *rn, Node *n) { + int match = 1; + List *matchlist = Getattr(rn, "matchlist"); +#ifdef SWIG_DEBUG + Printf(stdout, "name_match_nameobj: %s\n", Getattr(n, "name")); +#endif + if (matchlist) { + int ilen = Len(matchlist); + int i; + for (i = 0; match && (i < ilen); ++i) { + Node *mi = Getitem(matchlist, i); + List *lattr = Getattr(mi, "attrlist"); + String *nval = get_lattr(n, lattr); + int notmatch = GetFlag(mi, "notmatch"); + int regexmatch = GetFlag(mi, "regexmatch"); + match = 0; + if (nval) { + String *kwval = Getattr(mi, "value"); + match = regexmatch ? name_regexmatch_value(n, kwval, nval) + : name_match_value(kwval, nval); +#ifdef SWIG_DEBUG + Printf(stdout, "val %s %s %d %d \n", nval, kwval, match, ilen); +#endif + } + if (notmatch) + match = !match; + } + } +#ifdef SWIG_DEBUG + Printf(stdout, "name_match_nameobj: %d\n", match); +#endif + return match; +} + +/* ----------------------------------------------------------------------------- + * Hash *name_nameobj_lget() + * + * Get a nameobj (rename/namewarn) from the list of filters + * + * ----------------------------------------------------------------------------- */ + +static Hash *name_nameobj_lget(List *namelist, Node *n, String *prefix, String *name, String *decl) { + Hash *res = 0; + if (namelist) { + int len = Len(namelist); + int i; + int match = 0; + for (i = 0; !match && (i < len); i++) { + Hash *rn = Getitem(namelist, i); + String *rdecl = Getattr(rn, "decl"); + if (rdecl && (!decl || !Equal(rdecl, decl))) { + continue; + } else if (name_match_nameobj(rn, n)) { + String *tname = Getattr(rn, "targetname"); + if (tname) { + String *sfmt = Getattr(rn, "sourcefmt"); + String *sname = 0; + int fullname = GetFlag(rn, "fullname"); + int regextarget = GetFlag(rn, "regextarget"); + if (sfmt) { + if (fullname && prefix) { + String *pname = NewStringf("%s::%s", prefix, name); + sname = NewStringf(sfmt, pname); + Delete(pname); + } else { + sname = NewStringf(sfmt, name); + } + } else { + if (fullname && prefix) { + sname = NewStringf("%s::%s", prefix, name); + } else { + sname = name; + DohIncref(name); + } + } + match = regextarget ? name_regexmatch_value(n, tname, sname) + : name_match_value(tname, sname); + Delete(sname); + } else { + /* Applying the renaming rule may fail if it contains a %(regex)s expression that doesn't match the given name. */ + String *sname = NewStringf(Getattr(rn, "name"), name); + if (sname) { + if (Len(sname)) + match = 1; + Delete(sname); + } + } + } + if (match) { + res = rn; + break; + } + } + } + return res; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_namewarn_add + * + * Add a namewarn objects + * + * ----------------------------------------------------------------------------- */ + +void Swig_name_namewarn_add(String *prefix, String *name, SwigType *decl, Hash *namewrn) { + const char *namewrn_keys[] = { "rename", "error", "fullname", "sourcefmt", "targetfmt", 0 }; + name_object_attach_keys(namewrn_keys, namewrn); + name_nameobj_add(name_namewarn_hash(), name_namewarn_list(), prefix, name, decl, namewrn); +} + +/* ----------------------------------------------------------------------------- + * Hash *name_namewarn_get() + * + * Return the namewarn object, if there is one. + * + * ----------------------------------------------------------------------------- */ + +static Hash *name_namewarn_get(Node *n, String *prefix, String *name, SwigType *decl) { + if (!namewarn_hash && !namewarn_list) + return 0; + if (n) { + /* Return in the obvious cases */ + if (!name || !need_name_warning(n)) { + return 0; + } else { + String *access = Getattr(n, "access"); + int is_public = !access || Equal(access, "public"); + if (!is_public && !Swig_need_protected(n)) { + return 0; + } + } + } + if (name) { + /* Check to see if the name is in the hash */ + Hash *wrn = Swig_name_object_get(name_namewarn_hash(), prefix, name, decl); + if (wrn && !name_match_nameobj(wrn, n)) + wrn = 0; + if (!wrn) { + wrn = name_nameobj_lget(name_namewarn_list(), n, prefix, name, decl); + } + if (wrn && Getattr(wrn, "error")) { + if (n) { + Swig_error(Getfile(n), Getline(n), "%s\n", Getattr(wrn, "name")); + } else { + Swig_error(cparse_file, cparse_line, "%s\n", Getattr(wrn, "name")); + } + } + return wrn; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * String *Swig_name_warning() + * + * Return the name warning, if there is one. + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_warning(Node *n, String *prefix, String *name, SwigType *decl) { + Hash *wrn = name_namewarn_get(n, prefix, name, decl); + return (name && wrn) ? Getattr(wrn, "name") : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_name_rename_add() + * + * Manage the rename objects + * + * ----------------------------------------------------------------------------- */ + +static void single_rename_add(String *prefix, String *name, SwigType *decl, Hash *newname) { + name_nameobj_add(name_rename_hash(), name_rename_list(), prefix, name, decl, newname); +} + +/* Add a new rename. Works much like new_feature including default argument handling. */ +void Swig_name_rename_add(String *prefix, String *name, SwigType *decl, Hash *newname, ParmList *declaratorparms) { + + ParmList *declparms = declaratorparms; + + const char *rename_keys[] = { "fullname", "sourcefmt", "targetfmt", "continue", "regextarget", 0 }; + name_object_attach_keys(rename_keys, newname); + + /* Add the name */ + single_rename_add(prefix, name, decl, newname); + + /* Add extra names if there are default parameters in the parameter list */ + if (decl) { + int constqualifier = SwigType_isconst(decl); + while (declparms) { + if (ParmList_has_defaultargs(declparms)) { + + /* Create a parameter list for the new rename by copying all + but the last (defaulted) parameter */ + ParmList *newparms = CopyParmListMax(declparms,ParmList_len(declparms)-1); + + /* Create new declaration - with the last parameter removed */ + SwigType *newdecl = Copy(decl); + Delete(SwigType_pop_function(newdecl)); /* remove the old parameter list from newdecl */ + SwigType_add_function(newdecl, newparms); + if (constqualifier) + SwigType_add_qualifier(newdecl, "const"); + + single_rename_add(prefix, name, newdecl, newname); + declparms = newparms; + Delete(newdecl); + } else { + declparms = 0; + } + } + } +} + + +/* Create a name for the given node applying rename/namewarn if needed */ +static String *apply_rename(Node* n, String *newname, int fullname, String *prefix, String *name) { + String *result = 0; + if (newname && Len(newname)) { + if (Strcmp(newname, "$ignore") == 0) { + /* $ignore doesn't apply to parameters and while it's rare to explicitly write %ignore directives for them they could be caught by a wildcard ignore using + regex match, just ignore the attempt to ignore them in this case */ + if (!Equal(nodeType(n), "parm")) + result = Copy(newname); + } else { + char *cnewname = Char(newname); + if (cnewname) { + int destructor = name && (*(Char(name)) == '~'); + String *fmt = newname; + /* use name as a fmt, but avoid C++ "%" and "%=" operators */ + if (Len(newname) > 1 && strchr(cnewname, '%') && !(strcmp(cnewname, "%=") == 0)) { + if (fullname && prefix) { + result = NewStringf(fmt, prefix, name); + } else { + result = NewStringf(fmt, name); + } + } else { + result = Copy(newname); + } + if (destructor && result && (*(Char(result)) != '~')) { + Insert(result, 0, "~"); + } + } + } + } + + return result; +} + +/* ----------------------------------------------------------------------------- + * String *Swig_name_make() + * + * Make a name after applying all the rename/namewarn objects + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_make(Node *n, String *prefix, const_String_or_char_ptr cname, SwigType *decl, String *oldname) { + String *nname = 0; + String *result = 0; + String *name = NewString(cname); + Hash *wrn = 0; + String *rdecl = 0; + String *rname = 0; + + /* very specific hack for template constructors/destructors */ +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_make: looking for %s %s %s %s\n", prefix, name, decl, oldname); +#endif + + if (name && n && SwigType_istemplate(name)) { + String *nodetype = nodeType(n); + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + String *nprefix = 0; + String *nlast = 0; + String *tprefix; + Swig_scopename_split(name, &nprefix, &nlast); + tprefix = SwigType_templateprefix(nlast); + Delete(nlast); + if (Len(nprefix)) { + Append(nprefix, "::"); + Append(nprefix, tprefix); + Delete(tprefix); + rname = nprefix; + } else { + rname = tprefix; + Delete(nprefix); + } + rdecl = Copy(decl); + Replaceall(rdecl, name, rname); +#ifdef SWIG_DEBUG + Printf(stdout, "SWIG_name_make: use new name %s %s : %s %s\n", name, decl, rname, rdecl); +#endif + decl = rdecl; + Delete(name); + name = rname; + } + } + + if (rename_hash || rename_list || namewarn_hash || namewarn_list) { + Hash *rn = Swig_name_object_get(name_rename_hash(), prefix, name, decl); + if (!rn || !name_match_nameobj(rn, n)) { + rn = name_nameobj_lget(name_rename_list(), n, prefix, name, decl); + if (rn) { + String *sfmt = Getattr(rn, "sourcefmt"); + int fullname = GetFlag(rn, "fullname"); + if (fullname && prefix) { + String *sname = NewStringf("%s::%s", prefix, name); + Delete(name); + name = sname; + prefix = 0; + } + if (sfmt) { + String *sname = NewStringf(sfmt, name); + Delete(name); + name = sname; + } + } + } + if (rn) { + String *newname = Getattr(rn, "name"); + int fullname = GetFlag(rn, "fullname"); + result = apply_rename(n, newname, fullname, prefix, name); + } + if (result && !Equal(result, name)) { + /* operators in C++ allow aliases, we look for them */ + char *cresult = Char(result); + if (cresult && (strncmp(cresult, "operator ", 9) == 0)) { + String *nresult = Swig_name_make(n, prefix, result, decl, oldname); + if (!Equal(nresult, result)) { + Delete(result); + result = nresult; + } else { + Delete(nresult); + } + } + } + nname = result ? result : name; + wrn = name_namewarn_get(n, prefix, nname, decl); + if (wrn) { + String *rename = Getattr(wrn, "rename"); + if (rename) { + String *msg = Getattr(wrn, "name"); + int fullname = GetFlag(wrn, "fullname"); + if (result) + Delete(result); + result = apply_rename(n, rename, fullname, prefix, name); + if ((msg) && (Len(msg))) { + if (!Getmeta(nname, "already_warned")) { + String* suffix = 0; + if (Strcmp(result, "$ignore") == 0) { + suffix = NewStringf(": ignoring '%s'\n", name); + } else if (Strcmp(result, name) != 0) { + suffix = NewStringf(", renaming to '%s'\n", result); + } else { + /* No rename was performed */ + suffix = NewString("\n"); + } + if (n) { + /* Parameter renaming is not fully implemented. Mainly because there is no C/C++ syntax to + * for %rename to fully qualify a function's parameter name from outside the function. Hence it + * is not possible to implemented targeted warning suppression on one parameter in one function. */ + int suppress_parameter_rename_warning = Equal(nodeType(n), "parm"); + if (!suppress_parameter_rename_warning) { + SWIG_WARN_NODE_BEGIN(n); + Swig_warning(0, Getfile(n), Getline(n), "%s%s", msg, suffix); + SWIG_WARN_NODE_END(n); + } + } else { + Swig_warning(0, Getfile(name), Getline(name), "%s%s", msg, suffix); + } + Setmeta(nname, "already_warned", "1"); + Delete(suffix); + } + } + } + } + } + if (!result || !Len(result)) { + if (result) + Delete(result); + if (oldname) { + result = NewString(oldname); + } else { + result = NewString(cname); + } + } + Delete(name); + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_name_make: result '%s' '%s'\n", cname, result); +#endif + + return result; +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_inherit() + * + * Inherit namewarn, rename, and feature objects + * + * ----------------------------------------------------------------------------- */ + +void Swig_name_inherit(String *base, String *derived) { + /* Printf(stdout,"base = '%s', derived = '%s'\n", base, derived); */ + Swig_name_object_inherit(name_rename_hash(), base, derived); + Swig_name_object_inherit(name_namewarn_hash(), base, derived); + Swig_name_object_inherit(Swig_cparse_features(), base, derived); +} + +/* ----------------------------------------------------------------------------- + * Swig_inherit_base_symbols() + * ----------------------------------------------------------------------------- */ + +void Swig_inherit_base_symbols(List *bases) { + if (bases) { + Iterator s; + for (s = First(bases); s.item; s = Next(s)) { + Symtab *st = Getattr(s.item, "symtab"); + if (st) { + Setfile(st, Getfile(s.item)); + Setline(st, Getline(s.item)); + Swig_symbol_inherit(st); + } + } + Delete(bases); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_make_inherit_list() + * ----------------------------------------------------------------------------- */ + +List *Swig_make_inherit_list(String *clsname, List *names, String *Namespaceprefix) { + int i, ilen; + String *derived; + List *bases = NewList(); + + if (Namespaceprefix) + derived = NewStringf("%s::%s", Namespaceprefix, clsname); + else + derived = NewString(clsname); + + ilen = Len(names); + for (i = 0; i < ilen; i++) { + String *base; + String *n = Getitem(names, i); + /* Try to figure out where this symbol is */ + Node *s = Swig_symbol_clookup(n, 0); + if (s) { + while (s && (Strcmp(nodeType(s), "class") != 0)) { + /* Not a class. Could be a typedef though. */ + String *storage = Getattr(s, "storage"); + if (storage && (Strcmp(storage, "typedef") == 0)) { + String *nn = Getattr(s, "type"); + s = Swig_symbol_clookup(nn, Getattr(s, "sym:symtab")); + } else { + break; + } + } + if (s && ((Strcmp(nodeType(s), "class") == 0) || (Strcmp(nodeType(s), "template") == 0))) { + String *q = Swig_symbol_qualified(s); + Append(bases, s); + if (q) { + base = NewStringf("%s::%s", q, Getattr(s, "name")); + Delete(q); + } else { + base = NewString(Getattr(s, "name")); + } + } else { + base = NewString(n); + } + } else { + base = NewString(n); + } + if (base) { + Swig_name_inherit(base, derived); + Delete(base); + } + } + return bases; +} + + +/* ----------------------------------------------------------------------------- + * void Swig_name_str() + * + * Return a stringified version of a C/C++ symbol from a node. + * The node passed in is expected to be a function, constructor, destructor or + * variable. Some example return values: + * "MyNameSpace::MyTemplate<MyNameSpace::ABC >::~MyTemplate" + * "MyNameSpace::ABC::ABC" + * "MyNameSpace::ABC::constmethod" + * "MyNameSpace::ABC::variablename" + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_str(Node *n) { + String *qname; + String *qualifier = Swig_symbol_qualified(n); + String *name = Swig_scopename_last(Getattr(n, "name")); + if (qualifier) + qualifier = SwigType_namestr(qualifier); + + /* Very specific hack for template constructors/destructors */ + if (SwigType_istemplate(name)) { + String *nodetype = nodeType(n); + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + String *nprefix = 0; + String *nlast = 0; + String *tprefix; + Swig_scopename_split(name, &nprefix, &nlast); + tprefix = SwigType_templateprefix(nlast); + Delete(nlast); + Delete(nprefix); + Delete(name); + name = tprefix; + } + } + + qname = NewString(""); + if (qualifier && Len(qualifier) > 0) + Printf(qname, "%s::", qualifier); + Printf(qname, "%s", SwigType_str(name, 0)); + + Delete(name); + Delete(qualifier); + + return qname; +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_decl() + * + * Return a stringified version of a C/C++ declaration without the return type. + * The node passed in is expected to be a function, constructor, destructor or + * variable. Some example return values: + * "MyNameSpace::MyTemplate<MyNameSpace::ABC >::~MyTemplate()" + * "MyNameSpace::ABC::ABC(int,double)" + * "MyNameSpace::ABC::constmethod(int) const" + * "MyNameSpace::ABC::refqualifiermethod(int) const &" + * "MyNameSpace::ABC::variablename" + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_decl(Node *n) { + String *qname; + String *decl; + + qname = Swig_name_str(n); + decl = NewStringf("%s", qname); + + if (!checkAttribute(n, "kind", "variable")) { + String *d = Getattr(n, "decl"); + Printv(decl, "(", ParmList_errorstr(Getattr(n, "parms")), ")", NIL); + if (SwigType_isfunction(d)) { + SwigType *decl_temp = Copy(d); + SwigType *qualifiers = SwigType_pop_function_qualifiers(decl_temp); + if (qualifiers) { + String *qualifiers_string = SwigType_str(qualifiers, 0); + Printv(decl, " ", qualifiers_string, NIL); + Delete(qualifiers_string); + } + Delete(decl_temp); + } + } + + Delete(qname); + + return decl; +} + +/* ----------------------------------------------------------------------------- + * void Swig_name_fulldecl() + * + * Return a stringified version of a C/C++ declaration including the return type. + * The node passed in is expected to be a function, constructor or destructor. + * Some example return values: + * "MyNameSpace::MyTemplate<MyNameSpace::ABC >::~MyTemplate()" + * "MyNameSpace::ABC::ABC(int,double)" + * "int * MyNameSpace::ABC::constmethod(int) const" + * + * ----------------------------------------------------------------------------- */ + +String *Swig_name_fulldecl(Node *n) { + String *decl = Swig_name_decl(n); + String *type = Getattr(n, "type"); + String *nodetype = nodeType(n); + String *fulldecl; + /* add on the return type */ + if (nodetype && (Equal(nodetype, "constructor") || Equal(nodetype, "destructor"))) { + fulldecl = decl; + } else { + String *t = SwigType_str(type, 0); + fulldecl = NewStringf("%s %s", t, decl); + Delete(decl); + Delete(t); + } + return fulldecl; +} + diff --git a/contrib/tools/swig/Source/Swig/parms.c b/contrib/tools/swig/Source/Swig/parms.c new file mode 100644 index 0000000000..11071ce0cd --- /dev/null +++ b/contrib/tools/swig/Source/Swig/parms.c @@ -0,0 +1,272 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * parms.c + * + * Parameter list class. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" + +/* ------------------------------------------------------------------------ + * NewParm() + * + * Create a new parameter from datatype 'type' and name 'name' copying + * the file and line number from the Node from_node. + * ------------------------------------------------------------------------ */ + +Parm *NewParm(SwigType *type, const_String_or_char_ptr name, Node *from_node) { + Parm *p = NewParmWithoutFileLineInfo(type, name); + Setfile(p, Getfile(from_node)); + Setline(p, Getline(from_node)); + return p; +} + +/* ------------------------------------------------------------------------ + * NewParmWithoutFileLineInfo() + * + * Create a new parameter from datatype 'type' and name 'name' without any + * file / line numbering information. + * ------------------------------------------------------------------------ */ + +Parm *NewParmWithoutFileLineInfo(SwigType *type, const_String_or_char_ptr name) { + Parm *p = NewHash(); + set_nodeType(p, "parm"); + if (type) { + SwigType *ntype = Copy(type); + Setattr(p, "type", ntype); + Delete(ntype); + } + Setattr(p, "name", name); + return p; +} + +/* ------------------------------------------------------------------------ + * NewParmNode() + * + * Create a new parameter from datatype 'type' and name and symbol table as + * well as file and line number from the 'from_node'. + * The resulting Parm will be similar to a Node used for typemap lookups. + * ------------------------------------------------------------------------ */ + +Parm *NewParmNode(SwigType *type, Node *from_node) { + Parm *p = NewParm(type, Getattr(from_node, "name"), from_node); + Setattr(p, "sym:symtab", Getattr(from_node, "sym:symtab")); + return p; +} + +/* ------------------------------------------------------------------------ + * CopyParm() + * ------------------------------------------------------------------------ */ + +Parm *CopyParm(Parm *p) { + Parm *np = NewHash(); + Iterator ki; + for (ki = First(p); ki.key; ki = Next(ki)) { + if (DohIsString(ki.item)) { + DOH *c = Copy(ki.item); + Setattr(np,ki.key,c); + Delete(c); + } + } + Setfile(np, Getfile(p)); + Setline(np, Getline(p)); + return np; +} + +/* ------------------------------------------------------------------ + * CopyParmListMax() + * CopyParmList() + * ------------------------------------------------------------------ */ + +ParmList *CopyParmListMax(ParmList *p, int count) { + Parm *np; + Parm *pp = 0; + Parm *fp = 0; + + if (!p) + return 0; + + while (p) { + if (count == 0) break; + np = CopyParm(p); + if (pp) { + set_nextSibling(pp, np); + Delete(np); + } else { + fp = np; + } + pp = np; + p = nextSibling(p); + count--; + } + return fp; +} + +ParmList *CopyParmList(ParmList *p) { + return CopyParmListMax(p,-1); +} + +/* ----------------------------------------------------------------------------- + * int ParmList_numrequired(). Return number of required arguments + * ----------------------------------------------------------------------------- */ + +int ParmList_numrequired(ParmList *p) { + int i = 0; + while (p) { + SwigType *t = Getattr(p, "type"); + String *value = Getattr(p, "value"); + if (value) + return i; + if (!(SwigType_type(t) == T_VOID)) + i++; + else + break; + p = nextSibling(p); + } + return i; +} + +/* ----------------------------------------------------------------------------- + * int ParmList_len() + * ----------------------------------------------------------------------------- */ + +int ParmList_len(ParmList *p) { + int i = 0; + while (p) { + i++; + p = nextSibling(p); + } + return i; +} + +/* --------------------------------------------------------------------- + * get_empty_type() + * ---------------------------------------------------------------------- */ + +static SwigType *get_empty_type(void) { + return NewStringEmpty(); +} + +/* --------------------------------------------------------------------- + * ParmList_str() + * + * Generates a string of parameters + * ---------------------------------------------------------------------- */ + +String *ParmList_str(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + String *type = Getattr(p, "type"); + String *pstr = SwigType_str(type ? type : get_empty_type(), Getattr(p, "name")); + Append(out, pstr); + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + return out; +} + +/* --------------------------------------------------------------------- + * ParmList_str_defaultargs() + * + * Generates a string of parameters including default arguments + * ---------------------------------------------------------------------- */ + +String *ParmList_str_defaultargs(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + String *value = Getattr(p, "value"); + String *type = Getattr(p, "type"); + String *pstr = SwigType_str(type ? type : get_empty_type(), Getattr(p, "name")); + Append(out, pstr); + if (value) { + Printf(out, "=%s", value); + } + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + return out; +} + +/* ----------------------------------------------------------------------------- + * ParmList_str_multibrackets() + * + * Generates a string of parameters including default arguments adding brackets + * if more than one parameter + * ----------------------------------------------------------------------------- */ + +String *ParmList_str_multibrackets(ParmList *p) { + String *out; + String *parm_str = ParmList_str_defaultargs(p); + if (ParmList_len(p) > 1) + out = NewStringf("(%s)", parm_str); + else + out = NewStringf("%s", parm_str); + Delete(parm_str); + return out; +} + +/* --------------------------------------------------------------------- + * ParmList_protostr() + * + * Generate a prototype string. + * ---------------------------------------------------------------------- */ + +String *ParmList_protostr(ParmList *p) { + String *out = NewStringEmpty(); + while (p) { + String *type = Getattr(p, "type"); + String *pstr = SwigType_str(type ? type : get_empty_type(), 0); + Append(out, pstr); + p = nextSibling(p); + if (p) { + Append(out, ","); + } + Delete(pstr); + } + return out; +} + +/* --------------------------------------------------------------------- + * ParmList_has_defaultargs() + * + * Returns 1 if the parameter list passed in is has one or more default + * arguments. Otherwise returns 0. + * ---------------------------------------------------------------------- */ + +int ParmList_has_defaultargs(ParmList *p) { + while (p) { + if (Getattr(p, "value")) { + return 1; + } + p = nextSibling(p); + } + return 0; +} + +/* --------------------------------------------------------------------- + * ParmList_has_varargs() + * + * Returns 1 if the parameter list passed in has varargs. + * Otherwise returns 0. + * ---------------------------------------------------------------------- */ + +int ParmList_has_varargs(ParmList *p) { + Parm *lp = 0; + while (p) { + lp = p; + p = nextSibling(p); + } + return lp ? SwigType_isvarargs(Getattr(lp, "type")) : 0; +} diff --git a/contrib/tools/swig/Source/Swig/scanner.c b/contrib/tools/swig/Source/Swig/scanner.c new file mode 100644 index 0000000000..9dbb353648 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/scanner.c @@ -0,0 +1,1898 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * scanner.c + * + * This file implements a general purpose C/C++ compatible lexical scanner. + * This scanner isn't intended to be plugged directly into a parser built + * with yacc. Rather, it contains a lot of generic code that could be used + * to easily construct yacc-compatible scanners. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include <ctype.h> + +extern String *cparse_file; +extern int cparse_line; +extern int cparse_cplusplus; +extern int cparse_start_line; + +struct Scanner { + String *text; /* Current token value */ + List *scanobjs; /* Objects being scanned */ + String *str; /* Current object being scanned */ + char *idstart; /* Optional identifier start characters */ + int nexttoken; /* Next token to be returned */ + int start_line; /* Starting line of certain declarations */ + int line; + int yylen; /* Length of text pushed into text */ + String *file; + String *error; /* Last error message (if any) */ + int error_line; /* Error line number */ + int freeze_line; /* Suspend line number updates */ + List *brackets; /* Current level of < > brackets on each level */ +}; + +typedef struct Locator { + String *filename; + int line_number; + struct Locator *next; +} Locator; +static int follow_locators = 0; + +static void brackets_push(Scanner *); +static void brackets_clear(Scanner *); + +/* ----------------------------------------------------------------------------- + * NewScanner() + * + * Create a new scanner object + * ----------------------------------------------------------------------------- */ + +Scanner *NewScanner(void) { + Scanner *s; + s = (Scanner *) Malloc(sizeof(Scanner)); + s->line = 1; + s->file = 0; + s->nexttoken = -1; + s->start_line = 1; + s->yylen = 0; + s->idstart = NULL; + s->scanobjs = NewList(); + s->text = NewStringEmpty(); + s->str = 0; + s->error = 0; + s->error_line = 0; + s->freeze_line = 0; + s->brackets = NewList(); + brackets_push(s); + return s; +} + +/* ----------------------------------------------------------------------------- + * DelScanner() + * + * Delete a scanner object. + * ----------------------------------------------------------------------------- */ + +void DelScanner(Scanner *s) { + assert(s); + Delete(s->scanobjs); + Delete(s->brackets); + Delete(s->text); + Delete(s->file); + Delete(s->error); + Delete(s->str); + Free(s->idstart); + Free(s); +} + +/* ----------------------------------------------------------------------------- + * Scanner_clear() + * + * Clear the contents of a scanner object. + * ----------------------------------------------------------------------------- */ + +void Scanner_clear(Scanner *s) { + assert(s); + Delete(s->str); + Clear(s->text); + Clear(s->scanobjs); + brackets_clear(s); + Delete(s->error); + s->str = 0; + s->error = 0; + s->line = 1; + s->nexttoken = -1; + s->start_line = 0; + s->yylen = 0; + /* Should these be cleared too? + s->idstart; + s->file; + s->error_line; + s->freeze_line; + */ +} + +/* ----------------------------------------------------------------------------- + * Scanner_push() + * + * Push some new text into the scanner. The scanner will start parsing this text + * immediately before returning to the old text. + * ----------------------------------------------------------------------------- */ + +void Scanner_push(Scanner *s, String *txt) { + assert(s && txt); + Push(s->scanobjs, txt); + if (s->str) { + Setline(s->str,s->line); + Delete(s->str); + } + s->str = txt; + DohIncref(s->str); + s->line = Getline(txt); +} + +/* ----------------------------------------------------------------------------- + * Scanner_pushtoken() + * + * Push a token into the scanner. This token will be returned on the next + * call to Scanner_token(). + * ----------------------------------------------------------------------------- */ + +void Scanner_pushtoken(Scanner *s, int nt, const_String_or_char_ptr val) { + assert(s); + assert((nt >= 0) && (nt < SWIG_MAXTOKENS)); + s->nexttoken = nt; + if ( Char(val) != Char(s->text) ) { + Clear(s->text); + Append(s->text,val); + } +} + +/* ----------------------------------------------------------------------------- + * Scanner_set_location() + * + * Set the file and line number location of the scanner. + * ----------------------------------------------------------------------------- */ + +void Scanner_set_location(Scanner *s, String *file, int line) { + Setline(s->str, line); + Setfile(s->str, file); + s->line = line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_file() + * + * Get the current file. + * ----------------------------------------------------------------------------- */ + +String *Scanner_file(Scanner *s) { + return Getfile(s->str); +} + +/* ----------------------------------------------------------------------------- + * Scanner_line() + * + * Get the current line number + * ----------------------------------------------------------------------------- */ +int Scanner_line(Scanner *s) { + return s->line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_start_line() + * + * Get the line number on which the current token starts + * ----------------------------------------------------------------------------- */ +int Scanner_start_line(Scanner *s) { + return s->start_line; +} + +/* ----------------------------------------------------------------------------- + * Scanner_idstart() + * + * Change the set of additional characters that can be used to start an identifier. + * ----------------------------------------------------------------------------- */ + +void Scanner_idstart(Scanner *s, const char *id) { + Free(s->idstart); + s->idstart = Swig_copy_string(id); +} + +/* ----------------------------------------------------------------------------- + * nextchar() + * + * Returns the next character from the scanner or 0 if end of the string. + * ----------------------------------------------------------------------------- */ +static char nextchar(Scanner *s) { + int nc; + if (!s->str) + return 0; + while ((nc = Getc(s->str)) == EOF) { + Delete(s->str); + s->str = 0; + Delitem(s->scanobjs, 0); + if (Len(s->scanobjs) == 0) + return 0; + s->str = Getitem(s->scanobjs, 0); + s->line = Getline(s->str); + DohIncref(s->str); + } + if ((nc == '\n') && (!s->freeze_line)) + s->line++; + Putc(nc,s->text); + return (char)nc; +} + +/* ----------------------------------------------------------------------------- + * set_error() + * + * Sets error information on the scanner. + * ----------------------------------------------------------------------------- */ + +static void set_error(Scanner *s, int line, const_String_or_char_ptr msg) { + s->error_line = line; + s->error = NewString(msg); +} + +/* ----------------------------------------------------------------------------- + * Scanner_errmsg() + * Scanner_errline() + * + * Returns error information (if any) + * ----------------------------------------------------------------------------- */ + +String *Scanner_errmsg(Scanner *s) { + return s->error; +} + +int Scanner_errline(Scanner *s) { + return s->error_line; +} + +/* ----------------------------------------------------------------------------- + * freeze_line() + * + * Freezes the current line number. + * ----------------------------------------------------------------------------- */ + +static void freeze_line(Scanner *s, int val) { + s->freeze_line = val; +} + +/* ----------------------------------------------------------------------------- + * brackets_count() + * + * Returns the number of brackets at the current depth. + * A syntax error with unbalanced ) brackets will result in a NULL pointer return. + * ----------------------------------------------------------------------------- */ +static int *brackets_count(Scanner *s) { + int *count; + if (Len(s->brackets) > 0) + count = (int *)Data(Getitem(s->brackets, 0)); + else + count = 0; + return count; +} + +/* ----------------------------------------------------------------------------- + * brackets_clear() + * + * Resets the current depth and clears all brackets. + * Usually called at the end of statements; + * ----------------------------------------------------------------------------- */ +static void brackets_clear(Scanner *s) { + Clear(s->brackets); + brackets_push(s); /* base bracket count should always be created */ +} + +/* ----------------------------------------------------------------------------- + * brackets_increment() + * + * Increases the number of brackets at the current depth. + * Usually called when a single '<' is found. + * ----------------------------------------------------------------------------- */ +static void brackets_increment(Scanner *s) { + int *count = brackets_count(s); + if (count) + (*count)++; +} + +/* ----------------------------------------------------------------------------- + * brackets_decrement() + * + * Decreases the number of brackets at the current depth. + * Usually called when a single '>' is found. + * ----------------------------------------------------------------------------- */ +static void brackets_decrement(Scanner *s) { + int *count = brackets_count(s); + if (count) + (*count)--; +} + +/* ----------------------------------------------------------------------------- + * brackets_reset() + * + * Sets the number of '<' brackets back to zero. Called at the point where + * it is no longer possible to have a matching closing >> pair for a template. + * ----------------------------------------------------------------------------- */ +static void brackets_reset(Scanner *s) { + int *count = brackets_count(s); + if (count) + *count = 0; +} + +/* ----------------------------------------------------------------------------- + * brackets_push() + * + * Increases the depth of brackets. + * Usually called when '(' is found. + * ----------------------------------------------------------------------------- */ +static void brackets_push(Scanner *s) { + int *newInt = (int *)Malloc(sizeof(int)); + *newInt = 0; + Push(s->brackets, NewVoid(newInt, Free)); +} + +/* ----------------------------------------------------------------------------- + * brackets_pop() + * + * Decreases the depth of brackets. + * Usually called when ')' is found. + * ----------------------------------------------------------------------------- */ +static void brackets_pop(Scanner *s) { + if (Len(s->brackets) > 0) /* protect against unbalanced ')' brackets */ + Delitem(s->brackets, 0); +} + +/* ----------------------------------------------------------------------------- + * brackets_allow_shift() + * + * Return 1 to allow shift (>>), or 0 if (>>) should be split into (> >). + * This is for C++11 template syntax for closing templates. + * ----------------------------------------------------------------------------- */ +static int brackets_allow_shift(Scanner *s) { + int *count = brackets_count(s); + return !count || (*count <= 0); +} + +/* ----------------------------------------------------------------------------- + * retract() + * + * Retract n characters + * ----------------------------------------------------------------------------- */ +static void retract(Scanner *s, int n) { + int i, l; + char *str; + + str = Char(s->text); + l = Len(s->text); + assert(n <= l); + for (i = 0; i < n; i++) { + if (str[l - 1] == '\n') { + if (!s->freeze_line) s->line--; + } + (void)Seek(s->str, -1, SEEK_CUR); + Delitem(s->text, DOH_END); + } +} + +/* ----------------------------------------------------------------------------- + * get_escape() + * + * Get escape sequence. Called when a backslash is found in a string + * ----------------------------------------------------------------------------- */ + +static void get_escape(Scanner *s) { + int result = 0; + int state = 0; + int c; + + while (1) { + c = nextchar(s); + if (c == 0) + break; + switch (state) { + case 0: + if (c == 'n') { + Delitem(s->text, DOH_END); + Append(s->text,"\n"); + return; + } + if (c == 'r') { + Delitem(s->text, DOH_END); + Append(s->text,"\r"); + return; + } + if (c == 't') { + Delitem(s->text, DOH_END); + Append(s->text,"\t"); + return; + } + if (c == 'a') { + Delitem(s->text, DOH_END); + Append(s->text,"\a"); + return; + } + if (c == 'b') { + Delitem(s->text, DOH_END); + Append(s->text,"\b"); + return; + } + if (c == 'f') { + Delitem(s->text, DOH_END); + Append(s->text,"\f"); + return; + } + if (c == '\\') { + Delitem(s->text, DOH_END); + Append(s->text,"\\"); + return; + } + if (c == 'v') { + Delitem(s->text, DOH_END); + Append(s->text,"\v"); + return; + } + if (c == 'e') { + Delitem(s->text, DOH_END); + Append(s->text,"\033"); + return; + } + if (c == '\'') { + Delitem(s->text, DOH_END); + Append(s->text,"\'"); + return; + } + if (c == '\"') { + Delitem(s->text, DOH_END); + Append(s->text,"\""); + return; + } + if (c == '\n') { + Delitem(s->text, DOH_END); + return; + } + if (isdigit(c)) { + state = 10; + result = (c - '0'); + Delitem(s->text, DOH_END); + } else if (c == 'x') { + state = 20; + Delitem(s->text, DOH_END); + } else { + char tmp[3]; + tmp[0] = '\\'; + tmp[1] = (char)c; + tmp[2] = 0; + Delitem(s->text, DOH_END); + Append(s->text, tmp); + return; + } + break; + case 10: + if (!isdigit(c)) { + retract(s,1); + Putc((char)result,s->text); + return; + } + result = (result << 3) + (c - '0'); + Delitem(s->text, DOH_END); + break; + case 20: + if (!isxdigit(c)) { + retract(s,1); + Putc((char)result, s->text); + return; + } + if (isdigit(c)) + result = (result << 4) + (c - '0'); + else + result = (result << 4) + (10 + tolower(c) - 'a'); + Delitem(s->text, DOH_END); + break; + } + } + return; +} + +/* ----------------------------------------------------------------------------- + * look() + * + * Return the raw value of the next token. + * ----------------------------------------------------------------------------- */ + +static int look(Scanner *s) { + int state = 0; + int c = 0; + String *str_delimiter = 0; + + Clear(s->text); + s->start_line = s->line; + Setfile(s->text, Getfile(s->str)); + + + while (1) { + switch (state) { + case 0: + if ((c = nextchar(s)) == 0) + return (0); + + /* Process delimiters */ + + if (c == '\n') { + return SWIG_TOKEN_ENDLINE; + } else if (!isspace(c)) { + retract(s, 1); + state = 1000; + Clear(s->text); + Setline(s->text, s->line); + Setfile(s->text, Getfile(s->str)); + } + break; + + case 1000: + if ((c = nextchar(s)) == 0) + return (0); + if (c == '%') + state = 4; /* Possibly a SWIG directive */ + + /* Look for possible identifiers or unicode/delimiter strings */ + else if ((isalpha(c)) || (c == '_') || + (s->idstart && strchr(s->idstart, c))) { + state = 7; + } + + /* Look for single character symbols */ + + else if (c == '(') { + brackets_push(s); + return SWIG_TOKEN_LPAREN; + } + else if (c == ')') { + brackets_pop(s); + return SWIG_TOKEN_RPAREN; + } + else if (c == ';') { + brackets_clear(s); + return SWIG_TOKEN_SEMI; + } + else if (c == ',') + return SWIG_TOKEN_COMMA; + else if (c == '*') + state = 220; + else if (c == '}') + return SWIG_TOKEN_RBRACE; + else if (c == '{') { + brackets_reset(s); + return SWIG_TOKEN_LBRACE; + } + else if (c == '=') + state = 33; + else if (c == '+') + state = 200; + else if (c == '-') + state = 210; + else if (c == '&') + state = 31; + else if (c == '|') + state = 32; + else if (c == '^') + state = 230; + else if (c == '<') + state = 60; + else if (c == '>') + state = 61; + else if (c == '~') + return SWIG_TOKEN_NOT; + else if (c == '!') + state = 3; + else if (c == '\\') + return SWIG_TOKEN_BACKSLASH; + else if (c == '@') + return SWIG_TOKEN_AT; + else if (c == '$') + state = 75; + else if (c == '#') + return SWIG_TOKEN_POUND; + else if (c == '?') + return SWIG_TOKEN_QUESTION; + + /* Look for multi-character sequences */ + + else if (c == '/') { + state = 1; /* Comment (maybe) */ + s->start_line = s->line; + } + + else if (c == ':') + state = 5; /* maybe double colon */ + else if (c == '0') + state = 83; /* An octal or hex value */ + else if (c == '\"') { + state = 2; /* A string constant */ + s->start_line = s->line; + Clear(s->text); + } + else if (c == '\'') { + s->start_line = s->line; + Clear(s->text); + state = 9; /* A character constant */ + } else if (c == '`') { + s->start_line = s->line; + Clear(s->text); + state = 900; + } + + else if (c == '.') + state = 100; /* Maybe a number, maybe ellipsis, just a period */ + else if (c == '[') + state = 102; /* Maybe a bracket or a double bracket */ + else if (c == ']') + state = 103; /* Maybe a bracket or a double bracket */ + else if (isdigit(c)) + state = 8; /* A numerical value */ + else + state = 99; /* An error */ + break; + + case 1: /* Comment block */ + if ((c = nextchar(s)) == 0) + return (0); + if (c == '/') { + state = 10; /* C++ style comment */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + Append(s->text, "//"); + } else if (c == '*') { + state = 11; /* C style comment */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + Append(s->text, "/*"); + } else if (c == '=') { + return SWIG_TOKEN_DIVEQUAL; + } else { + retract(s, 1); + return SWIG_TOKEN_SLASH; + } + break; + case 10: /* C++ style comment */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\n') { + retract(s,1); + return SWIG_TOKEN_COMMENT; + } else { + state = 10; + } + break; + case 11: /* C style comment block */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '*') { + state = 12; + } else { + state = 11; + } + break; + case 12: /* Still in C style comment */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated comment\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '*') { + state = 12; + } else if (c == '/') { + return SWIG_TOKEN_COMMENT; + } else { + state = 11; + } + break; + + case 2: /* Processing a string */ + if (!str_delimiter) { + state=20; + break; + } + + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated string\n"); + return SWIG_TOKEN_ERROR; + } + else if (c == '(') { + state = 20; + } + else { + char temp[2] = { 0, 0 }; + temp[0] = c; + Append( str_delimiter, temp ); + } + + break; + + case 20: /* Inside the string */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated string\n"); + return SWIG_TOKEN_ERROR; + } + + if (!str_delimiter) { /* Ordinary string: "value" */ + if (c == '\"') { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_STRING; + } else if (c == '\\') { + Delitem(s->text, DOH_END); + get_escape(s); + } + } else { /* Custom delimiter string: R"XXXX(value)XXXX" */ + if (c==')') { + int i=0; + String *end_delimiter = NewStringEmpty(); + while ((c = nextchar(s)) != 0 && c!='\"') { + char temp[2] = { 0, 0 }; + temp[0] = c; + Append( end_delimiter, temp ); + i++; + } + + if (Strcmp( str_delimiter, end_delimiter )==0) { + int len = Len(s->text); + Delslice(s->text, len - 2 - Len(str_delimiter), len); /* Delete ending )XXXX" */ + Delslice(s->text, 0, Len(str_delimiter) + 1); /* Delete starting XXXX( */ + Delete( end_delimiter ); /* Correct end delimiter )XXXX" occurred */ + Delete( str_delimiter ); + str_delimiter = 0; + return SWIG_TOKEN_STRING; + } else { /* Incorrect end delimiter occurred */ + if (c == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated raw string, started with R\"%s( is not terminated by )%s\"\n", str_delimiter, str_delimiter); + return SWIG_TOKEN_ERROR; + } + retract( s, i ); + Delete( end_delimiter ); + } + } + } + + break; + + case 3: /* Maybe a not equals */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LNOT; + else if (c == '=') + return SWIG_TOKEN_NOTEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_LNOT; + } + break; + + case 31: /* AND or Logical AND or ANDEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_AND; + else if (c == '&') + return SWIG_TOKEN_LAND; + else if (c == '=') + return SWIG_TOKEN_ANDEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_AND; + } + break; + + case 32: /* OR or Logical OR */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_OR; + else if (c == '|') + return SWIG_TOKEN_LOR; + else if (c == '=') + return SWIG_TOKEN_OREQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_OR; + } + break; + + case 33: /* EQUAL or EQUALTO */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_EQUAL; + else if (c == '=') + return SWIG_TOKEN_EQUALTO; + else { + retract(s, 1); + return SWIG_TOKEN_EQUAL; + } + break; + + case 4: /* A wrapper generator directive (maybe) */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_PERCENT; + if (c == '{') { + state = 40; /* Include block */ + Clear(s->text); + Setline(s->text, Getline(s->str)); + Setfile(s->text, Getfile(s->str)); + s->start_line = s->line; + } else if (s->idstart && strchr(s->idstart, '%') && + ((isalpha(c)) || (c == '_'))) { + state = 7; + } else if (c == '=') { + return SWIG_TOKEN_MODEQUAL; + } else if (c == '}') { + Swig_error(cparse_file, cparse_line, "Syntax error. Extraneous '%%}'\n"); + Exit(EXIT_FAILURE); + } else { + retract(s, 1); + return SWIG_TOKEN_PERCENT; + } + break; + + case 40: /* Process an include block */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated block\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '%') + state = 41; + break; + case 41: /* Still processing include block */ + if ((c = nextchar(s)) == 0) { + set_error(s,s->start_line,"Unterminated code block"); + return 0; + } + if (c == '}') { + Delitem(s->text, DOH_END); + Delitem(s->text, DOH_END); + Seek(s->text,0,SEEK_SET); + return SWIG_TOKEN_CODEBLOCK; + } else { + state = 40; + } + break; + + case 5: /* Maybe a double colon */ + + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_COLON; + if (c == ':') + state = 50; + else { + retract(s, 1); + return SWIG_TOKEN_COLON; + } + break; + + case 50: /* DCOLON, DCOLONSTAR */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DCOLON; + else if (c == '*') + return SWIG_TOKEN_DCOLONSTAR; + else { + retract(s, 1); + return SWIG_TOKEN_DCOLON; + } + break; + + case 60: /* shift operators */ + if ((c = nextchar(s)) == 0) { + brackets_increment(s); + return SWIG_TOKEN_LESSTHAN; + } + if (c == '<') + state = 240; + else if (c == '=') { + if ((c = nextchar(s)) == 0) { + return SWIG_TOKEN_LTEQUAL; + } else if (c == '>' && cparse_cplusplus) { /* Spaceship operator */ + return SWIG_TOKEN_LTEQUALGT; + } else { + retract(s, 1); + return SWIG_TOKEN_LTEQUAL; + } + } else { + retract(s, 1); + brackets_increment(s); + return SWIG_TOKEN_LESSTHAN; + } + break; + case 61: + if ((c = nextchar(s)) == 0) { + brackets_decrement(s); + return SWIG_TOKEN_GREATERTHAN; + } + if (c == '>' && brackets_allow_shift(s)) + state = 250; + else if (c == '=') + return SWIG_TOKEN_GTEQUAL; + else { + retract(s, 1); + brackets_decrement(s); + return SWIG_TOKEN_GREATERTHAN; + } + break; + + case 7: /* Identifier or true/false or unicode/custom delimiter string */ + if (c == 'R') { /* Possibly CUSTOM DELIMITER string */ + state = 72; + break; + } + else if (c == 'L') { /* Probably identifier but may be a wide string literal */ + state = 77; + break; + } + else if (c != 'u' && c != 'U') { /* Definitely an identifier */ + state = 70; + break; + } + + if ((c = nextchar(s)) == 0) { + state = 76; + } + else if (c == '\"') { /* Definitely u, U or L string */ + retract(s, 1); + state = 1000; + } + else if (c == '\'') { /* Definitely u, U or L char */ + retract(s, 1); + state = 77; + } + else if (c == 'R') { /* Possibly CUSTOM DELIMITER u, U, L string */ + state = 73; + } + else if (c == '8') { /* Possibly u8 string/char */ + state = 71; + } + else { + retract(s, 1); /* Definitely an identifier */ + state = 70; + } + break; + + case 70: /* Identifier */ + if ((c = nextchar(s)) == 0) + state = 76; + else if (isalnum(c) || (c == '_') || (c == '$')) { + state = 70; + } else { + retract(s, 1); + state = 76; + } + break; + + case 71: /* Possibly u8 string/char */ + if ((c = nextchar(s)) == 0) { + state = 76; + } + else if (c=='\"') { + retract(s, 1); /* Definitely u8 string */ + state = 1000; + } + else if (c=='\'') { + retract(s, 1); /* Definitely u8 char */ + state = 77; + } + else if (c=='R') { + state = 74; /* Possibly CUSTOM DELIMITER u8 string */ + } + else { + retract(s, 2); /* Definitely an identifier. Retract 8" */ + state = 70; + } + + break; + + case 72: /* Possibly CUSTOM DELIMITER string */ + case 73: + case 74: + if ((c = nextchar(s)) == 0) { + state = 76; + } + else if (c=='\"') { + retract(s, 1); /* Definitely custom delimiter u, U or L string */ + str_delimiter = NewStringEmpty(); + state = 1000; + } + else { + if (state==72) { + retract(s, 1); /* Definitely an identifier. Retract ? */ + } + else if (state==73) { + retract(s, 2); /* Definitely an identifier. Retract R? */ + } + else if (state==74) { + retract(s, 3); /* Definitely an identifier. Retract 8R? */ + } + state = 70; + } + + break; + + case 75: /* Special identifier $ */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DOLLAR; + if (isalnum(c) || (c == '_') || (c == '*') || (c == '&')) { + state = 70; + } else { + retract(s,1); + if (Len(s->text) == 1) return SWIG_TOKEN_DOLLAR; + state = 76; + } + break; + + case 76: /* Identifier or true/false */ + if (cparse_cplusplus) { + if (Strcmp(s->text, "true") == 0) + return SWIG_TOKEN_BOOL; + else if (Strcmp(s->text, "false") == 0) + return SWIG_TOKEN_BOOL; + } + return SWIG_TOKEN_ID; + break; + + case 77: /*identifier or wide string literal*/ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_ID; + else if (c == '\"') { + s->start_line = s->line; + Clear(s->text); + state = 78; + } + else if (c == '\'') { + s->start_line = s->line; + Clear(s->text); + state = 79; + } + else if (isalnum(c) || (c == '_') || (c == '$')) + state = 7; + else { + retract(s, 1); + return SWIG_TOKEN_ID; + } + break; + + case 78: /* Processing a wide string literal*/ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated wide string\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\"') { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_WSTRING; + } else if (c == '\\') { + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated wide string\n"); + return SWIG_TOKEN_ERROR; + } + } + break; + + case 79: /* Processing a wide char literal */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated wide character constant\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\'') { + Delitem(s->text, DOH_END); + return (SWIG_TOKEN_WCHAR); + } else if (c == '\\') { + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated wide character literal\n"); + return SWIG_TOKEN_ERROR; + } + } + break; + + case 8: /* A numerical digit */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (c == '.') { + state = 81; + } else if ((c == 'e') || (c == 'E')) { + state = 82; + } else if ((c == 'f') || (c == 'F')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_FLOAT; + } else if (isdigit(c)) { + state = 8; + } else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 81: /* A floating pointer number of some sort */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DOUBLE; + if (isdigit(c)) + state = 81; + else if ((c == 'e') || (c == 'E')) + state = 820; + else if ((c == 'f') || (c == 'F')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_FLOAT; + } else if ((c == 'l') || (c == 'L')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_DOUBLE; + } else { + retract(s, 1); + return (SWIG_TOKEN_DOUBLE); + } + break; + case 82: + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n"); + return SWIG_TOKEN_ERROR; + } + if ((isdigit(c)) || (c == '-') || (c == '+')) + state = 86; + else { + retract(s, 2); + Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n"); + return SWIG_TOKEN_ERROR; + } + break; + case 820: + /* Like case 82, but we've seen a decimal point. */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n"); + return SWIG_TOKEN_ERROR; + } + if ((isdigit(c)) || (c == '-') || (c == '+')) + state = 86; + else { + retract(s, 2); + Swig_error(cparse_file, cparse_start_line, "Exponent does not have any digits\n"); + return SWIG_TOKEN_ERROR; + } + break; + case 83: + /* Might be a hexadecimal or octal number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (isdigit(c)) + state = 84; + else if ((c == 'e') || (c == 'E')) + state = 82; + else if ((c == 'x') || (c == 'X')) + state = 85; + else if ((c == 'b') || (c == 'B')) + state = 850; + else if (c == '.') + state = 81; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 84: + /* This is an octal number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (isdigit(c)) + state = 84; + else if (c == '.') + state = 81; + else if ((c == 'e') || (c == 'E')) + state = 82; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 85: + /* This is an hex number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if (isxdigit(c)) + state = 85; + else if (c == '.') /* hexadecimal float */ + state = 860; + else if ((c == 'p') || (c == 'P')) /* hexadecimal float */ + state = 820; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 850: + /* This is a binary number */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_INT; + if ((c == '0') || (c == '1')) + state = 850; + else if ((c == 'l') || (c == 'L')) { + state = 87; + } else if ((c == 'u') || (c == 'U')) { + state = 88; + } else { + retract(s, 1); + return SWIG_TOKEN_INT; + } + break; + case 860: + /* hexadecimal float */ + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Hexadecimal floating literals require an exponent\n"); + return SWIG_TOKEN_ERROR; + } + if (isxdigit(c)) + state = 860; + else if ((c == 'p') || (c == 'P')) + state = 820; + else { + retract(s, 2); + Swig_error(cparse_file, cparse_start_line, "Hexadecimal floating literals require an exponent\n"); + return SWIG_TOKEN_ERROR; + } + break; + case 86: + /* Rest of floating point number */ + + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_DOUBLE; + if (isdigit(c)) + state = 86; + else if ((c == 'f') || (c == 'F')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_FLOAT; + } else if ((c == 'l') || (c == 'L')) { + Delitem(s->text, DOH_END); + return SWIG_TOKEN_DOUBLE; + } else { + retract(s, 1); + return SWIG_TOKEN_DOUBLE; + } + break; + + case 87: + /* A long integer of some sort */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LONG; + if ((c == 'u') || (c == 'U')) { + return SWIG_TOKEN_ULONG; + } else if ((c == 'l') || (c == 'L')) { + state = 870; + } else { + retract(s, 1); + return SWIG_TOKEN_LONG; + } + break; + + /* A long long integer */ + + case 870: + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LONGLONG; + if ((c == 'u') || (c == 'U')) { + return SWIG_TOKEN_ULONGLONG; + } else { + retract(s, 1); + return SWIG_TOKEN_LONGLONG; + } + + /* An unsigned number */ + case 88: + + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_UINT; + if ((c == 'l') || (c == 'L')) { + state = 880; + } else { + retract(s, 1); + return SWIG_TOKEN_UINT; + } + break; + + /* Possibly an unsigned long long or unsigned long */ + case 880: + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_ULONG; + if ((c == 'l') || (c == 'L')) + return SWIG_TOKEN_ULONGLONG; + else { + retract(s, 1); + return SWIG_TOKEN_ULONG; + } + + /* A character constant */ + case 9: + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '\'') { + Delitem(s->text, DOH_END); + return (SWIG_TOKEN_CHAR); + } else if (c == '\\') { + Delitem(s->text, DOH_END); + get_escape(s); + } + break; + + /* A period or an ellipsis or maybe a floating point number */ + + case 100: + if ((c = nextchar(s)) == 0) + return (0); + if (isdigit(c)) + state = 81; + else if (c == '.') + state = 101; + else { + retract(s, 1); + return SWIG_TOKEN_PERIOD; + } + break; + + /* An ellipsis */ + + case 101: + if ((c = nextchar(s)) == 0) + return (0); + if (c == '.') { + return SWIG_TOKEN_ELLIPSIS; + } else { + retract(s, 2); + return SWIG_TOKEN_PERIOD; + } + break; + + /* A left bracket or a double left bracket */ + case 102: + + if ((c = nextchar(s)) == 0) { + return SWIG_TOKEN_LBRACKET; + } else if (c == '[') { + return SWIG_TOKEN_LLBRACKET; + } else { + retract(s, 1); + return SWIG_TOKEN_LBRACKET; + } + break; + + /* a right bracket or a double right bracket */ + case 103: + if ((c = nextchar(s)) == 0) { + return SWIG_TOKEN_RBRACKET; + } else if (c == ']') { + return SWIG_TOKEN_RRBRACKET; + } else { + retract(s, 1); + return SWIG_TOKEN_RBRACKET; + } + break; + + case 200: /* PLUS, PLUSPLUS, PLUSEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_PLUS; + else if (c == '+') + return SWIG_TOKEN_PLUSPLUS; + else if (c == '=') + return SWIG_TOKEN_PLUSEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_PLUS; + } + break; + + case 210: /* MINUS, MINUSMINUS, MINUSEQUAL, ARROW */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_MINUS; + else if (c == '-') + return SWIG_TOKEN_MINUSMINUS; + else if (c == '=') + return SWIG_TOKEN_MINUSEQUAL; + else if (c == '>') + state = 211; + else { + retract(s, 1); + return SWIG_TOKEN_MINUS; + } + break; + + case 211: /* ARROW, ARROWSTAR */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_ARROW; + else if (c == '*') + return SWIG_TOKEN_ARROWSTAR; + else { + retract(s, 1); + return SWIG_TOKEN_ARROW; + } + break; + + + case 220: /* STAR, TIMESEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_STAR; + else if (c == '=') + return SWIG_TOKEN_TIMESEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_STAR; + } + break; + + case 230: /* XOR, XOREQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_XOR; + else if (c == '=') + return SWIG_TOKEN_XOREQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_XOR; + } + break; + + case 240: /* LSHIFT, LSEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_LSHIFT; + else if (c == '=') + return SWIG_TOKEN_LSEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_LSHIFT; + } + break; + + case 250: /* RSHIFT, RSEQUAL */ + if ((c = nextchar(s)) == 0) + return SWIG_TOKEN_RSHIFT; + else if (c == '=') + return SWIG_TOKEN_RSEQUAL; + else { + retract(s, 1); + return SWIG_TOKEN_RSHIFT; + } + break; + + + /* An illegal character */ + + /* Reverse string */ + case 900: + if ((c = nextchar(s)) == 0) { + Swig_error(cparse_file, cparse_start_line, "Unterminated character constant\n"); + return SWIG_TOKEN_ERROR; + } + if (c == '`') { + Delitem(s->text, DOH_END); + return (SWIG_TOKEN_RSTRING); + } + break; + + default: + return SWIG_TOKEN_ILLEGAL; + } + } +} + +/* ----------------------------------------------------------------------------- + * Scanner_token() + * + * Real entry point to return the next token. Returns 0 if at end of input. + * ----------------------------------------------------------------------------- */ + +int Scanner_token(Scanner *s) { + int t; + Delete(s->error); + if (s->nexttoken >= 0) { + t = s->nexttoken; + s->nexttoken = -1; + return t; + } + s->start_line = 0; + t = look(s); + if (!s->start_line) { + Setline(s->text,s->line); + } else { + Setline(s->text,s->start_line); + } + return t; +} + +/* ----------------------------------------------------------------------------- + * Scanner_text() + * + * Return the lexene associated with the last returned token. + * ----------------------------------------------------------------------------- */ + +String *Scanner_text(Scanner *s) { + return s->text; +} + +/* ----------------------------------------------------------------------------- + * Scanner_skip_line() + * + * Skips to the end of a line + * ----------------------------------------------------------------------------- */ + +void Scanner_skip_line(Scanner *s) { + char c; + int done = 0; + Clear(s->text); + Setfile(s->text, Getfile(s->str)); + Setline(s->text, s->line); + while (!done) { + if ((c = nextchar(s)) == 0) + return; + if (c == '\\') { + nextchar(s); + } else if (c == '\n') { + done = 1; + } + } + return; +} + +/* ----------------------------------------------------------------------------- + * Scanner_skip_balanced() + * + * Skips a piece of code enclosed in begin/end symbols such as '{...}' or + * (...). Ignores symbols inside comments or strings. + * ----------------------------------------------------------------------------- */ + +int Scanner_skip_balanced(Scanner *s, int startchar, int endchar) { + char c; + int num_levels = 1; + int state = 0; + char temp[2] = { 0, 0 }; + String *locator = 0; + temp[0] = (char) startchar; + Clear(s->text); + Setfile(s->text, Getfile(s->str)); + Setline(s->text, s->line); + + Append(s->text, temp); + while (num_levels > 0) { + if ((c = nextchar(s)) == 0) { + Delete(locator); + return -1; + } + switch (state) { + case 0: + if (c == startchar) + num_levels++; + else if (c == endchar) + num_levels--; + else if (c == '/') + state = 10; + else if (c == '\"') + state = 20; + else if (c == '\'') + state = 30; + break; + case 10: + if (c == '/') + state = 11; + else if (c == '*') + state = 12; + else if (c == startchar) { + state = 0; + num_levels++; + } + else + state = 0; + break; + case 11: + if (c == '\n') + state = 0; + else + state = 11; + break; + case 12: /* first character inside C comment */ + if (c == '*') + state = 14; + else if (c == '@') + state = 40; + else + state = 13; + break; + case 13: + if (c == '*') + state = 14; + break; + case 14: /* possible end of C comment */ + if (c == '*') + state = 14; + else if (c == '/') + state = 0; + else + state = 13; + break; + case 20: + if (c == '\"') + state = 0; + else if (c == '\\') + state = 21; + break; + case 21: + state = 20; + break; + case 30: + if (c == '\'') + state = 0; + else if (c == '\\') + state = 31; + break; + case 31: + state = 30; + break; + /* 40-45 SWIG locator checks - a C comment with contents starting: @SWIG */ + case 40: + state = (c == 'S') ? 41 : (c == '*') ? 14 : 13; + break; + case 41: + state = (c == 'W') ? 42 : (c == '*') ? 14 : 13; + break; + case 42: + state = (c == 'I') ? 43 : (c == '*') ? 14 : 13; + break; + case 43: + state = (c == 'G') ? 44 : (c == '*') ? 14 : 13; + if (c == 'G') { + Delete(locator); + locator = NewString("/*@SWIG"); + } + break; + case 44: + if (c == '*') + state = 45; + Putc(c, locator); + break; + case 45: /* end of SWIG locator in C comment */ + if (c == '/') { + state = 0; + Putc(c, locator); + Scanner_locator(s, locator); + } else { + /* malformed locator */ + state = (c == '*') ? 14 : 13; + } + break; + default: + break; + } + } + Delete(locator); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Scanner_get_raw_text_balanced() + * + * Returns raw text between 2 braces, does not change scanner state in any way + * ----------------------------------------------------------------------------- */ + +String *Scanner_get_raw_text_balanced(Scanner *s, int startchar, int endchar) { + String *result = 0; + char c; + int old_line = s->line; + String *old_text = Copy(s->text); + long position = Tell(s->str); + + int num_levels = 1; + int state = 0; + char temp[2] = { 0, 0 }; + temp[0] = (char) startchar; + Clear(s->text); + Setfile(s->text, Getfile(s->str)); + Setline(s->text, s->line); + Append(s->text, temp); + while (num_levels > 0) { + if ((c = nextchar(s)) == 0) { + Clear(s->text); + Append(s->text, old_text); + Delete(old_text); + s->line = old_line; + return 0; + } + switch (state) { + case 0: + if (c == startchar) + num_levels++; + else if (c == endchar) + num_levels--; + else if (c == '/') + state = 10; + else if (c == '\"') + state = 20; + else if (c == '\'') + state = 30; + break; + case 10: + if (c == '/') + state = 11; + else if (c == '*') + state = 12; + else if (c == startchar) { + state = 0; + num_levels++; + } + else + state = 0; + break; + case 11: + if (c == '\n') + state = 0; + else + state = 11; + break; + case 12: /* first character inside C comment */ + if (c == '*') + state = 14; + else + state = 13; + break; + case 13: + if (c == '*') + state = 14; + break; + case 14: /* possible end of C comment */ + if (c == '*') + state = 14; + else if (c == '/') + state = 0; + else + state = 13; + break; + case 20: + if (c == '\"') + state = 0; + else if (c == '\\') + state = 21; + break; + case 21: + state = 20; + break; + case 30: + if (c == '\'') + state = 0; + else if (c == '\\') + state = 31; + break; + case 31: + state = 30; + break; + default: + break; + } + } + Seek(s->str, position, SEEK_SET); + result = Copy(s->text); + Clear(s->text); + Append(s->text, old_text); + Delete(old_text); + s->line = old_line; + return result; +} +/* ----------------------------------------------------------------------------- + * Scanner_isoperator() + * + * Returns 0 or 1 depending on whether or not a token corresponds to a C/C++ + * operator. + * ----------------------------------------------------------------------------- */ + +int Scanner_isoperator(int tokval) { + if (tokval >= 100) return 1; + return 0; +} + +/* ---------------------------------------------------------------------- + * locator() + * + * Support for locator strings. These are strings of the form + * @SWIG:filename,line,id@ emitted by the SWIG preprocessor. They + * are primarily used for macro line number reporting. + * We just use the locator to mark when to activate/deactivate linecounting. + * ---------------------------------------------------------------------- */ + + +void Scanner_locator(Scanner *s, String *loc) { + static Locator *locs = 0; + static int expanding_macro = 0; + + if (!follow_locators) { + if (Equal(loc, "/*@SWIG@*/")) { + /* End locator. */ + if (expanding_macro) + --expanding_macro; + } else { + /* Begin locator. */ + ++expanding_macro; + } + /* Freeze line number processing in Scanner */ + freeze_line(s,expanding_macro); + } else { + int c; + Locator *l; + (void)Seek(loc, 7, SEEK_SET); + c = Getc(loc); + if (c == '@') { + /* Empty locator. We pop the last location off */ + if (locs) { + Scanner_set_location(s, locs->filename, locs->line_number); + cparse_file = locs->filename; + cparse_line = locs->line_number; + l = locs->next; + Free(locs); + locs = l; + } + return; + } + + /* We're going to push a new location */ + l = (Locator *) Malloc(sizeof(Locator)); + l->filename = cparse_file; + l->line_number = cparse_line; + l->next = locs; + locs = l; + + /* Now, parse the new location out of the locator string */ + { + String *fn = NewStringEmpty(); + /* Putc(c, fn); */ + + while ((c = Getc(loc)) != EOF) { + if ((c == '@') || (c == ',')) + break; + Putc(c, fn); + } + cparse_file = Swig_copy_string(Char(fn)); + Clear(fn); + cparse_line = 1; + /* Get the line number */ + while ((c = Getc(loc)) != EOF) { + if ((c == '@') || (c == ',')) + break; + Putc(c, fn); + } + cparse_line = atoi(Char(fn)); + Clear(fn); + + /* Get the rest of it */ + while ((c = Getc(loc)) != EOF) { + if (c == '@') + break; + Putc(c, fn); + } + /* Swig_diagnostic(cparse_file, cparse_line, "Scanner_set_location\n"); */ + Scanner_set_location(s, cparse_file, cparse_line); + Delete(fn); + } + } +} + +void Swig_cparse_follow_locators(int v) { + follow_locators = v; +} + + diff --git a/contrib/tools/swig/Source/Swig/stype.c b/contrib/tools/swig/Source/Swig/stype.c new file mode 100644 index 0000000000..f227778f6c --- /dev/null +++ b/contrib/tools/swig/Source/Swig/stype.c @@ -0,0 +1,1422 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * stype.c + * + * This file provides general support for datatypes that are encoded in + * the form of simple strings. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * The purpose of this module is to provide a general purpose type representation + * based on simple text strings. + * + * General idea: + * + * Types are represented by a base type (e.g., "int") and a collection of + * type operators applied to the base (e.g., pointers, arrays, etc...). + * + * Encoding: + * + * Types are encoded as strings of type constructors such as follows: + * + * String Encoding C Example + * --------------- --------- + * p.p.int int ** + * a(300).a(400).int int [300][400] + * p.q(const).char char const * + * + * All type constructors are denoted by a trailing '.': + * + * 'p.' = Pointer (*) + * 'r.' = Reference (&) + * 'z.' = Rvalue reference (&&) + * 'a(n).' = Array of size n [n] + * 'f(..,..).' = Function with arguments (args) + * 'q(str).' = Qualifier, such as const or volatile (cv-qualifier) + * 'm(cls).' = Pointer to member (cls::*) + * + * The encoding follows the order that you might describe a type in words. + * For example "p.a(200).int" is "A pointer to array of int's" and + * "p.q(const).char" is "a pointer to a const char". + * + * This representation of types is fairly convenient because ordinary string + * operations can be used for type manipulation. For example, a type could be + * formed by combining two strings such as the following: + * + * "p.p." + "a(400).int" = "p.p.a(400).int" + * + * Similarly, one could strip a 'const' declaration from a type doing something + * like this: + * + * Replace(t,"q(const).","",DOH_REPLACE_ANY) + * + * More examples: + * + * String Encoding C++ Example + * --------------- ----------- + * p.f(bool).r.q(const).long const long & (*)(bool) + * m(Funcs).q(const).f(bool).long long (Funcs::*)(bool) const + * r.q(const).m(Funcs).f(int).long long (Funcs::*const &)(int) + * m(Funcs).z.q(const).f(bool).long long (Funcs::*)(bool) const && + * + * Function decl examples: + * + * f(bool). long a(bool); + * r.f(bool). long b(bool) &; + * z.f(bool). long c(bool) &&; + * z.q(const).f(bool). long d(bool) const &&; + * + * For the most part, this module tries to minimize the use of special + * characters (*, [, <, etc...) in its type encoding. One reason for this + * is that SWIG might be extended to encode data in formats such as XML + * where you might want to do this: + * + * <function> + * <type>p.p.int</type> + * ... + * </function> + * + * Or alternatively, + * + * <function type="p.p.int" ...>blah</function> + * + * In either case, it's probably best to avoid characters such as '&', '*', or '<'. + * + * Why not use C syntax? Well, C syntax is fairly complicated to parse + * and not particularly easy to manipulate---especially for adding, deleting and + * composing type constructors. The string representation presented here makes + * this pretty easy. + * + * Why not use a bunch of nested data structures? Are you kidding? How + * would that be easier to use than a few simple string operations? + * ----------------------------------------------------------------------------- */ + + +SwigType *NewSwigType(int t) { + switch (t) { + case T_BOOL: + return NewString("bool"); + break; + case T_INT: + return NewString("int"); + break; + case T_UINT: + return NewString("unsigned int"); + break; + case T_SHORT: + return NewString("short"); + break; + case T_USHORT: + return NewString("unsigned short"); + break; + case T_LONG: + return NewString("long"); + break; + case T_ULONG: + return NewString("unsigned long"); + break; + case T_FLOAT: + return NewString("float"); + break; + case T_DOUBLE: + return NewString("double"); + break; + case T_COMPLEX: + return NewString("_Complex"); + break; + case T_CHAR: + return NewString("char"); + break; + case T_SCHAR: + return NewString("signed char"); + break; + case T_UCHAR: + return NewString("unsigned char"); + break; + case T_STRING: { + SwigType *t = NewString("char"); + SwigType_add_qualifier(t, "const"); + SwigType_add_pointer(t); + return t; + break; + } + case T_WCHAR: + return NewString("wchar_t"); + break; + case T_WSTRING: { + SwigType *t = NewString("wchar_t"); + SwigType_add_pointer(t); + return t; + break; + } + case T_LONGLONG: + return NewString("long long"); + break; + case T_ULONGLONG: + return NewString("unsigned long long"); + break; + case T_VOID: + return NewString("void"); + break; + case T_AUTO: + return NewString("auto"); + break; + default: + break; + } + return NewStringEmpty(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_push() + * + * Push a type constructor onto the type + * ----------------------------------------------------------------------------- */ + +void SwigType_push(SwigType *t, String *cons) { + if (!cons) + return; + if (!Len(cons)) + return; + + if (Len(t)) { + char *c = Char(cons); + if (c[strlen(c) - 1] != '.') + Insert(t, 0, "."); + } + Insert(t, 0, cons); +} + +/* ----------------------------------------------------------------------------- + * SwigType_ispointer_return() + * + * Testing functions for querying a raw datatype + * ----------------------------------------------------------------------------- */ + +int SwigType_ispointer_return(const SwigType *t) { + char *c; + int idx; + if (!t) + return 0; + c = Char(t); + idx = (int)strlen(c) - 4; + if (idx >= 0) { + return (strcmp(c + idx, ").p.") == 0); + } + return 0; +} + +int SwigType_isreference_return(const SwigType *t) { + char *c; + int idx; + if (!t) + return 0; + c = Char(t); + idx = (int)strlen(c) - 4; + if (idx >= 0) { + return (strcmp(c + idx, ").r.") == 0); + } + return 0; +} + +int SwigType_isconst(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + String *q = SwigType_parm(t); + if (strstr(Char(q), "const")) { + Delete(q); + return 1; + } + Delete(q); + } + /* Hmmm. Might be const through a typedef */ + if (SwigType_issimple(t)) { + int ret; + SwigType *td = SwigType_typedef_resolve(t); + if (td) { + ret = SwigType_isconst(td); + Delete(td); + return ret; + } + } + return 0; +} + +int SwigType_ismutable(const SwigType *t) { + int r; + SwigType *qt = SwigType_typedef_resolve_all(t); + if (SwigType_isreference(qt) || SwigType_isrvalue_reference(qt) || SwigType_isarray(qt)) { + Delete(SwigType_pop(qt)); + } + r = SwigType_isconst(qt); + Delete(qt); + return r ? 0 : 1; +} + +int SwigType_isenum(const SwigType *t) { + char *c = Char(t); + if (!t) + return 0; + if (strncmp(c, "enum ", 5) == 0) { + return 1; + } + return 0; +} + +int SwigType_issimple(const SwigType *t) { + char *c = Char(t); + if (!t) + return 0; + while (*c) { + if (*c == '<') { + int nest = 1; + c++; + while (*c && nest) { + if (*c == '<') + nest++; + if (*c == '>') + nest--; + c++; + } + c--; + } + if (*c == '.') + return 0; + c++; + } + return 1; +} + +/* ----------------------------------------------------------------------------- + * SwigType_default_create() + * + * Create the default type for this datatype. This takes a type and strips it + * down to a generic form first by resolving all typedefs. + * + * Rules: + * Pointers: p.SWIGTYPE + * References: r.SWIGTYPE + * Arrays no dimension: a().SWIGTYPE + * Arrays with dimension: a(ANY).SWIGTYPE + * Member pointer: m(CLASS).SWIGTYPE + * Function pointer: f(ANY).SWIGTYPE + * Enums: enum SWIGTYPE + * Types: SWIGTYPE + * + * Examples (also see SwigType_default_deduce): + * + * int [2][4] + * a(2).a(4).int + * a(ANY).a(ANY).SWIGTYPE + * + * struct A {}; + * typedef A *Aptr; + * Aptr const & + * r.q(const).Aptr + * r.q(const).p.SWIGTYPE + * + * enum E {e1, e2}; + * enum E const & + * r.q(const).enum E + * r.q(const).enum SWIGTYPE + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_default_create(const SwigType *ty) { + SwigType *r = 0; + List *l; + Iterator it; + int numitems; + + if (!SwigType_isvarargs(ty)) { + SwigType *t = SwigType_typedef_resolve_all(ty); + r = NewStringEmpty(); + l = SwigType_split(t); + numitems = Len(l); + + if (numitems >= 1) { + String *last_subtype = Getitem(l, numitems-1); + if (SwigType_isenum(last_subtype)) + Setitem(l, numitems-1, NewString("enum SWIGTYPE")); + else + Setitem(l, numitems-1, NewString("SWIGTYPE")); + } + + for (it = First(l); it.item; it = Next(it)) { + String *subtype = it.item; + if (SwigType_isarray(subtype)) { + if (Equal(subtype, "a().")) + Append(r, NewString("a().")); + else + Append(r, NewString("a(ANY).")); + } else if (SwigType_isfunction(subtype)) { + Append(r, NewString("f(ANY).SWIGTYPE")); + break; + } else if (SwigType_ismemberpointer(subtype)) { + Append(r, NewString("m(CLASS).SWIGTYPE")); + break; + } else { + Append(r, subtype); + } + } + + Delete(l); + Delete(t); + } + + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_default_deduce() + * + * This function implements type deduction used in the typemap matching rules + * and is very close to the type deduction used in partial template class + * specialization matching in that the most specialized type is always chosen. + * SWIGTYPE is used as the generic type. The basic idea is to repeatedly call + * this function to find a deduced type until nothing matches. + * + * The type t must have already been converted to the default type via a call to + * SwigType_default_create() before calling this function. + * + * Example deductions (matching the examples described in SwigType_default_create), + * where the most specialized matches are highest in the list: + * + * a(ANY).a(ANY).SWIGTYPE + * a(ANY).a().SWIGTYPE + * a(ANY).p.SWIGTYPE + * a(ANY).SWIGTYPE + * a().SWIGTYPE + * p.SWIGTYPE + * SWIGTYPE + * + * r.q(const).p.SWIGTYPE + * r.q(const).SWIGTYPE + * r.SWIGTYPE + * SWIGTYPE + * + * r.q(const).enum SWIGTYPE + * r.enum SWIGTYPE + * r.SWIGTYPE + * SWIGTYPE + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_default_deduce(const SwigType *t) { + SwigType *r = NewStringEmpty(); + List *l; + Iterator it; + int numitems; + + l = SwigType_split(t); + + numitems = Len(l); + if (numitems >= 1) { + String *last_subtype = Getitem(l, numitems-1); + int is_enum = SwigType_isenum(last_subtype); + + if (numitems >=2 ) { + String *subtype = Getitem(l, numitems-2); /* last but one */ + if (SwigType_isarray(subtype)) { + if (is_enum) { + /* enum deduction, enum SWIGTYPE => SWIGTYPE */ + Setitem(l, numitems-1, NewString("SWIGTYPE")); + } else { + /* array deduction, a(ANY). => a(). => p. */ + String *deduced_subtype = 0; + if (Strcmp(subtype, "a().") == 0) { + deduced_subtype = NewString("p."); + } else if (Strcmp(subtype, "a(ANY).") == 0) { + deduced_subtype = NewString("a()."); + } else { + assert(0); + } + Setitem(l, numitems-2, deduced_subtype); + } + } else if (SwigType_ismemberpointer(subtype)) { + /* member pointer deduction, m(CLASS). => p. */ + Setitem(l, numitems-2, NewString("p.")); + } else if (is_enum && !SwigType_isqualifier(subtype)) { + /* enum deduction, enum SWIGTYPE => SWIGTYPE */ + Setitem(l, numitems-1, NewString("SWIGTYPE")); + } else { + /* simple type deduction, eg, r.p.p. => r.p. */ + /* also function pointers eg, p.f(ANY). => p. */ + Delitem(l, numitems-2); + } + } else { + if (is_enum) { + /* enum deduction, enum SWIGTYPE => SWIGTYPE */ + Setitem(l, numitems-1, NewString("SWIGTYPE")); + } else { + /* delete the only item, we are done with deduction */ + Delitem(l, 0); + } + } + } else { + assert(0); + } + + for (it = First(l); it.item; it = Next(it)) { + Append(r, it.item); + } + + if (Len(r) == 0) { + Delete(r); + r = 0; + } + + Delete(l); + return r; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_namestr() + * + * Returns a string of the base type. Takes care of template expansions + * ----------------------------------------------------------------------------- */ + +String *SwigType_namestr(const SwigType *t) { + String *r; + String *suffix; + List *p; + int i, sz; + char *d = Char(t); + char *c = strstr(d, "<("); + + if (!c || !strstr(c + 2, ")>")) + return NewString(t); + + r = NewStringWithSize(d, (int)(c - d)); + if (*(c - 1) == '<') + Putc(' ', r); + Putc('<', r); + + p = SwigType_parmlist(c + 1); + sz = Len(p); + for (i = 0; i < sz; i++) { + String *str = SwigType_str(Getitem(p, i), 0); + /* Avoid creating a <: token, which is the same as [ in C++ - put a space after '<'. */ + if (i == 0 && Len(str)) + Putc(' ', r); + Append(r, str); + if ((i + 1) < sz) + Putc(',', r); + Delete(str); + } + Putc(' ', r); + Putc('>', r); + suffix = SwigType_templatesuffix(t); + if (Len(suffix) > 0) { + String *suffix_namestr = SwigType_namestr(suffix); + Append(r, suffix_namestr); + Delete(suffix_namestr); + } else { + Append(r, suffix); + } + Delete(suffix); + Delete(p); + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_str() + * + * Create a C string representation of a datatype. + * ----------------------------------------------------------------------------- */ + +String *SwigType_str(const SwigType *s, const_String_or_char_ptr id) { + String *result; + String *element = 0; + String *nextelement; + String *forwardelement; + SwigType *member_function_qualifiers = 0; + List *elements; + int nelements, i; + + if (id) { + /* stringify the id expanding templates, for example when the id is a fully qualified templated class name */ + String *id_str = NewString(id); /* unfortunate copy due to current const limitations */ + result = SwigType_str(id_str, 0); + Delete(id_str); + } else { + result = NewStringEmpty(); + } + + elements = SwigType_split(s); + nelements = Len(elements); + + if (nelements > 0) { + element = Getitem(elements, 0); + } + /* Now, walk the type list and start emitting */ + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i + 1); + forwardelement = nextelement; + if (SwigType_isqualifier(nextelement)) { + if (i < (nelements - 2)) + forwardelement = Getitem(elements, i + 2); + } + } else { + nextelement = 0; + forwardelement = 0; + } + if (SwigType_isqualifier(element)) { + if (!member_function_qualifiers) { + DOH *q = 0; + q = SwigType_parm(element); + Insert(result, 0, " "); + Insert(result, 0, q); + Delete(q); + } + } else if (SwigType_ispointer(element)) { + Insert(result, 0, "*"); + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_ismemberpointer(element)) { + String *q; + q = SwigType_parm(element); + Insert(result, 0, "::*"); + Insert(result, 0, q); + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + { + String *next3elements = NewStringEmpty(); + int j; + for (j = i + 1; j < i + 4 && j < nelements; j++) { + Append(next3elements, Getitem(elements, j)); + } + if (SwigType_isfunction(next3elements)) + member_function_qualifiers = SwigType_pop_function_qualifiers(next3elements); + Delete(next3elements); + } + Delete(q); + } else if (SwigType_isreference(element)) { + if (!member_function_qualifiers) + Insert(result, 0, "&"); + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_isrvalue_reference(element)) { + if (!member_function_qualifiers) + Insert(result, 0, "&&"); + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_isarray(element)) { + DOH *size; + Append(result, "["); + size = SwigType_parm(element); + Append(result, size); + Append(result, "]"); + Delete(size); + } else if (SwigType_isfunction(element)) { + DOH *parms, *p; + int j, plen; + Append(result, "("); + parms = SwigType_parmlist(element); + plen = Len(parms); + for (j = 0; j < plen; j++) { + p = SwigType_str(Getitem(parms, j), 0); + Append(result, p); + if (j < (plen - 1)) + Append(result, ","); + } + Append(result, ")"); + if (member_function_qualifiers) { + String *p = SwigType_str(member_function_qualifiers, 0); + Append(result, " "); + Append(result, p); + Delete(p); + Delete(member_function_qualifiers); + member_function_qualifiers = 0; + } + Delete(parms); + } else { + if (strcmp(Char(element), "v(...)") == 0) { + Insert(result, 0, "..."); + } else { + String *bs = SwigType_namestr(element); + Insert(result, 0, " "); + Insert(result, 0, bs); + Delete(bs); + } + } + element = nextelement; + } + Delete(elements); + Chop(result); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_ltype(const SwigType *ty) + * + * Create a locally assignable type + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_ltype(const SwigType *s) { + String *result; + String *element; + SwigType *td, *tc = 0; + List *elements; + int nelements, i; + int firstarray = 1; + int notypeconv = 0; + int ignore_member_function_qualifiers = 0; + + result = NewStringEmpty(); + tc = Copy(s); + /* Nuke all leading qualifiers */ + while (SwigType_isqualifier(tc)) { + Delete(SwigType_pop(tc)); + } + if (SwigType_issimple(tc)) { + /* Resolve any typedef definitions */ + SwigType *tt = Copy(tc); + td = 0; + while ((td = SwigType_typedef_resolve(tt))) { + if (td && (SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td) || SwigType_isrvalue_reference(td))) { + /* We need to use the typedef type */ + Delete(tt); + break; + } else if (td) { + Delete(tt); + tt = td; + } + } + if (td) { + Delete(tc); + tc = td; + } + } + + elements = SwigType_split(tc); + nelements = Len(elements); + + /* Now, walk the type list and start emitting */ + for (i = 0; i < nelements; i++) { + element = Getitem(elements, i); + /* when we see a function, we need to preserve the following types */ + if (SwigType_isfunction(element)) { + notypeconv = 1; + ignore_member_function_qualifiers = 0; + } + if (ignore_member_function_qualifiers) { + /* cv-qualifiers and ref-qualifiers up until the f() element have already been added */ + } else if (SwigType_isqualifier(element)) { + /* swallow cv-qualifiers */ + } else if (SwigType_ispointer(element)) { + Append(result, element); + firstarray = 0; + } else if (SwigType_ismemberpointer(element)) { + Append(result, element); + { + String *next3elements = NewStringEmpty(); + int j; + for (j = i + 1; j < i + 4 && j < nelements; j++) { + Append(next3elements, Getitem(elements, j)); + } + if (SwigType_isfunction(next3elements)) { + SwigType *member_function_qualifiers = SwigType_pop_function_qualifiers(next3elements); + /* compilers won't let us cast from a member function without qualifiers to one with qualifiers, so the qualifiers are kept in the ltype */ + if (member_function_qualifiers) + Append(result, member_function_qualifiers); + Delete(member_function_qualifiers); + ignore_member_function_qualifiers = 1; + } + Delete(next3elements); + } + firstarray = 0; + } else if (SwigType_isreference(element)) { + if (notypeconv) { + Append(result, element); + } else { + Append(result, "p."); + } + firstarray = 0; + } else if (SwigType_isrvalue_reference(element)) { + if (notypeconv) { + Append(result, element); + } else { + Append(result, "p."); + } + firstarray = 0; + } else if (SwigType_isarray(element) && firstarray) { + if (notypeconv) { + Append(result, element); + } else { + Append(result, "p."); + } + firstarray = 0; + } else if (SwigType_isenum(element)) { + int anonymous_enum = (Cmp(element, "enum ") == 0); + if (notypeconv || !anonymous_enum) { + Append(result, element); + } else { + Append(result, "int"); + } + } else { + Append(result, element); + } + } + Delete(elements); + Delete(tc); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_lstr() + * + * Produces a type-string that is suitable as a lvalue in an expression. + * That is, a type that can be freely assigned a value without violating + * any C assignment rules. + * + * - Qualifiers such as 'const' and 'volatile' are stripped. + * Except for member function cv-qualifiers and ref-qualifiers. + * - Arrays are converted into a *single* pointer (i.e., + * double [][] becomes double *). + * - References are converted into a pointer. + * - Typedef names that refer to read-only types will be replaced + * with an equivalent assignable version. + * -------------------------------------------------------------------- */ + +String *SwigType_lstr(const SwigType *s, const_String_or_char_ptr id) { + String *result; + SwigType *tc; + + tc = SwigType_ltype(s); + result = SwigType_str(tc, id); + Delete(tc); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_rcaststr() + * + * Produces a casting string that maps the type returned by lstr() to the real + * datatype printed by str(). + * ----------------------------------------------------------------------------- */ + +String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr name) { + String *result, *cast; + String *element = 0; + String *nextelement; + String *forwardelement; + String *member_function_qualifiers = 0; + SwigType *td, *tc = 0; + const SwigType *rs; + List *elements; + int nelements, i; + int clear = 1; + int firstarray = 1; + int isreference = 0; + int isfunction = 0; + + result = NewStringEmpty(); + + if (SwigType_isconst(s)) { + tc = Copy(s); + Delete(SwigType_pop(tc)); + if (SwigType_ismemberpointer(tc)) + rs = s; + else + rs = tc; + } else { + rs = s; + } + + if ((SwigType_isconst(rs) || SwigType_isarray(rs) || SwigType_isreference(rs) || SwigType_isrvalue_reference(rs))) { + td = 0; + } else { + td = SwigType_typedef_resolve(rs); + } + + if (td) { + if ((SwigType_isconst(td) || SwigType_isarray(td) || SwigType_isreference(td) || SwigType_isrvalue_reference(td))) { + elements = SwigType_split(td); + } else { + elements = SwigType_split(rs); + } + Delete(td); + } else { + elements = SwigType_split(rs); + } + nelements = Len(elements); + if (nelements > 0) { + element = Getitem(elements, 0); + } + /* Now, walk the type list and start emitting */ + for (i = 0; i < nelements; i++) { + if (i < (nelements - 1)) { + nextelement = Getitem(elements, i + 1); + forwardelement = nextelement; + if (SwigType_isqualifier(nextelement)) { + if (i < (nelements - 2)) + forwardelement = Getitem(elements, i + 2); + } + } else { + nextelement = 0; + forwardelement = 0; + } + if (SwigType_isqualifier(element)) { + if (!member_function_qualifiers) { + DOH *q = 0; + q = SwigType_parm(element); + Insert(result, 0, " "); + Insert(result, 0, q); + Delete(q); + clear = 0; + } + } else if (SwigType_ispointer(element)) { + Insert(result, 0, "*"); + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + firstarray = 0; + } else if (SwigType_ismemberpointer(element)) { + String *q; + Insert(result, 0, "::*"); + q = SwigType_parm(element); + Insert(result, 0, q); + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + { + String *next3elements = NewStringEmpty(); + int j; + for (j = i + 1; j < i + 4 && j < nelements; j++) { + Append(next3elements, Getitem(elements, j)); + } + if (SwigType_isfunction(next3elements)) + member_function_qualifiers = SwigType_pop_function_qualifiers(next3elements); + Delete(next3elements); + } + firstarray = 0; + Delete(q); + } else if (SwigType_isreference(element)) { + if (!member_function_qualifiers) { + Insert(result, 0, "&"); + if (!isfunction) + isreference = 1; + } + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + } else if (SwigType_isrvalue_reference(element)) { + if (!member_function_qualifiers) { + Insert(result, 0, "&&"); + if (!isfunction) + isreference = 1; + } + if ((forwardelement) && ((SwigType_isfunction(forwardelement) || (SwigType_isarray(forwardelement))))) { + Insert(result, 0, "("); + Append(result, ")"); + } + clear = 0; + } else if (SwigType_isarray(element)) { + DOH *size; + if (firstarray && !isreference) { + Append(result, "(*)"); + firstarray = 0; + } else { + Append(result, "["); + size = SwigType_parm(element); + Append(result, size); + Append(result, "]"); + Delete(size); + clear = 0; + } + } else if (SwigType_isfunction(element)) { + DOH *parms, *p; + int j, plen; + Append(result, "("); + parms = SwigType_parmlist(element); + plen = Len(parms); + for (j = 0; j < plen; j++) { + p = SwigType_str(Getitem(parms, j), 0); + Append(result, p); + Delete(p); + if (j < (plen - 1)) + Append(result, ","); + } + Append(result, ")"); + Delete(parms); + if (member_function_qualifiers) { + String *p = SwigType_str(member_function_qualifiers, 0); + Append(result, " "); + Append(result, p); + Delete(p); + Delete(member_function_qualifiers); + member_function_qualifiers = 0; + clear = 0; + } + isfunction = 1; + } else { + String *bs = SwigType_namestr(element); + Insert(result, 0, " "); + Insert(result, 0, bs); + Delete(bs); + } + element = nextelement; + } + Delete(elements); + if (clear) { + cast = NewStringEmpty(); + } else { + cast = NewStringf("(%s)", result); + } + if (name) { + if (isreference) { + Append(cast, "*"); + } + Append(cast, name); + } + Delete(result); + Delete(tc); + return cast; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_lcaststr() + * + * Casts a variable from the real type to the local datatype. + * ----------------------------------------------------------------------------- */ + +String *SwigType_lcaststr(const SwigType *s, const_String_or_char_ptr name) { + String *result; + + result = NewStringEmpty(); + + if (SwigType_isarray(s)) { + String *lstr = SwigType_lstr(s, 0); + Printf(result, "(%s)%s", lstr, name); + Delete(lstr); + } else if (SwigType_isreference(s)) { + String *str = SwigType_str(s, 0); + Printf(result, "(%s)", str); + Delete(str); + if (name) + Append(result, name); + } else if (SwigType_isrvalue_reference(s)) { + String *str = SwigType_str(s, 0); + Printf(result, "(%s)", str); + Delete(str); + if (name) + Append(result, name); + } else if (SwigType_isqualifier(s)) { + String *lstr = SwigType_lstr(s, 0); + Printf(result, "(%s)%s", lstr, name); + Delete(lstr); + } else { + if (name) + Append(result, name); + } + return result; +} + +#if 0 +/* Alternative implementation for manglestr_default. Mangling is similar to the original + except for a few subtle differences for example in templates: + namespace foo { + template<class T> class bar {}; + typedef int Integer; + void test2(bar<Integer *> *x); + } + Mangling is more consistent and changes from + _p_foo__barT_int_p_t to + _p_foo__barT_p_int_t. +*/ +static void mangle_stringcopy(String *destination, const char *source, int count) { + while (count-- > 0) { + char newc = '_'; + if (!(*source == '.' || *source == ':' || *source == ' ')) + newc = *source; + /* TODO: occasionally '*' or numerics need converting to '_', eg in array dimensions and template expressions */ + Putc(newc, destination); + source++; + } +} + +static void mangle_subtype(String *mangled, SwigType *s); + +/* ----------------------------------------------------------------------------- + * mangle_namestr() + * + * Mangles a type taking care of template expansions. Similar to SwigType_namestr(). + * The type may include a trailing '.', for example "p." + * ----------------------------------------------------------------------------- */ + +static void mangle_namestr(String *mangled, SwigType *t) { + int length = Len(t); + if (SwigType_isqualifier(t)) { + Append(mangled, "q_"); + mangle_stringcopy(mangled, Char(t)+2, length-4); + Append(mangled, "__"); + } else if (SwigType_ismemberpointer(t)) { + Append(mangled, "m_"); + mangle_stringcopy(mangled, Char(t)+2, length-4); + Append(mangled, "__"); + } else if (SwigType_isarray(t)) { + Append(mangled, "a_"); + mangle_stringcopy(mangled, Char(t)+2, length-4); + Append(mangled, "__"); + } else if (SwigType_isfunction(t)) { + List *p = SwigType_parmlist(t); + int sz = Len(p); + int i; + Append(mangled, "f_"); + for (i = 0; i < sz; i++) { + mangle_subtype(mangled, Getitem(p, i)); + Putc('_', mangled); + } + Append(mangled, (sz > 0) ? "_" : "__"); + } else if (SwigType_isvarargs(t)) { + Append(mangled, "___"); + } else { + char *d = Char(t); + char *c = strstr(d, "<("); + if (!c || !strstr(c + 2, ")>")) { + /* not a template type */ + mangle_stringcopy(mangled, Char(t), Len(t)); + } else { + /* a template type */ + String *suffix; + List *p; + int i, sz; + mangle_stringcopy(mangled, d, c-d); + Putc('T', mangled); + Putc('_', mangled); + + p = SwigType_parmlist(c + 1); + sz = Len(p); + for (i = 0; i < sz; i++) { + mangle_subtype(mangled, Getitem(p, i)); + Putc('_', mangled); + } + Putc('t', mangled); + suffix = SwigType_templatesuffix(t); + if (Len(suffix) > 0) { + mangle_namestr(mangled, suffix); + } else { + Append(mangled, suffix); + } + Delete(suffix); + Delete(p); + } + } +} + +static void mangle_subtype(String *mangled, SwigType *s) { + List *elements; + int nelements, i; + + assert(s); + elements = SwigType_split(s); + nelements = Len(elements); + for (i = 0; i < nelements; i++) { + SwigType *element = Getitem(elements, i); + mangle_namestr(mangled, element); + } + Delete(elements); +} + +static String *manglestr_default(const SwigType *s) { + String *mangled = NewString("_"); + SwigType *sr = SwigType_typedef_resolve_all(s); + SwigType *sq = SwigType_typedef_qualified(sr); + SwigType *ss = SwigType_remove_global_scope_prefix(sq); + SwigType *type = ss; + SwigType *lt; + + if (SwigType_istemplate(ss)) { + SwigType *ty = Swig_symbol_template_deftype(ss, 0); + Delete(ss); + ss = ty; + type = ss; + } + + lt = SwigType_ltype(type); + + Replace(lt, "struct ", "", DOH_REPLACE_ANY); + Replace(lt, "class ", "", DOH_REPLACE_ANY); + Replace(lt, "union ", "", DOH_REPLACE_ANY); + Replace(lt, "enum ", "", DOH_REPLACE_ANY); + + mangle_subtype(mangled, lt); + + Delete(ss); + Delete(sq); + Delete(sr); + + return mangled; +} + +#else + +static String *manglestr_default(const SwigType *s) { + char *c; + String *result = 0; + String *base = 0; + SwigType *lt; + SwigType *sr = SwigType_typedef_resolve_all(s); + SwigType *sq = SwigType_typedef_qualified(sr); + SwigType *ss = SwigType_remove_global_scope_prefix(sq); + SwigType *type = ss; + + if (SwigType_istemplate(ss)) { + SwigType *ty = Swig_symbol_template_deftype(ss, 0); + Delete(ss); + ss = ty; + type = ss; + } + + lt = SwigType_ltype(type); + result = SwigType_prefix(lt); + base = SwigType_base(lt); + + c = Char(result); + while (*c) { + if (!isalnum((int) *c)) + *c = '_'; + c++; + } + if (SwigType_istemplate(base)) { + String *b = SwigType_namestr(base); + Delete(base); + base = b; + } + + Replace(base, "struct ", "", DOH_REPLACE_ANY); /* This might be problematic */ + Replace(base, "class ", "", DOH_REPLACE_ANY); + Replace(base, "union ", "", DOH_REPLACE_ANY); + Replace(base, "enum ", "", DOH_REPLACE_ANY); + + c = Char(base); + while (*c) { + if (*c == '<') + *c = 'T'; + else if (*c == '>') + *c = 't'; + else if (*c == '*') + *c = 'p'; + else if (*c == '[') + *c = 'a'; + else if (*c == ']') + *c = 'A'; + else if (*c == '&') + *c = 'R'; + else if (*c == '(') + *c = 'f'; + else if (*c == ')') + *c = 'F'; + else if (!isalnum((int) *c)) + *c = '_'; + c++; + } + Append(result, base); + Insert(result, 0, "_"); + Delete(lt); + Delete(base); + Delete(ss); + Delete(sq); + Delete(sr); + return result; +} +#endif + +String *SwigType_manglestr(const SwigType *s) { +#if 0 + /* Debugging checks to ensure a proper SwigType is passed in and not a stringified type */ + String *angle = Strstr(s, "<"); + if (angle && Strncmp(angle, "<(", 2) != 0) + Printf(stderr, "SwigType_manglestr error: %s\n", s); + else if (Strstr(s, "*") || Strstr(s, "&") || Strstr(s, "[")) + Printf(stderr, "SwigType_manglestr error: %s\n", s); +#endif + return manglestr_default(s); +} + +/* ----------------------------------------------------------------------------- + * SwigType_typename_replace() + * + * Replaces a typename in a type with something else. Needed for templates. + * ----------------------------------------------------------------------------- */ + +void SwigType_typename_replace(SwigType *t, String *pat, String *rep) { + String *nt; + int i, ilen; + List *elem; + + if (!Strstr(t, pat)) + return; + + if (Equal(t, pat)) { + Replace(t, pat, rep, DOH_REPLACE_ANY); + return; + } + nt = NewStringEmpty(); + elem = SwigType_split(t); + ilen = Len(elem); + for (i = 0; i < ilen; i++) { + String *e = Getitem(elem, i); + if (SwigType_issimple(e)) { + if (Equal(e, pat)) { + /* Replaces a type of the form 'pat' with 'rep<args>' */ + Replace(e, pat, rep, DOH_REPLACE_ANY); + } else if (SwigType_istemplate(e)) { + /* Replaces a type of the form 'pat<args>' with 'rep' */ + { + /* To match "e=TemplateTemplateT<(float)>" + * with "pat=TemplateTemplateT" + * we need to compare only the first part of the string e. + */ + int len = Len(pat); + + /* Len(e) > len, not >= (because we expect at least a + * character '<' following the template typename) + */ + if (Len(e) > len) { + String *firstPartOfType = NewStringWithSize(e, len); + const char* e_as_char = Char(e); + + if (Equal(firstPartOfType, pat) && e_as_char[len] == '<') { + String *repbase = SwigType_templateprefix(rep); + Replace(e, pat, repbase, DOH_REPLACE_ID | DOH_REPLACE_FIRST); + Delete(repbase); + } + Delete(firstPartOfType); + } + } + + { + String *tsuffix; + List *tparms = SwigType_parmlist(e); + int j, jlen; + String *nt = SwigType_templateprefix(e); + Append(nt, "<("); + jlen = Len(tparms); + for (j = 0; j < jlen; j++) { + SwigType_typename_replace(Getitem(tparms, j), pat, rep); + Append(nt, Getitem(tparms, j)); + if (j < (jlen - 1)) + Putc(',', nt); + } + tsuffix = SwigType_templatesuffix(e); + SwigType_typename_replace(tsuffix, pat, rep); + Printf(nt, ")>%s", tsuffix); + Delete(tsuffix); + Clear(e); + Append(e, nt); + Delete(nt); + Delete(tparms); + } + } else if (Swig_scopename_check(e)) { + String *first = 0; + String *rest = 0; + Swig_scopename_split(e, &first, &rest); + + /* Swig_scopename_split doesn't handle :: prefix very well ... could do with a rework */ + if (Strncmp(rest, "::", 2) == 0) { + String *tmp = NewString(Char(rest) + 2); + Clear(rest); + Printv(rest, tmp, NIL); + Delete(tmp); + assert(!first); + } + + Clear(e); + if (first) + SwigType_typename_replace(first, pat, rep); + SwigType_typename_replace(rest, pat, rep); + Printv(e, first ? first : "", "::", rest, NIL); + Delete(first); + Delete(rest); + } + } else if (SwigType_isfunction(e)) { + int j, jlen; + List *fparms = SwigType_parmlist(e); + Clear(e); + Append(e, "f("); + jlen = Len(fparms); + for (j = 0; j < jlen; j++) { + SwigType_typename_replace(Getitem(fparms, j), pat, rep); + Append(e, Getitem(fparms, j)); + if (j < (jlen - 1)) + Putc(',', e); + } + Append(e, ")."); + Delete(fparms); + } else if (SwigType_isarray(e)) { + Replace(e, pat, rep, DOH_REPLACE_ID); + } + Append(nt, e); + } + Clear(t); + Append(t, nt); + Delete(nt); + Delete(elem); +} + +/* ----------------------------------------------------------------------------- + * SwigType_remove_global_scope_prefix() + * + * Removes the unary scope operator (::) prefix indicating global scope in all + * components of the type + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_remove_global_scope_prefix(const SwigType *t) { + SwigType *result; + const char *type = Char(t); + if (strncmp(type, "::", 2) == 0) + type += 2; + result = NewString(type); + Replaceall(result, ".::", "."); + Replaceall(result, "(::", "("); + Replaceall(result, "enum ::", "enum "); + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_check_decl() + * + * Checks type declarators for a match + * ----------------------------------------------------------------------------- */ + +int SwigType_check_decl(const SwigType *ty, const SwigType *decl) { + SwigType *t, *t1, *t2; + int r; + t = SwigType_typedef_resolve_all(ty); + t1 = SwigType_strip_qualifiers(t); + t2 = SwigType_prefix(t1); + r = Equal(t2, decl); + Delete(t); + Delete(t1); + Delete(t2); + return r == 1; +} diff --git a/contrib/tools/swig/Source/Swig/swig.h b/contrib/tools/swig/Source/Swig/swig.h new file mode 100644 index 0000000000..19e61b4558 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swig.h @@ -0,0 +1,451 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swig.h + * + * Header file for the SWIG core. + * ----------------------------------------------------------------------------- */ + +#ifndef SWIG_SWIG_H +#define SWIG_SWIG_H + +#include "swigconfig.h" + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#include "doh.h" + +/* Status codes */ + +#define SWIG_OK 1 +#define SWIG_ERROR 0 +#define SWIG_NOWRAP 0 + +/* Global macros */ +#define NSPACE_SEPARATOR "." /* Namespace separator for the nspace feature - this should be changed to a target language configurable variable */ +#define NSPACE_TODO 0 /* Languages that still need to implement and test the nspace feature use this */ + +/* Short names for common data types */ + + typedef DOH String; + typedef DOH Hash; + typedef DOH List; + typedef DOH String_or_char; + typedef DOH File; + typedef DOH Parm; + typedef DOH ParmList; + typedef DOH Node; + typedef DOH Symtab; + typedef DOH Typetab; + typedef DOH SwigType; + +/* --- Legacy DataType interface. These type codes are provided solely + for backwards compatibility with older modules --- */ + +/* --- The ordering of type values is used to determine type-promotion + in the parser. Do not change */ + +/* Numeric types */ + +#define T_BOOL 1 +#define T_SCHAR 2 +#define T_UCHAR 3 +#define T_SHORT 4 +#define T_USHORT 5 +#define T_ENUM 6 +#define T_INT 7 +#define T_UINT 8 +#define T_LONG 9 +#define T_ULONG 10 +#define T_LONGLONG 11 +#define T_ULONGLONG 12 +#define T_FLOAT 20 +#define T_DOUBLE 21 +#define T_LONGDOUBLE 22 +#define T_FLTCPLX 23 +#define T_DBLCPLX 24 +#define T_NUMERIC 25 +#define T_AUTO 26 + +#define T_COMPLEX T_DBLCPLX + +/* non-numeric */ + +#define T_CHAR 29 +#define T_WCHAR 30 +#define T_USER 31 +#define T_VOID 32 +#define T_STRING 33 +#define T_POINTER 34 +#define T_REFERENCE 35 +#define T_ARRAY 36 +#define T_FUNCTION 37 +#define T_MPOINTER 38 +#define T_VARARGS 39 +#define T_RVALUE_REFERENCE 40 +#define T_WSTRING 41 + +#define T_SYMBOL 98 +#define T_ERROR 99 + + + +/* --- File interface --- */ + +#include "swigfile.h" + +/* --- Command line parsing --- */ + +#include "swigopt.h" + +/* --- Scanner Interface --- */ + +#include "swigscan.h" + +/* --- Functions for manipulating the string-based type encoding --- */ + + extern SwigType *NewSwigType(int typecode); + extern SwigType *SwigType_del_element(SwigType *t); + extern SwigType *SwigType_add_pointer(SwigType *t); + extern SwigType *SwigType_add_memberpointer(SwigType *t, const_String_or_char_ptr qual); + extern SwigType *SwigType_del_memberpointer(SwigType *t); + extern SwigType *SwigType_del_pointer(SwigType *t); + extern SwigType *SwigType_add_array(SwigType *t, const_String_or_char_ptr size); + extern SwigType *SwigType_del_array(SwigType *t); + extern SwigType *SwigType_pop_arrays(SwigType *t); + extern SwigType *SwigType_add_reference(SwigType *t); + extern SwigType *SwigType_del_reference(SwigType *t); + extern SwigType *SwigType_add_rvalue_reference(SwigType *t); + extern SwigType *SwigType_del_rvalue_reference(SwigType *t); + extern SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual); + extern SwigType *SwigType_del_qualifier(SwigType *t); + extern SwigType *SwigType_add_function(SwigType *t, ParmList *parms); + extern SwigType *SwigType_add_template(SwigType *t, ParmList *parms); + extern SwigType *SwigType_pop_function(SwigType *t); + extern SwigType *SwigType_pop_function_qualifiers(SwigType *t); + extern ParmList *SwigType_function_parms(const SwigType *t, Node *file_line_node); + extern List *SwigType_split(const SwigType *t); + extern String *SwigType_pop(SwigType *t); + extern void SwigType_push(SwigType *t, String *s); + extern SwigType *SwigType_last(SwigType *t); + extern List *SwigType_parmlist(const SwigType *p); + extern String *SwigType_parm(const SwigType *p); + extern String *SwigType_str(const SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_lstr(const SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_rcaststr(const SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_lcaststr(const SwigType *s, const_String_or_char_ptr id); + extern String *SwigType_manglestr(const SwigType *t); + extern SwigType *SwigType_ltype(const SwigType *t); + extern int SwigType_ispointer(const SwigType *t); + extern int SwigType_ispointer_return(const SwigType *t); + extern int SwigType_isfunctionpointer(const SwigType *t); + extern int SwigType_ismemberpointer(const SwigType *t); + extern int SwigType_isreference(const SwigType *t); + extern int SwigType_isreference_return(const SwigType *t); + extern int SwigType_isrvalue_reference(const SwigType *t); + extern int SwigType_isarray(const SwigType *t); + extern int SwigType_prefix_is_simple_1D_array(const SwigType *t); + extern int SwigType_isfunction(const SwigType *t); + extern int SwigType_isqualifier(const SwigType *t); + extern int SwigType_isconst(const SwigType *t); + extern int SwigType_issimple(const SwigType *t); + extern int SwigType_ismutable(const SwigType *t); + extern int SwigType_isvarargs(const SwigType *t); + extern int SwigType_istemplate(const SwigType *t); + extern int SwigType_isenum(const SwigType *t); + extern int SwigType_check_decl(const SwigType *t, const_String_or_char_ptr decl); + extern SwigType *SwigType_strip_qualifiers(const SwigType *t); + extern SwigType *SwigType_strip_single_qualifier(const SwigType *t); + extern SwigType *SwigType_functionpointer_decompose(SwigType *t); + extern String *SwigType_base(const SwigType *t); + extern String *SwigType_namestr(const SwigType *t); + extern String *SwigType_templateprefix(const SwigType *t); + extern String *SwigType_templatesuffix(const SwigType *t); + extern String *SwigType_istemplate_templateprefix(const SwigType *t); + extern String *SwigType_istemplate_only_templateprefix(const SwigType *t); + extern String *SwigType_templateargs(const SwigType *t); + extern String *SwigType_prefix(const SwigType *t); + extern int SwigType_array_ndim(const SwigType *t); + extern String *SwigType_array_getdim(const SwigType *t, int n); + extern void SwigType_array_setdim(SwigType *t, int n, const_String_or_char_ptr rep); + extern SwigType *SwigType_array_type(const SwigType *t); + extern SwigType *SwigType_default_create(const SwigType *ty); + extern SwigType *SwigType_default_deduce(const SwigType *t); + extern void SwigType_typename_replace(SwigType *t, String *pat, String *rep); + extern SwigType *SwigType_remove_global_scope_prefix(const SwigType *t); + extern SwigType *SwigType_alttype(const SwigType *t, int ltmap); + +/* --- Type-system management --- */ + extern void SwigType_typesystem_init(void); + extern int SwigType_typedef(const SwigType *type, const_String_or_char_ptr name); + extern int SwigType_typedef_class(const_String_or_char_ptr name); + extern int SwigType_typedef_using(const_String_or_char_ptr qname); + extern void SwigType_inherit(String *subclass, String *baseclass, String *cast, String *conversioncode); + extern int SwigType_issubtype(const SwigType *subtype, const SwigType *basetype); + extern void SwigType_scope_alias(String *aliasname, Typetab *t); + extern void SwigType_using_scope(Typetab *t); + extern void SwigType_new_scope(const_String_or_char_ptr name); + extern void SwigType_inherit_scope(Typetab *scope); + extern Typetab *SwigType_pop_scope(void); + extern Typetab *SwigType_set_scope(Typetab *h); + extern void SwigType_print_scope(void); + extern SwigType *SwigType_typedef_resolve(const SwigType *t); + extern SwigType *SwigType_typedef_resolve_all(const SwigType *t); + extern SwigType *SwigType_typedef_qualified(const SwigType *t); + extern int SwigType_istypedef(const SwigType *t); + extern int SwigType_isclass(const SwigType *t); + extern void SwigType_attach_symtab(Symtab *syms); + extern void SwigType_remember(const SwigType *t); + extern void SwigType_remember_clientdata(const SwigType *t, const_String_or_char_ptr clientdata); + extern void SwigType_remember_mangleddata(String *mangled, const_String_or_char_ptr clientdata); + extern void (*SwigType_remember_trace(void (*tf) (const SwigType *, String *, String *))) (const SwigType *, String *, String *); + extern void SwigType_emit_type_table(File *f_headers, File *f_table); + extern int SwigType_type(const SwigType *t); + +/* --- Symbol table module --- */ + + extern void Swig_symbol_print_tables(Symtab *symtab); + extern void Swig_symbol_print_tables_summary(void); + extern void Swig_symbol_print_symbols(void); + extern void Swig_symbol_print_csymbols(void); + extern void Swig_symbol_init(void); + extern void Swig_symbol_setscopename(const_String_or_char_ptr name); + extern String *Swig_symbol_getscopename(void); + extern String *Swig_symbol_qualifiedscopename(Symtab *symtab); + extern String *Swig_symbol_qualified_language_scopename(Symtab *symtab); + extern Symtab *Swig_symbol_newscope(void); + extern Symtab *Swig_symbol_setscope(Symtab *); + extern Symtab *Swig_symbol_getscope(const_String_or_char_ptr symname); + extern Symtab *Swig_symbol_global_scope(void); + extern Symtab *Swig_symbol_current(void); + extern Symtab *Swig_symbol_popscope(void); + extern Node *Swig_symbol_add(const_String_or_char_ptr symname, Node *node); + extern void Swig_symbol_cadd(const_String_or_char_ptr symname, Node *node); + extern Node *Swig_symbol_clookup(const_String_or_char_ptr symname, Symtab *tab); + extern Node *Swig_symbol_clookup_check(const_String_or_char_ptr symname, Symtab *tab, int (*check) (Node *)); + extern Node *Swig_symbol_clookup_no_inherit(const_String_or_char_ptr name, Symtab *n); + extern Symtab *Swig_symbol_cscope(const_String_or_char_ptr symname, Symtab *tab); + extern Node *Swig_symbol_clookup_local(const_String_or_char_ptr symname, Symtab *tab); + extern Node *Swig_symbol_clookup_local_check(const_String_or_char_ptr symname, Symtab *tab, int (*check) (Node *)); + extern String *Swig_symbol_qualified(Node *node); + extern Node *Swig_symbol_isoverloaded(Node *node); + extern void Swig_symbol_remove(Node *node); + extern void Swig_symbol_alias(const_String_or_char_ptr aliasname, Symtab *tab); + extern void Swig_symbol_inherit(Symtab *tab); + extern SwigType *Swig_symbol_type_qualify(const SwigType *ty, Symtab *tab); + extern String *Swig_symbol_string_qualify(String *s, Symtab *tab); + extern SwigType *Swig_symbol_typedef_reduce(const SwigType *ty, Symtab *tab); + + extern ParmList *Swig_symbol_template_defargs(Parm *parms, Parm *targs, Symtab *tscope, Symtab *tsdecl); + extern SwigType *Swig_symbol_template_deftype(const SwigType *type, Symtab *tscope); + extern SwigType *Swig_symbol_template_param_eval(const SwigType *p, Symtab *symtab); + +/* --- Parameters and Parameter Lists --- */ + +#include "swigparm.h" + +extern String *ParmList_errorstr(ParmList *); +extern int ParmList_is_compactdefargs(ParmList *p); + +/* --- Parse tree support --- */ + +#include "swigtree.h" + +/* -- Wrapper function Object */ + +#include "swigwrap.h" + +/* --- Naming functions --- */ + + extern void Swig_name_register(const_String_or_char_ptr method, const_String_or_char_ptr format); + extern void Swig_name_unregister(const_String_or_char_ptr method); + extern String *Swig_name_mangle(const_String_or_char_ptr s); + extern String *Swig_name_wrapper(const_String_or_char_ptr fname); + extern String *Swig_name_member(const_String_or_char_ptr nspace, const_String_or_char_ptr classname, const_String_or_char_ptr membername); + extern String *Swig_name_get(const_String_or_char_ptr nspace, const_String_or_char_ptr vname); + extern String *Swig_name_set(const_String_or_char_ptr nspace, const_String_or_char_ptr vname); + extern String *Swig_name_construct(const_String_or_char_ptr nspace, const_String_or_char_ptr classname); + extern String *Swig_name_copyconstructor(const_String_or_char_ptr nspace, const_String_or_char_ptr classname); + extern String *Swig_name_destroy(const_String_or_char_ptr nspace, const_String_or_char_ptr classname); + extern String *Swig_name_disown(const_String_or_char_ptr nspace, const_String_or_char_ptr classname); + + extern void Swig_naming_init(void); + extern void Swig_name_namewarn_add(String *prefix, String *name, SwigType *decl, Hash *namewrn); + extern void Swig_name_rename_add(String *prefix, String *name, SwigType *decl, Hash *namewrn, ParmList *declaratorparms); + extern void Swig_name_inherit(String *base, String *derived); + extern List *Swig_make_inherit_list(String *clsname, List *names, String *Namespaceprefix); + extern void Swig_inherit_base_symbols(List *bases); + extern int Swig_need_protected(Node *n); + extern int Swig_need_redefined_warn(Node *a, Node *b, int InClass); + + extern String *Swig_name_make(Node *n, String *prefix, const_String_or_char_ptr cname, SwigType *decl, String *oldname); + extern String *Swig_name_warning(Node *n, String *prefix, String *name, SwigType *decl); + extern String *Swig_name_str(Node *n); + extern String *Swig_name_decl(Node *n); + extern String *Swig_name_fulldecl(Node *n); + +/* --- parameterized rename functions --- */ + + extern void Swig_name_object_set(Hash *namehash, String *name, SwigType *decl, DOH *object); + extern DOH *Swig_name_object_get(Hash *namehash, String *prefix, String *name, SwigType *decl); + extern void Swig_name_object_inherit(Hash *namehash, String *base, String *derived); + extern void Swig_features_get(Hash *features, String *prefix, String *name, SwigType *decl, Node *n); + extern void Swig_feature_set(Hash *features, const_String_or_char_ptr name, SwigType *decl, const_String_or_char_ptr featurename, const_String_or_char_ptr value, Hash *featureattribs); + +/* --- Misc --- */ + extern char *Swig_copy_string(const char *c); + extern void Swig_set_fakeversion(const char *version); + extern const char *Swig_package_version(void); + extern String *Swig_package_version_hex(void); + extern void Swig_obligatory_macros(String *f_runtime, const char *language); + extern void Swig_banner(File *f); + extern void Swig_banner_target_lang(File *f, const_String_or_char_ptr commentchar); + extern String *Swig_strip_c_comments(const String *s); + extern String *Swig_new_subdirectory(String *basedirectory, String *subdirectory); + extern void Swig_filename_correct(String *filename); + extern String *Swig_filename_escape(String *filename); + extern String *Swig_filename_escape_space(String *filename); + extern void Swig_filename_unescape(String *filename); + extern int Swig_storage_isextern(Node *n); + extern int Swig_storage_isexternc(Node *n); + extern int Swig_storage_isstatic_custom(Node *n, const_String_or_char_ptr storage); + extern int Swig_storage_isstatic(Node *n); + extern String *Swig_string_escape(String *s); + extern String *Swig_string_mangle(const String *s); + extern void Swig_scopename_split(const String *s, String **prefix, String **last); + extern String *Swig_scopename_prefix(const String *s); + extern String *Swig_scopename_last(const String *s); + extern String *Swig_scopename_first(const String *s); + extern String *Swig_scopename_suffix(const String *s); + extern List *Swig_scopename_tolist(const String *s); + extern int Swig_scopename_check(const String *s); + extern String *Swig_string_lower(String *s); + extern String *Swig_string_upper(String *s); + extern String *Swig_string_title(String *s); + extern void Swig_offset_string(String *s, int number); + extern String *Swig_pcre_version(void); + extern void Swig_init(void); + + extern int Swig_value_wrapper_mode(int mode); + extern int Swig_is_generated_overload(Node *n); + + typedef enum { EMF_STANDARD, EMF_MICROSOFT } ErrorMessageFormat; + + extern void Swig_warning(int num, const_String_or_char_ptr filename, int line, const char *fmt, ...); + extern void Swig_error(const_String_or_char_ptr filename, int line, const char *fmt, ...); + extern int Swig_error_count(void); + extern void Swig_error_silent(int s); + extern void Swig_warnfilter(const_String_or_char_ptr wlist, int val); + extern void Swig_warnall(void); + extern int Swig_warn_count(void); + extern void Swig_error_msg_format(ErrorMessageFormat format); + extern void Swig_diagnostic(const_String_or_char_ptr filename, int line, const char *fmt, ...); + extern String *Swig_stringify_with_location(DOH *object); + +/* --- C Wrappers --- */ + extern void Swig_cresult_name_set(const char *new_name); + extern const char *Swig_cresult_name(void); + extern String *Swig_cparm_name(Parm *p, int i); + extern String *Swig_wrapped_var_type(SwigType *t, int varcref); + extern int Swig_cargs(Wrapper *w, ParmList *l); + extern String *Swig_cresult(SwigType *t, const_String_or_char_ptr name, const_String_or_char_ptr decl); + + extern String *Swig_cfunction_call(const_String_or_char_ptr name, ParmList *parms); + extern String *Swig_cconstructor_call(const_String_or_char_ptr name); + extern String *Swig_cppconstructor_call(const_String_or_char_ptr name, ParmList *parms); + extern String *Swig_unref_call(Node *n); + extern String *Swig_ref_call(Node *n, const String *lname); + extern String *Swig_cdestructor_call(Node *n); + extern String *Swig_cppdestructor_call(Node *n); + extern String *Swig_cmemberset_call(const_String_or_char_ptr name, SwigType *type, String *self, int varcref); + extern String *Swig_cmemberget_call(const_String_or_char_ptr name, SwigType *t, String *self, int varcref); + + extern int Swig_add_extension_code(Node *n, const String *function_name, ParmList *parms, SwigType *return_type, const String *code, int cplusplus, const String *self); + extern void Swig_replace_special_variables(Node *n, Node *parentnode, String *code); + +/* --- Transformations --- */ + + extern int Swig_MethodToFunction(Node *n, const_String_or_char_ptr nspace, String *classname, int flags, SwigType *director_type, int is_director); + extern int Swig_ConstructorToFunction(Node *n, const_String_or_char_ptr nspace, String *classname, String *none_comparison, String *director_ctor, int cplus, int flags, String *directorname); + extern int Swig_DestructorToFunction(Node *n, const_String_or_char_ptr nspace, String *classname, int cplus, int flags); + extern int Swig_MembersetToFunction(Node *n, String *classname, int flags); + extern int Swig_MembergetToFunction(Node *n, String *classname, int flags); + extern int Swig_VargetToFunction(Node *n, int flags); + extern int Swig_VarsetToFunction(Node *n, int flags); + +#define CWRAP_EXTEND 0x01 +#define CWRAP_SMART_POINTER 0x02 +#define CWRAP_NATURAL_VAR 0x04 +#define CWRAP_DIRECTOR_ONE_CALL 0x08 +#define CWRAP_DIRECTOR_TWO_CALLS 0x10 +#define CWRAP_ALL_PROTECTED_ACCESS 0x20 +#define CWRAP_SMART_POINTER_OVERLOAD 0x40 + +/* --- Director Helpers --- */ + extern Node *Swig_methodclass(Node *n); + extern int Swig_directorclass(Node *n); + extern Node *Swig_directormap(Node *n, String *type); + +/* --- Legacy Typemap API (somewhat simplified, ha!) --- */ + + extern void Swig_typemap_init(void); + extern void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *pattern, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs); + extern int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcpattern, ParmList *pattern); + extern void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *pattern); + extern int Swig_typemap_apply(ParmList *srcpat, ParmList *destpat); + extern void Swig_typemap_clear_apply(ParmList *pattern); + extern void Swig_typemap_replace_embedded_typemap(String *s, Node *file_line_node); + extern void Swig_typemap_debug(void); + extern void Swig_typemap_search_debug_set(void); + extern void Swig_typemap_used_debug_set(void); + extern void Swig_typemap_register_debug_set(void); + + extern String *Swig_typemap_lookup(const_String_or_char_ptr tmap_method, Node *n, const_String_or_char_ptr lname, Wrapper *f); + extern String *Swig_typemap_lookup_out(const_String_or_char_ptr tmap_method, Node *n, const_String_or_char_ptr lname, Wrapper *f, String *actioncode); + + extern void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f); + +/* --- Code fragment support --- */ + + extern void Swig_fragment_register(Node *fragment); + extern void Swig_fragment_emit(String *name); + extern void Swig_fragment_clear(String *section); + +/* --- Extension support --- */ + + extern Hash *Swig_extend_hash(void); + extern void Swig_extend_merge(Node *cls, Node *am); + extern void Swig_extend_append_previous(Node *cls, Node *am); + extern void Swig_extend_unused_check(void); + +/* hacks defined in C++ ! */ + extern int Swig_director_mode(void); + extern int Swig_director_protected_mode(void); + extern int Swig_all_protected_mode(void); + extern void Wrapper_director_mode_set(int); + extern void Wrapper_director_protected_mode_set(int); + extern void Wrapper_all_protected_mode_set(int); + extern void Language_replace_special_variables(String *method, String *tm, Parm *parm); + extern void Swig_print(DOH *object, int count); + extern void Swig_print_with_location(DOH *object, int count); + +/* -- template init -- */ + extern void SwigType_template_init(void); + + +#ifdef __cplusplus +} +#endif +#endif diff --git a/contrib/tools/swig/Source/Swig/swigfile.h b/contrib/tools/swig/Source/Swig/swigfile.h new file mode 100644 index 0000000000..009599a112 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swigfile.h @@ -0,0 +1,41 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swigfile.h + * + * File handling functions in the SWIG core + * ----------------------------------------------------------------------------- */ + +extern List *Swig_add_directory(const_String_or_char_ptr dirname); +extern void Swig_push_directory(const_String_or_char_ptr dirname); +extern void Swig_pop_directory(void); +extern String *Swig_last_file(void); +extern List *Swig_search_path(void); +extern FILE *Swig_include_open(const_String_or_char_ptr name); +extern FILE *Swig_open(const_String_or_char_ptr name); +extern String *Swig_read_file(FILE *f); +extern String *Swig_include(const_String_or_char_ptr name); +extern String *Swig_include_sys(const_String_or_char_ptr name); +extern int Swig_insert_file(const_String_or_char_ptr name, File *outfile); +extern void Swig_set_push_dir(int dopush); +extern int Swig_get_push_dir(void); +extern void Swig_register_filebyname(const_String_or_char_ptr filename, File *outfile); +extern File *Swig_filebyname(const_String_or_char_ptr filename); +extern String *Swig_file_extension(const_String_or_char_ptr filename); +extern String *Swig_file_basename(const_String_or_char_ptr filename); +extern String *Swig_file_filename(const_String_or_char_ptr filename); +extern String *Swig_file_dirname(const_String_or_char_ptr filename); +extern void Swig_file_debug_set(void); + +/* Delimiter used in accessing files and directories */ + +#if defined(_WIN32) +# define SWIG_FILE_DELIMITER "\\" +#else +# define SWIG_FILE_DELIMITER "/" +#endif diff --git a/contrib/tools/swig/Source/Swig/swigopt.h b/contrib/tools/swig/Source/Swig/swigopt.h new file mode 100644 index 0000000000..86a477b8f7 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swigopt.h @@ -0,0 +1,18 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swigopt.h + * + * Header file for the SWIG command line processing functions + * ----------------------------------------------------------------------------- */ + + extern void Swig_init_args(int argc, char **argv); + extern void Swig_mark_arg(int n); + extern int Swig_check_marked(int n); + extern void Swig_check_options(int check_input); + extern void Swig_arg_error(void); diff --git a/contrib/tools/swig/Source/Swig/swigparm.h b/contrib/tools/swig/Source/Swig/swigparm.h new file mode 100644 index 0000000000..7b63546ec0 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swigparm.h @@ -0,0 +1,35 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swigparm.h + * + * Functions related to the handling of function/method parameters and + * parameter lists. + * ----------------------------------------------------------------------------- */ + +/* Individual parameters */ +extern Parm *NewParm(SwigType *type, const_String_or_char_ptr name, Node *from_node); +extern Parm *NewParmWithoutFileLineInfo(SwigType *type, const_String_or_char_ptr name); +extern Parm *NewParmNode(SwigType *type, Node *from_node); +extern Parm *CopyParm(Parm *p); + +/* Parameter lists */ +extern ParmList *CopyParmList(ParmList *); +extern ParmList *CopyParmListMax(ParmList *, int count); +extern int ParmList_len(ParmList *); +extern int ParmList_numrequired(ParmList *); +extern int ParmList_has_defaultargs(ParmList *p); +extern int ParmList_has_varargs(ParmList *p); + +/* Output functions */ +extern String *ParmList_str(ParmList *); +extern String *ParmList_str_defaultargs(ParmList *); +extern String *ParmList_str_multibrackets(ParmList *); +extern String *ParmList_protostr(ParmList *); + + diff --git a/contrib/tools/swig/Source/Swig/swigscan.h b/contrib/tools/swig/Source/Swig/swigscan.h new file mode 100644 index 0000000000..6c9d1ff7fc --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swigscan.h @@ -0,0 +1,119 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swigscan.h + * + * C/C++ scanner. + * ----------------------------------------------------------------------------- */ + +typedef struct Scanner Scanner; + +extern Scanner *NewScanner(void); +extern void DelScanner(Scanner *); +extern void Scanner_clear(Scanner *); +extern void Scanner_push(Scanner *, String *); +extern void Scanner_pushtoken(Scanner *, int, const_String_or_char_ptr value); +extern int Scanner_token(Scanner *); +extern String *Scanner_text(Scanner *); +extern void Scanner_skip_line(Scanner *); +extern int Scanner_skip_balanced(Scanner *, int startchar, int endchar); +extern String *Scanner_get_raw_text_balanced(Scanner *, int startchar, int endchar); +extern void Scanner_set_location(Scanner *, String *file, int line); +extern String *Scanner_file(Scanner *); +extern int Scanner_line(Scanner *); +extern int Scanner_start_line(Scanner *); +extern void Scanner_idstart(Scanner *, const char *idchar); +extern String *Scanner_errmsg(Scanner *); +extern int Scanner_errline(Scanner *); +extern int Scanner_isoperator(int tokval); +extern void Scanner_locator(Scanner *, String *loc); + +/* Note: Tokens in range 100+ are for C/C++ operators */ + +#define SWIG_MAXTOKENS 200 +#define SWIG_TOKEN_LPAREN 1 /* ( */ +#define SWIG_TOKEN_RPAREN 2 /* ) */ +#define SWIG_TOKEN_SEMI 3 /* ; */ +#define SWIG_TOKEN_LBRACE 4 /* { */ +#define SWIG_TOKEN_RBRACE 5 /* } */ +#define SWIG_TOKEN_LBRACKET 6 /* [ */ +#define SWIG_TOKEN_RBRACKET 7 /* ] */ +#define SWIG_TOKEN_BACKSLASH 8 /* \ */ +#define SWIG_TOKEN_ENDLINE 9 /* \n */ +#define SWIG_TOKEN_STRING 10 /* "str" */ +#define SWIG_TOKEN_POUND 11 /* # */ +#define SWIG_TOKEN_COLON 12 /* : */ +#define SWIG_TOKEN_DCOLON 13 /* :: */ +#define SWIG_TOKEN_DCOLONSTAR 14 /* ::* */ +#define SWIG_TOKEN_ID 15 /* identifier */ +#define SWIG_TOKEN_FLOAT 16 /* 3.1415F */ +#define SWIG_TOKEN_DOUBLE 17 /* 3.1415 */ +#define SWIG_TOKEN_INT 18 /* 314 */ +#define SWIG_TOKEN_UINT 19 /* 314U */ +#define SWIG_TOKEN_LONG 20 /* 314L */ +#define SWIG_TOKEN_ULONG 21 /* 314UL */ +#define SWIG_TOKEN_CHAR 22 /* 'charconst' */ +#define SWIG_TOKEN_PERIOD 23 /* . */ +#define SWIG_TOKEN_AT 24 /* @ */ +#define SWIG_TOKEN_DOLLAR 25 /* $ */ +#define SWIG_TOKEN_CODEBLOCK 26 /* %{ ... %} ... */ +#define SWIG_TOKEN_RSTRING 27 /* `charconst` */ +#define SWIG_TOKEN_LONGLONG 28 /* 314LL */ +#define SWIG_TOKEN_ULONGLONG 29 /* 314ULL */ +#define SWIG_TOKEN_QUESTION 30 /* ? */ +#define SWIG_TOKEN_COMMENT 31 /* C or C++ comment */ +#define SWIG_TOKEN_BOOL 32 /* true or false */ +#define SWIG_TOKEN_WSTRING 33 /* L"str" */ +#define SWIG_TOKEN_WCHAR 34 /* L'c' */ +#define SWIG_TOKEN_ELLIPSIS 35 /* ... */ +#define SWIG_TOKEN_LLBRACKET 36 /* [[ */ +#define SWIG_TOKEN_RRBRACKET 37 /* ]] */ + +#define SWIG_TOKEN_ILLEGAL 99 +#define SWIG_TOKEN_ERROR -1 + +#define SWIG_TOKEN_COMMA 101 /* , */ +#define SWIG_TOKEN_STAR 102 /* * */ +#define SWIG_TOKEN_TIMES 102 /* * */ +#define SWIG_TOKEN_EQUAL 103 /* = */ +#define SWIG_TOKEN_EQUALTO 104 /* == */ +#define SWIG_TOKEN_NOTEQUAL 105 /* != */ +#define SWIG_TOKEN_PLUS 106 /* + */ +#define SWIG_TOKEN_MINUS 107 /* - */ +#define SWIG_TOKEN_AND 108 /* & */ +#define SWIG_TOKEN_LAND 109 /* && */ +#define SWIG_TOKEN_OR 110 /* | */ +#define SWIG_TOKEN_LOR 111 /* || */ +#define SWIG_TOKEN_XOR 112 /* ^ */ +#define SWIG_TOKEN_LESSTHAN 113 /* < */ +#define SWIG_TOKEN_GREATERTHAN 114 /* > */ +#define SWIG_TOKEN_LTEQUAL 115 /* <= */ +#define SWIG_TOKEN_GTEQUAL 116 /* >= */ +#define SWIG_TOKEN_NOT 117 /* ~ */ +#define SWIG_TOKEN_LNOT 118 /* ! */ +#define SWIG_TOKEN_SLASH 119 /* / */ +#define SWIG_TOKEN_DIVIDE 119 /* / */ +#define SWIG_TOKEN_PERCENT 120 /* % */ +#define SWIG_TOKEN_MODULO 120 /* % */ +#define SWIG_TOKEN_LSHIFT 121 /* << */ +#define SWIG_TOKEN_RSHIFT 122 /* >> */ +#define SWIG_TOKEN_PLUSPLUS 123 /* ++ */ +#define SWIG_TOKEN_MINUSMINUS 124 /* -- */ +#define SWIG_TOKEN_PLUSEQUAL 125 /* += */ +#define SWIG_TOKEN_MINUSEQUAL 126 /* -= */ +#define SWIG_TOKEN_TIMESEQUAL 127 /* *= */ +#define SWIG_TOKEN_DIVEQUAL 128 /* /= */ +#define SWIG_TOKEN_ANDEQUAL 129 /* &= */ +#define SWIG_TOKEN_OREQUAL 130 /* |= */ +#define SWIG_TOKEN_XOREQUAL 131 /* ^= */ +#define SWIG_TOKEN_LSEQUAL 132 /* <<= */ +#define SWIG_TOKEN_RSEQUAL 133 /* >>= */ +#define SWIG_TOKEN_MODEQUAL 134 /* %= */ +#define SWIG_TOKEN_ARROW 135 /* -> */ +#define SWIG_TOKEN_ARROWSTAR 136 /* ->* */ +#define SWIG_TOKEN_LTEQUALGT 137 /* <=> */ diff --git a/contrib/tools/swig/Source/Swig/swigtree.h b/contrib/tools/swig/Source/Swig/swigtree.h new file mode 100644 index 0000000000..8d63d8fd33 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swigtree.h @@ -0,0 +1,54 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swigtree.h + * + * These functions are used to access and manipulate the SWIG parse tree. + * The structure of this tree is modeled directly after XML-DOM. The attribute + * and function names are meant to be similar. + * ----------------------------------------------------------------------------- */ + +/* Macros to traverse the DOM tree */ + +#define nodeType(x) Getattr(x,"nodeType") +#define parentNode(x) Getattr(x,"parentNode") +#define previousSibling(x) Getattr(x,"previousSibling") +#define nextSibling(x) Getattr(x,"nextSibling") +#define firstChild(x) Getattr(x,"firstChild") +#define lastChild(x) Getattr(x,"lastChild") + +/* Macros to set up the DOM tree (mostly used by the parser) */ + +#define set_nodeType(x,v) Setattr(x,"nodeType",v) +#define set_parentNode(x,v) Setattr(x,"parentNode",v) +#define set_previousSibling(x,v) Setattr(x,"previousSibling",v) +#define set_nextSibling(x,v) Setattr(x,"nextSibling",v) +#define set_firstChild(x,v) Setattr(x,"firstChild",v) +#define set_lastChild(x,v) Setattr(x,"lastChild",v) + +/* Utility functions */ + +extern int checkAttribute(Node *obj, const_String_or_char_ptr name, const_String_or_char_ptr value); +extern void appendChild(Node *node, Node *child); +extern void prependChild(Node *node, Node *child); +extern void removeNode(Node *node); +extern Node *copyNode(Node *node); +extern void appendSibling(Node *node, Node *child); + +/* Node restoration/restore functions */ + +extern void Swig_require(const char *ns, Node *node, ...); +extern void Swig_save(const char *ns, Node *node, ...); +extern void Swig_restore(Node *node); + +/* Debugging of parse trees */ + +extern void Swig_print_tags(File *obj, Node *root); +extern void Swig_print_tree(Node *obj); +extern void Swig_print_node(Node *obj); +extern int Swig_print_quiet(int quiet); diff --git a/contrib/tools/swig/Source/Swig/swigwrap.h b/contrib/tools/swig/Source/Swig/swigwrap.h new file mode 100644 index 0000000000..b584ca495b --- /dev/null +++ b/contrib/tools/swig/Source/Swig/swigwrap.h @@ -0,0 +1,31 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * swigwrap.h + * + * Functions related to wrapper objects. + * ----------------------------------------------------------------------------- */ + +typedef struct Wrapper { + Hash *localh; + String *def; + String *locals; + String *code; +} Wrapper; + +extern Wrapper *NewWrapper(void); +extern void DelWrapper(Wrapper *w); +extern void Wrapper_compact_print_mode_set(int flag); +extern void Wrapper_pretty_print(String *str, File *f); +extern void Wrapper_compact_print(String *str, File *f); +extern void Wrapper_print(Wrapper *w, File *f); +extern int Wrapper_add_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl); +extern int Wrapper_add_localv(Wrapper *w, const_String_or_char_ptr name, ...); +extern int Wrapper_check_local(Wrapper *w, const_String_or_char_ptr name); +extern char *Wrapper_new_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl); +extern char *Wrapper_new_localv(Wrapper *w, const_String_or_char_ptr name, ...); diff --git a/contrib/tools/swig/Source/Swig/symbol.c b/contrib/tools/swig/Source/Swig/symbol.c new file mode 100644 index 0000000000..107b1caef9 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/symbol.c @@ -0,0 +1,2128 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * symbol.c + * + * This file implements the SWIG symbol table. See details below. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +/* #define SWIG_DEBUG*/ +/* ----------------------------------------------------------------------------- + * Synopsis + * + * This module provides symbol table management for all of SWIG. In previous + * releases, the management of symbols was rather haphazard. This module tries + * to correct that. + * + * All symbols are associated with simple identifiers. For example, here are some + * declarations that generate symbol table entries: + * + * decl symbol + * -------------- ------------ + * void foo(int); foo + * int x; x + * typedef int *blah; blah + * + * Associated with each symbol is a Hash table that can contain any set of + * attributes that make sense for that object. For example: + * + * typedef int *blah; ----> "name" : 'blah' + * "type" : 'int' + * "decl" : 'p.' + * "storage" : 'typedef' + * + * In some cases, the symbol table needs to manage overloaded entries. For instance, + * overloaded functions. In this case, a linked list is built. The "sym:nextSibling" + * attribute is reserved to hold a link to the next entry. For example: + * + * int foo(int); --> "name" : "foo" "name" : "foo" + * int foo(int,double); "type" : "int" "type" : "int" + * "decl" : "f(int)." "decl" : "f(int,double)." + * ... ... + * "sym:nextSibling" : --------> "sym:nextSibling": --------> ... + * + * When more than one symbol has the same name, the symbol declarator is + * used to detect duplicates. For example, in the above case, foo(int) and + * foo(int,double) are different because their "decl" attribute is different. + * However, if a third declaration "foo(int)" was made, it would generate a + * conflict (due to having a declarator that matches a previous entry). + * + * Structures and classes: + * + * C/C++ symbol tables are normally managed in a few different spaces. The + * most visible namespace is reserved for functions, variables, typedef, enum values + * and such. In C, a separate tag-space is reserved for 'struct name', 'class name', + * and 'union name' declarations. In SWIG, a single namespace is used for everything + * this means that certain incompatibilities will arise with some C programs. For instance: + * + * struct Foo { + * ... + * } + * + * int Foo(); // Error. Name clash. Works in C though + * + * Due to the unified namespace for structures, special handling is performed for + * the following: + * + * typedef struct Foo { + * + * } Foo; + * + * In this case, the symbol table contains an entry for the structure itself. The + * typedef is left out of the symbol table. + * + * Target language vs C: + * + * The symbol tables are normally managed *in the namespace of the target language*. + * This means that name-collisions can be resolved using %rename and related + * directives. A quirk of this is that sometimes the symbol tables need to + * be used for C type resolution as well. To handle this, each symbol table + * also has a C-symbol table lurking behind the scenes. This is used to locate + * symbols in the C namespace. However, this symbol table is not used for error + * reporting nor is it used for anything else during code generation. + * + * Symbol table structure: + * + * Symbol tables themselves are a special kind of node that is organized just like + * a normal parse tree node. Symbol tables are organized in a tree that can be + * traversed using the SWIG-DOM API. The following attributes names are reserved. + * + * name -- Name of the scope defined by the symbol table (if any) + * This name is the C-scope name and is not affected by + * %renaming operations + * symtab -- Hash table mapping identifiers to nodes. + * csymtab -- Hash table mapping C identifiers to nodes. + * + * Reserved attributes on symbol objects: + * + * When a symbol is placed in the symbol table, the following attributes + * are set: + * + * sym:name -- Symbol name + * sym:nextSibling -- Next symbol (if overloaded) + * sym:previousSibling -- Previous symbol (if overloaded) + * sym:symtab -- Symbol table object holding the symbol + * sym:overloaded -- Set to the first symbol if overloaded + * + * These names are modeled after XML namespaces. In particular, every attribute + * pertaining to symbol table management is prefaced by the "sym:" prefix. + * + * An example dump of the parse tree showing symbol table entries for the + * following code should clarify this: + * + * namespace OuterNamespace { + * namespace InnerNamespace { + * class Class { + * }; + * struct Struct { + * int Var; + * }; + * } + * } + * + * +++ namespace ---------------------------------------- + * | sym:name - "OuterNamespace" + * | symtab - 0xa064bf0 + * | sym:symtab - 0xa041690 + * | sym:overname - "__SWIG_0" + * + * +++ namespace ---------------------------------------- + * | sym:name - "InnerNamespace" + * | symtab - 0xa064cc0 + * | sym:symtab - 0xa064bf0 + * | sym:overname - "__SWIG_0" + * + * +++ class ---------------------------------------- + * | sym:name - "Class" + * | symtab - 0xa064d80 + * | sym:symtab - 0xa064cc0 + * | sym:overname - "__SWIG_0" + * | + * +++ class ---------------------------------------- + * | sym:name - "Struct" + * | symtab - 0xa064f00 + * | sym:symtab - 0xa064cc0 + * | sym:overname - "__SWIG_0" + * + * +++ cdecl ---------------------------------------- + * | sym:name - "Var" + * | sym:symtab - 0xa064f00 + * | sym:overname - "__SWIG_0" + * | + * + * + * Each class and namespace has its own scope and thus a new symbol table (sym) + * is created. The sym attribute is only set for the first entry in the symbol + * table. The sym:symtab entry points to the symbol table in which the symbol + * exists, so for example, Struct is in the scope OuterNamespace::InnerNamespace + * so sym:symtab points to this symbol table (0xa064cc0). + * + * ----------------------------------------------------------------------------- */ + +static Hash *current = 0; /* The current symbol table hash */ +static Hash *ccurrent = 0; /* The current c symbol table hash */ +static Hash *current_symtab = 0; /* Current symbol table node */ +static Hash *symtabs = 0; /* Hash of all symbol tables by fully-qualified name */ +static Hash *global_scope = 0; /* Global scope */ + +static int use_inherit = 1; + +/* common attribute keys, to avoid calling find_key all the times */ + + +/* ----------------------------------------------------------------------------- + * Swig_symbol_print_tables() + * + * Debug display of symbol tables + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_print_tables(Symtab *symtab) { + if (!symtab) + symtab = current_symtab; + + Printf(stdout, "SYMBOL TABLES start =======================================\n"); + Swig_print_tree(symtab); + Printf(stdout, "SYMBOL TABLES finish =======================================\n"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_print_tables_summary() + * + * Debug summary display of all symbol tables by fully-qualified name + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_print_tables_summary(void) { + Printf(stdout, "SYMBOL TABLES SUMMARY start =======================================\n"); + Swig_print_node(symtabs); + Printf(stdout, "SYMBOL TABLES SUMMARY finish =======================================\n"); +} + +/* ----------------------------------------------------------------------------- + * symbol_print_symbols() + * ----------------------------------------------------------------------------- */ + +static void symbol_print_symbols(const char *symboltabletype, const char *nextSibling) { + Node *table = symtabs; + Iterator ki = First(table); + int show_pointers = 0; + while (ki.key) { + String *k = ki.key; + Printf(stdout, "===================================================\n"); + Printf(stdout, "%s -\n", k); + { + Symtab *symtab = Getattr(Getattr(table, k), symboltabletype); + Iterator it = First(symtab); + while (it.key) { + String *symname = it.key; + Printf(stdout, " %s (%s)", symname, nodeType(it.item)); + if (show_pointers) + Printf(stdout, " %p", it.item); + Printf(stdout, "\n"); + { + Node *sibling = Getattr(it.item, nextSibling); + while (sibling) { + Printf(stdout, " %s (%s)", symname, nodeType(sibling)); + if (show_pointers) + Printf(stdout, " %p", sibling); + Printf(stdout, "\n"); + sibling = Getattr(sibling, nextSibling); + } + } + it = Next(it); + } + } + ki = Next(ki); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_print_symbols() + * + * Debug display of all the target language symbols + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_print_symbols(void) { + Printf(stdout, "SYMBOLS start =======================================\n"); + symbol_print_symbols("symtab", "sym:nextSibling"); + Printf(stdout, "SYMBOLS finish =======================================\n"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_print_csymbols() + * + * Debug display of all the C symbols + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_print_csymbols(void) { + Printf(stdout, "CSYMBOLS start =======================================\n"); + symbol_print_symbols("csymtab", "csym:nextSibling"); + Printf(stdout, "CSYMBOLS finish =======================================\n"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_init() + * + * Create a new symbol table object + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_init(void) { + + current = NewHash(); + current_symtab = NewHash(); + ccurrent = NewHash(); + set_nodeType(current_symtab, "symboltable"); + Setattr(current_symtab, "symtab", current); + Delete(current); + Setattr(current_symtab, "csymtab", ccurrent); + Delete(ccurrent); + + /* Set the global scope */ + symtabs = NewHash(); + Setattr(symtabs, "", current_symtab); + Delete(current_symtab); + global_scope = current_symtab; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_setscopename() + * + * Set the C scopename of the current symbol table. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_setscopename(const_String_or_char_ptr name) { + String *qname; + /* assert(!Getattr(current_symtab,"name")); */ + Setattr(current_symtab, "name", name); + + /* Set nested scope in parent */ + + qname = Swig_symbol_qualifiedscopename(current_symtab); + + /* Save a reference to this scope */ + Setattr(symtabs, qname, current_symtab); + Delete(qname); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_getscopename() + * + * Get the C scopename of the current symbol table + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_getscopename(void) { + return Getattr(current_symtab, "name"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_getscope() + * + * Given a fully qualified C scopename, this function returns a symbol table + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_getscope(const_String_or_char_ptr name) { + if (!symtabs) + return 0; + if (Equal("::", (const_String_or_char_ptr ) name)) + name = ""; + return Getattr(symtabs, name); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_qualifiedscopename() + * + * Get the fully qualified C scopename of a symbol table. Note, this only pertains + * to the C/C++ scope name. It is not affected by renaming. + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_qualifiedscopename(Symtab *symtab) { + String *result = 0; + Hash *parent; + String *name; + if (!symtab) + symtab = current_symtab; + parent = Getattr(symtab, "parentNode"); + if (parent) { + result = Swig_symbol_qualifiedscopename(parent); + } + name = Getattr(symtab, "name"); + if (name) { + if (!result) { + result = NewStringEmpty(); + } + if (Len(result)) { + Printv(result, "::", name, NIL); + } else { + Append(result, name); + } + } + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_qualified_language_scopename() + * + * Get the fully qualified C scopename of a symbol table but using a language + * specific separator for the scopenames. Basically the same as + * Swig_symbol_qualifiedscopename() but using the different separator. + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_qualified_language_scopename(Symtab *n) { + /* TODO: fix for %rename to work */ + String *result = Swig_symbol_qualifiedscopename(n); + Replaceall(result, "::", NSPACE_SEPARATOR); + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_newscope() + * + * Create a new scope. Returns the newly created scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_newscope(void) { + Hash *n; + Hash *hsyms, *h; + + hsyms = NewHash(); + h = NewHash(); + + set_nodeType(h, "symboltable"); + Setattr(h, "symtab", hsyms); + Delete(hsyms); + set_parentNode(h, current_symtab); + + n = lastChild(current_symtab); + if (!n) { + set_firstChild(current_symtab, h); + } else { + set_nextSibling(n, h); + Delete(h); + } + set_lastChild(current_symtab, h); + current = hsyms; + ccurrent = NewHash(); + Setattr(h, "csymtab", ccurrent); + Delete(ccurrent); + current_symtab = h; + return h; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_setscope() + * + * Set the current scope. Returns the previous current scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_setscope(Symtab *sym) { + Symtab *ret = current_symtab; + current_symtab = sym; + current = Getattr(sym, "symtab"); + assert(current); + ccurrent = Getattr(sym, "csymtab"); + assert(ccurrent); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_popscope() + * + * Pop out of the current scope. Returns the popped scope and sets the + * scope to the parent scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_popscope(void) { + Hash *h = current_symtab; + current_symtab = Getattr(current_symtab, "parentNode"); + assert(current_symtab); + current = Getattr(current_symtab, "symtab"); + assert(current); + ccurrent = Getattr(current_symtab, "csymtab"); + assert(ccurrent); + return h; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_global_scope() + * + * Return the symbol table for the global scope. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_global_scope(void) { + return global_scope; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_current() + * + * Return the current symbol table. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_current(void) { + return current_symtab; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_alias() + * + * Makes an alias for a symbol in the global symbol table. + * Primarily for namespace aliases such as 'namespace X = Y;'. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_alias(const_String_or_char_ptr aliasname, Symtab *s) { + String *qname = Swig_symbol_qualifiedscopename(current_symtab); + if (qname) { + Printf(qname, "::%s", aliasname); + } else { + qname = NewString(aliasname); + } + if (!Getattr(symtabs, qname)) { + Setattr(symtabs, qname, s); + } + Delete(qname); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_inherit() + * + * Inherit symbols from another scope. Primarily for C++ inheritance and + * for using directives, such as 'using namespace X;' + * but not for using declarations, such as 'using A;'. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_inherit(Symtab *s) { + int i, ilen; + List *inherit = Getattr(current_symtab, "inherit"); + if (!inherit) { + inherit = NewList(); + Setattr(current_symtab, "inherit", inherit); + Delete(inherit); + } + + if (s == current_symtab) { + Swig_warning(WARN_PARSE_REC_INHERITANCE, Getfile(s), Getline(s), "Recursive scope inheritance of '%s'.\n", Getattr(s, "name")); + return; + } + assert(s != current_symtab); + ilen = Len(inherit); + for (i = 0; i < ilen; i++) { + Node *n = Getitem(inherit, i); + if (n == s) + return; /* Already inherited */ + } + Append(inherit, s); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_cadd() + * + * Adds a node to the C symbol table only. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_cadd(const_String_or_char_ptr name, Node *n) { + Node *append = 0; + Node *cn; + /* There are a few options for weak symbols. A "weak" symbol + is any symbol that can be replaced by another symbol in the C symbol + table. An example would be a forward class declaration. A forward + class sits in the symbol table until a real class declaration comes along. + + Certain symbols are marked as "sym:typename". These are important + symbols related to the C++ type-system and take precedence in the C + symbol table. An example might be code like this: + + template<class T> T foo(T x); + int foo(int); + + In this case, the template is marked with "sym:typename" so that it + stays in the C symbol table (so that it can be expanded using %template). + */ + + if (!name) + return; + + if (SwigType_istemplate(name)) { + String *cname = NewString(name); + String *dname = Swig_symbol_template_deftype(cname, 0); + if (!Equal(dname, name)) { + Swig_symbol_cadd(dname, n); + } + Delete(dname); + Delete(cname); + } +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_cadd %s %p\n", name, n); +#endif + cn = Getattr(ccurrent, name); + + if (cn && (Getattr(cn, "sym:typename"))) { + /* The node in the C symbol table is a typename. Do nothing */ + /* We might append the symbol at the end */ + append = n; + } else if (cn && (Getattr(cn, "sym:weak"))) { + /* The node in the symbol table is weak. Replace it */ + if (checkAttribute(cn, "nodeType", "template") + && checkAttribute(cn, "templatetype", "classforward")) { + /* The node is a template classforward declaration, and the + default template parameters here take precedence. */ + ParmList *pc = Getattr(cn, "templateparms"); + ParmList *pn = Getattr(n, "templateparms"); +#ifdef SWIG_DEBUG + Printf(stderr, "found template classforward %s\n", Getattr(cn, "name")); +#endif + while (pc && pn) { + String *value = Getattr(pc, "value"); + if (value) { +#ifdef SWIG_DEBUG + Printf(stderr, "add default template value %s %s\n", Getattr(pc, "name"), value); +#endif + Setattr(pn, "value", value); + } + pc = nextSibling(pc); + pn = nextSibling(pn); + } + Setattr(n, "templateparms", Getattr(cn, "templateparms")); + } + Setattr(ccurrent, name, n); + + } else if (cn && (Getattr(n, "sym:weak"))) { + /* The node being added is weak. Don't worry about it */ + } else if (cn && (Getattr(n, "sym:typename"))) { + /* The node being added is a typename. We definitely add it */ + Setattr(ccurrent, name, n); + append = cn; + } else if (cn && (Checkattr(cn, "nodeType", "templateparm"))) { + Swig_error(Getfile(n), Getline(n), "Declaration of '%s' shadows template parameter,\n", name); + Swig_error(Getfile(cn), Getline(cn), "previous template parameter declaration '%s'.\n", name); + return; + } else if (cn) { + append = n; + } else if (!cn) { + /* No conflict. Add the symbol */ + Setattr(ccurrent, name, n); + } + + /* Multiple entries in the C symbol table. We append to the symbol table */ + if (append) { + Node *fn, *pn = 0; + cn = Getattr(ccurrent, name); + fn = cn; + while (fn) { + pn = fn; + if (fn == append) { + /* already added. Bail */ + return; + } + fn = Getattr(fn, "csym:nextSibling"); + } + if (pn) { + Setattr(pn, "csym:nextSibling", append); + } + } + + /* Special typedef handling. When a typedef node is added to the symbol table, we + might have to add a type alias. This would occur if the typedef mapped to another + scope in the system. For example: + + class Foo { + }; + + typedef Foo OtherFoo; + + In this case, OtherFoo becomes an alias for Foo. */ + + { + Node *td = n; + while (td && ((Equal(nodeType(td), "cdecl") && Checkattr(td, "storage", "typedef")) || (Equal(nodeType(td), "using") && !Getattr(n, "namespace")))) { + SwigType *type; + Node *td1; + int using_not_typedef = Equal(nodeType(td), "using"); + type = Copy(Getattr(td, using_not_typedef ? "uname" : "type")); + SwigType_push(type, Getattr(td, "decl")); + td1 = Swig_symbol_clookup(type, 0); + + /* Fix pathetic case #1214313: + + class Foo + { + }; + + typedef Foo FooBar; + + class CBaz + { + public: + typedef FooBar Foo; + }; + + ie, when Foo -> FooBar -> Foo, jump one scope up when possible. + + */ + if (td1) { + String *st = 0; + String *sn = Getattr(td, "name"); + if (Equal(nodeType(td1), "cdecl") && Checkattr(td1, "storage", "typedef")) + st = Getattr(td1, "type"); + else if (Equal(nodeType(td1), "using") && !Getattr(td1, "namespace")) + st = Getattr(td1, "uname"); + if (st && sn && Equal(st, sn)) { + Symtab *sc = Getattr(current_symtab, "parentNode"); + if (sc) + td1 = Swig_symbol_clookup(type, sc); + } + } + + Delete(type); + if (td1 == td) + break; + td = td1; + if (td) { + Symtab *st = Getattr(td, "symtab"); + if (st) { + Swig_symbol_alias(Getattr(n, "name"), st); + break; + } + } + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_add() + * + * Adds a node to the symbol table. Returns the node itself if successfully + * added. Otherwise, it returns the symbol table entry of the conflicting node. + * + * Also places the symbol in a behind-the-scenes C symbol table. This is needed + * for namespace support, type resolution, and other issues. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_add(const_String_or_char_ptr symname, Node *n) { + Hash *c, *cl = 0; + SwigType *decl, *ndecl; + String *cstorage, *nstorage; + int nt = 0, ct = 0; + int pn = 0; + int u1 = 0, u2 = 0; + String *name, *overname; + + /* See if the node has a name. If so, we place in the C symbol table for this + scope. We don't worry about overloading here---the primary purpose of this + is to record information for type/name resolution for later. Conflicts + in C namespaces are errors, but these will be caught by the C++ compiler + when compiling the wrapper code */ + + + /* There are a few options for weak symbols. A "weak" symbol + is any symbol that can be replaced by another symbol in the C symbol + table. An example would be a forward class declaration. A forward + class sits in the symbol table until a real class declaration comes along. + + Certain symbols are marked as "sym:typename". These are important + symbols related to the C++ type-system and take precedence in the C + symbol table. An example might be code like this: + + template<class T> T foo(T x); + int foo(int); + + In this case, the template is marked with "sym:typename" so that it + stays in the C symbol table (so that it can be expanded using %template). + */ + + name = Getattr(n, "name"); + if (name && Len(name)) { + Swig_symbol_cadd(name, n); + } + + /* No symbol name defined. We return. */ + if (!symname) { + Setattr(n, "sym:symtab", current_symtab); + return n; + } + + /* If node is ignored. We don't proceed any further */ + if (GetFlag(n, "feature:ignore")) + return n; + + /* See if the symbol already exists in the table */ + c = Getattr(current, symname); + + /* Check for a weak symbol. A weak symbol is allowed to be in the + symbol table, but is silently overwritten by other symbols. An example + would be a forward class declaration. For instance: + + class Foo; + + In this case, "Foo" sits in the symbol table. However, the + definition of Foo would replace the entry if it appeared later. */ + + if (c && Getattr(c, "sym:weak")) { + c = 0; + } + if (c) { + /* There is a symbol table conflict. There are a few cases to consider here: + (1) A conflict between a class/enum and a typedef declaration is okay. + In this case, the symbol table entry is set to the class/enum declaration + itself, not the typedef. + (2) A conflict between namespaces is okay--namespaces are open + (3) Otherwise, overloading is only allowed for functions + (4) This special case is okay: a class template instantiated with same name as the template's name + */ + + /* Check for namespaces */ + String *ntype = Getattr(n, "nodeType"); + if ((Equal(ntype, Getattr(c, "nodeType"))) && ((Equal(ntype, "namespace")))) { + Node *cl, *pcl = 0; + cl = c; + while (cl) { + pcl = cl; + cl = Getattr(cl, "sym:nextSibling"); + } + Setattr(pcl, "sym:nextSibling", n); + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + Setattr(n, "sym:previousSibling", pcl); + return n; + } + + /* Special case: class template instantiated with same name as the template's name eg: %template(X) X<int>; */ + if (Equal(nodeType(c), "template")) { + String *nt1 = Getattr(c, "templatetype"); + String *nt2 = nodeType(n); + if (Equal(nt1, "class") && Equal(nt1, nt2)) { + if (Getattr(n, "template")) { + /* Finally check that another %template with same name doesn't already exist */ + if (!Getattr(c, "sym:nextSibling")) { + Setattr(c, "sym:nextSibling", n); + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + Setattr(n, "sym:previousSibling", c); + return n; + } + } + } + } + + if (Getattr(n, "allows_typedef")) + nt = 1; + if (Getattr(c, "allows_typedef")) + ct = 1; + if (nt || ct) { + Node *td, *other; + String *s; + /* At least one of the nodes allows typedef overloading. Make sure that + both don't--this would be a conflict */ + + if (nt && ct) + return c; + + /* Figure out which node allows the typedef */ + if (nt) { + td = n; + other = c; + } else { + td = c; + other = n; + } + /* Make sure the other node is a typedef */ + s = Getattr(other, "storage"); + if (!s || (!Equal(s, "typedef"))) + return c; /* No. This is a conflict */ + + /* Hmmm. This appears to be okay. Make sure the symbol table refers to the allow_type node */ + + if (td != c) { + Setattr(current, symname, td); + Setattr(td, "sym:symtab", current_symtab); + Setattr(td, "sym:name", symname); + } + return n; + } + + decl = Getattr(c, "decl"); + ndecl = Getattr(n, "decl"); + + { + String *nt1, *nt2; + nt1 = Getattr(n, "nodeType"); + if (Equal(nt1, "template")) + nt1 = Getattr(n, "templatetype"); + nt2 = Getattr(c, "nodeType"); + if (Equal(nt2, "template")) + nt2 = Getattr(c, "templatetype"); + if (Equal(nt1, "using")) + u1 = 1; + if (Equal(nt2, "using")) + u2 = 1; + + if ((!Equal(nt1, nt2)) && !(u1 || u2)) + return c; + } + if (!(u1 || u2)) { + if ((!SwigType_isfunction(decl)) || (!SwigType_isfunction(ndecl))) { + /* Symbol table conflict */ + return c; + } + } + + /* Hmmm. Declarator seems to indicate that this is a function */ + /* Look at storage class to see if compatible */ + cstorage = Getattr(c, "storage"); + nstorage = Getattr(n, "storage"); + + /* If either one is declared as typedef, forget it. We're hosed */ + if (Cmp(cstorage, "typedef") == 0) { + return c; + } + if (Cmp(nstorage, "typedef") == 0) { + return c; + } + + /* Okay. Walk down the list of symbols and see if we get a declarator match */ + { + String *nt = Getattr(n, "nodeType"); + int n_template = Equal(nt, "template") && Checkattr(n, "templatetype", "cdecl"); + int n_plain_cdecl = Equal(nt, "cdecl"); + Node *cn = c; + pn = 0; + while (cn) { + decl = Getattr(cn, "decl"); + if (!(u1 || u2)) { + if (Cmp(ndecl, decl) == 0) { + /* Declarator conflict */ + /* Now check we don't have a non-templated function overloaded by a templated function with same params, + * eg void foo(); template<typename> void foo(); */ + String *cnt = Getattr(cn, "nodeType"); + int cn_template = Equal(cnt, "template") && Checkattr(cn, "templatetype", "cdecl"); + int cn_plain_cdecl = Equal(cnt, "cdecl"); + if (!((n_template && cn_plain_cdecl) || (cn_template && n_plain_cdecl))) { + /* found a conflict */ + return cn; + } + } + } + cl = cn; + cn = Getattr(cn, "sym:nextSibling"); + pn++; + } + } + /* Well, we made it this far. Guess we can drop the symbol in place */ + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + /* Printf(stdout,"%s %p\n", Getattr(n,"sym:overname"), current_symtab); */ + assert(!Getattr(n, "sym:overname")); + overname = NewStringf("__SWIG_%d", pn); + Setattr(n, "sym:overname", overname); + /*Printf(stdout,"%s %s %s\n", symname, Getattr(n,"decl"), Getattr(n,"sym:overname")); */ + Setattr(cl, "sym:nextSibling", n); + Setattr(n, "sym:previousSibling", cl); + Setattr(cl, "sym:overloaded", c); + Setattr(n, "sym:overloaded", c); + Delete(overname); + return n; + } + + /* No conflict. Just add it */ + Setattr(n, "sym:symtab", current_symtab); + Setattr(n, "sym:name", symname); + /* Printf(stdout,"%s\n", Getattr(n,"sym:overname")); */ + overname = NewStringf("__SWIG_%d", pn); + Setattr(n, "sym:overname", overname); + Delete(overname); + /* Printf(stdout,"%s %s %s\n", symname, Getattr(n,"decl"), Getattr(n,"sym:overname")); */ + Setattr(current, symname, n); + return n; +} + +/* ----------------------------------------------------------------------------- + * symbol_lookup() + * + * Internal function to handle fully qualified symbol table lookups. This + * works from the symbol table supplied in symtab and unwinds its way out + * towards the global scope. + * + * This function operates in the C namespace, not the target namespace. + * + * The check function is an optional callback that can be used to verify a particular + * symbol match. This is only used in some of the more exotic parts of SWIG. For instance, + * verifying that a class hierarchy implements all pure virtual methods. + * ----------------------------------------------------------------------------- */ + +static Node *_symbol_lookup(const String *name, Symtab *symtab, int (*check) (Node *n)) { + Node *n; + List *inherit; + Hash *sym = Getattr(symtab, "csymtab"); + if (Getmark(symtab)) + return 0; + Setmark(symtab, 1); + + n = Getattr(sym, name); + +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_look %s %p %p %s\n", name, n, symtab, Getattr(symtab, "name")); +#endif + + if (n) { + /* if a check-function is defined. Call it to determine a match */ + if (check) { + int c = check(n); + if (c == 1) { + Setmark(symtab, 0); + return n; + } + if (c < 0) { + /* Terminate the search right away */ + Setmark(symtab, 0); + return 0; + } + } else { + Setmark(symtab, 0); + return n; + } + } + + if (!n && SwigType_istemplate(name)) { + String *dname = 0; + Setmark(symtab, 0); + dname = Swig_symbol_template_deftype(name, symtab); + if (!Equal(dname, name)) { + n = _symbol_lookup(dname, symtab, check); + } + Delete(dname); + if (n) + return n; + Setmark(symtab, 1); + } + + inherit = Getattr(symtab, "inherit"); + if (inherit && use_inherit) { + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + n = _symbol_lookup(name, Getitem(inherit, i), check); + if (n) { + Setmark(symtab, 0); + return n; + } + } + } + + Setmark(symtab, 0); + return 0; +} + +static Node *symbol_lookup(const_String_or_char_ptr name, Symtab *symtab, int (*check) (Node *n)) { + Node *n = 0; + if (DohCheck(name)) { + n = _symbol_lookup(name, symtab, check); + } else { + String *sname = NewString(name); + n = _symbol_lookup(sname, symtab, check); + Delete(sname); + } + return n; +} + + + +/* ----------------------------------------------------------------------------- + * symbol_lookup_qualified() + * ----------------------------------------------------------------------------- */ + +static Node *symbol_lookup_qualified(const_String_or_char_ptr name, Symtab *symtab, const String *prefix, int local, int (*checkfunc) (Node *n)) { + /* This is a little funky, we search by fully qualified names */ + + if (!symtab) + return 0; + if (!prefix) { + Node *n; + String *bname = 0; + String *prefix = 0; + Swig_scopename_split(name, &prefix, &bname); + n = symbol_lookup_qualified(bname, symtab, prefix, local, checkfunc); + Delete(bname); + Delete(prefix); + return n; + } else { + Symtab *st; + Node *n = 0; + /* Make qualified name of current scope */ + String *qalloc = 0; + String *qname = Swig_symbol_qualifiedscopename(symtab); + const String *cqname; + if (qname) { + if (Len(qname)) { + if (prefix && Len(prefix)) { + Printv(qname, "::", prefix, NIL); + } + } else { + Append(qname, prefix); + } + qalloc = qname; + cqname = qname; + } else { + cqname = prefix; + } + st = Getattr(symtabs, cqname); + /* Found a scope match */ + if (st) { + if (!name) { + if (qalloc) + Delete(qalloc); + return st; + } + n = symbol_lookup(name, st, checkfunc); + } + if (qalloc) + Delete(qalloc); + + if (!n) { + if (!local) { + Node *pn = Getattr(symtab, "parentNode"); + if (pn) + n = symbol_lookup_qualified(name, pn, prefix, local, checkfunc); + + /* Check inherited scopes */ + if (!n) { + List *inherit = Getattr(symtab, "inherit"); + if (inherit && use_inherit) { + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + Node *prefix_node = symbol_lookup(prefix, Getitem(inherit, i), checkfunc); + if (prefix_node) { + Node *prefix_symtab = Getattr(prefix_node, "symtab"); + if (prefix_symtab) { + n = symbol_lookup(name, prefix_symtab, checkfunc); + break; + } + } + } + } + } + } else { + n = 0; + } + } + return n; + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup() + * + * Look up a symbol in the symbol table. This uses the C name, not scripting + * names. Note: If we come across a using declaration, we follow it to + * to get the real node. Any using directives are also followed (but this is + * implemented in symbol_lookup()). + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup(const_String_or_char_ptr name, Symtab *n) { + Hash *hsym = 0; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + if (n) { + hsym = n; + } + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, 0); + } else { + s = symbol_lookup(nname, global_scope, 0); + } + Delete(nname); + } else { + String *prefix = Swig_scopename_prefix(name); + if (prefix) { + s = symbol_lookup_qualified(name, hsym, 0, 0, 0); + Delete(prefix); + if (!s) { + return 0; + } + } + } + } + if (!s) { + while (hsym) { + s = symbol_lookup(name, hsym, 0); + if (s) + break; + hsym = Getattr(hsym, "parentNode"); + if (!hsym) + break; + } + } + + if (!s) { + return 0; + } + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + String *uname = Getattr(s, "uname"); + Symtab *un = Getattr(s, "sym:symtab"); + Node *ss = (!Equal(name, uname) || (un != n)) ? Swig_symbol_clookup(uname, un) : 0; /* avoid infinity loop */ + if (!ss) { + SWIG_WARN_NODE_BEGIN(s); + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(s, "uname"))); + SWIG_WARN_NODE_END(s); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_check() + * + * This function is identical to Swig_symbol_clookup() except that it + * accepts a callback function that is invoked to determine a symbol match. + * The purpose of this function is to support complicated algorithms that need + * to examine multiple definitions of the same symbol that might appear in an + * inheritance hierarchy. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_check(const_String_or_char_ptr name, Symtab *n, int (*checkfunc) (Node *n)) { + Hash *hsym = 0; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + if (n) { + hsym = n; + } + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, checkfunc); + } else { + s = symbol_lookup(nname, global_scope, checkfunc); + } + Delete(nname); + } else { + String *prefix = Swig_scopename_prefix(name); + if (prefix) { + s = symbol_lookup_qualified(name, hsym, 0, 0, checkfunc); + Delete(prefix); + if (!s) { + return 0; + } + } + } + } + if (!s) { + while (hsym) { + s = symbol_lookup(name, hsym, checkfunc); + if (s) + break; + hsym = Getattr(hsym, "parentNode"); + if (!hsym) + break; + } + } + if (!s) { + return 0; + } + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + Node *ss; + ss = Swig_symbol_clookup(Getattr(s, "uname"), Getattr(s, "sym:symtab")); + if (!ss && !checkfunc) { + SWIG_WARN_NODE_BEGIN(s); + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(s, "uname"))); + SWIG_WARN_NODE_END(s); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_local() + * + * Same as Swig_symbol_clookup but parent nodes are not searched, that is, just + * this symbol table is searched. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_local(const_String_or_char_ptr name, Symtab *n) { + Hash *hsym; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + hsym = n; + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, 0); + } else { + s = symbol_lookup(nname, global_scope, 0); + } + Delete(nname); + } else { + s = symbol_lookup_qualified(name, hsym, 0, 0, 0); + } + } + if (!s) { + s = symbol_lookup(name, hsym, 0); + } + if (!s) + return 0; + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + Node *ss = Swig_symbol_clookup_local(Getattr(s, "uname"), Getattr(s, "sym:symtab")); + if (!ss) { + SWIG_WARN_NODE_BEGIN(s); + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(s, "uname"))); + SWIG_WARN_NODE_END(s); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_local_check() + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_local_check(const_String_or_char_ptr name, Symtab *n, int (*checkfunc) (Node *)) { + Hash *hsym; + Node *s = 0; + + if (!n) { + hsym = current_symtab; + } else { + if (!Checkattr(n, "nodeType", "symboltable")) { + n = Getattr(n, "sym:symtab"); + } + assert(n); + hsym = n; + } + + if (Swig_scopename_check(name)) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) { + String *nname = NewString(cname + 2); + if (Swig_scopename_check(nname)) { + s = symbol_lookup_qualified(nname, global_scope, 0, 0, checkfunc); + } else { + s = symbol_lookup(nname, global_scope, checkfunc); + } + Delete(nname); + } else { + s = symbol_lookup_qualified(name, hsym, 0, 0, checkfunc); + } + } + if (!s) { + s = symbol_lookup(name, hsym, checkfunc); + } + if (!s) + return 0; + /* Check if s is a 'using' node */ + while (s && Checkattr(s, "nodeType", "using")) { + Node *ss = Swig_symbol_clookup_local_check(Getattr(s, "uname"), Getattr(s, "sym:symtab"), checkfunc); + if (!ss && !checkfunc) { + SWIG_WARN_NODE_BEGIN(s); + Swig_warning(WARN_PARSE_USING_UNDEF, Getfile(s), Getline(s), "Nothing known about '%s'.\n", SwigType_namestr(Getattr(s, "uname"))); + SWIG_WARN_NODE_END(s); + } + s = ss; + } + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_clookup_no_inherit() + * + * Symbol lookup like Swig_symbol_clookup but does not follow using declarations. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_clookup_no_inherit(const_String_or_char_ptr name, Symtab *n) { + Node *s = 0; + assert(use_inherit==1); + use_inherit = 0; + s = Swig_symbol_clookup(name, n); + use_inherit = 1; + return s; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_cscope() + * + * Look up a scope name. + * ----------------------------------------------------------------------------- */ + +Symtab *Swig_symbol_cscope(const_String_or_char_ptr name, Symtab *symtab) { + char *cname = Char(name); + if (strncmp(cname, "::", 2) == 0) + return symbol_lookup_qualified(0, global_scope, name, 0, 0); + return symbol_lookup_qualified(0, symtab, name, 0, 0); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_remove() + * + * Remove a symbol. If the symbol is an overloaded function and the symbol removed + * is not the last in the list of overloaded functions, then the overloaded + * names (sym:overname attribute) are changed to start from zero, eg __SWIG_0. + * ----------------------------------------------------------------------------- */ + +void Swig_symbol_remove(Node *n) { + Symtab *symtab; + String *symname; + String *overname; + Node *symprev; + Node *symnext; + Node *fixovername = 0; + symtab = Getattr(n, "sym:symtab"); /* Get symbol table object */ + symtab = Getattr(symtab, "symtab"); /* Get actual hash table of symbols */ + symname = Getattr(n, "sym:name"); + symprev = Getattr(n, "sym:previousSibling"); + symnext = Getattr(n, "sym:nextSibling"); + + /* If previous symbol, just fix the links */ + if (symprev) { + if (symnext) { + Setattr(symprev, "sym:nextSibling", symnext); + fixovername = symprev; /* fix as symbol to remove is somewhere in the middle of the linked list */ + } else { + Delattr(symprev, "sym:nextSibling"); + } + } else { + /* If no previous symbol, see if there is a next symbol */ + if (symnext) { + Setattr(symtab, symname, symnext); + fixovername = symnext; /* fix as symbol to remove is at head of linked list */ + } else { + if (symname) + Delattr(symtab, symname); + } + } + if (symnext) { + if (symprev) { + Setattr(symnext, "sym:previousSibling", symprev); + } else { + Delattr(symnext, "sym:previousSibling"); + } + } + Delattr(n, "sym:symtab"); + Delattr(n, "sym:previousSibling"); + Delattr(n, "sym:nextSibling"); + Delattr(n, "csym:nextSibling"); + Delattr(n, "sym:overname"); + Delattr(n, "csym:previousSibling"); + Delattr(n, "sym:overloaded"); + n = 0; + + if (fixovername) { + Node *nn = fixovername; + Node *head = fixovername; + int pn = 0; + + /* find head of linked list */ + while (nn) { + head = nn; + nn = Getattr(nn, "sym:previousSibling"); + } + + /* adjust all the sym:overname strings to start from 0 and increment by one */ + nn = head; + while (nn) { + assert(Getattr(nn, "sym:overname")); + Delattr(nn, "sym:overname"); + overname = NewStringf("__SWIG_%d", pn); + Setattr(nn, "sym:overname", overname); + Delete(overname); + pn++; + nn = Getattr(nn, "sym:nextSibling"); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_qualified() + * + * Return the qualified name of a symbol + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_qualified(Node *n) { + Hash *symtab; + if (Checkattr(n, "nodeType", "symboltable")) { + symtab = n; + } else { + symtab = Getattr(n, "sym:symtab"); + } + if (!symtab) + return NewStringEmpty(); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qscope %s %p %s\n", Getattr(n, "name"), symtab, Getattr(symtab, "name")); +#endif + return Swig_symbol_qualifiedscopename(symtab); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_isoverloaded() + * + * Check if a symbol is overloaded. Returns the first symbol if so. + * ----------------------------------------------------------------------------- */ + +Node *Swig_symbol_isoverloaded(Node *n) { + return Getattr(n, "sym:overloaded"); +} + +/* ----------------------------------------------------------------------------- + * symbol_template_qualify() + * + * Internal function to create a fully qualified type name for templates + * ----------------------------------------------------------------------------- */ + +/* This cache produces problems with OSS, don't active it */ +/* #define SWIG_TEMPLATE_QUALIFY_CACHE */ +static SwigType *symbol_template_qualify(const SwigType *e, Symtab *st) { + String *tprefix, *tsuffix; + SwigType *qprefix; + String *targs; + List *targslist; + Node *tempn; + Symtab *tscope; + Iterator ti; +#ifdef SWIG_TEMPLATE_QUALIFY_CACHE + static Hash *qualify_cache = 0; + String *scopetype = st ? NewStringf("%s::%s", Getattr(st, "name"), e) + : NewStringf("%s::%s", Swig_symbol_getscopename(), e); + if (!qualify_cache) { + qualify_cache = NewHash(); + } + if (scopetype) { + String *cres = Getattr(qualify_cache, scopetype); + if (cres) { + Delete(scopetype); + return Copy(cres); + } + } +#endif + + tprefix = SwigType_templateprefix(e); + tsuffix = SwigType_templatesuffix(e); + qprefix = Swig_symbol_type_qualify(tprefix, st); + targs = SwigType_templateargs(e); + targslist = SwigType_parmlist(targs); + tempn = Swig_symbol_clookup_local(tprefix, st); + tscope = tempn ? Getattr(tempn, "sym:symtab") : 0; + Append(qprefix, "<("); + for (ti = First(targslist); ti.item;) { + String *vparm; + /* TODO: the logic here should be synchronised with that in SwigType_typedef_qualified() */ + /* TODO: ti.item might be a non-type parameter possibly within (), eg: (std::is_integral_v<(A)>||std::is_same_v<(A,node_t)>) */ + String *qparm = Swig_symbol_type_qualify(ti.item, st); + if (tscope && (tscope != st)) { + String *ty = Swig_symbol_type_qualify(qparm, tscope); + Delete(qparm); + qparm = ty; + } + + vparm = Swig_symbol_template_param_eval(qparm, st); + Append(qprefix, vparm); + ti = Next(ti); + if (ti.item) { + Putc(',', qprefix); + } + Delete(qparm); + Delete(vparm); + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(tprefix); + Delete(tsuffix); + Delete(targs); + Delete(targslist); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_temp_qual %s %s\n", e, qprefix); +#endif +#ifdef SWIG_TEMPLATE_QUALIFY_CACHE + Setattr(qualify_cache, scopetype, qprefix); + Delete(scopetype); +#endif + + return qprefix; +} + + +static int symbol_no_constructor(Node *n) { + return !Checkattr(n, "nodeType", "constructor"); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_type_qualify() + * + * Create a fully qualified type name + * Note: Does not resolve a constructor if passed in as the 'type'. + * ----------------------------------------------------------------------------- */ + +SwigType *Swig_symbol_type_qualify(const SwigType *t, Symtab *st) { + List *elements; + String *result = NewStringEmpty(); + int i, len; + char *c = Char(t); + if (strncmp(c, "::", 2) == 0) { + Append(result, t); + return result; + } + + elements = SwigType_split(t); + + len = Len(elements); + for (i = 0; i < len; i++) { + String *e = Getitem(elements, i); + if (SwigType_issimple(e)) { + /* Note: the unary scope operator (::) is being removed from the template parameters here. */ + Node *n = Swig_symbol_clookup_check(e, st, symbol_no_constructor); + if (n) { + String *name = Getattr(n, "name"); + Clear(e); + Append(e, name); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qual_ei %d %s %s %p\n", i, name, e, st); +#endif + if (!Swig_scopename_check(name)) { + String *qname = Swig_symbol_qualified(n); + if (qname && Len(qname)) { + Insert(e, 0, "::"); + Insert(e, 0, qname); + } +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qual_sc %d %s %s %p\n", i, qname, e, st); +#endif + Delete(qname); + } + } else if (SwigType_istemplate(e)) { + SwigType *ty = symbol_template_qualify(e, st); + Clear(e); + Append(e, ty); + Delete(ty); + } + if (strncmp(Char(e), "::", 2) == 0) { + Delitem(e, 0); + Delitem(e, 0); + } + Append(result, e); + } else if (SwigType_isfunction(e)) { + List *parms = SwigType_parmlist(e); + String *s = NewString("f("); + Iterator pi = First(parms); + while (pi.item) { + String *pf = Swig_symbol_type_qualify(pi.item, st); + Append(s, pf); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + Delete(pf); + } + Append(s, ")."); + Append(result, s); + Delete(parms); + Delete(s); + } else { + Append(result, e); + } + } + Delete(elements); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_qualify %s %s %p %s\n", t, result, st, st ? Getattr(st, "name") : 0); +#endif + + return result; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_template_reduce() + * Resolves template parameter types + * For example: + * typedef int Int; + * typedef Int Integer; + * with input: + * Foo<(Int,Integer)> + * returns: + * Foo<(int,int)> + * ----------------------------------------------------------------------------- */ + +static +SwigType *Swig_symbol_template_reduce(SwigType *qt, Symtab *ntab) { + Parm *p; + String *templateargs = SwigType_templateargs(qt); + List *parms = SwigType_parmlist(templateargs); + Iterator pi = First(parms); + String *tprefix = SwigType_templateprefix(qt); + String *tsuffix = SwigType_templatesuffix(qt); + String *qprefix = SwigType_typedef_qualified(tprefix); + Append(qprefix, "<("); + while ((p = pi.item)) { + String *np; + String *tp = Swig_symbol_typedef_reduce(p, ntab); + String *qp = Swig_symbol_type_qualify(tp, ntab); + Node *n = Swig_symbol_clookup(qp, ntab); + if (n) { + String *qual = Swig_symbol_qualified(n); + np = Copy(Getattr(n, "name")); + Delete(tp); + tp = np; + if (qual && Len(qual)) { + Insert(np, 0, "::"); + Insert(np, 0, qual); + } + Delete(qual); + } else { + np = qp; + } + Append(qprefix, np); + pi = Next(pi); + if (pi.item) { + Append(qprefix, ","); + } + Delete(qp); + Delete(tp); + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(parms); + Delete(tprefix); + Delete(tsuffix); + Delete(templateargs); + return qprefix; +} + + +/* ----------------------------------------------------------------------------- + * Swig_symbol_typedef_reduce() + * + * Chase a typedef through symbol tables looking for a match. + * ----------------------------------------------------------------------------- */ + +SwigType *Swig_symbol_typedef_reduce(const SwigType *ty, Symtab *tab) { + SwigType *prefix, *base; + Node *n; + String *nt; + + base = SwigType_base(ty); + prefix = SwigType_prefix(ty); + + n = Swig_symbol_clookup(base, tab); + if (!n) { + if (SwigType_istemplate(ty)) { + SwigType *qt = Swig_symbol_template_reduce(base, tab); + Append(prefix, qt); + Delete(qt); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (a) %s %s\n", ty, prefix); +#endif + Delete(base); + return prefix; + } else { + Delete(prefix); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (b) %s %s\n", ty, ty); +#endif + return Copy(ty); + } + } + nt = Getattr(n, "nodeType"); + if (Equal(nt, "using")) { + String *uname = Getattr(n, "uname"); + if (uname) { + n = Swig_symbol_clookup(base, Getattr(n, "sym:symtab")); + if (!n) { + Delete(base); + Delete(prefix); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (c) %s %s\n", ty, ty); +#endif + return Copy(ty); + } + } + } + if (Equal(nt, "cdecl")) { + String *storage = Getattr(n, "storage"); + if (storage && (Equal(storage, "typedef"))) { + SwigType *decl; + SwigType *rt; + SwigType *qt; + Symtab *ntab; + SwigType *nt = Copy(Getattr(n, "type")); + + /* Fix for case 'typedef struct Hello hello;' */ + { + const char *dclass[3] = { "struct ", "union ", "class " }; + int i; + char *c = Char(nt); + for (i = 0; i < 3; i++) { + if (strstr(c, dclass[i]) == c) { + Replace(nt, dclass[i], "", DOH_REPLACE_FIRST); + } + } + } + decl = Getattr(n, "decl"); + if (decl) { + SwigType_push(nt, decl); + } + SwigType_push(nt, prefix); + Delete(base); + Delete(prefix); + ntab = Getattr(n, "sym:symtab"); + rt = Swig_symbol_typedef_reduce(nt, ntab); + qt = Swig_symbol_type_qualify(rt, ntab); + if (SwigType_istemplate(qt)) { + SwigType *qtr = Swig_symbol_template_reduce(qt, ntab); + Delete(qt); + qt = qtr; + } + Delete(nt); + Delete(rt); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (d) %s %s\n", qt, ty); +#endif + return qt; + } + } + Delete(base); + Delete(prefix); +#ifdef SWIG_DEBUG + Printf(stderr, "symbol_reduce (e) %s %s\n", ty, ty); +#endif + return Copy(ty); +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_string_qualify() + * + * This function takes a string and looks for identifiers. Identifiers are + * then qualified according to scope rules. This function is used in a number + * of settings including expression evaluation, scoping of conversion operators, + * and so forth. + * ----------------------------------------------------------------------------- */ + +String *Swig_symbol_string_qualify(String *s, Symtab *st) { + int have_id = 0; + String *id = NewStringEmpty(); + String *r = NewStringEmpty(); + char *c = Char(s); + int first_char = 1; + while (*c) { + if (isalpha((int) *c) || (*c == '_') || (*c == ':') || (*c == '~' && first_char) || (isdigit((int) *c) && !first_char)) { + Putc(*c, id); + have_id = 1; + } else { + if (have_id) { + String *qid = Swig_symbol_type_qualify(id, st); + Append(r, qid); + Clear(id); + Delete(qid); + have_id = 0; + } + Putc(*c, r); + } + first_char = (*c == ':'); + c++; + } + if (have_id) { + String *qid = Swig_symbol_type_qualify(id, st); + Append(r, qid); + Delete(qid); + } + Delete(id); + return r; +} + + +/* ----------------------------------------------------------------------------- + * Swig_symbol_template_defargs() + * + * Apply default arg from generic template default args + * Returns a parameter list which contains missing default arguments (if any) + * Note side effects: parms will also contain the extra parameters in its list + * (but only if non-zero). + * ----------------------------------------------------------------------------- */ + + +ParmList *Swig_symbol_template_defargs(Parm *parms, Parm *targs, Symtab *tscope, Symtab *tsdecl) { + ParmList *expandedparms = parms; + if (Len(parms) < Len(targs)) { + Parm *lp = parms; + Parm *p = lp; + Parm *tp = targs; + while (p && tp) { + p = nextSibling(p); + tp = nextSibling(tp); + if (p) + lp = p; + } + while (tp) { + String *value = Getattr(tp, "value"); + if (value) { + Parm *cp; + Parm *ta = targs; + Parm *p = parms; + SwigType *nt = Swig_symbol_string_qualify(value, tsdecl); + SwigType *ntq = 0; +#ifdef SWIG_DEBUG + Printf(stderr, "value %s %s %s\n", value, nt, tsdecl ? Getattr(tsdecl, "name") : tsdecl); +#endif + while (p && ta) { + String *name = Getattr(ta, "name"); + String *pvalue = Getattr(p, "value"); + String *value = pvalue ? pvalue : Getattr(p, "type"); + String *ttq = Swig_symbol_type_qualify(value, tscope); + /* value = SwigType_typedef_resolve_all(value); */ + Replaceid(nt, name, ttq); + p = nextSibling(p); + ta = nextSibling(ta); + Delete(ttq); + } + ntq = Swig_symbol_type_qualify(nt, tsdecl); + if (SwigType_istemplate(ntq)) { + String *ty = Swig_symbol_template_deftype(ntq, tscope); + Delete(ntq); + ntq = ty; + } + cp = NewParmWithoutFileLineInfo(ntq, 0); + if (lp) { + set_nextSibling(lp, cp); + Delete(cp); + } else { + expandedparms = cp; + } + lp = cp; + tp = nextSibling(tp); + Delete(nt); + Delete(ntq); + } else { + tp = 0; + } + } + } + return expandedparms; +} + +/* ----------------------------------------------------------------------------- + * Swig_symbol_template_deftype() + * + * Apply default args to generic template type + * ----------------------------------------------------------------------------- */ + +#define SWIG_TEMPLATE_DEFTYPE_CACHE +SwigType *Swig_symbol_template_deftype(const SwigType *type, Symtab *tscope) { + String *result = NewStringEmpty(); + List *elements = SwigType_split(type); + int len = Len(elements); + int i; +#ifdef SWIG_TEMPLATE_DEFTYPE_CACHE + static Hash *s_cache = 0; + Hash *scope_cache; + /* The lookup depends on the current scope and potential namespace qualification. + Looking up x in namespace y is not the same as looking up x::y in outer scope. + -> we use a 2-level hash: first scope and then symbol. */ + String *scope_name = tscope + ? Swig_symbol_qualifiedscopename(tscope) + : Swig_symbol_qualifiedscopename(current_symtab); + String *type_name = tscope + ? NewStringf("%s::%s", Getattr(tscope, "name"), type) + : NewStringf("%s::%s", Swig_symbol_getscopename(), type); + if (!scope_name) scope_name = NewString("::"); + if (!s_cache) { + s_cache = NewHash(); + } + scope_cache = Getattr(s_cache, scope_name); + if (scope_cache) { + String *cres = Getattr(scope_cache, type_name); + if (cres) { + Append(result, cres); +#ifdef SWIG_DEBUG + Printf(stderr, "cached deftype %s(%s) -> %s\n", type, scope_name, result); +#endif + Delete(type_name); + Delete(scope_name); + return result; + } + } else { + scope_cache = NewHash(); + Setattr(s_cache, scope_name, scope_cache); + Delete(scope_name); + } +#endif + +#ifdef SWIG_DEBUG + Printf(stderr, "finding deftype %s\n", type); +#endif + + for (i = 0; i < len; i++) { + String *e = Getitem(elements, i); + if (SwigType_isfunction(e)) { + String *s = NewString("f("); + List *parms = SwigType_parmlist(e); + Iterator pi = First(parms); + while (pi.item) { + String *pf = SwigType_istemplate(e) ? Swig_symbol_template_deftype(pi.item, tscope) + : Swig_symbol_type_qualify(pi.item, tscope); + Append(s, pf); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + Delete(pf); + } + Append(s, ")."); + Append(result, s); + Delete(s); + Delete(parms); + } else if (SwigType_istemplate(e)) { + String *prefix = SwigType_prefix(e); + String *base = SwigType_base(e); + String *tprefix = SwigType_templateprefix(base); + String *targs = SwigType_templateargs(base); + String *tsuffix = SwigType_templatesuffix(base); + ParmList *tparms = SwigType_function_parms(targs, 0); + Node *tempn = Swig_symbol_clookup_local(tprefix, tscope); + if (!tempn && tsuffix && Len(tsuffix)) { + tempn = Swig_symbol_clookup(tprefix, 0); + } +#ifdef SWIG_DEBUG + Printf(stderr, "deftype type %s %s %d\n", e, tprefix, (long) tempn); +#endif + if (tempn) { + ParmList *tnargs = Getattr(tempn, "templateparms"); + ParmList *expandedparms; + Parm *p; + Symtab *tsdecl = Getattr(tempn, "sym:symtab"); + +#ifdef SWIG_DEBUG + Printf(stderr, "deftype type %s %s %s\n", tprefix, targs, tsuffix); +#endif + Append(tprefix, "<("); + expandedparms = Swig_symbol_template_defargs(tparms, tnargs, tscope, tsdecl); + p = expandedparms; + tscope = tsdecl; + while (p) { + SwigType *ptype = Getattr(p, "type"); + SwigType *ttr = ptype ? ptype : Getattr(p, "value"); + SwigType *ttf = Swig_symbol_type_qualify(ttr, tscope); + SwigType *ttq = Swig_symbol_template_param_eval(ttf, tscope); +#ifdef SWIG_DEBUG + Printf(stderr, "arg type %s\n", ttq); +#endif + if (SwigType_istemplate(ttq)) { + SwigType *ttd = Swig_symbol_template_deftype(ttq, tscope); + Delete(ttq); + ttq = ttd; +#ifdef SWIG_DEBUG + Printf(stderr, "arg deftype %s\n", ttq); +#endif + } + Append(tprefix, ttq); + p = nextSibling(p); + if (p) + Putc(',', tprefix); + Delete(ttf); + Delete(ttq); + } + Append(tprefix, ")>"); + Append(tprefix, tsuffix); + Append(prefix, tprefix); +#ifdef SWIG_DEBUG + Printf(stderr, "deftype %s %s \n", type, tprefix); +#endif + Append(result, prefix); + } else { + Append(result, e); + } + Delete(prefix); + Delete(base); + Delete(tprefix); + Delete(tsuffix); + Delete(targs); + Delete(tparms); + } else { + Append(result, e); + } + } + Delete(elements); +#ifdef SWIG_TEMPLATE_DEFTYPE_CACHE + Setattr(scope_cache, type_name, result); + Delete(type_name); +#endif + + return result; +} + +SwigType *Swig_symbol_template_param_eval(const SwigType *p, Symtab *symtab) { + String *value = Copy(p); + Node *lastnode = 0; + while (1) { + Node *n = Swig_symbol_clookup(value, symtab); + if (n == lastnode) + break; + lastnode = n; + if (n) { + String *nt = Getattr(n, "nodeType"); + if (Equal(nt, "enumitem")) { + /* An enum item. Generate a fully qualified name */ + String *qn = Swig_symbol_qualified(n); + if (qn && Len(qn)) { + Append(qn, "::"); + Append(qn, Getattr(n, "name")); + Delete(value); + value = qn; + continue; + } else { + Delete(qn); + break; + } + } else if ((Equal(nt, "cdecl"))) { + String *nv = Getattr(n, "value"); + if (nv) { + Delete(value); + value = Copy(nv); + continue; + } + } + } + break; + } + return value; +} diff --git a/contrib/tools/swig/Source/Swig/tree.c b/contrib/tools/swig/Source/Swig/tree.c new file mode 100644 index 0000000000..438e8b73dc --- /dev/null +++ b/contrib/tools/swig/Source/Swig/tree.c @@ -0,0 +1,426 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * tree.c + * + * This file provides some general purpose functions for manipulating + * parse trees. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include <stdarg.h> +#include <assert.h> + +static int debug_quiet = 0; + +/* ----------------------------------------------------------------------------- + * Swig_print_quiet() + * + * Set quiet mode when printing a parse tree node + * ----------------------------------------------------------------------------- */ + +int Swig_print_quiet(int quiet) { + int previous_quiet = debug_quiet; + debug_quiet = quiet; + return previous_quiet; +} + +/* ----------------------------------------------------------------------------- + * Swig_print_tags() + * + * Dump the tag structure of a parse tree to standard output + * ----------------------------------------------------------------------------- */ + +void Swig_print_tags(DOH *obj, DOH *root) { + DOH *croot, *newroot; + DOH *cobj; + + if (!root) + croot = NewStringEmpty(); + else + croot = root; + + while (obj) { + Swig_diagnostic(Getfile(obj), Getline(obj), "%s . %s\n", croot, nodeType(obj)); + cobj = firstChild(obj); + if (cobj) { + newroot = NewStringf("%s . %s", croot, nodeType(obj)); + Swig_print_tags(cobj, newroot); + Delete(newroot); + } + obj = nextSibling(obj); + } + if (!root) + Delete(croot); +} + +static int indent_level = 0; + +static void print_indent(int l) { + int i; + for (i = 0; i < indent_level; i++) { + fputc(' ', stdout); + } + if (l) { + fputc('|', stdout); + fputc(' ', stdout); + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_print_node(Node *n) + * ----------------------------------------------------------------------------- */ + +void Swig_print_node(Node *obj) { + Iterator ki; + Node *cobj; + List *keys = Keys(obj); + + print_indent(0); + if (debug_quiet) + Printf(stdout, "+++ %s ----------------------------------------\n", nodeType(obj)); + else + Printf(stdout, "+++ %s - %p ----------------------------------------\n", nodeType(obj), obj); + + SortList(keys, 0); + ki = First(keys); + while (ki.item) { + String *k = ki.item; + DOH *value = Getattr(obj, k); + if (Equal(k, "nodeType") || (*(Char(k)) == '$')) { + /* Do nothing */ + } else if (debug_quiet && (Equal(k, "firstChild") || Equal(k, "lastChild") || Equal(k, "parentNode") || Equal(k, "nextSibling") || + Equal(k, "previousSibling") || Equal(k, "symtab") || Equal(k, "csymtab") || Equal(k, "sym:symtab") || Equal(k, "sym:nextSibling") || + Equal(k, "sym:previousSibling") || Equal(k, "csym:nextSibling") || Equal(k, "csym:previousSibling"))) { + /* Do nothing */ + } else if (Equal(k, "kwargs") || Equal(k, "parms") || Equal(k, "wrap:parms") || Equal(k, "pattern") || Equal(k, "templateparms") || Equal(k, "throws")) { + print_indent(2); + /* Differentiate parameter lists by displaying within single quotes */ + Printf(stdout, "%-12s - \'%s\'\n", k, ParmList_str_defaultargs(value)); + } else { + DOH *o; + const char *trunc = ""; + print_indent(2); + if (DohIsString(value)) { + o = Str(value); + if (Len(o) > 80) { + trunc = "..."; + } + Printf(stdout, "%-12s - \"%(escape)-0.80s%s\"\n", k, o, trunc); + Delete(o); + } else { + Printf(stdout, "%-12s - %p\n", k, value); + } + } + ki = Next(ki); + } + cobj = firstChild(obj); + if (cobj) { + indent_level += 6; + Printf(stdout, "\n"); + Swig_print_tree(cobj); + indent_level -= 6; + } else { + print_indent(1); + Printf(stdout, "\n"); + } + Delete(keys); +} + +/* ----------------------------------------------------------------------------- + * Swig_print_tree() + * + * Dump the tree structure of a parse tree to standard output + * ----------------------------------------------------------------------------- */ + +void Swig_print_tree(DOH *obj) { + while (obj) { + Swig_print_node(obj); + obj = nextSibling(obj); + } +} + +/* ----------------------------------------------------------------------------- + * appendChild() + * + * Appends a new child to a node + * ----------------------------------------------------------------------------- */ + +void appendChild(Node *node, Node *chd) { + Node *lc; + + if (!chd) + return; + + lc = lastChild(node); + if (!lc) { + set_firstChild(node, chd); + } else { + set_nextSibling(lc, chd); + set_previousSibling(chd, lc); + } + while (chd) { + lc = chd; + set_parentNode(chd, node); + chd = nextSibling(chd); + } + set_lastChild(node, lc); +} + +/* ----------------------------------------------------------------------------- + * prependChild() + * + * Prepends a new child to a node + * ----------------------------------------------------------------------------- */ + +void prependChild(Node *node, Node *chd) { + Node *fc; + + if (!chd) + return; + + fc = firstChild(node); + if (fc) { + set_nextSibling(chd, fc); + set_previousSibling(fc, chd); + } + set_firstChild(node, chd); + while (chd) { + set_parentNode(chd, node); + chd = nextSibling(chd); + } +} + +void appendSibling(Node *node, Node *chd) { + Node *parent; + Node *lc = node; + while (nextSibling(lc)) + lc = nextSibling(lc); + set_nextSibling(lc, chd); + set_previousSibling(chd, lc); + parent = parentNode(node); + if (parent) { + while (chd) { + lc = chd; + set_parentNode(chd, parent); + chd = nextSibling(chd); + } + set_lastChild(parent, lc); + } +} + +/* ----------------------------------------------------------------------------- + * removeNode() + * + * Removes a node from the parse tree. Detaches it from its parent's child list. + * ----------------------------------------------------------------------------- */ + +void removeNode(Node *n) { + Node *parent; + Node *prev; + Node *next; + + parent = parentNode(n); + if (!parent) return; + + prev = previousSibling(n); + next = nextSibling(n); + if (prev) { + set_nextSibling(prev, next); + } else { + if (parent) { + set_firstChild(parent, next); + } + } + if (next) { + set_previousSibling(next, prev); + } else { + if (parent) { + set_lastChild(parent, prev); + } + } + + /* Delete attributes */ + Delattr(n,"parentNode"); + Delattr(n,"nextSibling"); + Delattr(n,"previousSibling"); +} + +/* ----------------------------------------------------------------------------- + * copyNode() + * + * Copies a node, but only copies simple attributes (no lists, hashes). + * ----------------------------------------------------------------------------- */ + +Node *copyNode(Node *n) { + Iterator ki; + Node *c = NewHash(); + for (ki = First(n); ki.key; ki = Next(ki)) { + if (DohIsString(ki.item)) { + Setattr(c, ki.key, Copy(ki.item)); + } + } + Setfile(c, Getfile(n)); + Setline(c, Getline(n)); + return c; +} + +/* ----------------------------------------------------------------------------- + * checkAttribute() + * ----------------------------------------------------------------------------- */ + +int checkAttribute(Node *n, const_String_or_char_ptr name, const_String_or_char_ptr value) { + String *v = Getattr(n, name); + return v ? Equal(v, value) : 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_require() + * ns - namespace for the view name for saving any attributes under + * n - node + * ... - list of attribute names of type char* + * + * An attribute is optional if it is prefixed by ?, eg "?value". All + * non-optional attributes are checked for on node n and if any do not exist + * SWIG exits with a fatal error. + * + * If the attribute name is prefixed by * or ?, eg "*value" then a copy of the + * attribute is saved. The saved attributes will be restored on a subsequent + * call to Swig_restore(). All the saved attributes are saved in the view + * namespace (prefixed by ns). + * + * This function can be called more than once with different namespaces. + * ----------------------------------------------------------------------------- */ + +void Swig_require(const char *ns, Node *n, ...) { + va_list ap; + char *name; + DOH *obj; + + va_start(ap, n); + name = va_arg(ap, char *); + while (name) { + int newref = 0; + int opt = 0; + if (*name == '*') { + newref = 1; + name++; + } else if (*name == '?') { + newref = 1; + opt = 1; + name++; + } + obj = Getattr(n, name); + if (!opt && !obj) { + Swig_error(Getfile(n), Getline(n), "Fatal error (Swig_require). Missing attribute '%s' in node '%s'.\n", name, nodeType(n)); + Exit(EXIT_FAILURE); + } + if (!obj) + obj = DohNone; + if (newref) { + /* Save a copy of the attribute */ + Setattr(n, NewStringf("%s:%s", ns, name), obj); + } + name = va_arg(ap, char *); + } + va_end(ap); + + /* Save the view */ + { + String *view = Getattr(n, "view"); + if (view) { + if (Strcmp(view, ns) != 0) { + Setattr(n, NewStringf("%s:view", ns), view); + Setattr(n, "view", NewString(ns)); + } + } else { + Setattr(n, "view", NewString(ns)); + } + } +} + + +/* ----------------------------------------------------------------------------- + * Swig_save() + * Same as Swig_require(), but all attribute names are optional and all attributes + * are saved, ie behaves as if all the attribute names were prefixed by ?. + * ----------------------------------------------------------------------------- */ + +void Swig_save(const char *ns, Node *n, ...) { + va_list ap; + char *name; + DOH *obj; + + va_start(ap, n); + name = va_arg(ap, char *); + while (name) { + if (*name == '*') { + name++; + } else if (*name == '?') { + name++; + } + obj = Getattr(n, name); + if (!obj) + obj = DohNone; + + /* Save a copy of the attribute */ + if (Setattr(n, NewStringf("%s:%s", ns, name), obj)) { + Printf(stderr, "Swig_save('%s','%s'): Warning, attribute '%s' was already saved.\n", ns, nodeType(n), name); + } + name = va_arg(ap, char *); + } + va_end(ap); + + /* Save the view */ + { + String *view = Getattr(n, "view"); + if (view) { + if (Strcmp(view, ns) != 0) { + Setattr(n, NewStringf("%s:view", ns), view); + Setattr(n, "view", NewString(ns)); + } + } else { + Setattr(n, "view", NewString(ns)); + } + } +} + +/* ----------------------------------------------------------------------------- + * Swig_restore() + * Restores attributes saved by a previous call to Swig_require() or Swig_save(). + * ----------------------------------------------------------------------------- */ + +void Swig_restore(Node *n) { + String *temp; + int len; + List *l; + String *ns; + Iterator ki; + + ns = Getattr(n, "view"); + assert(ns); + + l = NewList(); + + temp = NewStringf("%s:", ns); + len = Len(temp); + + for (ki = First(n); ki.key; ki = Next(ki)) { + if (Strncmp(temp, ki.key, len) == 0) { + Append(l, ki.key); + } + } + for (ki = First(l); ki.item; ki = Next(ki)) { + DOH *obj = Getattr(n, ki.item); + Setattr(n, Char(ki.item) + len, obj); + Delattr(n, ki.item); + } + Delete(l); + Delete(temp); +} diff --git a/contrib/tools/swig/Source/Swig/typemap.c b/contrib/tools/swig/Source/Swig/typemap.c new file mode 100644 index 0000000000..f0dee59d9e --- /dev/null +++ b/contrib/tools/swig/Source/Swig/typemap.c @@ -0,0 +1,2210 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * typemap.c + * + * A somewhat generalized implementation of SWIG1.1 typemaps. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" +#include <ctype.h> + +#if 0 +#define SWIG_DEBUG +#endif + +static int typemap_search_debug = 0; +static int typemaps_used_debug = 0; +static int typemap_register_debug = 0; +static int in_typemap_search_multi = 0; + +static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f, Node *file_line_node); + +/* ----------------------------------------------------------------------------- + * Typemaps are stored in a collection of nested hash tables. Something like + * this: + * + * [ type ] + * +-------- [ name ] + * +-------- [ name ] + * + * Each hash table [ type ] or [ name ] then contains references to the + * different typemap methods. These are referenced by names such as + * "tmap:in", "tmap:out", "tmap:argout", and so forth. + * + * The object corresponding to a specific typemap method has the following attributes: + * + * "type" - Typemap type + * "pname" - Parameter name + * "code" - Typemap code + * "source" - Source directive (%apply or %typemap) for the typemap + * "locals" - Local variables (if any) + * "kwargs" - Typemap attributes + * + * Example for a typemap method named "in": + * %typemap(in, warning="987:my warning", noblock=1) int &my_int (int tmp) "$1 = $input;" + * + * "type" - r.int + * "pname" - my_int + * "code" - $1 = $input; + * "source" - typemap(in) int &my_int + * "locals" - int tmp + * "kwargs" - warning="987:my typemap warning", foo=123 + * + * ----------------------------------------------------------------------------- */ + +static Hash *typemaps; + +/* ----------------------------------------------------------------------------- + * typemap_identifier_fix() + * + * Create a type that can be used as a hash key lookup independent of the various + * ways a template parameter list can be defined. This is achieved by fully + * resolving the template parameters. + * + * This is a copy and modification of feature_identifier_fix in parser.y. + * ----------------------------------------------------------------------------- */ + +static SwigType *typemap_identifier_fix(const SwigType *s) { + String *tp = SwigType_istemplate_templateprefix(s); + if (tp) { + String *ts, *ta, *tq, *tr; + ts = SwigType_templatesuffix(s); + ta = SwigType_templateargs(s); + tq = Swig_symbol_type_qualify(ta, 0); + tr = SwigType_typedef_resolve_all(ta); + Append(tp,tr); + Append(tp,ts); + Delete(ts); + Delete(ta); + Delete(tq); + Delete(tr); + return tp; + } else { + return NewString(s); + } +} + +static Hash *get_typemap(const SwigType *type) { + Hash *tm = 0; + SwigType *dtype = 0; + SwigType *hashtype; + + if (SwigType_istemplate(type)) { + SwigType *rty = typemap_identifier_fix(type); + String *ty = Swig_symbol_template_deftype(rty, 0); + dtype = Swig_symbol_type_qualify(ty, 0); + type = dtype; + Delete(ty); + } + + /* remove unary scope operator (::) prefix indicating global scope for looking up in the hashmap */ + hashtype = SwigType_remove_global_scope_prefix(type); + tm = Getattr(typemaps, hashtype); + + Delete(dtype); + Delete(hashtype); + + return tm; +} + +static void set_typemap(const SwigType *type, Hash **tmhash) { + SwigType *hashtype = 0; + Hash *new_tm = 0; + assert(*tmhash == 0); + if (SwigType_istemplate(type)) { + SwigType *rty = typemap_identifier_fix(type); + String *ty = Swig_symbol_template_deftype(rty, 0); + String *tyq = Swig_symbol_type_qualify(ty, 0); + hashtype = SwigType_remove_global_scope_prefix(tyq); + *tmhash = Getattr(typemaps, hashtype); + Delete(rty); + Delete(tyq); + Delete(ty); + } else { + hashtype = SwigType_remove_global_scope_prefix(type); + } + + if (!*tmhash) { + /* this type has not been seen before even after resolving template parameter types */ + new_tm = NewHash(); + *tmhash = new_tm; + } + + /* note that the unary scope operator (::) prefix indicating global scope has been removed from the type */ + Setattr(typemaps, hashtype, *tmhash); + + Delete(hashtype); + Delete(new_tm); +} + + +/* ----------------------------------------------------------------------------- + * Swig_typemap_init() + * + * Initialize the typemap system + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_init(void) { + typemaps = NewHash(); +} + +static String *typemap_method_name(const_String_or_char_ptr tmap_method) { + static Hash *names = 0; + String *s; + /* Due to "interesting" object-identity semantics of DOH, + we have to make sure that we only intern strings without object + identity into the hash table. + + (typemap_attach_kwargs calls typemap_method_name several times with + the "same" String *tmap_method (i.e., same object identity) but differing + string values.) + + Most other callers work around this by using char* rather than + String *. + -- mkoeppe, Jun 17, 2003 + */ + const char *method_without_object_identity = Char(tmap_method); + if (!names) + names = NewHash(); + s = Getattr(names, method_without_object_identity); + if (s) + return s; + s = NewStringf("tmap:%s", tmap_method); + Setattr(names, method_without_object_identity, s); + Delete(s); + return s; +} + +/* ----------------------------------------------------------------------------- + * typemap_register() + * + * Internal implementation for Swig_typemap_register() + * ----------------------------------------------------------------------------- */ + +static void typemap_register(const_String_or_char_ptr tmap_method, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs, String *source_directive) { + Hash *tm; + Hash *tm1; + Hash *tm2; + Parm *np; + String *tm_method; + SwigType *type; + String *pname; + if (!parms) + return; + + if (typemap_register_debug) { + Printf(stdout, "Registering - %s\n", tmap_method); + Swig_print_node(parms); + } + + tm_method = typemap_method_name(tmap_method); + + /* Register the first type in the parameter list */ + + type = Getattr(parms, "type"); + pname = Getattr(parms, "name"); + + /* See if this type has been seen before */ + tm = get_typemap(type); + if (!tm) { + set_typemap(type, &tm); + } + if (pname) { + /* See if parameter has been seen before */ + tm1 = Getattr(tm, pname); + if (!tm1) { + tm1 = NewHash(); + Setattr(tm, pname, tm1); + Delete(tm1); + } + tm = tm1; + } + + /* Now see if this typemap method has been seen before */ + tm2 = Getattr(tm, tm_method); + if (!tm2) { + tm2 = NewHash(); + Setattr(tm, tm_method, tm2); + Delete(tm2); + } + + /* For a multi-argument typemap, the typemap code and information + is really only stored in the last argument. However, to + make this work, we perform a really neat trick using + the typemap method name. + + For example, consider this typemap + + %typemap(in) (int foo, int *bar, char *blah[]) { + ... + } + + To store it, we look at typemaps for the following: + + typemap method type-name + ---------------------------------------------- + "in" int foo + "in-int+foo:" int *bar + "in-int+foo:-p.int+bar: char *blah[] + + Notice how the typemap method name expands to encode information about + previous arguments. + + */ + + np = nextSibling(parms); + if (np) { + /* Make an entirely new typemap method key */ + String *multi_tmap_method = NewStringf("%s-%s+%s:", tmap_method, type, pname); + + /* Now reregister on the remaining arguments */ + typemap_register(multi_tmap_method, np, code, locals, kwargs, source_directive); + + Delete(multi_tmap_method); + } else { + ParmList *clocals = CopyParmList(locals); + ParmList *ckwargs = CopyParmList(kwargs); + + Setfile(tm2, Getfile(code)); + Setline(tm2, Getline(code)); + Setattr(tm2, "code", code); + Setattr(tm2, "type", type); + Setattr(tm2, "source", source_directive); + if (pname) { + Setattr(tm2, "pname", pname); + } + Setattr(tm2, "locals", clocals); + Setattr(tm2, "kwargs", ckwargs); + + Delete(clocals); + Delete(ckwargs); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_register() + * + * Add a new, possibly multi-argument, typemap + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_register(const_String_or_char_ptr tmap_method, ParmList *parms, const_String_or_char_ptr code, ParmList *locals, ParmList *kwargs) { + String *parms_str = ParmList_str_multibrackets(parms); + String *source_directive = NewStringf("typemap(%s) %s", tmap_method, parms_str); + + typemap_register(tmap_method, parms, code, locals, kwargs, source_directive); + + Delete(source_directive); + Delete(parms_str); +} + +/* ----------------------------------------------------------------------------- + * typemap_get() + * + * Retrieve typemap information. + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_get(SwigType *type, const_String_or_char_ptr name) { + Hash *tm, *tm1; + tm = get_typemap(type); + if (!tm) { + return 0; + } + if ((name) && Len(name)) { + tm1 = Getattr(tm, name); + return tm1; + } + return tm; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_copy() + * + * Copy a typemap + * ----------------------------------------------------------------------------- */ + +int Swig_typemap_copy(const_String_or_char_ptr tmap_method, ParmList *srcparms, ParmList *parms) { + Hash *tm = 0; + String *tm_method; + Parm *p; + String *pname; + SwigType *ptype; + String *tm_methods, *multi_tmap_method; + if (ParmList_len(parms) != ParmList_len(srcparms)) + return -1; + + tm_method = typemap_method_name(tmap_method); + p = srcparms; + tm_methods = NewString(tm_method); + while (p) { + ptype = Getattr(p, "type"); + pname = Getattr(p, "name"); + + /* Lookup the type */ + tm = typemap_get(ptype, pname); + if (!tm) + break; + + tm = Getattr(tm, tm_methods); + if (!tm) + break; + + /* Got a match. Look for next typemap */ + multi_tmap_method = NewStringf("%s-%s+%s:", tm_methods, ptype, pname); + Delete(tm_methods); + tm_methods = multi_tmap_method; + p = nextSibling(p); + } + Delete(tm_methods); + + if (!p && tm) { + /* Got some kind of match */ + String *parms_str = ParmList_str_multibrackets(parms); + String *srcparms_str = ParmList_str_multibrackets(srcparms); + String *source_directive = NewStringf("typemap(%s) %s = %s", tmap_method, parms_str, srcparms_str); + + typemap_register(tmap_method, parms, Getattr(tm, "code"), Getattr(tm, "locals"), Getattr(tm, "kwargs"), source_directive); + + Delete(source_directive); + Delete(srcparms_str); + Delete(parms_str); + return 0; + } + + /* Not found */ + return -1; + +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_clear() + * + * Delete a multi-argument typemap + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_clear(const_String_or_char_ptr tmap_method, ParmList *parms) { + SwigType *type; + String *name; + Parm *p; + String *multi_tmap_method; + Hash *tm = 0; + + /* This might not work */ + multi_tmap_method = NewString(tmap_method); + p = parms; + while (p) { + type = Getattr(p, "type"); + name = Getattr(p, "name"); + tm = typemap_get(type, name); + if (!tm) + return; + p = nextSibling(p); + if (p) + Printf(multi_tmap_method, "-%s+%s:", type, name); + } + if (tm) { + tm = Getattr(tm, typemap_method_name(multi_tmap_method)); + if (tm) { + Delattr(tm, "code"); + Delattr(tm, "locals"); + Delattr(tm, "kwargs"); + } + } + Delete(multi_tmap_method); +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_apply() + * + * Multi-argument %apply directive. This is pretty horrible so I sure hope + * it works. + * ----------------------------------------------------------------------------- */ + +static int count_args(String *s) { + /* Count up number of arguments */ + int na = 0; + char *c = Char(s); + while (*c) { + if (*c == '+') + na++; + c++; + } + return na; +} + +int Swig_typemap_apply(ParmList *src, ParmList *dest) { + String *ssig, *dsig; + Parm *p, *np, *lastp, *dp, *lastdp = 0; + int narg = 0; + SwigType *type = 0, *name; + Hash *tm, *sm; + int match = 0; + + /* Printf(stdout,"apply : %s --> %s\n", ParmList_str(src), ParmList_str(dest)); */ + + /* Create type signature of source */ + ssig = NewStringEmpty(); + dsig = NewStringEmpty(); + p = src; + dp = dest; + lastp = 0; + while (p) { + lastp = p; + lastdp = dp; + np = nextSibling(p); + if (np) { + Printf(ssig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name")); + Printf(dsig, "-%s+%s:", Getattr(dp, "type"), Getattr(dp, "name")); + narg++; + } + p = np; + dp = nextSibling(dp); + } + + /* make sure a typemap node exists for the last destination node */ + type = Getattr(lastdp, "type"); + tm = get_typemap(type); + if (!tm) { + set_typemap(type, &tm); + } + name = Getattr(lastdp, "name"); + if (name) { + Hash *tm1 = Getattr(tm, name); + if (!tm1) { + tm1 = NewHash(); + Setattr(tm, NewString(name), tm1); + Delete(tm1); + } + tm = tm1; + } + + /* This is a little nasty. We need to go searching for all possible typemaps in the + source and apply them to the target */ + + type = Getattr(lastp, "type"); + name = Getattr(lastp, "name"); + + /* See if there is a matching typemap in this scope */ + sm = typemap_get(type, name); + + /* if there is not matching, look for a typemap in the + original typedef, if any, like in: + + typedef unsigned long size_t; + ... + %apply(size_t) {my_size}; ==> %apply(unsigned long) {my_size}; + */ + if (!sm) { + SwigType *ntype = SwigType_typedef_resolve(type); + if (ntype && (Cmp(ntype, type) != 0)) { + sm = typemap_get(ntype, name); + } + Delete(ntype); + } + + if (sm) { + /* Got a typemap. Need to only merge attributes for methods that match our signature */ + Iterator ki; + Hash *deferred_add; + match = 1; + + /* Since typemap_register can modify the `sm` hash, we *cannot* call typemap_register while iterating over sm. + * Create a temporary hash of typemaps to add immediately after. */ + deferred_add = NewHash(); + for (ki = First(sm); ki.key; ki = Next(ki)) { + /* Check for a signature match with the source signature */ + if ((count_args(ki.key) == narg) && (Strstr(ki.key, ssig))) { + String *oldm; + /* A typemap we have to copy */ + String *nkey = Copy(ki.key); + Replace(nkey, ssig, dsig, DOH_REPLACE_ANY); + + /* Make sure the typemap doesn't already exist in the target map */ + oldm = Getattr(tm, nkey); + if (!oldm || (!Getattr(tm, "code"))) { + String *code; + Hash *sm1 = ki.item; + + code = Getattr(sm1, "code"); + if (code) { + Replace(nkey, dsig, "", DOH_REPLACE_ANY); + Replace(nkey, "tmap:", "", DOH_REPLACE_ANY); + Setattr(deferred_add, nkey, sm1); + } + } + Delete(nkey); + } + } + + /* After assembling the key/item pairs, add the resulting typemaps */ + for (ki = First(deferred_add); ki.key; ki = Next(ki)) { + Hash *sm1 = ki.item; + String *src_str = ParmList_str_multibrackets(src); + String *dest_str = ParmList_str_multibrackets(dest); + String *source_directive = NewStringf("apply %s { %s }", src_str, dest_str); + + typemap_register(ki.key, dest, Getattr(sm1, "code"), Getattr(sm1, "locals"), Getattr(sm1, "kwargs"), source_directive); + + Delete(source_directive); + Delete(dest_str); + Delete(src_str); + } + Delete(deferred_add); + } + Delete(ssig); + Delete(dsig); + return match; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_clear_apply() + * + * %clear directive. Clears all typemaps for a type (in the current scope only). + * ----------------------------------------------------------------------------- */ + +/* Multi-argument %clear directive */ +void Swig_typemap_clear_apply(Parm *parms) { + String *tsig; + Parm *p, *np, *lastp; + int narg = 0; + Hash *tm; + String *name; + + /* Create a type signature of the parameters */ + tsig = NewStringEmpty(); + p = parms; + lastp = 0; + while (p) { + lastp = p; + np = nextSibling(p); + if (np) { + Printf(tsig, "-%s+%s:", Getattr(p, "type"), Getattr(p, "name")); + narg++; + } + p = np; + } + tm = get_typemap(Getattr(lastp, "type")); + if (!tm) { + Delete(tsig); + return; + } + name = Getattr(lastp, "name"); + if (name) { + tm = Getattr(tm, name); + } + if (tm) { + /* Clear typemaps that match our signature */ + Iterator ki, ki2; + char *ctsig = Char(tsig); + for (ki = First(tm); ki.key; ki = Next(ki)) { + char *ckey = Char(ki.key); + if (strncmp(ckey, "tmap:", 5) == 0) { + int na = count_args(ki.key); + if ((na == narg) && strstr(ckey, ctsig)) { + Hash *h = ki.item; + for (ki2 = First(h); ki2.key; ki2 = Next(ki2)) { + Delattr(h, ki2.key); + } + } + } + } + } + Delete(tsig); +} + +/* Internal function to strip array dimensions. */ +static SwigType *strip_arrays(SwigType *type) { + SwigType *t; + int ndim; + int i; + t = Copy(type); + ndim = SwigType_array_ndim(t); + for (i = 0; i < ndim; i++) { + SwigType_array_setdim(t, i, "ANY"); + } + return t; +} + +static void debug_search_result_display(Node *tm) { + if (tm) + Printf(stdout, " Using: %%%s\n", Getattr(tm, "source")); + else + Printf(stdout, " None found\n"); +} + +/* ----------------------------------------------------------------------------- + * typemap_search_helper() + * + * Helper function for typemap_search to see if there is a type match in the typemap + * tm. A match is sought in this order: + * %typemap(tm_method) ctype cqualifiedname + * %typemap(tm_method) ctype cname + * %typemap(tm_method) ctype + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_search_helper(int debug_display, Hash *tm, const String *tm_method, SwigType *ctype, const String *cqualifiedname, const String *cname, Hash **backup) { + Hash *result = 0; + Hash *tm1; + if (debug_display && cqualifiedname) + Printf(stdout, " Looking for: %s\n", SwigType_str(ctype, cqualifiedname)); + if (tm && cqualifiedname) { + tm1 = Getattr(tm, cqualifiedname); + if (tm1) { + result = Getattr(tm1, tm_method); /* See if there is a type - qualified name match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + *backup = result; + } + } + if (debug_display && cname) + Printf(stdout, " Looking for: %s\n", SwigType_str(ctype, cname)); + if (tm && cname) { + tm1 = Getattr(tm, cname); + if (tm1) { + result = Getattr(tm1, tm_method); /* See if there is a type - name match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + *backup = result; + } + } + if (debug_display) + Printf(stdout, " Looking for: %s\n", SwigType_str(ctype, 0)); + if (tm) { + result = Getattr(tm, tm_method); /* See if there is simply a type without name match */ + if (result && Getattr(result, "code")) + goto ret_result; + if (result) + *backup = result; + } +ret_result: + return result; +} + +/* ----------------------------------------------------------------------------- + * typemap_search() + * + * Search for a typemap match. This is where the typemap pattern matching rules + * are implemented... tries to find the most specific typemap that includes a + * 'code' attribute. + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_search(const_String_or_char_ptr tmap_method, SwigType *type, const_String_or_char_ptr name, const_String_or_char_ptr qualifiedname, SwigType **matchtype, Node *node) { + Hash *result = 0; + Hash *tm; + Hash *backup = 0; + SwigType *primitive = 0; + SwigType *ctype = 0; + SwigType *ctype_unstripped = 0; + int isarray; + const String *cname = 0; + const String *cqualifiedname = 0; + String *tm_method = typemap_method_name(tmap_method); + int debug_display = (in_typemap_search_multi == 0) && typemap_search_debug; + + if ((name) && Len(name)) + cname = name; + if ((qualifiedname) && Len(qualifiedname)) + cqualifiedname = qualifiedname; + + if (debug_display) { + String *typestr = SwigType_str(type, cqualifiedname ? cqualifiedname : cname); + Swig_diagnostic(Getfile(node), Getline(node), "Searching for a suitable '%s' typemap for: %s\n", tmap_method, typestr); + Delete(typestr); + } + ctype = Copy(type); + ctype_unstripped = Copy(ctype); + while (ctype) { + /* Try to get an exact type-match */ + tm = get_typemap(ctype); + result = typemap_search_helper(debug_display, tm, tm_method, ctype, cqualifiedname, cname, &backup); + if (result && Getattr(result, "code")) + goto ret_result; + + { + /* Look for the type reduced to just the template prefix - for templated types without the template parameter list being specified */ + SwigType *template_prefix = SwigType_istemplate_only_templateprefix(ctype); + if (template_prefix) { + tm = get_typemap(template_prefix); + result = typemap_search_helper(debug_display, tm, tm_method, template_prefix, cqualifiedname, cname, &backup); + Delete(template_prefix); + if (result && Getattr(result, "code")) + goto ret_result; + } + } + + /* look for [ANY] arrays */ + isarray = SwigType_isarray(ctype); + if (isarray) { + /* If working with arrays, strip away all of the dimensions and replace with "ANY". + See if that generates a match */ + SwigType *noarrays = strip_arrays(ctype); + tm = get_typemap(noarrays); + result = typemap_search_helper(debug_display, tm, tm_method, noarrays, cqualifiedname, cname, &backup); + Delete(noarrays); + if (result && Getattr(result, "code")) + goto ret_result; + } + + /* No match so far - try with a qualifier stripped (strip one qualifier at a time until none remain) + * The order of stripping in SwigType_strip_single_qualifier is used to provide some sort of consistency + * with the default (SWIGTYPE) typemap matching rules for the first qualifier to be stripped. */ + { + SwigType *oldctype = ctype; + ctype = SwigType_strip_single_qualifier(oldctype); + if (!Equal(ctype, oldctype)) { + Delete(oldctype); + continue; + } + Delete(oldctype); + } + + /* Once all qualifiers are stripped try resolve a typedef */ + { + SwigType *oldctype = ctype; + ctype = SwigType_typedef_resolve(ctype_unstripped); + Delete(oldctype); + Delete(ctype_unstripped); + ctype_unstripped = Copy(ctype); + } + } + + /* Hmmm. Well, no match seems to be found at all. See if there is some kind of default (SWIGTYPE) mapping */ + + primitive = SwigType_default_create(type); + while (primitive) { + tm = get_typemap(primitive); + result = typemap_search_helper(debug_display, tm, tm_method, primitive, cqualifiedname, cname, &backup); + if (result && Getattr(result, "code")) + goto ret_result; + + { + SwigType *nprim = SwigType_default_deduce(primitive); + Delete(primitive); + primitive = nprim; + } + } + if (ctype != type) { + Delete(ctype); + ctype = 0; + } + result = backup; + +ret_result: + Delete(primitive); + if (matchtype) + *matchtype = Copy(ctype); + Delete(ctype); + Delete(ctype_unstripped); + return result; +} + + +/* ----------------------------------------------------------------------------- + * typemap_search_multi() + * + * Search for a multi-argument typemap. + * ----------------------------------------------------------------------------- */ + +static Hash *typemap_search_multi(const_String_or_char_ptr tmap_method, ParmList *parms, int *nmatch) { + SwigType *type; + SwigType *mtype = 0; + String *name; + String *multi_tmap_method; + Hash *tm; + Hash *tm1 = 0; + + if (!parms) { + *nmatch = 0; + return 0; + } + type = Getattr(parms, "type"); + name = Getattr(parms, "name"); + + /* Try to find a match on the first type */ + tm = typemap_search(tmap_method, type, name, 0, &mtype, parms); + if (tm) { + if (mtype && SwigType_isarray(mtype)) { + Setattr(parms, "tmap:match", mtype); + } + Delete(mtype); + multi_tmap_method = NewStringf("%s-%s+%s:", tmap_method, type, name); + in_typemap_search_multi++; + tm1 = typemap_search_multi(multi_tmap_method, nextSibling(parms), nmatch); + in_typemap_search_multi--; + if (tm1) + tm = tm1; + if (Getattr(tm, "code")) { + *(nmatch) = *nmatch + 1; + if (typemap_search_debug && tm1 && (in_typemap_search_multi == 0)) { + Printf(stdout, " Multi-argument typemap found...\n"); + } + } else { + tm = 0; + } + Delete(multi_tmap_method); + } + + if (typemap_search_debug && (in_typemap_search_multi == 0)) + debug_search_result_display(tm); + if (typemaps_used_debug && (in_typemap_search_multi == 0) && tm) { + String *typestr = SwigType_str(type, name); + Swig_diagnostic(Getfile(parms), Getline(parms), "Typemap for %s (%s) : %%%s\n", typestr, tmap_method, Getattr(tm, "source")); + assert(Getfile(parms) && Len(Getfile(parms)) > 0); /* Missing file and line numbering information */ + Delete(typestr); + } + + return tm; +} + + +/* ----------------------------------------------------------------------------- + * typemap_replace_vars() + * + * Replaces typemap variables on a string. index is the $n variable. + * type and pname are the type and parameter name. + * ----------------------------------------------------------------------------- */ + +static void replace_local_types(ParmList *p, const String *name, const String *rep) { + SwigType *t; + while (p) { + t = Getattr(p, "type"); + Replace(t, name, rep, DOH_REPLACE_ANY); + p = nextSibling(p); + } +} + +static int check_locals(ParmList *p, const char *s) { + while (p) { + char *c = GetChar(p, "type"); + if (strstr(c, s)) + return 1; + p = nextSibling(p); + } + return 0; +} + +static int typemap_replace_vars(String *s, ParmList *locals, SwigType *type, SwigType *rtype, String *pname, String *lname, int index) { + char var[512]; + char *varname; + SwigType *ftype; + int bare_substitution_count = 0; + + Replaceall(s, "$typemap", "$TYPEMAP"); /* workaround for $type substitution below */ + + ftype = SwigType_typedef_resolve_all(type); + + if (!pname) + pname = lname; + { + Parm *p; + int rep = 0; + p = locals; + while (p) { + if (Strchr(Getattr(p, "type"), '$')) + rep = 1; + p = nextSibling(p); + } + if (!rep) + locals = 0; + } + + sprintf(var, "$%d_", index); + varname = &var[strlen(var)]; + + /* If the original datatype was an array. We're going to go through and substitute + its array dimensions */ + + if (SwigType_isarray(type) || SwigType_isarray(ftype)) { + String *size; + int ndim; + int i; + if (SwigType_array_ndim(type) != SwigType_array_ndim(ftype)) + type = ftype; + ndim = SwigType_array_ndim(type); + size = NewStringEmpty(); + for (i = 0; i < ndim; i++) { + String *dim = SwigType_array_getdim(type, i); + if (index == 1) { + char t[32]; + sprintf(t, "$dim%d", i); + Replace(s, t, dim, DOH_REPLACE_ANY); + replace_local_types(locals, t, dim); + } + sprintf(varname, "dim%d", i); + Replace(s, var, dim, DOH_REPLACE_ANY); + replace_local_types(locals, var, dim); + if (Len(size)) + Putc('*', size); + Append(size, dim); + Delete(dim); + } + sprintf(varname, "size"); + Replace(s, var, size, DOH_REPLACE_ANY); + replace_local_types(locals, var, size); + Delete(size); + } + + /* Parameter name substitution */ + if (index == 1) { + Replace(s, "$parmname", pname, DOH_REPLACE_ANY); + } + strcpy(varname, "name"); + Replace(s, var, pname, DOH_REPLACE_ANY); + + /* Type-related stuff */ + { + SwigType *star_type, *amp_type, *base_type, *lex_type; + SwigType *ltype, *star_ltype, *amp_ltype; + String *mangle, *star_mangle, *amp_mangle, *base_mangle, *base_name, *base_type_str; + String *descriptor, *star_descriptor, *amp_descriptor; + String *ts; + char *sc; + + sc = Char(s); + + if (strstr(sc, "type") || check_locals(locals, "type")) { + /* Given type : $type */ + ts = SwigType_str(type, 0); + if (index == 1) { + Replace(s, "$type", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$type", type); + } + strcpy(varname, "type"); + Replace(s, var, ts, DOH_REPLACE_ANY); + replace_local_types(locals, var, type); + Delete(ts); + sc = Char(s); + } + if (strstr(sc, "ltype") || check_locals(locals, "ltype")) { + /* Local type: $ltype */ + ltype = SwigType_ltype(type); + ts = SwigType_str(ltype, 0); + if (index == 1) { + Replace(s, "$ltype", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$ltype", ltype); + } + strcpy(varname, "ltype"); + Replace(s, var, ts, DOH_REPLACE_ANY); + replace_local_types(locals, var, ltype); + Delete(ts); + Delete(ltype); + sc = Char(s); + } + if (strstr(sc, "mangle") || strstr(sc, "descriptor")) { + /* Mangled type */ + + mangle = SwigType_manglestr(type); + if (index == 1) + Replace(s, "$mangle", mangle, DOH_REPLACE_ANY); + strcpy(varname, "mangle"); + Replace(s, var, mangle, DOH_REPLACE_ANY); + + descriptor = NewStringf("SWIGTYPE%s", mangle); + + if (index == 1) + if (Replace(s, "$descriptor", descriptor, DOH_REPLACE_ANY)) + SwigType_remember(type); + + strcpy(varname, "descriptor"); + if (Replace(s, var, descriptor, DOH_REPLACE_ANY)) + SwigType_remember(type); + + Delete(descriptor); + Delete(mangle); + } + + /* One pointer level removed */ + /* This creates variables of the form + $*n_type + $*n_ltype + */ + + if (SwigType_ispointer(ftype) || (SwigType_isarray(ftype)) || (SwigType_isreference(ftype)) || (SwigType_isrvalue_reference(ftype))) { + if (!(SwigType_isarray(type) || SwigType_ispointer(type) || SwigType_isreference(type) || SwigType_isrvalue_reference(type))) { + star_type = Copy(ftype); + } else { + star_type = Copy(type); + } + if (!(SwigType_isreference(star_type) || SwigType_isrvalue_reference(star_type))) { + if (SwigType_isarray(star_type)) { + SwigType_del_element(star_type); + } else { + SwigType_del_pointer(star_type); + } + ts = SwigType_str(star_type, 0); + if (index == 1) { + Replace(s, "$*type", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$*type", star_type); + } + sprintf(varname, "$*%d_type", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, star_type); + Delete(ts); + } else { + SwigType_del_element(star_type); + } + star_ltype = SwigType_ltype(star_type); + ts = SwigType_str(star_ltype, 0); + if (index == 1) { + Replace(s, "$*ltype", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$*ltype", star_ltype); + } + sprintf(varname, "$*%d_ltype", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, star_ltype); + Delete(ts); + Delete(star_ltype); + + star_mangle = SwigType_manglestr(star_type); + if (index == 1) + Replace(s, "$*mangle", star_mangle, DOH_REPLACE_ANY); + + sprintf(varname, "$*%d_mangle", index); + Replace(s, varname, star_mangle, DOH_REPLACE_ANY); + + star_descriptor = NewStringf("SWIGTYPE%s", star_mangle); + if (index == 1) + if (Replace(s, "$*descriptor", star_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(star_type); + sprintf(varname, "$*%d_descriptor", index); + if (Replace(s, varname, star_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(star_type); + + Delete(star_descriptor); + Delete(star_mangle); + Delete(star_type); + } else { + /* TODO: Signal error if one of the $* substitutions is + requested */ + } + /* One pointer level added */ + amp_type = Copy(type); + SwigType_add_pointer(amp_type); + ts = SwigType_str(amp_type, 0); + if (index == 1) { + Replace(s, "$&type", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$&type", amp_type); + } + sprintf(varname, "$&%d_type", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, amp_type); + Delete(ts); + + amp_ltype = SwigType_ltype(type); + SwigType_add_pointer(amp_ltype); + ts = SwigType_str(amp_ltype, 0); + + if (index == 1) { + Replace(s, "$<ype", ts, DOH_REPLACE_ANY); + replace_local_types(locals, "$<ype", amp_ltype); + } + sprintf(varname, "$&%d_ltype", index); + Replace(s, varname, ts, DOH_REPLACE_ANY); + replace_local_types(locals, varname, amp_ltype); + Delete(ts); + Delete(amp_ltype); + + amp_mangle = SwigType_manglestr(amp_type); + if (index == 1) + Replace(s, "$&mangle", amp_mangle, DOH_REPLACE_ANY); + sprintf(varname, "$&%d_mangle", index); + Replace(s, varname, amp_mangle, DOH_REPLACE_ANY); + + amp_descriptor = NewStringf("SWIGTYPE%s", amp_mangle); + if (index == 1) + if (Replace(s, "$&descriptor", amp_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(amp_type); + sprintf(varname, "$&%d_descriptor", index); + if (Replace(s, varname, amp_descriptor, DOH_REPLACE_ANY)) + SwigType_remember(amp_type); + + Delete(amp_descriptor); + Delete(amp_mangle); + Delete(amp_type); + + /* Base type */ + if (SwigType_isarray(type)) { + base_type = Copy(type); + Delete(SwigType_pop_arrays(base_type)); + } else { + base_type = SwigType_base(type); + } + + base_type_str = SwigType_str(base_type, 0); + base_name = SwigType_namestr(base_type_str); + if (index == 1) { + Replace(s, "$basetype", base_name, DOH_REPLACE_ANY); + replace_local_types(locals, "$basetype", base_name); + } + strcpy(varname, "basetype"); + Replace(s, var, base_type_str, DOH_REPLACE_ANY); + replace_local_types(locals, var, base_name); + + base_mangle = SwigType_manglestr(base_type); + if (index == 1) + Replace(s, "$basemangle", base_mangle, DOH_REPLACE_ANY); + strcpy(varname, "basemangle"); + Replace(s, var, base_mangle, DOH_REPLACE_ANY); + Delete(base_mangle); + Delete(base_name); + Delete(base_type_str); + Delete(base_type); + + lex_type = SwigType_base(rtype); + if (index == 1) + Replace(s, "$lextype", lex_type, DOH_REPLACE_ANY); + strcpy(varname, "lextype"); + Replace(s, var, lex_type, DOH_REPLACE_ANY); + Delete(lex_type); + } + + /* Replace any $n. with (&n)-> */ + { + char temp[64]; + sprintf(var, "$%d.", index); + sprintf(temp, "(&$%d)->", index); + Replace(s, var, temp, DOH_REPLACE_ANY); + } + + /* Replace the bare $n variable */ + sprintf(var, "$%d", index); + bare_substitution_count = Replace(s, var, lname, DOH_REPLACE_NUMBER_END); + Delete(ftype); + return bare_substitution_count; +} + +/* ------------------------------------------------------------------------ + * static typemap_locals() + * + * Takes a string, a parameter list and a wrapper function argument and + * creates the local variables. + * ------------------------------------------------------------------------ */ + +static void typemap_locals(String *s, ParmList *l, Wrapper *f, int argnum) { + Parm *p; + char *new_name; + + p = l; + while (p) { + SwigType *pt = Getattr(p, "type"); + SwigType *at = SwigType_alttype(pt, 1); + String *pn = Getattr(p, "name"); + String *value = Getattr(p, "value"); + if (at) + pt = at; + if (pn) { + if (Len(pn) > 0) { + String *str; + int isglobal = 0; + + str = NewStringEmpty(); + + if (strncmp(Char(pn), "_global_", 8) == 0) { + isglobal = 1; + } + + /* If the user gave us $type as the name of the local variable, we'll use + the passed datatype instead */ + + if ((argnum >= 0) && (!isglobal)) { + Printf(str, "%s%d", pn, argnum); + } else { + Append(str, pn); + } + if (isglobal && Wrapper_check_local(f, str)) { + p = nextSibling(p); + Delete(str); + if (at) + Delete(at); + continue; + } + if (value) { + String *pstr = SwigType_str(pt, str); + new_name = Wrapper_new_localv(f, str, pstr, "=", value, NIL); + Delete(pstr); + } else { + String *pstr = SwigType_str(pt, str); + new_name = Wrapper_new_localv(f, str, pstr, NIL); + Delete(pstr); + } + if (!isglobal) { + /* Substitute */ + Replace(s, pn, new_name, DOH_REPLACE_ID | DOH_REPLACE_NOQUOTE); + } + Delete(str); + } + } + p = nextSibling(p); + if (at) + Delete(at); + } +} + +/* ----------------------------------------------------------------------------- + * typemap_warn() + * + * If any warning message is attached to this parameter's "tmap:<method>:warning" + * attribute, return the warning message (special variables will need expanding + * before displaying the warning). + * ----------------------------------------------------------------------------- */ + +static String *typemap_warn(const_String_or_char_ptr tmap_method, Parm *p) { + String *temp = NewStringf("%s:warning", tmap_method); + String *w = Getattr(p, typemap_method_name(temp)); + Delete(temp); + return w ? Copy(w) : 0; +} + +/* ----------------------------------------------------------------------------- + * typemap_merge_fragment_kwargs() + * + * If multiple 'fragment' attributes are provided to a typemap, combine them by + * concatenating with commas. + * ----------------------------------------------------------------------------- */ + +static void typemap_merge_fragment_kwargs(Parm *kw) { + Parm *reattach_kw = NULL; + Parm *prev_kw = NULL; + Parm *next_kw = NULL; + String *fragment = NULL; + while (kw) { + next_kw = nextSibling(kw); + if (Strcmp(Getattr(kw, "name"), "fragment") == 0) { + String *thisfragment = Getattr(kw, "value"); + String *kwtype = Getattr(kw, "type"); + if (!fragment) { + /* First fragment found; it should remain in the list */ + fragment = thisfragment; + prev_kw = kw; + } else { + /* Concatenate to previously found fragment */ + Printv(fragment, ",", thisfragment, NULL); + reattach_kw = prev_kw; + } + if (kwtype) { + String *mangle = Swig_string_mangle(kwtype); + Append(fragment, mangle); + Delete(mangle); + /* Remove 'type' from kwargs so it's not duplicated later */ + Setattr(kw, "type", NULL); + } + } else { + /* Not a fragment */ + if (reattach_kw) { + /* Update linked list to remove duplicate fragment */ + DohIncref(kw); + set_nextSibling(reattach_kw, kw); + set_previousSibling(kw, reattach_kw); + Delete(reattach_kw); + reattach_kw = NULL; + } + prev_kw = kw; + } + kw = next_kw; + } + if (reattach_kw) { + /* Update linked list to remove duplicate fragment */ + set_nextSibling(reattach_kw, kw); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_lookup() + * + * Attach one or more typemaps to a node and optionally generate the typemap contents + * into the wrapper. + * + * Looks for a typemap matching the given type and name and attaches the typemap code + * and any typemap attributes to the provided node. + * + * The node should contain the "type" and "name" attributes for the typemap match on. + * input. The typemap code and typemap attribute values are attached onto the node + * prefixed with "tmap:". For example with tmap_method="in", the typemap code can be retrieved + * with a call to Getattr(node, "tmap:in") (this is also the string returned) and the + * "noblock" attribute can be retrieved with a call to Getattr(node, "tmap:in:noblock"). + * + * tmap_method - typemap method, eg "in", "out", "newfree" + * node - the node to attach the typemap and typemap attributes to + * lname - name of variable to substitute $1, $2 etc for + * f - wrapper code to generate into if non null + * actioncode - code to generate into f before the out typemap code, unless + * the optimal attribute is set in the out typemap in which case + * $1 in the out typemap will be replaced by the code in actioncode. + * ----------------------------------------------------------------------------- */ + +static String *Swig_typemap_lookup_impl(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) { + SwigType *type; + SwigType *mtype = 0; + String *pname; + String *qpname = 0; + String *noscope_pname = 0; + Hash *tm = 0; + String *s = 0; + String *sdef = 0; + String *warning = 0; + ParmList *locals; + ParmList *kw; + char temp[256]; + String *symname; + String *cname = 0; + String *clname = 0; + char *cmethod = Char(tmap_method); + int optimal_attribute = 0; + int optimal_substitution = 0; + int delete_optimal_attribute = 0; + int num_substitutions = 0; + SwigType *matchtype = 0; + + type = Getattr(node, "type"); + if (!type) + return sdef; + + /* Special hook (hack!). Check for the 'ref' feature and add code it contains to any 'newfree' typemap code. + * We could choose to put this hook into a number of different typemaps, not necessarily 'newfree'... + * Rather confusingly 'newfree' is used to release memory and the 'ref' feature is used to add in memory references - yuck! */ + if (Cmp(tmap_method, "newfree") == 0) { + String *base = SwigType_base(type); + Node *typenode = Swig_symbol_clookup(base, 0); + if (typenode) + sdef = Swig_ref_call(typenode, lname); + Delete(base); + } + + pname = Getattr(node, "name"); + noscope_pname = Copy(pname); + + if (pname && Getattr(node, "sym:symtab")) { + /* Add on a qualified name search for any symbol in the symbol table, for example: + * struct Foo { + * int *foo(int bar) -> Foo::foo + * }; + * Note that if node is a parameter (Parm *) then there will be no symbol table attached to the Parm *. + */ + String *qsn; + if (Swig_scopename_check(pname)) { + /* sometimes pname is qualified, so we remove all the scope for the lookup */ + Delete(noscope_pname); + noscope_pname = Swig_scopename_last(pname); + /* + Printf(stdout, "Removed scope: %s => %s\n", pname, noscope_pname); + */ + } + qsn = Swig_symbol_qualified(node); + if (qsn && Len(qsn)) { + qpname = NewStringf("%s::%s", qsn, noscope_pname); + Delete(qsn); + } + } + + tm = typemap_search(tmap_method, type, noscope_pname, qpname, &mtype, node); + if (typemap_search_debug) + debug_search_result_display(tm); + if (typemaps_used_debug && tm) { + String *typestr = SwigType_str(type, qpname ? qpname : pname); + Swig_diagnostic(Getfile(node), Getline(node), "Typemap for %s (%s) : %%%s\n", typestr, tmap_method, Getattr(tm, "source")); + assert(Getfile(node) && Len(Getfile(node)) > 0); /* Missing file and line numbering information */ + Delete(typestr); + } + + Delete(qpname); + qpname = 0; + Delete(noscope_pname); + noscope_pname = 0; + + if (!tm) + return sdef; + + s = Getattr(tm, "code"); + if (!s) + return sdef; + + /* Empty typemap. No match */ + if (Cmp(s, "pass") == 0) + return sdef; + + s = Copy(s); /* Make a local copy of the typemap code */ + + /* Look in the "out" typemap for the "optimal" attribute */ + if (Cmp(cmethod, "out") == 0) { + kw = Getattr(tm, "kwargs"); + while (kw) { + if (Cmp(Getattr(kw, "name"), "optimal") == 0) { + optimal_attribute = GetFlag(kw, "value"); + break; + } + kw = nextSibling(kw); + } + } + + if (optimal_attribute) { + /* Note: "out" typemap is the only typemap that will have the "optimal" attribute set. + * If f and actioncode are NULL, then the caller is just looking to attach the "out" attributes + * ie, not use the typemap code, otherwise both f and actioncode must be non null. */ + if (actioncode) { + const String *result_equals = NewStringf("%s = ", Swig_cresult_name()); + /* check that the code in the typemap can be used in this optimal way. + * The code should be in the form "result = ...;\n". We need to extract + * the "..." part. This may not be possible for various reasons, eg + * code added by %exception. This optimal code generation is bit of a + * hack and circumvents the normal requirement for a temporary variable + * to hold the result returned from a wrapped function call. + */ + if (Strncmp(actioncode, result_equals, Len(result_equals)) == 0 && + Strchr(actioncode, ';') == Char(actioncode) + Len(actioncode) - 2 && + Char(actioncode)[Len(actioncode) - 1] == '\n') { + clname = NewStringWithSize(Char(actioncode) + Len(result_equals), + Len(actioncode) - Len(result_equals) - 2); + lname = clname; + actioncode = 0; + optimal_substitution = 1; + } else { + Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_IGNORED, Getfile(node), Getline(node), "Method %s usage of the optimal attribute ignored\n", Swig_name_decl(node)); + Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_IGNORED, Getfile(s), Getline(s), "in the out typemap as the following cannot be used to generate optimal code: %s\n", actioncode); + delete_optimal_attribute = 1; + } + } else { + assert(!f); + } + } + + if (actioncode) { + assert(f); + Append(f->code, actioncode); + } + + /* emit local variables declared in typemap, eg emit declarations for aa and bb in: + * %typemap(in) foo (int aa, int bb) "..." */ + locals = Getattr(tm, "locals"); + if (locals) + locals = CopyParmList(locals); + + if (pname) { + if (SwigType_istemplate(pname)) { + cname = SwigType_namestr(pname); + pname = cname; + } + } + if (SwigType_istemplate((char *) lname)) { + clname = SwigType_namestr((char *) lname); + lname = clname; + } + + matchtype = mtype && SwigType_isarray(mtype) ? mtype : type; + num_substitutions = typemap_replace_vars(s, locals, matchtype, type, pname, (char *) lname, 1); + if (optimal_substitution && num_substitutions > 1) { + Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE, Getfile(node), Getline(node), "Multiple calls to %s might be generated due to\n", Swig_name_decl(node)); + Swig_warning(WARN_TYPEMAP_OUT_OPTIMAL_MULTIPLE, Getfile(s), Getline(s), "optimal attribute usage in the out typemap.\n"); + } + + if (locals && f) { + typemap_locals(s, locals, f, -1); + } + + { + ParmList *parm_sublist = NewParmWithoutFileLineInfo(type, pname); + Setattr(parm_sublist, "lname", lname); + replace_embedded_typemap(s, parm_sublist, f, tm); + Delete(parm_sublist); + } + + /* Attach kwargs - ie the typemap attributes */ + kw = Getattr(tm, "kwargs"); + typemap_merge_fragment_kwargs(kw); + while (kw) { + String *value = Copy(Getattr(kw, "value")); + String *kwtype = Getattr(kw, "type"); + char *ckwname = Char(Getattr(kw, "name")); + { + /* Expand special variables in typemap attributes. */ + SwigType *ptype = Getattr(node, "type"); + String *pname = Getattr(node, "name"); + SwigType *mtype = Getattr(node, "tmap:match"); + SwigType *matchtype = mtype ? mtype : ptype; + ParmList *parm_sublist; + typemap_replace_vars(value, NULL, matchtype, ptype, pname, (char *)lname, 1); + + /* Expand special variable macros (embedded typemaps) in typemap attributes. */ + parm_sublist = NewParmWithoutFileLineInfo(ptype, pname); + Setattr(parm_sublist, "lname", lname); + replace_embedded_typemap(value, parm_sublist, NULL, tm); + Delete(parm_sublist); + } + if (kwtype) { + String *mangle = Swig_string_mangle(kwtype); + Append(value, mangle); + Delete(mangle); + } + sprintf(temp, "%s:%s", cmethod, ckwname); + Setattr(node, typemap_method_name(temp), value); + Delete(value); + kw = nextSibling(kw); + } + + if (delete_optimal_attribute) + Delattr(node, "tmap:out:optimal"); + + Replace(s, "$name", pname, DOH_REPLACE_ANY); + + symname = Getattr(node, "sym:name"); + if (symname) + Replace(s, "$symname", symname, DOH_REPLACE_ANY); + + Setattr(node, typemap_method_name(tmap_method), s); + if (locals) { + sprintf(temp, "%s:locals", cmethod); + Setattr(node, typemap_method_name(temp), locals); + Delete(locals); + } + + if (Checkattr(tm, "type", "SWIGTYPE")) { + sprintf(temp, "%s:SWIGTYPE", cmethod); + Setattr(node, typemap_method_name(temp), "1"); + } + + /* Print warnings, if any */ + warning = typemap_warn(cmethod, node); + if (warning) { + typemap_replace_vars(warning, 0, matchtype, type, pname, (char *) lname, 1); + Replace(warning, "$name", pname, DOH_REPLACE_ANY); + if (symname) + Replace(warning, "$symname", symname, DOH_REPLACE_ANY); + Swig_warning(0, Getfile(node), Getline(node), "%s\n", warning); + Delete(warning); + } + + /* Look for code fragments */ + { + String *fragment; + sprintf(temp, "%s:fragment", cmethod); + fragment = Getattr(node, typemap_method_name(temp)); + if (fragment) { + String *fname = Copy(fragment); + Setfile(fname, Getfile(node)); + Setline(fname, Getline(node)); + Swig_fragment_emit(fname); + Delete(fname); + } + } + + Delete(cname); + Delete(clname); + Delete(mtype); + if (sdef) { /* put 'ref' and 'newfree' codes together */ + String *p = NewStringf("%s\n%s", sdef, s); + Delete(s); + Delete(sdef); + s = p; + } + Delete(actioncode); + return s; +} + +String *Swig_typemap_lookup_out(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f, String *actioncode) { + assert(actioncode); + assert(Cmp(tmap_method, "out") == 0); + return Swig_typemap_lookup_impl(tmap_method, node, lname, f, actioncode); +} + +String *Swig_typemap_lookup(const_String_or_char_ptr tmap_method, Node *node, const_String_or_char_ptr lname, Wrapper *f) { + return Swig_typemap_lookup_impl(tmap_method, node, lname, f, 0); +} + +/* ----------------------------------------------------------------------------- + * typemap_attach_kwargs() + * + * If this hash (tm) contains a linked list of parameters under its "kwargs" + * attribute, add keys for each of those named keyword arguments to this + * parameter for later use. + * For example, attach the typemap attributes to firstp (first parameter in parameter list): + * %typemap(in, foo="xyz") ... + * A new attribute called "tmap:in:foo" with value "xyz" is attached to firstp. + * Also expands special variables and special variable macros in the typemap attributes. + * ----------------------------------------------------------------------------- */ + +static void typemap_attach_kwargs(Hash *tm, const_String_or_char_ptr tmap_method, Parm *firstp, int nmatch) { + String *temp = NewStringEmpty(); + Parm *kw = Getattr(tm, "kwargs"); + typemap_merge_fragment_kwargs(kw); + while (kw) { + String *value = Copy(Getattr(kw, "value")); + String *type = Getattr(kw, "type"); + int i; + Parm *p = firstp; + /* Expand special variables */ + for (i = 0; i < nmatch; i++) { + SwigType *type = Getattr(p, "type"); + String *pname = Getattr(p, "name"); + String *lname = Getattr(p, "lname"); + SwigType *mtype = Getattr(p, "tmap:match"); + SwigType *matchtype = mtype ? mtype : type; + typemap_replace_vars(value, NULL, matchtype, type, pname, lname, i + 1); + p = nextSibling(p); + } + + /* Expand special variable macros (embedded typemaps). + * Special variable are expanded first above as they might be used in the special variable macros. + * For example: $typemap(imtype, $2_type). */ + p = firstp; + for (i = 0; i < nmatch; i++) { + SwigType *type = Getattr(p, "type"); + String *pname = Getattr(p, "name"); + String *lname = Getattr(p, "lname"); + ParmList *parm_sublist = NewParmWithoutFileLineInfo(type, pname); + Setattr(parm_sublist, "lname", lname); + replace_embedded_typemap(value, parm_sublist, NULL, tm); + p = nextSibling(p); + } + if (type) { + Hash *v = NewHash(); + Setattr(v, "type", type); + Setattr(v, "value", value); + Delete(value); + value = v; + } + Clear(temp); + Printf(temp, "%s:%s", tmap_method, Getattr(kw, "name")); + Setattr(firstp, typemap_method_name(temp), value); + Delete(value); + kw = nextSibling(kw); + } + Clear(temp); + Printf(temp, "%s:match_type", tmap_method); + Setattr(firstp, typemap_method_name(temp), Getattr(tm, "type")); + Delete(temp); +} + +static void typemap_emit_code_fragments(const_String_or_char_ptr tmap_method, Parm *p) { + String *temp = NewStringf("%s:fragment", tmap_method); + String *f = Getattr(p, typemap_method_name(temp)); + if (f) { + String *fname = Copy(f); + Setfile(fname, Getfile(p)); + Setline(fname, Getline(p)); + Swig_fragment_emit(fname); + Delete(fname); + } + Delete(temp); +} + +static String *typemap_get_option(Hash *tm, const_String_or_char_ptr name) { + Parm *kw = Getattr(tm, "kwargs"); + while (kw) { + String *kname = Getattr(kw, "name"); + if (Equal(kname, name)) { + return Getattr(kw, "value"); + } + kw = nextSibling(kw); + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_attach_parms() + * + * Given a parameter list, this function attaches all of the typemaps and typemap + * attributes to the parameter for each type in the parameter list. + * + * This function basically provides the typemap code and typemap attribute values as + * attributes on each parameter prefixed with "tmap:". For example with tmap_method="in", the typemap + * code can be retrieved for the first parameter with a call to Getattr(parm, "tmap:in") + * and the "numinputs" attribute can be retrieved with a call to Getattr(parm, "tmap:in:numinputs"). + * + * tmap_method - typemap method, eg "in", "out", "newfree" + * parms - parameter list to attach each typemap and all typemap attributes + * f - wrapper code to generate into if non null + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_attach_parms(const_String_or_char_ptr tmap_method, ParmList *parms, Wrapper *f) { + Parm *p, *firstp; + Hash *tm; + int nmatch = 0; + int i; + String *s; + String *warning = 0; + ParmList *locals; + int argnum = 0; + char temp[256]; + char *cmethod = Char(tmap_method); + String *kwmatch = 0; + p = parms; + +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_typemap_attach_parms: %s\n", tmap_method); +#endif + + while (p) { + argnum++; + nmatch = 0; +#ifdef SWIG_DEBUG + Printf(stdout, "parms: %s %s %s\n", tmap_method, Getattr(p, "name"), Getattr(p, "type")); +#endif + tm = typemap_search_multi(tmap_method, p, &nmatch); +#ifdef SWIG_DEBUG + if (tm) + Printf(stdout, "found: %s\n", tm); +#endif + if (!tm) { + p = nextSibling(p); + continue; + } + /* + Check if the typemap requires to match the type of another + typemap, for example: + + %typemap(in) SWIGTYPE * (int var) {...} + %typemap(freearg,match="in") SWIGTYPE * {if (var$argnum) ...} + + here, the freearg typemap requires the "in" typemap to match, + or the 'var$argnum' variable will not exist. + */ + kwmatch = typemap_get_option(tm, "match"); + if (kwmatch) { + String *tmname = NewStringf("tmap:%s", kwmatch); + String *tmin = Getattr(p, tmname); + Delete(tmname); +#ifdef SWIG_DEBUG + if (tm) + Printf(stdout, "matching: %s\n", kwmatch); +#endif + if (tmin) { + String *tmninp = NewStringf("tmap:%s:numinputs", kwmatch); + String *ninp = Getattr(p, tmninp); + Delete(tmninp); + if (ninp && Equal(ninp, "0")) { + p = nextSibling(p); + continue; + } else { + SwigType *typetm = Getattr(tm, "type"); + String *temp = NewStringf("tmap:%s:match_type", kwmatch); + SwigType *typein = Getattr(p, temp); + Delete(temp); + if (!Equal(typein, typetm)) { + p = nextSibling(p); + continue; + } else { + int nnmatch; + Hash *tmapin = typemap_search_multi(kwmatch, p, &nnmatch); + String *tmname = Getattr(tm, "pname"); + String *tnname = Getattr(tmapin, "pname"); + if (!(tmname && tnname && Equal(tmname, tnname)) && !(!tmname && !tnname)) { + p = nextSibling(p); + continue; + } + } + + } + } else { + p = nextSibling(p); + continue; + } + } + + s = Getattr(tm, "code"); + if (!s) { + p = nextSibling(p); + continue; + } +#ifdef SWIG_DEBUG + if (s) + Printf(stdout, "code: %s\n", s); +#endif + + /* Empty typemap. No match */ + if (Cmp(s, "pass") == 0) { + p = nextSibling(p); + continue; + } + + s = Copy(s); + locals = Getattr(tm, "locals"); + if (locals) + locals = CopyParmList(locals); + firstp = p; +#ifdef SWIG_DEBUG + Printf(stdout, "nmatch: %d\n", nmatch); +#endif + for (i = 0; i < nmatch; i++) { + SwigType *type = Getattr(p, "type"); + String *pname = Getattr(p, "name"); + String *lname = Getattr(p, "lname"); + SwigType *mtype = Getattr(p, "tmap:match"); + SwigType *matchtype = mtype ? mtype : type; + + typemap_replace_vars(s, locals, matchtype, type, pname, lname, i + 1); + if (mtype) + Delattr(p, "tmap:match"); + + if (Checkattr(tm, "type", "SWIGTYPE")) { + sprintf(temp, "%s:SWIGTYPE", cmethod); + Setattr(p, typemap_method_name(temp), "1"); + } + p = nextSibling(p); + } + + if (locals && f) { + typemap_locals(s, locals, f, argnum); + } + + replace_embedded_typemap(s, firstp, f, tm); + + /* Attach attributes to object */ +#ifdef SWIG_DEBUG + Printf(stdout, "attach: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), s); +#endif + Setattr(firstp, typemap_method_name(tmap_method), s); /* Code object */ + + if (locals) { + sprintf(temp, "%s:locals", cmethod); + Setattr(firstp, typemap_method_name(temp), locals); + Delete(locals); + } + + /* Attach a link to the next parameter. Needed for multimaps */ + sprintf(temp, "%s:next", cmethod); + Setattr(firstp, typemap_method_name(temp), p); + + /* Attach kwargs */ + typemap_attach_kwargs(tm, tmap_method, firstp, nmatch); + + /* Replace the argument number */ + sprintf(temp, "%d", argnum); + Replace(s, "$argnum", temp, DOH_REPLACE_ANY); + + /* Print warnings, if any */ + warning = typemap_warn(tmap_method, firstp); + if (warning) { + SwigType *type = Getattr(firstp, "type"); + String *pname = Getattr(firstp, "name"); + String *lname = Getattr(firstp, "lname"); + SwigType *mtype = Getattr(firstp, "tmap:match"); + SwigType *matchtype = mtype ? mtype : type; + typemap_replace_vars(warning, 0, matchtype, type, pname, lname, 1); + Replace(warning, "$argnum", temp, DOH_REPLACE_ANY); + Swig_warning(0, Getfile(firstp), Getline(firstp), "%s\n", warning); + Delete(warning); + } + + /* Look for code fragments */ + typemap_emit_code_fragments(tmap_method, firstp); + + /* increase argnum to consider numinputs */ + argnum += nmatch - 1; + Delete(s); +#ifdef SWIG_DEBUG + Printf(stdout, "res: %s %s %s\n", Getattr(firstp, "name"), typemap_method_name(tmap_method), Getattr(firstp, typemap_method_name(tmap_method))); +#endif + + } +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_typemap_attach_parms: end\n"); +#endif + +} + +/* Splits the arguments of an embedded typemap */ +static List *split_embedded_typemap(String *s) { + List *args = 0; + char *c, *start; + int level = 0; + int angle_level = 0; + int leading = 1; + + args = NewList(); + c = strchr(Char(s), '('); + assert(c); + c++; + + start = c; + while (*c) { + if (*c == '\"') { + c++; + while (*c) { + if (*c == '\\') { + c++; + } else { + if (*c == '\"') + break; + } + c++; + } + } + if ((level == 0) && angle_level == 0 && ((*c == ',') || (*c == ')'))) { + String *tmp = NewStringWithSize(start, (int)(c - start)); + Append(args, tmp); + Delete(tmp); + start = c + 1; + leading = 1; + if (*c == ')') + break; + c++; + continue; + } + if (*c == '(') + level++; + if (*c == ')') + level--; + if (*c == '<') + angle_level++; + if (*c == '>') + angle_level--; + if (isspace((int) *c) && leading) + start++; + if (!isspace((int) *c)) + leading = 0; + c++; + } + return args; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_replace_embedded_typemap() + * + * For special variable macro $typemap(...) expansion outside of typemaps. + * Only limited usage works as most typemap special variables ($1, $input etc) + * are not expanded correctly outside of typemaps. + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_replace_embedded_typemap(String *s, Node *file_line_node) { + Setfile(s, Getfile(file_line_node)); + Setline(s, Getline(file_line_node)); + Replaceall(s, "$typemap", "$TYPEMAP"); + replace_embedded_typemap(s, 0, 0, file_line_node); +} + +/* ----------------------------------------------------------------------------- + * replace_embedded_typemap() + * + * This function replaces the special variable macro $typemap(...) with typemap + * code. The general form of $typemap is as follows: + * + * $typemap(method, typelist, var1=value, var2=value, ...) + * + * where varx parameters are optional and undocumented; they were used in an earlier version of $typemap. + * A search is made using the typemap matching rules of form: + * + * %typemap(method) typelist {...} + * + * and if found will substitute in the typemap contents, making appropriate variable replacements. + * + * For example: + * $typemap(in, int) # simple usage matching %typemap(in) int { ... } + * $typemap(in, int b) # simple usage matching %typemap(in) int b { ... } or above %typemap + * $typemap(in, (Foo<int, bool> a, int b)) # multi-argument typemap matching %typemap(in) (Foo<int, bool> a, int b) {...} + * ----------------------------------------------------------------------------- */ + +static void replace_embedded_typemap(String *s, ParmList *parm_sublist, Wrapper *f, Node *file_line_node) { + char *start = 0; + while ((start = strstr(Char(s), "$TYPEMAP("))) { /* note $typemap capitalisation to $TYPEMAP hack */ + + /* Gather the parameters */ + char *end = 0, *c; + int level = 0; + String *dollar_typemap; + int syntax_error = 1; + c = start; + while (*c) { + if (*c == '(') + level++; + if (*c == ')') { + level--; + if (level == 0) { + end = c + 1; + break; + } + } + c++; + } + if (end) { + dollar_typemap = NewStringWithSize(start, (int)((end - start))); + syntax_error = 0; + } else { + dollar_typemap = NewStringWithSize(start, (int)((c - start))); + } + + if (!syntax_error) { + List *l; + String *tmap_method; + Hash *vars; + syntax_error = 1; + + /* Split apart each parameter in $typemap(...) */ + l = split_embedded_typemap(dollar_typemap); + + if (Len(l) >= 2) { + ParmList *to_match_parms; + tmap_method = Getitem(l, 0); + + /* the second parameter might contain multiple sub-parameters for multi-argument + * typemap matching, so split these parameters apart */ + to_match_parms = Swig_cparse_parms(Getitem(l, 1), file_line_node); + if (to_match_parms) { + Parm *p = to_match_parms; + Parm *sub_p = parm_sublist; + String *empty_string = NewStringEmpty(); + String *lname = empty_string; + while (p) { + if (sub_p) { + lname = Getattr(sub_p, "lname"); + sub_p = nextSibling(sub_p); + } + Setattr(p, "lname", lname); + p = nextSibling(p); + } + Delete(empty_string); + } + + /* process optional extra parameters - the variable replacements (undocumented) */ + vars = NewHash(); + { + int i, ilen; + ilen = Len(l); + for (i = 2; i < ilen; i++) { + String *parm = Getitem(l, i); + char *eq = strchr(Char(parm), '='); + char *c = Char(parm); + if (eq && (eq - c > 0)) { + String *name = NewStringWithSize(c, (int)(eq - c)); + String *value = NewString(eq + 1); + Insert(name, 0, "$"); + Setattr(vars, name, value); + } else { + to_match_parms = 0; /* error - variable replacement parameters must be of form varname=value */ + } + } + } + + /* Perform a typemap search */ + if (to_match_parms) { + static int already_substituting = 0; + String *tm; + String *attr; + int match = 0; +#ifdef SWIG_DEBUG + Printf(stdout, "Swig_typemap_attach_parms: embedded\n"); +#endif + if (already_substituting < 10) { + char* found_colon; + already_substituting++; + if ((in_typemap_search_multi == 0) && typemap_search_debug) { + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Printf(stdout, " Containing: %s\n", dtypemap); + Delete(dtypemap); + } + found_colon = Strchr(tmap_method, ':'); + if (found_colon) { + /* Substitute from a keyword argument to a typemap. Avoid emitting local variables from the attached typemap by passing NULL for the file. */ + String *temp_tmap_method = NewStringWithSize(Char(tmap_method), (int)(found_colon - Char(tmap_method))); + Swig_typemap_attach_parms(temp_tmap_method, to_match_parms, NULL); + Delete(temp_tmap_method); + } else { + Swig_typemap_attach_parms(tmap_method, to_match_parms, f); + } + already_substituting--; + + /* Look for the typemap code */ + attr = NewStringf("tmap:%s", tmap_method); + tm = Getattr(to_match_parms, attr); + if (tm) { + Printf(attr, "%s", ":next"); + /* fail if multi-argument lookup requested in $typemap(...) and the lookup failed */ + if (!Getattr(to_match_parms, attr)) { + /* Replace parameter variables */ + Iterator ki; + for (ki = First(vars); ki.key; ki = Next(ki)) { + Replace(tm, ki.key, ki.item, DOH_REPLACE_ANY); + } + /* offer the target language module the chance to make special variable substitutions */ + Language_replace_special_variables(tmap_method, tm, to_match_parms); + /* finish up - do the substitution */ + Replace(s, dollar_typemap, tm, DOH_REPLACE_ANY); + Delete(tm); + match = 1; + } + } + + if (!match) { + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Swig_error(Getfile(s), Getline(s), "No typemap found for %s\n", dtypemap); + Delete(dtypemap); + } + Delete(attr); + } else { + /* Simple recursive call check to prevent infinite recursion - this strategy only allows a limited + * number of calls by a embedded typemaps to other embedded typemaps though */ + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Swig_error(Getfile(s), Getline(s), "Likely recursive $typemap calls containing %s. Use -debug-tmsearch to debug.\n", dtypemap); + Delete(dtypemap); + } + syntax_error = 0; + } + Delete(vars); + } + Delete(l); + } + + if (syntax_error) { + String *dtypemap = NewString(dollar_typemap); + Replaceall(dtypemap, "$TYPEMAP", "$typemap"); + Swig_error(Getfile(s), Getline(s), "Syntax error in: %s\n", dtypemap); + Delete(dtypemap); + } + Replace(s, dollar_typemap, "<error in embedded typemap>", DOH_REPLACE_ANY); + Delete(dollar_typemap); + } +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_debug() + * + * Display all typemaps + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_debug(void) { + int nesting_level = 2; + Printf(stdout, "---[ typemaps ]--------------------------------------------------------------\n"); + Swig_print(typemaps, nesting_level); + Printf(stdout, "-----------------------------------------------------------------------------\n"); +} + + +/* ----------------------------------------------------------------------------- + * Swig_typemap_search_debug_set() + * + * Turn on typemap searching debug display + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_search_debug_set(void) { + typemap_search_debug = 1; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_used_debug_set() + * + * Turn on typemaps used debug display + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_used_debug_set(void) { + typemaps_used_debug = 1; +} + +/* ----------------------------------------------------------------------------- + * Swig_typemap_register_debug_set() + * + * Turn on typemaps used debug display + * ----------------------------------------------------------------------------- */ + +void Swig_typemap_register_debug_set(void) { + typemap_register_debug = 1; +} + diff --git a/contrib/tools/swig/Source/Swig/typeobj.c b/contrib/tools/swig/Source/Swig/typeobj.c new file mode 100644 index 0000000000..8cd2e28e98 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/typeobj.c @@ -0,0 +1,1367 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * typeobj.c + * + * This file provides functions for constructing, manipulating, and testing + * type objects. Type objects are merely the raw low-level representation + * of C++ types. They do not incorporate high-level type system features + * like typedef, namespaces, etc. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include <ctype.h> +#include <limits.h> + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * This file provides a collection of low-level functions for constructing and + * manipulating C++ data types. In SWIG, C++ datatypes are encoded as simple + * text strings. This representation is compact, easy to debug, and easy to read. + * + * General idea: + * + * Types are represented by a base type (e.g., "int") and a collection of + * type operators applied to the base (e.g., pointers, arrays, etc...). + * + * Encoding: + * + * Types are encoded as strings of type constructors such as follows: + * + * String Encoding C Example + * --------------- --------- + * p.p.int int ** + * a(300).a(400).int int [300][400] + * p.q(const).char char const * + * + * All type constructors are denoted by a trailing '.': + * + * 'p.' = Pointer (*) + * 'r.' = Reference or ref-qualifier (&) + * 'z.' = Rvalue reference or ref-qualifier (&&) + * 'a(n).' = Array of size n [n] + * 'f(..,..).' = Function with arguments (args) + * 'q(str).' = Qualifier, such as const or volatile (cv-qualifier) + * 'm(cls).' = Pointer to member (cls::*) + * + * The complete type representation for varargs is: + * 'v(...)' + * + * The encoding follows the order that you might describe a type in words. + * For example "p.a(200).int" is "A pointer to array of int's" and + * "p.q(const).char" is "a pointer to a const char". + * + * This representation of types is fairly convenient because ordinary string + * operations can be used for type manipulation. For example, a type could be + * formed by combining two strings such as the following: + * + * "p.p." + "a(400).int" = "p.p.a(400).int" + * + * For C++, typenames may be parameterized using <(...)>. Here are some + * examples: + * + * String Encoding C++ Example + * --------------- ------------ + * p.vector<(int)> vector<int> * + * r.foo<(int,p.double)> foo<int,double *> & + * + * Contents of this file: + * + * Most of this functions in this file pertain to the low-level manipulation + * of type objects. There are constructor functions like this: + * + * SwigType_add_pointer() + * SwigType_add_reference() + * SwigType_add_rvalue_reference() + * SwigType_add_array() + * + * These are used to build new types. There are also functions to undo these + * operations. For example: + * + * SwigType_del_pointer() + * SwigType_del_reference() + * SwigType_del_rvalue_reference() + * SwigType_del_array() + * + * In addition, there are query functions + * + * SwigType_ispointer() + * SwigType_isreference() + * SwigType_isrvalue_reference() + * SwigType_isarray() + * + * Finally, there are some data extraction functions that can be used to + * extract array dimensions, template arguments, and so forth. + * + * It is very important for developers to realize that the functions in this + * module do *NOT* incorporate higher-level type system features like typedef. + * For example, you could have C code like this: + * + * typedef int *intptr; + * + * In this case, a SwigType of type 'intptr' will be treated as a simple type and + * functions like SwigType_ispointer() will evaluate as false. It is strongly + * advised that developers use the TypeSys_* interface to check types in a more + * reliable manner. + * ----------------------------------------------------------------------------- */ + + +/* ----------------------------------------------------------------------------- + * NewSwigType() + * + * Constructs a new type object. Eventually, it would be nice for this function + * to accept an initial value in the form a C/C++ abstract type (currently unimplemented). + * ----------------------------------------------------------------------------- */ + +#ifdef NEW +SwigType *NewSwigType(const_String_or_char_ptr initial) { + return NewString(initial); +} + +#endif + +/* The next few functions are utility functions used in the construction and + management of types */ + +/* ----------------------------------------------------------------------------- + * static element_size() + * + * This utility function finds the size of a single type element in a type string. + * Type elements are always delimited by periods, but may be nested with + * parentheses. A nested element is always handled as a single item. + * + * Returns the integer size of the element (which can be used to extract a + * substring, to chop the element off, or for other purposes). + * ----------------------------------------------------------------------------- */ + +static int element_size(char *c) { + int nparen; + char *s = c; + while (*c) { + if (*c == '.') { + c++; + return (int) (c - s); + } else if (*c == '(') { + nparen = 1; + c++; + while (*c) { + if (*c == '(') + nparen++; + if (*c == ')') { + nparen--; + if (nparen == 0) + break; + } + c++; + } + } + if (*c) + c++; + } + return (int) (c - s); +} + +/* ----------------------------------------------------------------------------- + * SwigType_del_element() + * + * Deletes one type element from the type. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_del_element(SwigType *t) { + int sz = element_size(Char(t)); + Delslice(t, 0, sz); + return t; +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop() + * + * Pop one type element off the type. + * For example: + * t in: q(const).p.Integer + * t out: p.Integer + * result: q(const). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_pop(SwigType *t) { + SwigType *result; + char *c; + int sz; + + c = Char(t); + if (!*c) + return 0; + + sz = element_size(c); + result = NewStringWithSize(c, sz); + Delslice(t, 0, sz); + c = Char(t); + if (*c == '.') { + Delitem(t, 0); + } + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_last() + * + * Return the last element of the given (partial) type. + * For example: + * t: q(const).p. + * result: p. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_last(SwigType *t) { + SwigType *result; + char *c; + char *last; + int sz = 0; + + if (!t) + return 0; + + /* Find the last element */ + c = Char(t); + last = 0; + while (*c) { + last = c; + sz = element_size(c); + c = c + sz; + if (*c == '.') { + c++; + sz++; + } + } + + /* Extract the last element */ + if (last) { + result = NewStringWithSize(last, sz); + } else { + result = 0; + } + + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_parm() + * + * Returns the parameter of an operator as a string + * ----------------------------------------------------------------------------- */ + +String *SwigType_parm(const SwigType *t) { + char *start, *c; + int nparens = 0; + + c = Char(t); + while (*c && (*c != '(') && (*c != '.')) + c++; + if (!*c || (*c == '.')) + return 0; + c++; + start = c; + while (*c) { + if (*c == ')') { + if (nparens == 0) + break; + nparens--; + } else if (*c == '(') { + nparens++; + } + c++; + } + return NewStringWithSize(start, (int) (c - start)); +} + +/* ----------------------------------------------------------------------------- + * SwigType_split() + * + * Splits a type into its component parts and returns a list of string. + * ----------------------------------------------------------------------------- */ + +List *SwigType_split(const SwigType *t) { + String *item; + List *list; + char *c; + int len; + + c = Char(t); + list = NewList(); + while (*c) { + len = element_size(c); + item = NewStringWithSize(c, len); + Append(list, item); + Delete(item); + c = c + len; + if (*c == '.') + c++; + } + return list; +} + +/* ----------------------------------------------------------------------------- + * SwigType_parmlist() + * + * Splits a comma separated list of parameters into its component parts + * The input is expected to contain the parameter list within () brackets + * Returns 0 if no argument list in the input, ie there are no round brackets () + * Returns an empty List if there are no parameters in the () brackets + * For example: + * + * Foo(std::string,p.f().Bar<(int,double)>) + * + * returns 2 elements in the list: + * std::string + * p.f().Bar<(int,double)> + * ----------------------------------------------------------------------------- */ + +List *SwigType_parmlist(const String *p) { + String *item = 0; + List *list; + char *c; + char *itemstart; + int size; + + assert(p); + c = Char(p); + while (*c && (*c != '(') && (*c != '.')) + c++; + if (!*c) + return 0; + assert(*c != '.'); /* p is expected to contain sub elements of a type */ + c++; + list = NewList(); + itemstart = c; + while (*c) { + if (*c == ',') { + size = (int) (c - itemstart); + item = NewStringWithSize(itemstart, size); + Append(list, item); + Delete(item); + itemstart = c + 1; + } else if (*c == '(') { + int nparens = 1; + c++; + while (*c) { + if (*c == '(') + nparens++; + if (*c == ')') { + nparens--; + if (nparens == 0) + break; + } + c++; + } + } else if (*c == ')') { + break; + } + if (*c) + c++; + } + size = (int) (c - itemstart); + if (size > 0) { + item = NewStringWithSize(itemstart, size); + Append(list, item); + } + Delete(item); + return list; +} + +/* ----------------------------------------------------------------------------- + * Pointers + * + * SwigType_add_pointer() + * SwigType_del_pointer() + * SwigType_ispointer() + * + * Add, remove, and test if a type is a pointer. The deletion and query + * functions take into account qualifiers (if any). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_pointer(SwigType *t) { + Insert(t, 0, "p."); + return t; +} + +SwigType *SwigType_del_pointer(SwigType *t) { + char *c, *s; + c = Char(t); + s = c; + /* Skip qualifiers, if any */ + if (strncmp(c, "q(", 2) == 0) { + c = strchr(c, '.'); + assert(c); + c++; + } + if (strncmp(c, "p.", 2)) { + printf("Fatal error: SwigType_del_pointer applied to non-pointer.\n"); + Exit(EXIT_FAILURE); + } + Delslice(t, 0, (int)((c - s) + 2)); + return t; +} + +int SwigType_ispointer(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + /* Skip qualifiers, if any */ + if (strncmp(c, "q(", 2) == 0) { + c = strchr(c, '.'); + if (!c) + return 0; + c++; + } + if (strncmp(c, "p.", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * References + * + * SwigType_add_reference() + * SwigType_del_reference() + * SwigType_isreference() + * + * Add, remove, and test if a type is a reference. The deletion and query + * functions take into account qualifiers (if any). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_reference(SwigType *t) { + Insert(t, 0, "r."); + return t; +} + +SwigType *SwigType_del_reference(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "r.", 2)) { + printf("Fatal error: SwigType_del_reference applied to non-reference.\n"); + Exit(EXIT_FAILURE); + } + Delslice(t, 0, 2); + return t; +} + +int SwigType_isreference(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "r.", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Rvalue References + * + * SwigType_add_rvalue_reference() + * SwigType_del_rvalue_reference() + * SwigType_isrvalue_reference() + * + * Add, remove, and test if a type is a rvalue reference. The deletion and query + * functions take into account qualifiers (if any). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_rvalue_reference(SwigType *t) { + Insert(t, 0, "z."); + return t; +} + +SwigType *SwigType_del_rvalue_reference(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "z.", 2)) { + fprintf(stderr, "Fatal error: SwigType_del_rvalue_reference() applied to non-rvalue-reference.\n"); + Exit(EXIT_FAILURE); + } + Delslice(t, 0, 2); + return t; +} + +int SwigType_isrvalue_reference(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "z.", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Qualifiers + * + * SwigType_add_qualifier() + * SwigType_del_qualifier() + * SwigType_is_qualifier() + * + * Adds type qualifiers like "const" and "volatile". When multiple qualifiers + * are added to a type, they are combined together into a single qualifier. + * Repeated qualifications have no effect. Moreover, the order of qualifications + * is alphabetical---meaning that "const volatile" and "volatile const" are + * stored in exactly the same way as "q(const volatile)". + * 'qual' can be a list of multiple qualifiers in any order, separated by spaces. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_qualifier(SwigType *t, const_String_or_char_ptr qual) { + List *qlist; + String *allq, *newq; + int i, sz; + const char *cqprev = 0; + const char *c = Char(t); + const char *cqual = Char(qual); + + /* if 't' has no qualifiers and 'qual' is a single qualifier, simply add it */ + if ((strncmp(c, "q(", 2) != 0) && (strstr(cqual, " ") == 0)) { + String *temp = NewStringf("q(%s).", cqual); + Insert(t, 0, temp); + Delete(temp); + return t; + } + + /* create string of all qualifiers */ + if (strncmp(c, "q(", 2) == 0) { + allq = SwigType_parm(t); + Append(allq, " "); + SwigType_del_element(t); /* delete old qualifier list from 't' */ + } else { + allq = NewStringEmpty(); + } + Append(allq, qual); + + /* create list of all qualifiers from string */ + qlist = Split(allq, ' ', INT_MAX); + Delete(allq); + + /* sort in alphabetical order */ + SortList(qlist, Strcmp); + + /* create new qualifier string from unique elements of list */ + sz = Len(qlist); + newq = NewString("q("); + for (i = 0; i < sz; ++i) { + String *q = Getitem(qlist, i); + const char *cq = Char(q); + if (cqprev == 0 || strcmp(cqprev, cq) != 0) { + if (i > 0) { + Append(newq, " "); + } + Append(newq, q); + cqprev = cq; + } + } + Append(newq, ")."); + Delete(qlist); + + /* replace qualifier string with new one */ + Insert(t, 0, newq); + Delete(newq); + return t; +} + +SwigType *SwigType_del_qualifier(SwigType *t) { + char *c = Char(t); + int check = strncmp(c, "q(", 2); + assert(check == 0); + (void)check; + Delslice(t, 0, element_size(c)); + return t; +} + +int SwigType_isqualifier(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "q(", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Function Pointers + * ----------------------------------------------------------------------------- */ + +int SwigType_isfunctionpointer(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "p.f(", 4) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_functionpointer_decompose + * + * Decompose the function pointer into the parameter list and the return type + * t - input and on completion contains the return type + * returns the function's parameters + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_functionpointer_decompose(SwigType *t) { + String *p; + assert(SwigType_isfunctionpointer(t)); + p = SwigType_pop(t); + Delete(p); + p = SwigType_pop(t); + return p; +} + +/* ----------------------------------------------------------------------------- + * Member Pointers + * + * SwigType_add_memberpointer() + * SwigType_del_memberpointer() + * SwigType_ismemberpointer() + * + * Add, remove, and test for C++ pointer to members. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_memberpointer(SwigType *t, const_String_or_char_ptr name) { + String *temp = NewStringf("m(%s).", name); + Insert(t, 0, temp); + Delete(temp); + return t; +} + +SwigType *SwigType_del_memberpointer(SwigType *t) { + char *c = Char(t); + int check = strncmp(c, "m(", 2); + assert(check == 0); + (void)check; + Delslice(t, 0, element_size(c)); + return t; +} + +int SwigType_ismemberpointer(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "m(", 2) == 0) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Arrays + * + * SwigType_add_array() + * SwigType_del_array() + * SwigType_isarray() + * + * Utility functions: + * + * SwigType_array_ndim() - Calculate number of array dimensions. + * SwigType_array_getdim() - Get array dimension + * SwigType_array_setdim() - Set array dimension + * SwigType_array_type() - Return array type + * SwigType_pop_arrays() - Remove all arrays + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_array(SwigType *t, const_String_or_char_ptr size) { + String *temp = NewString("a("); + Append(temp, size); + Append(temp, ")."); + Insert(t, 0, temp); + Delete(temp); + return t; +} + +SwigType *SwigType_del_array(SwigType *t) { + char *c = Char(t); + if (strncmp(c, "a(", 2)) { + fprintf(stderr, "Fatal error: SwigType_del_array() applied to non-array.\n"); + Exit(EXIT_FAILURE); + } + Delslice(t, 0, element_size(c)); + return t; +} + +int SwigType_isarray(const SwigType *t) { + char *c; + if (!t) + return 0; + c = Char(t); + if (strncmp(c, "a(", 2) == 0) { + return 1; + } + return 0; +} +/* + * SwigType_prefix_is_simple_1D_array + * + * Determine if the type is a 1D array type that is treated as a pointer within SWIG + * eg Foo[], Foo[3] return true, but Foo[3][3], Foo*[], Foo*[3], Foo**[] return false + */ +int SwigType_prefix_is_simple_1D_array(const SwigType *t) { + char *c = Char(t); + + if (c && (strncmp(c, "a(", 2) == 0)) { + c = strchr(c, '.'); + if (c) + return (*(++c) == 0); + } + return 0; +} + + +/* Remove all arrays */ +SwigType *SwigType_pop_arrays(SwigType *t) { + String *ta; + assert(SwigType_isarray(t)); + ta = NewStringEmpty(); + while (SwigType_isarray(t)) { + SwigType *td = SwigType_pop(t); + Append(ta, td); + Delete(td); + } + return ta; +} + +/* Return number of array dimensions */ +int SwigType_array_ndim(const SwigType *t) { + int ndim = 0; + char *c = Char(t); + + while (c && (strncmp(c, "a(", 2) == 0)) { + c = strchr(c, '.'); + if (c) { + c++; + ndim++; + } + } + return ndim; +} + +/* Get nth array dimension */ +String *SwigType_array_getdim(const SwigType *t, int n) { + char *c = Char(t); + while (c && (strncmp(c, "a(", 2) == 0) && (n > 0)) { + c = strchr(c, '.'); + if (c) { + c++; + n--; + } + } + if (n == 0) { + String *dim = SwigType_parm(c); + if (SwigType_istemplate(dim)) { + String *ndim = SwigType_namestr(dim); + Delete(dim); + dim = ndim; + } + + return dim; + } + + return 0; +} + +/* Replace nth array dimension */ +void SwigType_array_setdim(SwigType *t, int n, const_String_or_char_ptr rep) { + String *result = 0; + char temp; + char *start; + char *c = Char(t); + + start = c; + if (strncmp(c, "a(", 2)) { + fprintf(stderr, "Fatal error: SwigType_array_type applied to non-array.\n"); + Exit(EXIT_FAILURE); + } + + while (c && (strncmp(c, "a(", 2) == 0) && (n > 0)) { + c = strchr(c, '.'); + if (c) { + c++; + n--; + } + } + if (n == 0) { + temp = *c; + *c = 0; + result = NewString(start); + Printf(result, "a(%s)", rep); + *c = temp; + c = strchr(c, '.'); + Append(result, c); + } + Clear(t); + Append(t, result); + Delete(result); +} + +/* Return base type of an array */ +SwigType *SwigType_array_type(const SwigType *ty) { + SwigType *t; + t = Copy(ty); + while (SwigType_isarray(t)) { + Delete(SwigType_pop(t)); + } + return t; +} + + +/* ----------------------------------------------------------------------------- + * Functions + * + * SwigType_add_function() + * SwigType_isfunction() + * SwigType_pop_function() + * + * Add, remove, and test for function types. + * ----------------------------------------------------------------------------- */ + +/* Returns the function type, t, constructed from the parameters, parms */ +SwigType *SwigType_add_function(SwigType *t, ParmList *parms) { + String *pstr; + Parm *p; + + Insert(t, 0, ")."); + pstr = NewString("f("); + for (p = parms; p; p = nextSibling(p)) { + if (p != parms) + Putc(',', pstr); + Append(pstr, Getattr(p, "type")); + } + Insert(t, 0, pstr); + Delete(pstr); + return t; +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop_function() + * + * Pop and return the function from the input type leaving the function's return + * type, if any. + * For example: + * t in: q(const).f().p. + * t out: p. + * result: q(const).f(). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_pop_function(SwigType *t) { + SwigType *f = 0; + SwigType *g = 0; + char *c = Char(t); + if (strncmp(c, "r.", 2) == 0 || strncmp(c, "z.", 2) == 0) { + /* Remove ref-qualifier */ + f = SwigType_pop(t); + c = Char(t); + } + if (strncmp(c, "q(", 2) == 0) { + /* Remove cv-qualifier */ + String *qual = SwigType_pop(t); + if (f) { + SwigType_push(qual, f); + Delete(f); + } + f = qual; + c = Char(t); + } + if (strncmp(c, "f(", 2)) { + fprintf(stderr, "Fatal error. SwigType_pop_function applied to non-function.\n"); + Exit(EXIT_FAILURE); + } + g = SwigType_pop(t); + if (f) + SwigType_push(g, f); + Delete(f); + return g; +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop_function_qualifiers() + * + * Pop and return the function qualifiers from the input type leaving the rest of + * function declaration. Returns NULL if no qualifiers. + * For example: + * t in: r.q(const).f().p. + * t out: f().p. + * result: r.q(const) + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_pop_function_qualifiers(SwigType *t) { + SwigType *qualifiers = 0; + char *c = Char(t); + if (strncmp(c, "r.", 2) == 0 || strncmp(c, "z.", 2) == 0) { + /* Remove ref-qualifier */ + String *qual = SwigType_pop(t); + qualifiers = qual; + c = Char(t); + } + if (strncmp(c, "q(", 2) == 0) { + /* Remove cv-qualifier */ + String *qual = SwigType_pop(t); + if (qualifiers) { + SwigType_push(qual, qualifiers); + Delete(qualifiers); + } + qualifiers = qual; + } + assert(Strncmp(t, "f(", 2) == 0); + + return qualifiers; +} + +int SwigType_isfunction(const SwigType *t) { + char *c; + if (!t) { + return 0; + } + c = Char(t); + if (strncmp(c, "r.", 2) == 0 || strncmp(c, "z.", 2) == 0) { + /* Might be a function with a ref-qualifier, skip over */ + c += 2; + if (!*c) + return 0; + } + if (strncmp(c, "q(", 2) == 0) { + /* Might be a function with a cv-qualifier, skip over */ + c = strchr(c, '.'); + if (c) + c++; + else + return 0; + } + if (strncmp(c, "f(", 2) == 0) { + return 1; + } + return 0; +} + +/* Create a list of parameters from the type t, using the file_line_node Node for + * file and line numbering for the parameters */ +ParmList *SwigType_function_parms(const SwigType *t, Node *file_line_node) { + List *l = SwigType_parmlist(t); + Hash *p, *pp = 0, *firstp = 0; + Iterator o; + + for (o = First(l); o.item; o = Next(o)) { + p = file_line_node ? NewParm(o.item, 0, file_line_node) : NewParmWithoutFileLineInfo(o.item, 0); + if (!firstp) + firstp = p; + if (pp) { + set_nextSibling(pp, p); + Delete(p); + } + pp = p; + } + Delete(l); + return firstp; +} + +int SwigType_isvarargs(const SwigType *t) { + if (Strcmp(t, "v(...)") == 0) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * Templates + * + * SwigType_add_template() + * + * Template handling. + * ----------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * SwigType_add_template() + * + * Adds a template to a type. This template is encoded in the SWIG type + * mechanism and produces a string like this: + * + * vector<int *> ----> "vector<(p.int)>" + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_add_template(SwigType *t, ParmList *parms) { + Parm *p; + + Append(t, "<("); + for (p = parms; p; p = nextSibling(p)) { + String *v; + if (Getattr(p, "default")) + continue; + if (p != parms) + Append(t, ","); + v = Getattr(p, "value"); + if (v) { + Append(t, v); + } else { + Append(t, Getattr(p, "type")); + } + } + Append(t, ")>"); + return t; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_templateprefix() + * + * Returns the prefix before the first template definition. + * Returns the type unmodified if not a template. + * For example: + * + * Foo<(p.int)>::bar => Foo + * r.q(const).Foo<(p.int)>::bar => r.q(const).Foo + * Foo => Foo + * ----------------------------------------------------------------------------- */ + +String *SwigType_templateprefix(const SwigType *t) { + const char *s = Char(t); + const char *c = strstr(s, "<("); + return c ? NewStringWithSize(s, (int)(c - s)) : NewString(s); +} + +/* ----------------------------------------------------------------------------- + * SwigType_templatesuffix() + * + * Returns text after a template substitution. Used to handle scope names + * for example: + * + * Foo<(p.int)>::bar + * + * returns "::bar" + * ----------------------------------------------------------------------------- */ + +String *SwigType_templatesuffix(const SwigType *t) { + const char *c; + c = Char(t); + while (*c) { + if ((*c == '<') && (*(c + 1) == '(')) { + int nest = 1; + c++; + while (*c && nest) { + if (*c == '<') + nest++; + if (*c == '>') + nest--; + c++; + } + return NewString(c); + } + c++; + } + return NewStringEmpty(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_istemplate_templateprefix() + * + * Combines SwigType_istemplate and SwigType_templateprefix efficiently into one function. + * Returns the prefix before the first template definition. + * Returns NULL if not a template. + * For example: + * + * Foo<(p.int)>::bar => Foo + * r.q(const).Foo<(p.int)>::bar => r.q(const).Foo + * Foo => NULL + * ----------------------------------------------------------------------------- */ + +String *SwigType_istemplate_templateprefix(const SwigType *t) { + const char *s = Char(t); + const char *c = strstr(s, "<("); + return c ? NewStringWithSize(s, (int)(c - s)) : 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_istemplate_only_templateprefix() + * + * Similar to SwigType_istemplate_templateprefix() but only returns the template + * prefix if the type is just the template and not a subtype/symbol within the template. + * Returns NULL if not a template or is a template with a symbol within the template. + * For example: + * + * Foo<(p.int)> => Foo + * Foo<(p.int)>::bar => NULL + * r.q(const).Foo<(p.int)> => r.q(const).Foo + * r.q(const).Foo<(p.int)>::bar => NULL + * Foo => NULL + * ----------------------------------------------------------------------------- */ + +String *SwigType_istemplate_only_templateprefix(const SwigType *t) { + int len = Len(t); + const char *s = Char(t); + if (len >= 4 && strcmp(s + len - 2, ")>") == 0) { + const char *c = strstr(s, "<("); + return c ? NewStringWithSize(s, (int)(c - s)) : 0; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * SwigType_templateargs() + * + * Returns the template arguments + * For example: + * + * Foo<(p.int)>::bar + * + * returns "<(p.int)>" + * ----------------------------------------------------------------------------- */ + +String *SwigType_templateargs(const SwigType *t) { + const char *c; + const char *start; + c = Char(t); + while (*c) { + if ((*c == '<') && (*(c + 1) == '(')) { + int nest = 1; + start = c; + c++; + while (*c && nest) { + if (*c == '<') + nest++; + if (*c == '>') + nest--; + c++; + } + return NewStringWithSize(start, (int)(c - start)); + } + c++; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_istemplate() + * + * Tests a type to see if it includes template parameters + * ----------------------------------------------------------------------------- */ + +int SwigType_istemplate(const SwigType *t) { + char *ct = Char(t); + ct = strstr(ct, "<("); + if (ct && (strstr(ct + 2, ")>"))) + return 1; + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_base() + * + * This function returns the base of a type. For example, if you have a + * type "p.p.int", the function would return "int". + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_base(const SwigType *t) { + char *c; + char *lastop = 0; + c = Char(t); + + lastop = c; + + /* Search for the last type constructor separator '.' */ + while (*c) { + if (*c == '.') { + if (*(c + 1)) { + lastop = c + 1; + } + c++; + continue; + } + if (*c == '<') { + /* Skip over template---it's part of the base name */ + int ntemp = 1; + c++; + while ((*c) && (ntemp > 0)) { + if (*c == '>') + ntemp--; + else if (*c == '<') + ntemp++; + c++; + } + if (ntemp) + break; + continue; + } + if (*c == '(') { + /* Skip over params */ + int nparen = 1; + c++; + while ((*c) && (nparen > 0)) { + if (*c == '(') + nparen++; + else if (*c == ')') + nparen--; + c++; + } + if (nparen) + break; + continue; + } + c++; + } + return NewString(lastop); +} + +/* ----------------------------------------------------------------------------- + * SwigType_prefix() + * + * Returns the prefix of a datatype. For example, the prefix of the + * type "p.p.int" is "p.p.". + * ----------------------------------------------------------------------------- */ + +String *SwigType_prefix(const SwigType *t) { + char *c, *d; + String *r = 0; + + c = Char(t); + d = c + strlen(c); + + /* Check for a type constructor */ + if ((d > c) && (*(d - 1) == '.')) + d--; + + while (d > c) { + d--; + if (*d == '>') { + int nest = 1; + d--; + while ((d > c) && (nest)) { + if (*d == '>') + nest++; + if (*d == '<') + nest--; + d--; + } + } + if (*d == ')') { + /* Skip over params */ + int nparen = 1; + d--; + while ((d > c) && (nparen)) { + if (*d == ')') + nparen++; + if (*d == '(') + nparen--; + d--; + } + } + + if (*d == '.') { + char t = *(d + 1); + *(d + 1) = 0; + r = NewString(c); + *(d + 1) = t; + return r; + } + } + return NewStringEmpty(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_strip_qualifiers() + * + * Strip all qualifiers from a type and return a new type + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_strip_qualifiers(const SwigType *t) { + static Hash *memoize_stripped = 0; + SwigType *r; + List *l; + Iterator ei; + + if (!memoize_stripped) + memoize_stripped = NewHash(); + r = Getattr(memoize_stripped, t); + if (r) + return Copy(r); + + l = SwigType_split(t); + r = NewStringEmpty(); + + for (ei = First(l); ei.item; ei = Next(ei)) { + if (SwigType_isqualifier(ei.item)) + continue; + Append(r, ei.item); + } + Delete(l); + { + String *key, *value; + key = Copy(t); + value = Copy(r); + Setattr(memoize_stripped, key, value); + Delete(key); + Delete(value); + } + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_strip_single_qualifier() + * + * If the type contains a qualifier, strip one qualifier and return a new type. + * The left most qualifier is stripped first (when viewed as C source code) but + * this is the equivalent to the right most qualifier using SwigType notation. + * Example: + * r.q(const).p.q(const).int => r.q(const).p.int + * r.q(const).p.int => r.p.int + * r.p.int => r.p.int + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_strip_single_qualifier(const SwigType *t) { + static Hash *memoize_stripped = 0; + SwigType *r = 0; + List *l; + int numitems; + + if (!memoize_stripped) + memoize_stripped = NewHash(); + r = Getattr(memoize_stripped, t); + if (r) + return Copy(r); + + l = SwigType_split(t); + + numitems = Len(l); + if (numitems >= 2) { + int item; + /* iterate backwards from last but one item */ + for (item = numitems - 2; item >= 0; --item) { + String *subtype = Getitem(l, item); + if (SwigType_isqualifier(subtype)) { + Iterator it; + Delitem(l, item); + r = NewStringEmpty(); + for (it = First(l); it.item; it = Next(it)) { + Append(r, it.item); + } + break; + } + } + } + if (!r) + r = Copy(t); + + Delete(l); + { + String *key, *value; + key = Copy(t); + value = Copy(r); + Setattr(memoize_stripped, key, value); + Delete(key); + Delete(value); + } + return r; +} + diff --git a/contrib/tools/swig/Source/Swig/typesys.c b/contrib/tools/swig/Source/Swig/typesys.c new file mode 100644 index 0000000000..4a11790c72 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/typesys.c @@ -0,0 +1,2309 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * typesys.c + * + * SWIG type system management. These functions are used to manage + * the C++ type system including typenames, typedef, type scopes, + * inheritance, and namespaces. Generation of support code for the + * run-time type checker is also handled here. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include "cparse.h" + +/* ----------------------------------------------------------------------------- + * Synopsis + * + * The purpose of this module is to manage type names and scoping issues related + * to the C++ type system. The primary use is tracking typenames through typedef + * and inheritance. + * + * New typenames are introduced by typedef, class, and enum declarations. + * Each type is declared in a scope. This is either the global scope, a + * class, or a namespace. For example: + * + * typedef int A; // Typename A, in global scope + * namespace Foo { + * typedef int A; // Typename A, in scope Foo:: + * } + * class Bar { // Typename Bar, in global scope + * typedef int A; // Typename A, in scope Bar:: + * } + * + * To manage scopes, the type system is constructed as a tree of hash tables. Each + * hash table contains the following attributes: + * + * "name" - Scope name + * "qname" - Fully qualified typename + * "typetab" - Type table containing typenames and typedef information + * For a given key in the typetab table, the value is a fully + * qualified name if not pointing to itself. + * "symtab" - Hash table of symbols defined in a scope + * "inherit" - List of inherited scopes + * "parent" - Parent scope + * + * The contents of these tables can be viewed for debugging using the -debug-typedef + * option which calls SwigType_print_scope(). + * + * Typedef information is stored in the "typetab" hash table. For example, + * if you have these declarations: + * + * typedef int A; + * typedef A B; + * typedef B *C; + * + * typetab in scope '' contains: + * "A" : "int" + * "B" : "A" + * "C" : "p.B" + * + * To resolve a type back to its root type, one repeatedly expands on the type base. + * For example: + * + * C *[40] ---> a(40).p.C (string type representation, see stype.c) + * ---> a(40).p.p.B (C --> p.B) + * ---> a(40).p.p.A (B --> A) + * ---> a(40).p.p.int (A --> int) + * + * + * Using declarations are stored in the "typetab" hash table. For example, + * + * namespace NN { + * struct SS {}; + * } + * namespace N { + * struct S {}; + * using NN::SS; + * } + * using N::S; + * + * typetab in scope '' contains: + * "S" : "N::S" + * + * and typetab in scope 'N' contains: + * "SS" : "NN::SS" + * "S" : "S" + * + * + * For inheritance, SWIG tries to resolve types back to the base class. For instance, if + * you have this: + * + * class Foo { + * public: + * typedef int Integer; + * }; + * struct Bar : public Foo { + * void blah(Integer x); + * }; + * + * In this case typetab in scope '' contains: + * "Foo" : "Foo" + * "Bar" : "Bar" + * and scope 'Foo' contains: + * "Integer" : "int" + * and scope 'Bar' inherits from 'Foo' but is empty (observe that blah is not a scope or typedef) + * + * The argument type of Bar::blah will be set to Foo::Integer. + * + * + * The scope-inheritance mechanism is used to manage C++ using directives. + * + * namespace XX { + * class CC {}; + * } + * namespace X { + * class C {}; + * using namespace XX; + * } + * using namespace X; + * + * typetab in scope '' inherits from 'X' + * typetab in scope 'X' inherits from 'XX' and contains: + * "C" : "C" + * typetab in scope 'XX' contains: + * "CC" : "CC" + * + * + * The scope-inheritance mechanism is used to manage C++ namespace aliases. + * For example, if you have this: + * + * namespace Foo { + * typedef int Integer; + * } + * + * namespace F = Foo; + * + * In this case, F is defined as a scope that "inherits" from Foo. Internally, + * F will merely be an empty scope that points to Foo. SWIG will never + * place new type information into a namespace alias---attempts to do so + * will generate a warning message (in the parser) and will place information into + * Foo instead. + * + *----------------------------------------------------------------------------- */ + +static Typetab *current_scope = 0; /* Current type scope */ +static Hash *current_typetab = 0; /* Current type table */ +static Hash *current_symtab = 0; /* Current symbol table */ +static Typetab *global_scope = 0; /* The global scope */ +static Hash *scopes = 0; /* Hash table containing fully qualified scopes */ + +/* Performance optimization */ +#define SWIG_TYPEDEF_RESOLVE_CACHE +static Hash *typedef_resolve_cache = 0; +static Hash *typedef_all_cache = 0; +static Hash *typedef_qualified_cache = 0; + +static Typetab *SwigType_find_scope(Typetab *s, const SwigType *nameprefix); + +/* common attribute keys, to avoid calling find_key all the times */ + +/* + Enable this one if your language fully support SwigValueWrapper<T>. + + Leaving at '0' keeps the old swig behavior, which is not + always safe, but is well known. + + Setting at '1' activates the new scheme, which is always safe but + it requires all the typemaps to be ready for that. + +*/ +static int value_wrapper_mode = 0; +int Swig_value_wrapper_mode(int mode) { + value_wrapper_mode = mode; + return mode; +} + + +static void flush_cache(void) { + typedef_resolve_cache = 0; + typedef_all_cache = 0; + typedef_qualified_cache = 0; +} + +/* Initialize the scoping system */ + +void SwigType_typesystem_init(void) { + if (global_scope) + Delete(global_scope); + if (scopes) + Delete(scopes); + + current_scope = NewHash(); + global_scope = current_scope; + + Setattr(current_scope, "name", ""); /* No name for global scope */ + current_typetab = NewHash(); + Setattr(current_scope, "typetab", current_typetab); + + current_symtab = 0; + scopes = NewHash(); + Setattr(scopes, "", current_scope); +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef() + * + * Defines a new typedef in the current scope. Returns -1 if the type name is + * already defined. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef(const SwigType *type, const_String_or_char_ptr name) { + /* Printf(stdout, "typedef %s %s\n", type, name); */ + if (Getattr(current_typetab, name)) + return -1; /* Already defined */ + if (Strcmp(type, name) == 0) { /* Can't typedef a name to itself */ + return 0; + } + + /* Check if 'type' is already a scope. If so, we create an alias in the type + system for it. This is needed to make strange nested scoping problems work + correctly. */ + { + Typetab *t = SwigType_find_scope(current_scope, type); + if (t) { + SwigType_new_scope(name); + SwigType_inherit_scope(t); + SwigType_pop_scope(); + } + } + Setattr(current_typetab, name, type); + flush_cache(); + return 0; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_class() + * + * Defines a class in the current scope. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef_class(const_String_or_char_ptr name) { + String *cname; + /* Printf(stdout,"class : '%s'\n", name); */ + if (Getattr(current_typetab, name)) + return -1; /* Already defined */ + cname = NewString(name); + Setmeta(cname, "class", "1"); + Setattr(current_typetab, cname, cname); + Delete(cname); + flush_cache(); + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_scope_name() + * + * Returns the qualified scope name of a type table + * ----------------------------------------------------------------------------- */ + +String *SwigType_scope_name(Typetab *ttab) { + String *qname = NewString(Getattr(ttab, "name")); + ttab = Getattr(ttab, "parent"); + while (ttab) { + String *pname = Getattr(ttab, "name"); + if (Len(pname)) { + Insert(qname, 0, "::"); + Insert(qname, 0, pname); + } + ttab = Getattr(ttab, "parent"); + } + return qname; +} + +/* ----------------------------------------------------------------------------- + * SwigType_new_scope() + * + * Creates a new scope + * ----------------------------------------------------------------------------- */ + +void SwigType_new_scope(const_String_or_char_ptr name) { + Typetab *s; + Hash *ttab; + String *qname; + + if (!name) { + name = "<unnamed>"; + } + s = NewHash(); + Setattr(s, "name", name); + Setattr(s, "parent", current_scope); + ttab = NewHash(); + Setattr(s, "typetab", ttab); + + /* Build fully qualified name */ + qname = SwigType_scope_name(s); +#if 1 + { + /* TODO: only do with templates? What happens with non-templates with code below? */ + String *stripped_qname; + stripped_qname = SwigType_remove_global_scope_prefix(qname); + /* Use fully qualified name for hash key without unary scope prefix, qname may contain unary scope */ + Setattr(scopes, stripped_qname, s); + Setattr(s, "qname", qname); + /* + Printf(stdout, "SwigType_new_scope stripped %s %s\n", qname, stripped_qname); + */ + Delete(stripped_qname); + } +#else + Printf(stdout, "SwigType_new_scope %s\n", qname); + Setattr(scopes, qname, s); + Setattr(s, "qname", qname); +#endif + Delete(qname); + + current_scope = s; + current_typetab = ttab; + current_symtab = 0; + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_inherit_scope() + * + * Makes the current scope inherit from another scope. This is used for both + * C++ class inheritance, namespaces, and namespace aliases. + * ----------------------------------------------------------------------------- */ + +void SwigType_inherit_scope(Typetab *scope) { + List *inherits; + int i, len; + inherits = Getattr(current_scope, "inherit"); + if (!inherits) { + inherits = NewList(); + Setattr(current_scope, "inherit", inherits); + Delete(inherits); + } + assert(scope != current_scope); + + len = Len(inherits); + for (i = 0; i < len; i++) { + Node *n = Getitem(inherits, i); + if (n == scope) + return; + } + Append(inherits, scope); +} + +/* ----------------------------------------------------------------------------- + * SwigType_scope_alias() + * + * Creates a scope-alias. + * ----------------------------------------------------------------------------- */ + +void SwigType_scope_alias(String *aliasname, Typetab *ttab) { + String *q; + /* Printf(stdout,"alias: '%s' '%p'\n", aliasname, ttab); */ + q = SwigType_scope_name(current_scope); + if (Len(q)) { + Append(q, "::"); + } + Append(q, aliasname); + Setattr(scopes, q, ttab); + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_using_scope() + * + * Import another scope into this scope. + * ----------------------------------------------------------------------------- */ + +void SwigType_using_scope(Typetab *scope) { + SwigType_inherit_scope(scope); + { + List *ulist; + int i, len; + ulist = Getattr(current_scope, "using"); + if (!ulist) { + ulist = NewList(); + Setattr(current_scope, "using", ulist); + Delete(ulist); + } + assert(scope != current_scope); + len = Len(ulist); + for (i = 0; i < len; i++) { + Typetab *n = Getitem(ulist, i); + if (n == scope) + return; + } + Append(ulist, scope); + } + flush_cache(); +} + +/* ----------------------------------------------------------------------------- + * SwigType_pop_scope() + * + * Pop off the last scope and perform a merge operation. Returns the hash + * table for the scope that was popped off. + * ----------------------------------------------------------------------------- */ + +Typetab *SwigType_pop_scope(void) { + Typetab *t, *old = current_scope; + t = Getattr(current_scope, "parent"); + if (!t) + t = global_scope; + current_scope = t; + current_typetab = Getattr(t, "typetab"); + current_symtab = Getattr(t, "symtab"); + flush_cache(); + return old; +} + +/* ----------------------------------------------------------------------------- + * SwigType_set_scope() + * + * Set the scope. Returns the old scope. + * ----------------------------------------------------------------------------- */ + +Typetab *SwigType_set_scope(Typetab *t) { + Typetab *old = current_scope; + if (!t) + t = global_scope; + current_scope = t; + current_typetab = Getattr(t, "typetab"); + current_symtab = Getattr(t, "symtab"); + flush_cache(); + return old; +} + +/* ----------------------------------------------------------------------------- + * SwigType_attach_symtab() + * + * Attaches a symbol table to a type scope + * ----------------------------------------------------------------------------- */ + +void SwigType_attach_symtab(Symtab *sym) { + Setattr(current_scope, "symtab", sym); + current_symtab = sym; +} + +/* ----------------------------------------------------------------------------- + * SwigType_print_scope() + * + * Debugging function for printing out current scope + * ----------------------------------------------------------------------------- */ + +void SwigType_print_scope(void) { + Hash *ttab; + Iterator i, j; + + Printf(stdout, "SCOPES start =======================================\n"); + for (i = First(scopes); i.key; i = Next(i)) { + Printf(stdout, "-------------------------------------------------------------\n"); + ttab = Getattr(i.item, "typetab"); + + Printf(stdout, "Type scope '%s' (%p)\n", i.key, i.item); + { + List *inherit = Getattr(i.item, "inherit"); + if (inherit) { + Iterator j; + for (j = First(inherit); j.item; j = Next(j)) { + Printf(stdout, " Inherits from '%s' (%p)\n", Getattr(j.item, "qname"), j.item); + } + } + } + for (j = First(ttab); j.key; j = Next(j)) { + Printf(stdout, "%40s -> %s\n", j.key, j.item); + } + } + Printf(stdout, "SCOPES finish =======================================\n"); +} + +static Typetab *SwigType_find_scope(Typetab *s, const SwigType *nameprefix) { + Typetab *ss; + Typetab *s_orig = s; + String *nnameprefix = 0; + static int check_parent = 1; + int is_template = 0; + + if (Getmark(s)) + return 0; + Setmark(s, 1); + + is_template = SwigType_istemplate(nameprefix); + if (is_template) { + nnameprefix = SwigType_typedef_resolve_all(nameprefix); + nameprefix = nnameprefix; + } + + ss = s; + while (ss) { + String *full; + String *qname = Getattr(ss, "qname"); + if (qname) { + full = NewStringf("%s::%s", qname, nameprefix); + } else { + full = NewString(nameprefix); + } + s = Getattr(scopes, full); + if (!s && is_template) { + /* try look up scope with all the unary scope operators within the template parameter list removed */ + SwigType *full_stripped = SwigType_remove_global_scope_prefix(full); + s = Getattr(scopes, full_stripped); + Delete(full_stripped); + } + Delete(full); + if (s) { + if (nnameprefix) + Delete(nnameprefix); + Setmark(s_orig, 0); + return s; + } + if (!s) { + /* Check inheritance */ + List *inherit; + inherit = Getattr(ss, "using"); + if (inherit) { + Typetab *ttab; + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + int oldcp = check_parent; + ttab = Getitem(inherit, i); + check_parent = 0; + s = SwigType_find_scope(ttab, nameprefix); + check_parent = oldcp; + if (s) { + if (nnameprefix) + Delete(nnameprefix); + Setmark(s_orig, 0); + return s; + } + } + } + } + if (!check_parent) + break; + ss = Getattr(ss, "parent"); + } + if (nnameprefix) + Delete(nnameprefix); + Setmark(s_orig, 0); + return 0; +} + +/* ----------------------------------------------------------------------------- + * typedef_resolve() + * + * Resolves a typedef and returns a new type string. Returns 0 if there is no + * typedef mapping. base is a name without qualification. + * Internal function. + * ----------------------------------------------------------------------------- */ + +static Typetab *resolved_scope = 0; + +/* Internal function */ + +static SwigType *_typedef_resolve(Typetab *s, String *base, int look_parent) { + Hash *ttab; + SwigType *type = 0; + List *inherit; + Typetab *parent; + + /* if (!s) return 0; *//* now is checked below */ + /* Printf(stdout,"Typetab %s : %s\n", Getattr(s,"name"), base); */ + + if (!Getmark(s)) { + Setmark(s, 1); + + ttab = Getattr(s, "typetab"); + type = Getattr(ttab, base); + if (type) { + resolved_scope = s; + Setmark(s, 0); + } else { + /* Hmmm. Not found in my scope. It could be in an inherited scope */ + inherit = Getattr(s, "inherit"); + if (inherit) { + int i, len; + len = Len(inherit); + for (i = 0; i < len; i++) { + type = _typedef_resolve(Getitem(inherit, i), base, 0); + if (type) { + Setmark(s, 0); + break; + } + } + } + if (!type) { + /* Hmmm. Not found in my scope. check parent */ + if (look_parent) { + parent = Getattr(s, "parent"); + type = parent ? _typedef_resolve(parent, base, 1) : 0; + } + } + Setmark(s, 0); + } + } + return type; +} + +/* ----------------------------------------------------------------------------- + * template_parameters_resolve() + * + * For use with templates only. Attempts to resolve one template parameter. + * + * If one of the template parameters can be resolved, the type is returned with + * just the one parameter resolved and the remaining parameters left as is. + * If none of the template parameters can be resolved, zero is returned. + * ----------------------------------------------------------------------------- */ + +static String *template_parameters_resolve(const String *base) { + List *tparms; + String *suffix; + String *type; + int i, sz; + int rep = 0; + type = SwigType_templateprefix(base); + suffix = SwigType_templatesuffix(base); + Append(type, "<("); + tparms = SwigType_parmlist(base); + sz = Len(tparms); + for (i = 0; i < sz; i++) { + SwigType *tpr; + SwigType *tp = Getitem(tparms, i); + if (!rep) { + tpr = SwigType_typedef_resolve(tp); + } else { + tpr = 0; + } + if (tpr) { + Append(type, tpr); + Delete(tpr); + rep = 1; + } else { + Append(type, tp); + } + if ((i + 1) < sz) + Append(type, ","); + } + if (rep) { + Append(type, ")>"); + Append(type, suffix); + } else { + Delete(type); + type = 0; + } + Delete(suffix); + Delete(tparms); + return type; +} + +static SwigType *typedef_resolve(Typetab *s, String *base) { + return _typedef_resolve(s, base, 1); +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_resolve() + * + * Given a type declaration, this function looks to reduce/resolve the type via a + * typedef (including via C++ using declarations). + * + * If it is able to find a typedef, the resolved type is returned. If no typedef + * is found NULL is returned. The type name is resolved in the current scope. + * The type returned is not always fully qualified for the global scope, it is + * valid for use in the current scope. If the current scope is global scope, a + * fully qualified type should be returned. + * + * Some additional notes are in Doc/Manual/Extending.html. + * ----------------------------------------------------------------------------- */ + +/* #define SWIG_DEBUG */ +SwigType *SwigType_typedef_resolve(const SwigType *t) { + String *base; + String *type = 0; + String *r = 0; + Typetab *s; + Hash *ttab; + String *namebase = 0; + String *nameprefix = 0, *rnameprefix = 0; + int newtype = 0; + + resolved_scope = 0; + +#ifdef SWIG_TYPEDEF_RESOLVE_CACHE + if (!typedef_resolve_cache) { + typedef_resolve_cache = NewHash(); + } + r = Getattr(typedef_resolve_cache, t); + if (r) { + resolved_scope = Getmeta(r, "scope"); + return Copy(r); + } +#endif + + base = SwigType_base(t); + +#ifdef SWIG_DEBUG + Printf(stdout, "base = '%s' t='%s'\n", base, t); +#endif + + if (SwigType_issimple(base)) { + s = current_scope; + ttab = current_typetab; + if (strncmp(Char(base), "::", 2) == 0) { + s = global_scope; + ttab = Getattr(s, "typetab"); + Delitem(base, 0); + Delitem(base, 0); + } + /* Do a quick check in the local scope */ + type = Getattr(ttab, base); + if (type) { + resolved_scope = s; + } + if (!type) { + /* Didn't find in this scope. We need to do a little more searching */ + if (Swig_scopename_check(base)) { + /* A qualified name. */ + Swig_scopename_split(base, &nameprefix, &namebase); +#ifdef SWIG_DEBUG + Printf(stdout, "nameprefix = '%s'\n", nameprefix); +#endif + if (nameprefix) { + rnameprefix = SwigType_typedef_resolve(nameprefix); + if(rnameprefix != NULL) { +#ifdef SWIG_DEBUG + Printf(stdout, "nameprefix '%s' is a typedef to '%s'\n", nameprefix, rnameprefix); +#endif + type = Copy(namebase); + Insert(type, 0, "::"); + Insert(type, 0, rnameprefix); + if (strncmp(Char(type), "::", 2) == 0) { + Delitem(type, 0); + Delitem(type, 0); + } + newtype = 1; + } else { + /* Name had a prefix on it. See if we can locate the proper scope for it */ + String *rnameprefix = template_parameters_resolve(nameprefix); + nameprefix = rnameprefix ? Copy(rnameprefix) : nameprefix; + Delete(rnameprefix); + s = SwigType_find_scope(s, nameprefix); + + /* Couldn't locate a scope for the type. */ + if (!s) { + Delete(base); + Delete(namebase); + Delete(nameprefix); + r = 0; + goto return_result; + } + /* Try to locate the name starting in the scope */ +#ifdef SWIG_DEBUG + Printf(stdout, "namebase = '%s'\n", namebase); +#endif + type = typedef_resolve(s, namebase); + if (type && resolved_scope) { + /* we need to look for the resolved type, this will also + fix the resolved_scope if 'type' and 'namebase' are + declared in different scopes */ + String *rtype = 0; + rtype = typedef_resolve(resolved_scope, type); + if (rtype) + type = rtype; + } +#ifdef SWIG_DEBUG + Printf(stdout, "%s type = '%s'\n", Getattr(s, "name"), type); +#endif + if ((type) && (!Swig_scopename_check(type)) && resolved_scope) { + Typetab *rtab = resolved_scope; + String *qname = Getattr(resolved_scope, "qname"); + /* If qualified *and* the typename is defined from the resolved scope, we qualify */ + if ((qname) && typedef_resolve(resolved_scope, type)) { + type = Copy(type); + Insert(type, 0, "::"); + Insert(type, 0, qname); +#ifdef SWIG_DEBUG + Printf(stdout, "qual %s \n", type); +#endif + newtype = 1; + } + resolved_scope = rtab; + } + } + } else { + /* Name is unqualified. */ + type = typedef_resolve(s, base); + } + } else { + /* Name is unqualified. */ + type = typedef_resolve(s, base); + } + } + + if (!type && SwigType_istemplate(base)) { + String *tprefix = SwigType_templateprefix(base); + String *rtprefix = SwigType_typedef_resolve(tprefix); + /* We're looking for a using declaration on the template prefix to resolve the template prefix + * in another scope. Using declaration do not have template parameters. */ + if (rtprefix && !SwigType_istemplate(rtprefix)) { + String *tsuffix = SwigType_templatesuffix(base); + String *targs = SwigType_templateargs(base); + type = NewString(rtprefix); + newtype = 1; + Append(type, targs); + Append(type, tsuffix); + Delete(targs); + Delete(tsuffix); + Delete(rtprefix); + } + Delete(tprefix); + } + + if (type && (Equal(base, type))) { + if (newtype) + Delete(type); + Delete(base); + Delete(namebase); + Delete(nameprefix); + r = 0; + goto return_result; + } + + /* If the type is a template, and no typedef was found, we need to check the + template arguments one by one to see if they can be resolved. */ + + if (!type && SwigType_istemplate(base)) { + newtype = 1; + type = template_parameters_resolve(base); + } + Delete(namebase); + Delete(nameprefix); + } else { + if (SwigType_isfunction(base)) { + List *parms; + int i, sz; + int rep = 0; + type = NewString("f("); + newtype = 1; + parms = SwigType_parmlist(base); + sz = Len(parms); + for (i = 0; i < sz; i++) { + SwigType *tpr; + SwigType *tp = Getitem(parms, i); + if (!rep) { + tpr = SwigType_typedef_resolve(tp); + } else { + tpr = 0; + } + if (tpr) { + Append(type, tpr); + Delete(tpr); + rep = 1; + } else { + Append(type, tp); + } + if ((i + 1) < sz) + Append(type, ","); + } + Append(type, ")."); + Delete(parms); + if (!rep) { + Delete(type); + type = 0; + } + } else if (SwigType_ismemberpointer(base)) { + String *rt; + String *mtype = SwigType_parm(base); + rt = SwigType_typedef_resolve(mtype); + if (rt) { + type = NewStringf("m(%s).", rt); + newtype = 1; + Delete(rt); + } + Delete(mtype); + } else { + type = 0; + } + } + r = SwigType_prefix(t); + if (!type) { + if (r && Len(r)) { + char *cr = Char(r); + if ((strstr(cr, "f(") || (strstr(cr, "m(")))) { + SwigType *rt = SwigType_typedef_resolve(r); + if (rt) { + Delete(r); + Append(rt, base); + Delete(base); + r = rt; + goto return_result; + } + } + } + Delete(r); + Delete(base); + r = 0; + goto return_result; + } + Delete(base); + + /* If 'type' is an array, then the right-most qualifier in 'r' should + be added to 'type' after the array qualifier, so that given + a(7).q(volatile).double myarray // typedef volatile double[7] myarray; + the type + q(const).myarray // const myarray + becomes + a(7).q(const volatile).double // const volatile double[7] + and NOT + q(const).a(7).q(volatile).double // non-sensical type + */ + if (r && Len(r) && SwigType_isarray(type)) { + List *r_elem; + String *r_qual; + int r_sz; + r_elem = SwigType_split(r); + r_sz = Len(r_elem); + r_qual = Getitem(r_elem, r_sz-1); + if (SwigType_isqualifier(r_qual)) { + String *new_r; + String *new_type; + List *type_elem; + String *type_qual; + String *r_qual_arg; + int i, type_sz; + + type_elem = SwigType_split(type); + type_sz = Len(type_elem); + + for (i = 0; i < type_sz; ++i) { + String *e = Getitem(type_elem, i); + if (!SwigType_isarray(e)) + break; + } + type_qual = Copy(Getitem(type_elem, i)); + r_qual_arg = SwigType_parm(r_qual); + SwigType_add_qualifier(type_qual, r_qual_arg); + Delete(r_qual_arg); + Setitem(type_elem, i, type_qual); + + new_r = NewStringEmpty(); + for (i = 0; i < r_sz-1; ++i) { + Append(new_r, Getitem(r_elem, i)); + } + new_type = NewStringEmpty(); + for (i = 0; i < type_sz; ++i) { + Append(new_type, Getitem(type_elem, i)); + } +#ifdef SWIG_DEBUG + Printf(stdout, "r+type='%s%s' new_r+new_type='%s%s'\n", r, type, new_r, new_type); +#endif + + Delete(r); + r = new_r; + newtype = 1; + type = new_type; + Delete(type_elem); + } + Delete(r_elem); + } + + Append(r, type); + if (newtype) { + Delete(type); + } + +return_result: +#ifdef SWIG_TYPEDEF_RESOLVE_CACHE + { + String *key = NewString(t); + if (r) { + SwigType *r1; + Setattr(typedef_resolve_cache, key, r); + Setmeta(r, "scope", resolved_scope); + r1 = Copy(r); + Delete(r); + r = r1; + } + Delete(key); + } +#endif + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_resolve_all() + * + * Fully resolve a type down to its most basic datatype + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_typedef_resolve_all(const SwigType *t) { + SwigType *n; + SwigType *r; + int count = 0; + + /* Check to see if the typedef resolve has been done before by checking the cache */ + if (!typedef_all_cache) { + typedef_all_cache = NewHash(); + } + r = Getattr(typedef_all_cache, t); + if (r) { + return Copy(r); + } + +#ifdef SWIG_DEBUG + Printf(stdout, "SwigType_typedef_resolve_all start ... %s\n", t); +#endif + /* Recursively resolve the typedef */ + r = NewString(t); + while ((n = SwigType_typedef_resolve(r))) { + Delete(r); + r = n; + if (++count >= 512) { + Swig_error(Getfile(t), Getline(t), "Recursive typedef detected resolving '%s' to '%s' to '%s' and so on...\n", SwigType_str(t, 0), SwigType_str(SwigType_typedef_resolve(t), 0), SwigType_str(SwigType_typedef_resolve(SwigType_typedef_resolve(t)), 0)); + break; + } + } + + /* Add the typedef to the cache for next time it is looked up */ + { + String *key; + SwigType *rr = Copy(r); + key = NewString(t); + Setattr(typedef_all_cache, key, rr); + Delete(key); + Delete(rr); + } +#ifdef SWIG_DEBUG + Printf(stdout, "SwigType_typedef_resolve_all end === %s => %s\n", t, r); +#endif + return r; +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_qualified() + * + * Given a type declaration, this function tries to fully qualify it so that the + * resulting type can be used in the global scope. The type name is resolved in + * the current scope. + * + * It provides a fully qualified name, not necessarily a fully expanded name. + * When a using declaration or using directive is found the type may not be fully + * expanded, but it will be resolved and fully qualified for use in the global scope. + * + * This function is for looking up scopes to qualify a type. It does not resolve + * C typedefs, it just qualifies them. See SwigType_typedef_resolve for resolving. + * + * If the unary scope operator (::) is used as a prefix to the type to denote global + * scope, it is left in place. + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_typedef_qualified(const SwigType *t) { + List *elements; + String *result; + int i, len; + + if (!typedef_qualified_cache) + typedef_qualified_cache = NewHash(); + result = Getattr(typedef_qualified_cache, t); + if (result) { + String *rc = Copy(result); + return rc; + } + + result = NewStringEmpty(); + elements = SwigType_split(t); + len = Len(elements); + for (i = 0; i < len; i++) { + String *ty = 0; + String *e = Getitem(elements, i); + if (SwigType_issimple(e)) { + if (!SwigType_istemplate(e)) { + String *isenum = 0; + if (SwigType_isenum(e)) { + isenum = NewString("enum "); + ty = NewString(Char(e) + 5); + e = ty; + } + resolved_scope = 0; + if (typedef_resolve(current_scope, e) && resolved_scope) { + /* resolved_scope contains the scope that actually resolved the symbol */ + String *qname = Getattr(resolved_scope, "qname"); + if (qname) { + Insert(e, 0, "::"); + Insert(e, 0, qname); + } + } else { + if (Swig_scopename_check(e)) { + String *qlast; + String *qname; + Swig_scopename_split(e, &qname, &qlast); + if (qname) { + String *tqname = SwigType_typedef_qualified(qname); + Clear(e); + Printf(e, "%s::%s", tqname, qlast); + Delete(qname); + Delete(tqname); + } + Delete(qlast); + + /* Automatic template instantiation might go here??? */ + } else { + /* It's a bare name. It's entirely possible, that the + name is part of a namespace. We'll check this by unrolling + out of the current scope */ + + Typetab *cs = current_scope; + if (cs) { + Typetab *found_scope = SwigType_find_scope(cs, e); + if (found_scope) { + String *qs = SwigType_scope_name(found_scope); + Clear(e); + Append(e, qs); + Delete(qs); + } + } + } + } + if (isenum) { + Insert(e, 0, isenum); + Delete(isenum); + } + } else { + /* Template. We need to qualify template parameters as well as the template itself */ + String *tprefix, *qprefix; + String *tsuffix; + Iterator pi; + Parm *p; + List *parms; + ty = Swig_symbol_template_deftype(e, current_symtab); + e = ty; + parms = SwigType_parmlist(e); + tprefix = SwigType_templateprefix(e); + tsuffix = SwigType_templatesuffix(e); + qprefix = SwigType_typedef_qualified(tprefix); + Append(qprefix, "<("); + pi = First(parms); + while ((p = pi.item)) { + /* TODO: the logic here should be synchronised with that in symbol_template_qualify() in symbol.c */ + String *qt = SwigType_typedef_qualified(p); + if (Equal(qt, p)) { /* && (!Swig_scopename_check(qt))) */ + /* No change in value. It is entirely possible that the parameter is an integer value. + If there is a symbol table associated with this scope, we're going to check for this */ + + if (current_symtab) { + Node *lastnode = 0; + String *value = Copy(p); + while (1) { + Node *n = Swig_symbol_clookup(value, current_symtab); + if (n == lastnode) + break; + lastnode = n; + if (n) { + char *ntype = Char(nodeType(n)); + if (strcmp(ntype, "enumitem") == 0) { + /* An enum item. Generate a fully qualified name */ + String *qn = Swig_symbol_qualified(n); + if (Len(qn)) { + Append(qn, "::"); + Append(qn, Getattr(n, "name")); + Delete(value); + value = qn; + continue; + } else { + Delete(qn); + break; + } + } else if ((strcmp(ntype, "cdecl") == 0) && (Getattr(n, "value"))) { + Delete(value); + value = Copy(Getattr(n, "value")); + continue; + } + } + break; + } + Append(qprefix, value); + Delete(value); + } else { + Append(qprefix, p); + } + } else { + Append(qprefix, qt); + } + Delete(qt); + pi = Next(pi); + if (pi.item) { + Append(qprefix, ","); + } + } + Append(qprefix, ")>"); + Append(qprefix, tsuffix); + Delete(tsuffix); + Clear(e); + Append(e, qprefix); + Delete(tprefix); + Delete(qprefix); + Delete(parms); + } + Append(result, e); + Delete(ty); + } else if (SwigType_isfunction(e)) { + List *parms = SwigType_parmlist(e); + String *s = NewString("f("); + Iterator pi; + pi = First(parms); + while (pi.item) { + String *pq = SwigType_typedef_qualified(pi.item); + Append(s, pq); + Delete(pq); + pi = Next(pi); + if (pi.item) { + Append(s, ","); + } + } + Append(s, ")."); + Append(result, s); + Delete(s); + Delete(parms); + } else if (SwigType_isarray(e)) { + String *ndim; + String *dim = SwigType_parm(e); + ndim = Swig_symbol_string_qualify(dim, 0); + Printf(result, "a(%s).", ndim); + Delete(dim); + Delete(ndim); + } else { + Append(result, e); + } + } + Delete(elements); + { + String *key, *cresult; + key = NewString(t); + cresult = NewString(result); + Setattr(typedef_qualified_cache, key, cresult); + Delete(key); + Delete(cresult); + } + return result; +} + +/* ----------------------------------------------------------------------------- + * SwigType_istypedef() + * + * Checks a typename to see if it is a typedef. + * ----------------------------------------------------------------------------- */ + +int SwigType_istypedef(const SwigType *t) { + String *type; + + type = SwigType_typedef_resolve(t); + if (type) { + Delete(type); + return 1; + } else { + return 0; + } +} + + +/* ----------------------------------------------------------------------------- + * SwigType_typedef_using() + * + * Processes a 'using' declaration to import types from one scope into another. + * Name is a qualified name like A::B. + * ----------------------------------------------------------------------------- */ + +int SwigType_typedef_using(const_String_or_char_ptr name) { + String *base; + String *td; + String *prefix; + Typetab *s; + Typetab *tt = 0; + + String *defined_name = 0; + + /* Printf(stdout, "using %s\n", name); */ + + if (!Swig_scopename_check(name)) + return -1; /* Not properly qualified */ + base = Swig_scopename_last(name); + + /* See if the base is already defined in this scope */ + if (Getattr(current_typetab, base)) { + Delete(base); + return -1; + } + + /* See if the using name is a scope */ + /* tt = SwigType_find_scope(current_scope,name); + Printf(stdout,"tt = %p, name = '%s'\n", tt, name); */ + + /* We set up a typedef B --> A::B */ + Setattr(current_typetab, base, name); + + /* Find the scope name where the symbol is defined */ + td = SwigType_typedef_resolve(name); + /* Printf(stdout,"td = '%s' %p\n", td, resolved_scope); */ + if (resolved_scope) { + defined_name = Getattr(resolved_scope, "qname"); + if (defined_name) { + defined_name = Copy(defined_name); + Append(defined_name, "::"); + Append(defined_name, base); + /* Printf(stdout,"defined_name = '%s'\n", defined_name); */ + tt = SwigType_find_scope(current_scope, defined_name); + } + } + if (td) + Delete(td); + + + /* Figure out the scope the using directive refers to */ + { + prefix = Swig_scopename_prefix(name); + if (prefix) { + s = SwigType_find_scope(current_scope, prefix); + if (s) { + Hash *ttab = Getattr(s, "typetab"); + if (!Getattr(ttab, base) && defined_name) { + Setattr(ttab, base, defined_name); + } + } + } + } + + if (tt) { + /* Using directive had its own scope. We need to create a new scope for it */ + SwigType_new_scope(base); + SwigType_inherit_scope(tt); + SwigType_pop_scope(); + } + + if (defined_name) + Delete(defined_name); + Delete(prefix); + Delete(base); + return 0; +} + +/* ----------------------------------------------------------------------------- + * SwigType_isclass() + * + * Determines if a type defines a class or not. A class is defined by + * its type-table entry maps to itself. Note: a pointer to a class is not + * a class. + * ----------------------------------------------------------------------------- */ + +int SwigType_isclass(const SwigType *t) { + SwigType *qty, *qtys; + int isclass = 0; + + qty = SwigType_typedef_resolve_all(t); + qtys = SwigType_strip_qualifiers(qty); + if (SwigType_issimple(qtys)) { + String *td = SwigType_typedef_resolve(qtys); + if (td) { + Delete(td); + } + if (resolved_scope) { + isclass = 1; + } + /* Hmmm. Not a class. If a template, it might be uninstantiated */ + if (!isclass) { + String *tp = SwigType_istemplate_templateprefix(qtys); + if (tp && Strcmp(tp, t) != 0) { + isclass = SwigType_isclass(tp); + } + Delete(tp); + } + } + Delete(qty); + Delete(qtys); + return isclass; +} + +/* ----------------------------------------------------------------------------- + * SwigType_type() + * + * Returns an integer code describing the datatype. This is only used for + * compatibility with SWIG1.1 language modules and is likely to go away once + * everything is based on typemaps. + * ----------------------------------------------------------------------------- */ + +int SwigType_type(const SwigType *t) { + char *c; + /* Check for the obvious stuff */ + c = Char(t); + + if (strncmp(c, "p.", 2) == 0) { + if (SwigType_type(c + 2) == T_CHAR) + return T_STRING; + else if (SwigType_type(c + 2) == T_WCHAR) + return T_WSTRING; + else + return T_POINTER; + } + if (strncmp(c, "a(", 2) == 0) + return T_ARRAY; + if (strncmp(c, "r.", 2) == 0) + return T_REFERENCE; + if (strncmp(c, "z.", 2) == 0) + return T_RVALUE_REFERENCE; + if (strncmp(c, "m(", 2) == 0) + return T_MPOINTER; + if (strncmp(c, "q(", 2) == 0) { + while (*c && (*c != '.')) + c++; + if (*c) + return SwigType_type(c + 1); + return T_ERROR; + } + if (strncmp(c, "f(", 2) == 0) + return T_FUNCTION; + + /* Look for basic types */ + if (strcmp(c, "int") == 0) + return T_INT; + if (strcmp(c, "long") == 0) + return T_LONG; + if (strcmp(c, "short") == 0) + return T_SHORT; + if (strcmp(c, "unsigned") == 0) + return T_UINT; + if (strcmp(c, "unsigned short") == 0) + return T_USHORT; + if (strcmp(c, "unsigned long") == 0) + return T_ULONG; + if (strcmp(c, "unsigned int") == 0) + return T_UINT; + if (strcmp(c, "char") == 0) + return T_CHAR; + if (strcmp(c, "signed char") == 0) + return T_SCHAR; + if (strcmp(c, "unsigned char") == 0) + return T_UCHAR; + if (strcmp(c, "wchar_t") == 0) + return T_WCHAR; + if (strcmp(c, "float") == 0) + return T_FLOAT; + if (strcmp(c, "double") == 0) + return T_DOUBLE; + if (strcmp(c, "long double") == 0) + return T_LONGDOUBLE; + if (!cparse_cplusplus && (strcmp(c, "float _Complex") == 0)) + return T_FLTCPLX; + if (!cparse_cplusplus && (strcmp(c, "double _Complex") == 0)) + return T_DBLCPLX; + if (!cparse_cplusplus && (strcmp(c, "_Complex") == 0)) + return T_COMPLEX; + if (strcmp(c, "void") == 0) + return T_VOID; + if (strcmp(c, "bool") == 0) + return T_BOOL; + if (strcmp(c, "long long") == 0) + return T_LONGLONG; + if (strcmp(c, "unsigned long long") == 0) + return T_ULONGLONG; + if (strncmp(c, "enum ", 5) == 0) + return T_INT; + if (strcmp(c, "auto") == 0) + return T_AUTO; + + if (strcmp(c, "v(...)") == 0) + return T_VARARGS; + /* Hmmm. Unknown type */ + if (SwigType_istypedef(t)) { + int r; + SwigType *nt = SwigType_typedef_resolve(t); + r = SwigType_type(nt); + Delete(nt); + return r; + } + return T_USER; +} + +/* ----------------------------------------------------------------------------- + * SwigType_alttype() + * + * Returns the alternative value type needed in C++ for class value + * types. When swig is not sure about using a plain $ltype value, + * since the class doesn't have a default constructor, or it can't be + * assigned, you will get back 'SwigValueWrapper<type >'. + * + * This is the default behavior unless: + * + * 1.- swig detects a default_constructor and 'setallocate:default_constructor' + * attribute. + * + * 2.- swig doesn't mark 'type' as non-assignable. + * + * 3.- the user specifies that the value wrapper is not needed by using + * %feature("novaluewrapper") like so: + * + * %feature("novaluewrapper") MyOpaqueClass; + * class MyOpaqueClass; + * + * The user can also force the use of the value wrapper with + * %feature("valuewrapper"). + * ----------------------------------------------------------------------------- */ + +SwigType *SwigType_alttype(const SwigType *t, int local_tmap) { + Node *n; + SwigType *w = 0; + int use_wrapper = 0; + SwigType *td = 0; + + if (!cparse_cplusplus) + return 0; + + if (value_wrapper_mode == 0) { + /* old partial use of SwigValueTypes, it can fail for opaque types */ + if (local_tmap) + return 0; + if (SwigType_isclass(t)) { + SwigType *ftd = SwigType_typedef_resolve_all(t); + td = SwigType_strip_qualifiers(ftd); + Delete(ftd); + n = Swig_symbol_clookup(td, 0); + if (n) { + if (GetFlag(n, "feature:valuewrapper")) { + use_wrapper = 1; + } else { + if (Checkattr(n, "nodeType", "class") + && (!Getattr(n, "allocate:default_constructor") + || (Getattr(n, "allocate:noassign")))) { + use_wrapper = !GetFlag(n, "feature:novaluewrapper") || GetFlag(n, "feature:nodefault"); + } + } + } else { + if (SwigType_issimple(td) && SwigType_istemplate(td)) { + use_wrapper = 1; + } + } + } + } else { + /* safe use of SwigValueTypes, it can fail with some typemaps */ + SwigType *ftd = SwigType_typedef_resolve_all(t); + td = SwigType_strip_qualifiers(ftd); + Delete(ftd); + if (SwigType_type(td) == T_USER) { + use_wrapper = 1; + n = Swig_symbol_clookup(td, 0); + if (n) { + if ((Checkattr(n, "nodeType", "class") + && !Getattr(n, "allocate:noassign") + && (Getattr(n, "allocate:default_constructor"))) + || (GetFlag(n, "feature:novaluewrapper"))) { + use_wrapper = GetFlag(n, "feature:valuewrapper"); + } + } + } + } + + if (use_wrapper) { + /* Need a space before the type in case it starts "::" (since the <: + * token is a digraph for [ in C++. Also need a space after the + * type in case it ends with ">" since then we form the token ">>". + */ + w = NewStringf("SwigValueWrapper< %s >", td); + } + Delete(td); + return w; +} + +/* ---------------------------------------------------------------------------- + * * * * WARNING * * * *** + * *** + * Don't even think about modifying anything below this line unless you *** + * are completely on top of *EVERY* subtle aspect of the C++ type system *** + * and you are prepared to suffer endless hours of agony trying to *** + * debug the SWIG run-time type checker after you break it. *** + * ------------------------------------------------------------------------- */ + +/* ----------------------------------------------------------------------------- + * SwigType_remember() + * + * This function "remembers" a datatype that was used during wrapper code generation + * so that a type-checking table can be generated later on. It is up to the language + * modules to actually call this function--it is not done automatically. + * + * Type tracking is managed through two separate hash tables. The hash 'r_mangled' + * is mapping between mangled type names (used in the target language) and + * fully-resolved C datatypes used in the source input. The second hash 'r_resolved' + * is the inverse mapping that maps fully-resolved C datatypes to all of the mangled + * names in the scripting languages. For example, consider the following set of + * typedef declarations: + * + * typedef double Real; + * typedef double Float; + * typedef double Point[3]; + * + * Now, suppose that the types 'double *', 'Real *', 'Float *', 'double[3]', and + * 'Point' were used in an interface file and "remembered" using this function. + * The hash tables would look like this: + * + * r_mangled { + * _p_double : [ p.double, a(3).double ] + * _p_Real : [ p.double ] + * _p_Float : [ p.double ] + * _Point : [ a(3).double ] + * + * r_resolved { + * p.double : [ _p_double, _p_Real, _p_Float ] + * a(3).double : [ _p_double, _Point ] + * } + * + * Together these two hash tables can be used to determine type-equivalency between + * mangled typenames. To do this, we view the two hash tables as a large graph and + * compute the transitive closure. + * ----------------------------------------------------------------------------- */ + +static Hash *r_mangled = 0; /* Hash mapping mangled types to fully resolved types */ +static Hash *r_resolved = 0; /* Hash mapping resolved types to mangled types */ +static Hash *r_ltype = 0; /* Hash mapping mangled names to their local c type */ +static Hash *r_clientdata = 0; /* Hash mapping resolved types to client data */ +static Hash *r_mangleddata = 0; /* Hash mapping mangled types to client data */ +static Hash *r_remembered = 0; /* Hash of types we remembered already */ + +static void (*r_tracefunc) (const SwigType *t, String *mangled, String *clientdata) = 0; + +void SwigType_remember_mangleddata(String *mangled, const_String_or_char_ptr clientdata) { + if (!r_mangleddata) { + r_mangleddata = NewHash(); + } + Setattr(r_mangleddata, mangled, clientdata); +} + + +void SwigType_remember_clientdata(const SwigType *t, const_String_or_char_ptr clientdata) { + String *mt; + SwigType *lt; + Hash *h; + SwigType *fr; + SwigType *qr; + String *tkey; + String *cd; + Hash *lthash; + + if (!r_mangled) { + r_mangled = NewHash(); + r_resolved = NewHash(); + r_ltype = NewHash(); + r_clientdata = NewHash(); + r_remembered = NewHash(); + } + + { + String *last; + last = Getattr(r_remembered, t); + if (last && (Cmp(last, clientdata) == 0)) + return; + } + + tkey = Copy(t); + cd = clientdata ? NewString(clientdata) : NewStringEmpty(); + Setattr(r_remembered, tkey, cd); + Delete(tkey); + Delete(cd); + + mt = SwigType_manglestr(t); /* Create mangled string */ + + if (r_tracefunc) { + (*r_tracefunc) (t, mt, (String *) clientdata); + } + + if (SwigType_istypedef(t)) { + lt = Copy(t); + } else { + lt = SwigType_ltype(t); + } + + lthash = Getattr(r_ltype, mt); + if (!lthash) { + lthash = NewHash(); + Setattr(r_ltype, mt, lthash); + } + Setattr(lthash, lt, "1"); + Delete(lt); + + fr = SwigType_typedef_resolve_all(t); /* Create fully resolved type */ + qr = SwigType_typedef_qualified(fr); + Delete(fr); + + /* Added to deal with possible table bug */ + fr = SwigType_strip_qualifiers(qr); + Delete(qr); + + /*Printf(stdout,"t = '%s'\n", t); + Printf(stdout,"fr= '%s'\n\n", fr); */ + + if (t) { + char *ct = Char(t); + const char *lt = strchr(ct, '<'); + /* Allow for `<<` operator in constant expression for array size. */ + if (lt && lt[1] != '(' && lt[1] != '<') { + Printf(stdout, "Bad template type passed to SwigType_remember: %s\n", t); + assert(0); + } + } + + h = Getattr(r_mangled, mt); + if (!h) { + h = NewHash(); + Setattr(r_mangled, mt, h); + Delete(h); + } + Setattr(h, fr, mt); + + h = Getattr(r_resolved, fr); + if (!h) { + h = NewHash(); + Setattr(r_resolved, fr, h); + Delete(h); + } + Setattr(h, mt, fr); + + if (clientdata) { + String *cd = Getattr(r_clientdata, fr); + if (cd) { + if (Strcmp(clientdata, cd) != 0) { + Printf(stderr, "*** Internal error. Inconsistent clientdata for type '%s'\n", SwigType_str(fr, 0)); + Printf(stderr, "*** '%s' != '%s'\n", clientdata, cd); + assert(0); + } + } else { + String *cstr = NewString(clientdata); + Setattr(r_clientdata, fr, cstr); + Delete(cstr); + } + } + + /* If the remembered type is a reference, we also remember the pointer version. + This is to prevent odd problems with mixing pointers and references--especially + when different functions are using different typenames (via typedef). */ + + if (SwigType_isreference(t)) { + SwigType *tt = Copy(t); + SwigType_del_reference(tt); + SwigType_add_pointer(tt); + SwigType_remember_clientdata(tt, clientdata); + } else if (SwigType_isrvalue_reference(t)) { + SwigType *tt = Copy(t); + SwigType_del_rvalue_reference(tt); + SwigType_add_pointer(tt); + SwigType_remember_clientdata(tt, clientdata); + } +} + +void SwigType_remember(const SwigType *ty) { + SwigType_remember_clientdata(ty, 0); +} + +void (*SwigType_remember_trace(void (*tf) (const SwigType *, String *, String *))) (const SwigType *, String *, String *) { + void (*o) (const SwigType *, String *, String *) = r_tracefunc; + r_tracefunc = tf; + return o; +} + +/* ----------------------------------------------------------------------------- + * SwigType_equivalent_mangle() + * + * Return a list of all of the mangled typenames that are equivalent to another + * mangled name. This works as follows: For each fully qualified C datatype + * in the r_mangled hash entry, we collect all of the mangled names from the + * r_resolved hash and combine them together in a list (removing duplicate entries). + * ----------------------------------------------------------------------------- */ + +List *SwigType_equivalent_mangle(String *ms, Hash *checked, Hash *found) { + List *l; + Hash *h; + Hash *ch; + Hash *mh; + + if (found) { + h = found; + } else { + h = NewHash(); + } + if (checked) { + ch = checked; + } else { + ch = NewHash(); + } + if (Getattr(ch, ms)) + goto check_exit; /* Already checked this type */ + Setattr(h, ms, "1"); + Setattr(ch, ms, "1"); + mh = Getattr(r_mangled, ms); + if (mh) { + Iterator ki; + ki = First(mh); + while (ki.key) { + Hash *rh; + if (Getattr(ch, ki.key)) { + ki = Next(ki); + continue; + } + Setattr(ch, ki.key, "1"); + rh = Getattr(r_resolved, ki.key); + if (rh) { + Iterator rk; + rk = First(rh); + while (rk.key) { + Setattr(h, rk.key, "1"); + SwigType_equivalent_mangle(rk.key, ch, h); + rk = Next(rk); + } + } + ki = Next(ki); + } + } +check_exit: + if (!found) { + l = Keys(h); + Delete(h); + Delete(ch); + return l; + } else { + return 0; + } +} + +/* ----------------------------------------------------------------------------- + * SwigType_clientdata_collect() + * + * Returns the clientdata field for a mangled type-string. + * ----------------------------------------------------------------------------- */ + +static +String *SwigType_clientdata_collect(String *ms) { + Hash *mh; + String *clientdata = 0; + + if (r_mangleddata) { + clientdata = Getattr(r_mangleddata, ms); + if (clientdata) + return clientdata; + } + + mh = Getattr(r_mangled, ms); + if (mh) { + Iterator ki; + ki = First(mh); + while (ki.key) { + clientdata = Getattr(r_clientdata, ki.key); + if (clientdata) + break; + ki = Next(ki); + } + } + return clientdata; +} + + + + +/* ----------------------------------------------------------------------------- + * SwigType_inherit() + * + * Record information about inheritance. We keep a hash table that keeps + * a mapping between base classes and all of the classes that are derived + * from them. + * + * subclass is a hash that maps base-classes to all of the classes derived from them. + * + * derived - name of derived class + * base - name of base class + * cast - additional casting code when casting from derived to base + * conversioncode - if set, overrides the default code in the function when casting + * from derived to base + * ----------------------------------------------------------------------------- */ + +static Hash *subclass = 0; +static Hash *conversions = 0; + +void SwigType_inherit(String *derived, String *base, String *cast, String *conversioncode) { + Hash *h; + String *dd = 0; + String *bb = 0; + if (!subclass) + subclass = NewHash(); + + /* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */ + + if (SwigType_istemplate(derived)) { + String *ty = SwigType_typedef_resolve_all(derived); + dd = SwigType_typedef_qualified(ty); + derived = dd; + Delete(ty); + } + if (SwigType_istemplate(base)) { + String *ty = SwigType_typedef_resolve_all(base); + bb = SwigType_typedef_qualified(ty); + base = bb; + Delete(ty); + } + + /* Printf(stdout,"'%s' --> '%s' '%s'\n", derived, base, cast); */ + + h = Getattr(subclass, base); + if (!h) { + h = NewHash(); + Setattr(subclass, base, h); + Delete(h); + } + if (!Getattr(h, derived)) { + Hash *c = NewHash(); + if (cast) + Setattr(c, "cast", cast); + if (conversioncode) + Setattr(c, "convcode", conversioncode); + Setattr(h, derived, c); + Delete(c); + } + + Delete(dd); + Delete(bb); +} + +/* ----------------------------------------------------------------------------- + * SwigType_issubtype() + * + * Determines if a t1 is a subtype of t2, ie, is t1 derived from t2 + * ----------------------------------------------------------------------------- */ + +int SwigType_issubtype(const SwigType *t1, const SwigType *t2) { + SwigType *ft1, *ft2; + String *b1, *b2; + Hash *h; + int r = 0; + + if (!subclass) + return 0; + + ft1 = SwigType_typedef_resolve_all(t1); + ft2 = SwigType_typedef_resolve_all(t2); + b1 = SwigType_base(ft1); + b2 = SwigType_base(ft2); + + h = Getattr(subclass, b2); + if (h) { + if (Getattr(h, b1)) { + r = 1; + } + } + Delete(ft1); + Delete(ft2); + Delete(b1); + Delete(b2); + /* Printf(stdout, "issubtype(%s,%s) --> %d\n", t1, t2, r); */ + return r; +} + +/* ----------------------------------------------------------------------------- + * SwigType_inherit_equiv() + * + * Modify the type table to handle C++ inheritance + * ----------------------------------------------------------------------------- */ + +void SwigType_inherit_equiv(File *out) { + String *ckey; + String *prefix, *base; + String *mprefix, *mkey; + Hash *sub; + Hash *rh; + List *rlist; + List *r_resolved_sorted_keys; + Iterator rk, bk, ck; + + if (!conversions) + conversions = NewHash(); + if (!subclass) + subclass = NewHash(); + + r_resolved_sorted_keys = SortedKeys(r_resolved, Strcmp); + rk = First(r_resolved_sorted_keys); + while (rk.item) { + List *sub_sorted_keys; + /* rkey is a fully qualified type. We strip all of the type constructors off of it just to get the base */ + base = SwigType_base(rk.item); + /* Check to see whether the base is recorded in the subclass table */ + sub = Getattr(subclass, base); + Delete(base); + if (!sub) { + rk = Next(rk); + continue; + } + + /* This type has subclasses. We now need to walk through these subtypes and generate pointer conversion functions */ + + rh = Getattr(r_resolved, rk.item); + rlist = NewList(); + for (ck = First(rh); ck.key; ck = Next(ck)) { + Append(rlist, ck.key); + } + /* Printf(stdout,"rk.item = '%s'\n", rk.item); + Printf(stdout,"rh = %p '%s'\n", rh,rh); */ + + sub_sorted_keys = SortedKeys(sub, Strcmp); + bk = First(sub_sorted_keys); + while (bk.item) { + prefix = SwigType_prefix(rk.item); + Append(prefix, bk.item); + /* Printf(stdout,"set %p = '%s' : '%s'\n", rh, SwigType_manglestr(prefix),prefix); */ + mprefix = SwigType_manglestr(prefix); + Setattr(rh, mprefix, prefix); + mkey = SwigType_manglestr(rk.item); + ckey = NewStringf("%s+%s", mprefix, mkey); + if (!Getattr(conversions, ckey)) { + String *convname = NewStringf("%sTo%s", mprefix, mkey); + String *lkey = SwigType_lstr(rk.item, 0); + String *lprefix = SwigType_lstr(prefix, 0); + Hash *subhash = Getattr(sub, bk.item); + String *convcode = Getattr(subhash, "convcode"); + if (convcode) { + char *newmemoryused = Strstr(convcode, "newmemory"); /* see if newmemory parameter is used in order to avoid unused parameter warnings */ + String *fn = Copy(convcode); + Replaceall(fn, "$from", "x"); + Printf(out, "static void *%s(void *x, int *%s) {", convname, newmemoryused ? "newmemory" : "SWIGUNUSEDPARM(newmemory)"); + Printf(out, "%s", fn); + } else { + String *cast = Getattr(subhash, "cast"); + Printf(out, "static void *%s(void *x, int *SWIGUNUSEDPARM(newmemory)) {", convname); + Printf(out, "\n return (void *)((%s) ", lkey); + if (cast) + Printf(out, "%s", cast); + Printf(out, " ((%s) x));\n", lprefix); + } + Printf(out, "}\n"); + Setattr(conversions, ckey, convname); + Delete(ckey); + Delete(lkey); + Delete(lprefix); + + /* This inserts conversions for typedefs */ + { + Hash *r = Getattr(r_resolved, prefix); + if (r) { + Iterator rrk; + rrk = First(r); + while (rrk.key) { + Iterator rlk; + String *rkeymangle; + + /* Make sure this name equivalence is not due to inheritance */ + if (Cmp(prefix, Getattr(r, rrk.key)) == 0) { + rkeymangle = Copy(mkey); + ckey = NewStringf("%s+%s", rrk.key, rkeymangle); + if (!Getattr(conversions, ckey)) { + Setattr(conversions, ckey, convname); + } + Delete(ckey); + for (rlk = First(rlist); rlk.item; rlk = Next(rlk)) { + ckey = NewStringf("%s+%s", rrk.key, rlk.item); + Setattr(conversions, ckey, convname); + Delete(ckey); + } + Delete(rkeymangle); + /* This is needed to pick up other alternative names for the same type. + Needed to make templates work */ + Setattr(rh, rrk.key, rrk.item); + } + rrk = Next(rrk); + } + } + } + Delete(convname); + } + Delete(prefix); + Delete(mprefix); + Delete(mkey); + bk = Next(bk); + } + Delete(sub_sorted_keys); + rk = Next(rk); + Delete(rlist); + } + Delete(r_resolved_sorted_keys); +} + +/* ----------------------------------------------------------------------------- + * SwigType_type_table() + * + * Generate the type-table for the type-checker. + * ----------------------------------------------------------------------------- */ + +void SwigType_emit_type_table(File *f_forward, File *f_table) { + Iterator ki; + String *types, *table, *cast, *cast_init, *cast_temp; + Hash *imported_types; + List *mangled_list; + List *table_list = NewList(); + int i = 0; + + if (!r_mangled) { + r_mangled = NewHash(); + r_resolved = NewHash(); + } + + Printf(f_table, "\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (BEGIN) -------- */\n\n"); + + SwigType_inherit_equiv(f_table); + + /*#define DEBUG 1*/ +#ifdef DEBUG + Printf(stdout, "---r_mangled---\n"); + Swig_print(r_mangled, 2); + + Printf(stdout, "---r_resolved---\n"); + Swig_print(r_resolved, 2); + + Printf(stdout, "---r_ltype---\n"); + Swig_print(r_ltype, 2); + + Printf(stdout, "---subclass---\n"); + Swig_print(subclass, 2); + + Printf(stdout, "---conversions---\n"); + Swig_print(conversions, 2); + + Printf(stdout, "---r_clientdata---\n"); + Swig_print(r_clientdata, 2); + +#endif + table = NewStringEmpty(); + types = NewStringEmpty(); + cast = NewStringEmpty(); + cast_init = NewStringEmpty(); + imported_types = NewHash(); + + Printf(table, "static swig_type_info *swig_type_initial[] = {\n"); + Printf(cast_init, "static swig_cast_info *swig_cast_initial[] = {\n"); + + Printf(f_forward, "\n/* -------- TYPES TABLE (BEGIN) -------- */\n\n"); + + mangled_list = SortedKeys(r_mangled, Strcmp); + for (ki = First(mangled_list); ki.item; ki = Next(ki)) { + List *el; + Iterator ei; + String *nt; + String *ln; + String *rn; + const String *cd; + Hash *lthash; + Iterator ltiter; + Hash *nthash; + String *cast_temp_conv; + String *resolved_lstr = 0; + List *ntlist; + + cast_temp = NewStringEmpty(); + cast_temp_conv = NewStringEmpty(); + + Printv(types, "static swig_type_info _swigt_", ki.item, " = {", NIL); + Append(table_list, ki.item); + Printf(cast_temp, "static swig_cast_info _swigc_%s[] = {", ki.item); + i++; + + cd = SwigType_clientdata_collect(ki.item); + if (!cd) + cd = "0"; + + lthash = Getattr(r_ltype, ki.item); + nt = 0; + nthash = NewHash(); + ltiter = First(lthash); + while (ltiter.key) { + SwigType *lt = ltiter.key; + SwigType *rt = SwigType_typedef_resolve_all(lt); + /* we save the original type and the fully resolved version */ + ln = SwigType_lstr(lt, 0); + rn = SwigType_lstr(rt, 0); + if (Equal(ln, rn)) { + Setattr(nthash, ln, "1"); + } else { + Setattr(nthash, rn, "1"); + Setattr(nthash, ln, "1"); + } + if (!resolved_lstr) { + resolved_lstr = Copy(rn); + } else if (Len(rn) < Len(resolved_lstr)) { + Delete(resolved_lstr); + resolved_lstr = Copy(rn); + } + if (SwigType_istemplate(rt)) { + String *dt = Swig_symbol_template_deftype(rt, 0); + String *dn = SwigType_lstr(dt, 0); + if (!Equal(dn, rn) && !Equal(dn, ln)) { + Setattr(nthash, dn, "1"); + } + Delete(dt); + Delete(dn); + } + Delete(rt); + Delete(rn); + Delete(ln); + + ltiter = Next(ltiter); + } + + /* now build nt */ + ntlist = SortedKeys(nthash, Strcmp); + ltiter = First(ntlist); + nt = 0; + while (ltiter.item) { + if (!Equal(resolved_lstr, ltiter.item)) { + if (nt) { + Printf(nt, "|%s", ltiter.item); + } else { + nt = NewString(ltiter.item); + } + } + ltiter = Next(ltiter); + } + /* Last in list is a resolved type used by SWIG_TypePrettyName. + * There can be more than one resolved type and the chosen one is simply the + * shortest in length, arguably the most user friendly/readable. */ + if (nt) { + Printf(nt, "|%s", resolved_lstr); + } else { + nt = NewString(resolved_lstr); + } + Delete(ntlist); + Delete(nthash); + Delete(resolved_lstr); + + Printf(types, "\"%s\", \"%s\", 0, 0, (void*)%s, 0};\n", ki.item, nt, cd); + + el = SwigType_equivalent_mangle(ki.item, 0, 0); + SortList(el, Strcmp); + for (ei = First(el); ei.item; ei = Next(ei)) { + String *ckey; + String *conv; + ckey = NewStringf("%s+%s", ei.item, ki.item); + conv = Getattr(conversions, ckey); + if (conv) { + Printf(cast_temp_conv, " {&_swigt_%s, %s, 0, 0},", ei.item, conv); + } else { + Printf(cast_temp, " {&_swigt_%s, 0, 0, 0},", ei.item); + } + Delete(ckey); + + if (!Getattr(r_mangled, ei.item) && !Getattr(imported_types, ei.item)) { + Printf(types, "static swig_type_info _swigt_%s = {\"%s\", 0, 0, 0, 0, 0};\n", ei.item, ei.item); + Append(table_list, ei.item); + + Printf(cast, "static swig_cast_info _swigc_%s[] = {{&_swigt_%s, 0, 0, 0},{0, 0, 0, 0}};\n", ei.item, ei.item); + i++; + + Setattr(imported_types, ei.item, "1"); + } + } + Delete(el); + Printf(cast, "%s%s{0, 0, 0, 0}};\n", cast_temp, cast_temp_conv); + Delete(cast_temp_conv); + Delete(cast_temp); + Delete(nt); + } + /* print the tables in the proper order */ + SortList(table_list, Strcmp); + i = 0; + for (ki = First(table_list); ki.item; ki = Next(ki)) { + Printf(f_forward, "#define SWIGTYPE%s swig_types[%d]\n", ki.item, i++); + Printf(table, " &_swigt_%s,\n", ki.item); + Printf(cast_init, " _swigc_%s,\n", ki.item); + } + if (i == 0) { + /* empty arrays are not allowed by ISO C */ + Printf(table, " NULL\n"); + Printf(cast_init, " NULL\n"); + } + + Delete(table_list); + + Delete(mangled_list); + + Printf(table, "};\n"); + Printf(cast_init, "};\n"); + Printf(f_table, "%s\n", types); + Printf(f_table, "%s\n", table); + Printf(f_table, "%s\n", cast); + Printf(f_table, "%s\n", cast_init); + Printf(f_table, "\n/* -------- TYPE CONVERSION AND EQUIVALENCE RULES (END) -------- */\n\n"); + + Printf(f_forward, "static swig_type_info *swig_types[%d];\n", i + 1); + Printf(f_forward, "static swig_module_info swig_module = {swig_types, %d, 0, 0, 0, 0};\n", i); + Printf(f_forward, "#define SWIG_TypeQuery(name) SWIG_TypeQueryModule(&swig_module, &swig_module, name)\n"); + Printf(f_forward, "#define SWIG_MangledTypeQuery(name) SWIG_MangledTypeQueryModule(&swig_module, &swig_module, name)\n"); + Printf(f_forward, "\n/* -------- TYPES TABLE (END) -------- */\n\n"); + + Delete(types); + Delete(table); + Delete(cast); + Delete(cast_init); + Delete(imported_types); +} diff --git a/contrib/tools/swig/Source/Swig/wrapfunc.c b/contrib/tools/swig/Source/Swig/wrapfunc.c new file mode 100644 index 0000000000..6d82372453 --- /dev/null +++ b/contrib/tools/swig/Source/Swig/wrapfunc.c @@ -0,0 +1,520 @@ +/* ----------------------------------------------------------------------------- + * 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 https://www.swig.org/legal.html. + * + * wrapfunc.c + * + * This file defines a object for creating wrapper functions. Primarily + * this is used for convenience since it allows pieces of a wrapper function + * to be created in a piecemeal manner. + * ----------------------------------------------------------------------------- */ + +#include "swig.h" +#include <ctype.h> + +static int Compact_mode = 0; /* set to 0 on default */ +static int Max_line_size = 128; + +/* ----------------------------------------------------------------------------- + * NewWrapper() + * + * Create a new wrapper function object. + * ----------------------------------------------------------------------------- */ + +Wrapper *NewWrapper(void) { + Wrapper *w; + w = (Wrapper *) Malloc(sizeof(Wrapper)); + w->localh = NewHash(); + w->locals = NewStringEmpty(); + w->code = NewStringEmpty(); + w->def = NewStringEmpty(); + return w; +} + +/* ----------------------------------------------------------------------------- + * DelWrapper() + * + * Delete a wrapper function object. + * ----------------------------------------------------------------------------- */ + +void DelWrapper(Wrapper *w) { + Delete(w->localh); + Delete(w->locals); + Delete(w->code); + Delete(w->def); + Free(w); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_compact_print_mode_set() + * + * Set compact_mode. + * ----------------------------------------------------------------------------- */ + +void Wrapper_compact_print_mode_set(int flag) { + Compact_mode = flag; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_pretty_print() + * + * Formats a wrapper function and fixes up the indentation. + * ----------------------------------------------------------------------------- */ + +void Wrapper_pretty_print(String *str, File *f) { + String *ts; + int level = 0; + int c, i; + int empty = 1; + int indent = 2; + int plevel = 0; + int label = 0; + + ts = NewStringEmpty(); + Seek(str, 0, SEEK_SET); + while ((c = Getc(str)) != EOF) { + if (c == '\"') { + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\"') + break; + } + empty = 0; + } else if (c == '\'') { + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\'') + break; + } + empty = 0; + } else if (c == ':') { + Putc(c, ts); + if ((c = Getc(str)) == '\n') { + if (!empty && !strchr(Char(ts), '?')) + label = 1; + } + Ungetc(c, str); + } else if (c == '(') { + Putc(c, ts); + plevel += indent; + empty = 0; + } else if (c == ')') { + Putc(c, ts); + plevel -= indent; + empty = 0; + } else if (c == '{') { + Putc(c, ts); + Putc('\n', ts); + for (i = 0; i < level; i++) + Putc(' ', f); + Printf(f, "%s", ts); + Clear(ts); + level += indent; + while ((c = Getc(str)) != EOF) { + if (!isspace(c)) { + Ungetc(c, str); + break; + } + } + empty = 0; + } else if (c == '}') { + if (!empty) { + Putc('\n', ts); + for (i = 0; i < level; i++) + Putc(' ', f); + Printf(f, "%s", ts); + Clear(ts); + } + level -= indent; + Putc(c, ts); + empty = 0; + } else if (c == '\n') { + Putc(c, ts); + empty = 0; + if (!empty) { + int slevel = level; + if (label && (slevel >= indent)) + slevel -= indent; + if ((Char(ts))[0] != '#') { + for (i = 0; i < slevel; i++) + Putc(' ', f); + } + Printf(f, "%s", ts); + for (i = 0; i < plevel; i++) + Putc(' ', f); + } + Clear(ts); + label = 0; + empty = 1; + } else if (c == '/') { + empty = 0; + Putc(c, ts); + c = Getc(str); + if (c != EOF) { + Putc(c, ts); + if (c == '/') { /* C++ comment */ + while ((c = Getc(str)) != EOF) { + if (c == '\n') { + Ungetc(c, str); + break; + } + Putc(c, ts); + } + } else if (c == '*') { /* C comment */ + int endstar = 0; + while ((c = Getc(str)) != EOF) { + if (endstar && c == '/') { /* end of C comment */ + Putc(c, ts); + break; + } + endstar = (c == '*'); + Putc(c, ts); + if (c == '\n') { /* multi-line C comment. Could be improved slightly. */ + for (i = 0; i < level; i++) + Putc(' ', ts); + } + } + } + } + } else { + if (!empty || !isspace(c)) { + Putc(c, ts); + empty = 0; + } + } + } + if (!empty) + Printf(f, "%s", ts); + Delete(ts); + Printf(f, "\n"); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_compact_print() + * + * Formats a wrapper function and fixes up the indentation. + * Print out in compact format, with Compact enabled. + * ----------------------------------------------------------------------------- */ + +void Wrapper_compact_print(String *str, File *f) { + String *ts, *tf; /*temp string & temp file */ + int level = 0; + int c, i; + int empty = 1; + int indent = 2; + + ts = NewStringEmpty(); + tf = NewStringEmpty(); + Seek(str, 0, SEEK_SET); + + while ((c = Getc(str)) != EOF) { + if (c == '\"') { /* string 1 */ + empty = 0; + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\"') + break; + } + } else if (c == '\'') { /* string 2 */ + empty = 0; + Putc(c, ts); + while ((c = Getc(str)) != EOF) { + if (c == '\\') { + Putc(c, ts); + c = Getc(str); + } + Putc(c, ts); + if (c == '\'') + break; + } + } else if (c == '{') { /* start of {...} */ + empty = 0; + Putc(c, ts); + if (Len(tf) == 0) { + for (i = 0; i < level; i++) + Putc(' ', tf); + } else if ((Len(tf) + Len(ts)) < Max_line_size) { + Putc(' ', tf); + } else { + Putc('\n', tf); + Printf(f, "%s", tf); + Clear(tf); + for (i = 0; i < level; i++) + Putc(' ', tf); + } + Append(tf, ts); + Clear(ts); + level += indent; + while ((c = Getc(str)) != EOF) { + if (!isspace(c)) { + Ungetc(c, str); + break; + } + } + } else if (c == '}') { /* end of {...} */ + empty = 0; + if (Len(tf) == 0) { + for (i = 0; i < level; i++) + Putc(' ', tf); + } else if ((Len(tf) + Len(ts)) < Max_line_size) { + Putc(' ', tf); + } else { + Putc('\n', tf); + Printf(f, "%s", tf); + Clear(tf); + for (i = 0; i < level; i++) + Putc(' ', tf); + } + Append(tf, ts); + Putc(c, tf); + Clear(ts); + level -= indent; + } else if (c == '\n') { /* line end */ + while ((c = Getc(str)) != EOF) { + if (!isspace(c)) + break; + } + if (c == '#') { + Putc('\n', ts); + } else if (c == '}') { + Putc(' ', ts); + } else if ((c != EOF) || (Len(ts) != 0)) { + if (Len(tf) == 0) { + for (i = 0; i < level; i++) + Putc(' ', tf); + } else if ((Len(tf) + Len(ts)) < Max_line_size) { + Putc(' ', tf); + } else { + Putc('\n', tf); + Printf(f, "%s", tf); + Clear(tf); + for (i = 0; i < level; i++) + Putc(' ', tf); + } + Append(tf, ts); + Clear(ts); + } + Ungetc(c, str); + + empty = 1; + } else if (c == '/') { /* comment */ + empty = 0; + c = Getc(str); + if (c != EOF) { + if (c == '/') { /* C++ comment */ + while ((c = Getc(str)) != EOF) { + if (c == '\n') { + Ungetc(c, str); + break; + } + } + } else if (c == '*') { /* C comment */ + int endstar = 0; + while ((c = Getc(str)) != EOF) { + if (endstar && c == '/') { /* end of C comment */ + break; + } + endstar = (c == '*'); + } + } else { + Putc('/', ts); + Putc(c, ts); + } + } + } else if (c == '#') { /* Preprocessor line */ + Putc('#', ts); + while ((c = Getc(str)) != EOF) { + Putc(c, ts); + if (c == '\\') { /* Continued line of the same PP */ + c = Getc(str); + if (c == '\n') + Putc(c, ts); + else + Ungetc(c, str); + } else if (c == '\n') + break; + } + if (!empty) { + Append(tf, "\n"); + } + Append(tf, ts); + Printf(f, "%s", tf); + Clear(tf); + Clear(ts); + for (i = 0; i < level; i++) + Putc(' ', tf); + empty = 1; + } else { + if (!empty || !isspace(c)) { + Putc(c, ts); + empty = 0; + } + } + } + if (!empty) { + Append(tf, ts); + } + if (Len(tf) != 0) + Printf(f, "%s", tf); + Delete(ts); + Delete(tf); + Printf(f, "\n"); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_print() + * + * Print out a wrapper function. Does pretty or compact printing as well. + * ----------------------------------------------------------------------------- */ + +void Wrapper_print(Wrapper *w, File *f) { + String *str; + + str = NewStringEmpty(); + Printf(str, "%s\n", w->def); + Printf(str, "%s\n", w->locals); + Printf(str, "%s\n", w->code); + if (Compact_mode == 1) + Wrapper_compact_print(str, f); + else + Wrapper_pretty_print(str, f); + + Delete(str); +} + +/* ----------------------------------------------------------------------------- + * Wrapper_add_local() + * + * Adds a new local variable declaration to a function. Returns -1 if already + * present (which may or may not be okay to the caller). + * ----------------------------------------------------------------------------- */ + +int Wrapper_add_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl) { + /* See if the local has already been declared */ + if (Getattr(w->localh, name)) { + return -1; + } + Setattr(w->localh, name, decl); + Printf(w->locals, "%s;\n", decl); + return 0; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_add_localv() + * + * Same as add_local(), but allows a NULL terminated list of strings to be + * used as a replacement for decl. This saves the caller the trouble of having + * to manually construct the 'decl' string before calling. + * ----------------------------------------------------------------------------- */ + +int Wrapper_add_localv(Wrapper *w, const_String_or_char_ptr name, ...) { + va_list ap; + int ret; + String *decl; + DOH *obj; + decl = NewStringEmpty(); + va_start(ap, name); + + obj = va_arg(ap, void *); + while (obj) { + Append(decl, obj); + Putc(' ', decl); + obj = va_arg(ap, void *); + } + va_end(ap); + + ret = Wrapper_add_local(w, name, decl); + Delete(decl); + return ret; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_check_local() + * + * Check to see if a local name has already been declared + * ----------------------------------------------------------------------------- */ + +int Wrapper_check_local(Wrapper *w, const_String_or_char_ptr name) { + if (Getattr(w->localh, name)) { + return 1; + } + return 0; +} + +/* ----------------------------------------------------------------------------- + * Wrapper_new_local() + * + * Adds a new local variable with a guarantee that a unique local name will be + * used. Returns the name that was actually selected. + * ----------------------------------------------------------------------------- */ + +char *Wrapper_new_local(Wrapper *w, const_String_or_char_ptr name, const_String_or_char_ptr decl) { + int i; + String *nname = NewString(name); + String *ndecl = NewString(decl); + char *ret; + + i = 0; + + while (Wrapper_check_local(w, nname)) { + Clear(nname); + Printf(nname, "%s%d", name, i); + i++; + } + Replace(ndecl, name, nname, DOH_REPLACE_ID); + Setattr(w->localh, nname, ndecl); + Printf(w->locals, "%s;\n", ndecl); + ret = Char(nname); + Delete(nname); + Delete(ndecl); + return ret; /* Note: nname should still exists in the w->localh hash */ +} + + +/* ----------------------------------------------------------------------------- + * Wrapper_new_localv() + * + * Same as add_local(), but allows a NULL terminated list of strings to be + * used as a replacement for decl. This saves the caller the trouble of having + * to manually construct the 'decl' string before calling. + * ----------------------------------------------------------------------------- */ + +char *Wrapper_new_localv(Wrapper *w, const_String_or_char_ptr name, ...) { + va_list ap; + char *ret; + String *decl; + DOH *obj; + decl = NewStringEmpty(); + va_start(ap, name); + + obj = va_arg(ap, void *); + while (obj) { + Append(decl, obj); + Putc(' ', decl); + obj = va_arg(ap, void *); + } + va_end(ap); + + ret = Wrapper_new_local(w, name, decl); + Delete(decl); + return ret; +} |