Get rid of separate cmodtype typemap
Use the same ctype for wrapper declarations and definitions and just expand $resolved_type differently in the two cases. This simplifies the typemaps and ensures that the declarations and definitions use the same types, at least for all non-object parameters.
This commit is contained in:
parent
5de29df38e
commit
8cae88dd39
4 changed files with 51 additions and 112 deletions
|
|
@ -431,20 +431,6 @@ area: 7.068583
|
||||||
</code>
|
</code>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
|
||||||
<td><tt>cmodtype</tt></td>
|
|
||||||
<td>Provides types used by wrapper functions and</br>
|
|
||||||
Casts of function parameters of wrapper function calls</br>
|
|
||||||
</br>
|
|
||||||
<code>
|
|
||||||
extern void _wrap_MyClass_delete(SwigObj *o);</br>
|
|
||||||
</br>
|
|
||||||
void MyClass_delete(MyClass *c) {</br>
|
|
||||||
_wrap_MyClass_delete((Swig_Obj *)c);</br>
|
|
||||||
}
|
|
||||||
</code>
|
|
||||||
</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
<tr>
|
||||||
<td><tt>in</tt></td>
|
<td><tt>in</tt></td>
|
||||||
<td>Mapping of wrapper functions parameters to local C++ variables</br>
|
<td>Mapping of wrapper functions parameters to local C++ variables</br>
|
||||||
|
|
@ -556,7 +542,7 @@ A typical wrapper will be composited with these [optional] blocks:
|
||||||
Let's go through it step by step and start with the wrapper prototype
|
Let's go through it step by step and start with the wrapper prototype
|
||||||
|
|
||||||
<div class="targetlang"><pre>
|
<div class="targetlang"><pre>
|
||||||
cmodtype cmodtype cmodtype
|
ctype ctype ctype
|
||||||
--------- --------- ---
|
--------- --------- ---
|
||||||
SwigObj * _wrap_someFunction(SwigObj * carg1, int carg2);
|
SwigObj * _wrap_someFunction(SwigObj * carg1, int carg2);
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
@ -564,7 +550,7 @@ SwigObj * _wrap_someFunction(SwigObj * carg1, int carg2);
|
||||||
As first unit of the wrapper code, a variable to hold the return value of the function is emitted to the wrapper's body
|
As first unit of the wrapper code, a variable to hold the return value of the function is emitted to the wrapper's body
|
||||||
|
|
||||||
<div class="targetlang"><pre>
|
<div class="targetlang"><pre>
|
||||||
cmodtype
|
ctype
|
||||||
---------
|
---------
|
||||||
SwigObj * result;
|
SwigObj * result;
|
||||||
</pre></div>
|
</pre></div>
|
||||||
|
|
|
||||||
32
Lib/c/c.swg
32
Lib/c/c.swg
|
|
@ -90,7 +90,7 @@ same_action(TM, size_t, ACTION);
|
||||||
%typemap(TM) void*, void const* ACTION
|
%typemap(TM) void*, void const* ACTION
|
||||||
%enddef
|
%enddef
|
||||||
|
|
||||||
// Typemaps for proxy function parameters
|
// "ctype" is the type used with C wrapper functions.
|
||||||
// void
|
// void
|
||||||
%typemap(ctype) void "void"
|
%typemap(ctype) void "void"
|
||||||
%typemap(ctype) void*, void& "void *"
|
%typemap(ctype) void*, void& "void *"
|
||||||
|
|
@ -118,36 +118,6 @@ same_type_all_primitive_types_but_void(ctype);
|
||||||
%typemap(ctype, fragment="stdbool_inc") bool & "$1_ltype"
|
%typemap(ctype, fragment="stdbool_inc") bool & "$1_ltype"
|
||||||
%typemap(ctype, fragment="stdbool_inc") const bool & "const $1_ltype"
|
%typemap(ctype, fragment="stdbool_inc") const bool & "const $1_ltype"
|
||||||
|
|
||||||
// Typemaps for wrapper function parameters and its local variables
|
|
||||||
// void
|
|
||||||
%typemap(cmodtype) void "void"
|
|
||||||
%typemap(cmodtype) void*, void& "void *"
|
|
||||||
%typemap(cmodtype) const void&, const void* "const void *"
|
|
||||||
%typemap(cmodtype) void**, void*&, void*[ANY], void[ANY][ANY] "void **"
|
|
||||||
%typemap(cmodtype) const void**, const void*& "const void **"
|
|
||||||
%typemap(cmodtype) void* * const "void* *"
|
|
||||||
%typemap(cmodtype) const void* * const "const void* *"
|
|
||||||
|
|
||||||
same_type_all_primitive_types_but_void(cmodtype);
|
|
||||||
|
|
||||||
// special cases of array passing - does not intended to be used for objects
|
|
||||||
%typemap(cmodtype) SWIGTYPE [] "$1_ltype"
|
|
||||||
%typemap(cmodtype) SWIGTYPE ((&)[ANY]) "$1_basetype **"
|
|
||||||
|
|
||||||
%typemap(cmodtype) SWIGTYPE "SwigObj *"
|
|
||||||
%typemap(cmodtype) SWIGTYPE * "SwigObj *"
|
|
||||||
%typemap(cmodtype) SWIGTYPE & "SwigObj *"
|
|
||||||
%typemap(cmodtype) SWIGTYPE [ANY][ANY], SWIGTYPE ** "/* whoa */ SwigObj ***"
|
|
||||||
%typemap(cmodtype) SWIGTYPE *[ANY] "/*ooooh*/ SwigObj **"
|
|
||||||
%typemap(cmodtype) SWIGTYPE *& "/* *& */ SwigObj **"
|
|
||||||
%typemap(cmodtype) enum SWIGTYPE "int"
|
|
||||||
%typemap(cmodtype) enum SWIGTYPE &, enum SWIGTYPE * "int *"
|
|
||||||
|
|
||||||
%typemap(cmodtype, fragment="stdbool_inc") bool, bool *, bool **, const bool, const bool *, bool * [ANY] "$1_type"
|
|
||||||
%typemap(cmodtype, fragment="stdbool_inc") bool & "$1_ltype"
|
|
||||||
%typemap(cmodtype, fragment="stdbool_inc") const bool & "const $1_ltype"
|
|
||||||
|
|
||||||
|
|
||||||
// Typemaps for assigning wrapper parameters to local variables
|
// Typemaps for assigning wrapper parameters to local variables
|
||||||
same_action_all_primitive_types(in, "$1 = ($1_ltype) $input;")
|
same_action_all_primitive_types(in, "$1 = ($1_ltype) $input;")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,10 +9,6 @@ namespace std {
|
||||||
|
|
||||||
class string;
|
class string;
|
||||||
|
|
||||||
%typemap(cmodtype) string "char *"
|
|
||||||
%typemap(cmodtype) string * "char *"
|
|
||||||
%typemap(cmodtype) string & "char *"
|
|
||||||
%typemap(cmodtype) const string & "char *"
|
|
||||||
%typemap(ctype) string "char *"
|
%typemap(ctype) string "char *"
|
||||||
%typemap(ctype) string * "char *"
|
%typemap(ctype) string * "char *"
|
||||||
%typemap(ctype) string & "char *"
|
%typemap(ctype) string & "char *"
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,12 @@ class C:public Language {
|
||||||
|
|
||||||
bool except_flag;
|
bool except_flag;
|
||||||
|
|
||||||
|
// Selects between the wrappers (public) declarations and (private) definitions.
|
||||||
|
enum output_target {
|
||||||
|
output_wrapper_decl,
|
||||||
|
output_wrapper_def
|
||||||
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
/* -----------------------------------------------------------------------------
|
/* -----------------------------------------------------------------------------
|
||||||
|
|
@ -243,7 +249,7 @@ public:
|
||||||
* substituteResolvedTypeSpecialVariable()
|
* substituteResolvedTypeSpecialVariable()
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
void substituteResolvedTypeSpecialVariable(SwigType *classnametype, String *tm, const char *classnamespecialvariable) {
|
void substituteResolvedTypeSpecialVariable(output_target target, SwigType *classnametype, String *tm, const char *classnamespecialvariable) {
|
||||||
if (!CPlusPlus) {
|
if (!CPlusPlus) {
|
||||||
// Just use the original C type when not using C++, we know that this type can be used in the wrappers.
|
// Just use the original C type when not using C++, we know that this type can be used in the wrappers.
|
||||||
Clear(tm);
|
Clear(tm);
|
||||||
|
|
@ -260,27 +266,29 @@ public:
|
||||||
else
|
else
|
||||||
Replaceall(tm, classnamespecialvariable, NewStringf("int"));
|
Replaceall(tm, classnamespecialvariable, NewStringf("int"));
|
||||||
} else {
|
} else {
|
||||||
String *classname = getProxyName(classnametype);
|
scoped_dohptr btype(SwigType_base(classnametype));
|
||||||
if (classname) {
|
String* typestr = NIL;
|
||||||
Replaceall(tm, classnamespecialvariable, classname); // getProxyName() works for pointers to classes too
|
if (target == output_wrapper_def || Cmp(btype, "SwigObj") == 0) {
|
||||||
|
// Special case, just leave it unchanged.
|
||||||
|
typestr = NewString("SwigObj");
|
||||||
} else {
|
} else {
|
||||||
String* typestr = NIL;
|
typestr = getProxyName(classnametype);
|
||||||
SwigType *btype = SwigType_base(classnametype);
|
if (!typestr) {
|
||||||
if (SwigType_isbuiltin(btype)) {
|
if (SwigType_isbuiltin(btype)) {
|
||||||
// This should work just as well in C without any changes.
|
// This should work just as well in C without any changes.
|
||||||
typestr = SwigType_str(classnametype, 0);
|
typestr = SwigType_str(classnametype, 0);
|
||||||
} else {
|
} else {
|
||||||
// Swig doesn't know anything about this type, use descriptor for it.
|
// Swig doesn't know anything about this type, use descriptor for it.
|
||||||
typestr = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
|
typestr = NewStringf("SWIGTYPE%s", SwigType_manglestr(classnametype));
|
||||||
|
|
||||||
// And make sure it is declared before it is used.
|
// And make sure it is declared before it is used.
|
||||||
Printf(f_wrappers_types, "typedef struct %s %s;\n\n", typestr, typestr);
|
Printf(f_wrappers_types, "typedef struct %s %s;\n\n", typestr, typestr);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Delete(btype);
|
|
||||||
|
|
||||||
Replaceall(tm, classnamespecialvariable, typestr);
|
|
||||||
Delete(typestr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Replaceall(tm, classnamespecialvariable, typestr);
|
||||||
|
Delete(typestr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -300,14 +308,14 @@ public:
|
||||||
* substitution_performed - flag indicating if a substitution was performed
|
* substitution_performed - flag indicating if a substitution was performed
|
||||||
* ----------------------------------------------------------------------------- */
|
* ----------------------------------------------------------------------------- */
|
||||||
|
|
||||||
bool substituteResolvedType(SwigType *pt, String *tm) {
|
bool substituteResolvedType(output_target target, SwigType *pt, String *tm) {
|
||||||
bool substitution_performed = false;
|
bool substitution_performed = false;
|
||||||
SwigType *type = Copy(SwigType_typedef_resolve_all(pt));
|
SwigType *type = Copy(SwigType_typedef_resolve_all(pt));
|
||||||
SwigType *strippedtype = SwigType_strip_qualifiers(type);
|
SwigType *strippedtype = SwigType_strip_qualifiers(type);
|
||||||
|
|
||||||
if (Strstr(tm, "$resolved_type")) {
|
if (Strstr(tm, "$resolved_type")) {
|
||||||
SwigType *classnametype = Copy(strippedtype);
|
SwigType *classnametype = Copy(strippedtype);
|
||||||
substituteResolvedTypeSpecialVariable(classnametype, tm, "$resolved_type");
|
substituteResolvedTypeSpecialVariable(target, classnametype, tm, "$resolved_type");
|
||||||
substitution_performed = true;
|
substitution_performed = true;
|
||||||
Delete(classnametype);
|
Delete(classnametype);
|
||||||
}
|
}
|
||||||
|
|
@ -315,7 +323,7 @@ public:
|
||||||
SwigType *classnametype = Copy(strippedtype);
|
SwigType *classnametype = Copy(strippedtype);
|
||||||
Delete(SwigType_pop(classnametype));
|
Delete(SwigType_pop(classnametype));
|
||||||
if (Len(classnametype) > 0) {
|
if (Len(classnametype) > 0) {
|
||||||
substituteResolvedTypeSpecialVariable(classnametype, tm, "$*resolved_type");
|
substituteResolvedTypeSpecialVariable(target, classnametype, tm, "$*resolved_type");
|
||||||
substitution_performed = true;
|
substitution_performed = true;
|
||||||
}
|
}
|
||||||
Delete(classnametype);
|
Delete(classnametype);
|
||||||
|
|
@ -323,7 +331,7 @@ public:
|
||||||
if (Strstr(tm, "$&resolved_type")) {
|
if (Strstr(tm, "$&resolved_type")) {
|
||||||
SwigType *classnametype = Copy(strippedtype);
|
SwigType *classnametype = Copy(strippedtype);
|
||||||
SwigType_add_pointer(classnametype);
|
SwigType_add_pointer(classnametype);
|
||||||
substituteResolvedTypeSpecialVariable(classnametype, tm, "$&resolved_type");
|
substituteResolvedTypeSpecialVariable(target, classnametype, tm, "$&resolved_type");
|
||||||
substitution_performed = true;
|
substitution_performed = true;
|
||||||
Delete(classnametype);
|
Delete(classnametype);
|
||||||
}
|
}
|
||||||
|
|
@ -741,38 +749,13 @@ ready:
|
||||||
Wrapper_add_local(wrapper, "cppresult", SwigType_str(cpptype, "cppresult"));
|
Wrapper_add_local(wrapper, "cppresult", SwigType_str(cpptype, "cppresult"));
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual SwigType *functionWrapperCPPSpecificWrapperReturnTypeGet(Node *n)
|
String *get_wrapper_func_return_type(output_target target, Node *n)
|
||||||
{
|
|
||||||
SwigType *type = Getattr(n, "type");
|
|
||||||
SwigType *return_type = NewString("");
|
|
||||||
String *tm;
|
|
||||||
|
|
||||||
// set the return type
|
|
||||||
if (IS_SET_TO_ONE(n, "c:objstruct")) {
|
|
||||||
Printv(return_type, SwigType_str(type, 0), NIL);
|
|
||||||
}
|
|
||||||
else if ((tm = Swig_typemap_lookup("cmodtype", n, "", 0))) {
|
|
||||||
String *ctypeout = Getattr(n, "tmap:cmodtype:out");
|
|
||||||
if (ctypeout)
|
|
||||||
{
|
|
||||||
tm = ctypeout;
|
|
||||||
Printf(stdout, "Obscure cmodtype:out found! O.o\n");
|
|
||||||
}
|
|
||||||
Printf(return_type, "%s", tm);
|
|
||||||
// template handling
|
|
||||||
Replaceall(return_type, "$tt", SwigType_lstr(type, 0));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No cmodtype typemap defined for %s\n", SwigType_str(type, 0));
|
|
||||||
}
|
|
||||||
return return_type;
|
|
||||||
}
|
|
||||||
|
|
||||||
String *get_wrapper_func_return_type(Node *n)
|
|
||||||
{
|
{
|
||||||
|
if (target == output_wrapper_decl) {
|
||||||
SwigType *proxy_type = Getattr(n, "c:stype"); // use proxy-type for return type if supplied
|
SwigType *proxy_type = Getattr(n, "c:stype"); // use proxy-type for return type if supplied
|
||||||
if (proxy_type)
|
if (proxy_type)
|
||||||
return SwigType_str(proxy_type, 0);
|
return SwigType_str(proxy_type, 0);
|
||||||
|
}
|
||||||
|
|
||||||
SwigType *type = Getattr(n, "type");
|
SwigType *type = Getattr(n, "type");
|
||||||
String *return_type = NewString("");
|
String *return_type = NewString("");
|
||||||
|
|
@ -792,12 +775,12 @@ ready:
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
substituteResolvedType(type, tm);
|
substituteResolvedType(target, type, tm);
|
||||||
return_type = tm;
|
return_type = tm;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No cmodtype typemap defined for %s\n", SwigType_str(type, 0));
|
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(type, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Replaceall(return_type, "::", "_");
|
Replaceall(return_type, "::", "_");
|
||||||
|
|
@ -856,7 +839,7 @@ ready:
|
||||||
if ((stype = Getattr(p, "c:stype"))) {
|
if ((stype = Getattr(p, "c:stype"))) {
|
||||||
proxy_parm_type = SwigType_lstr(stype, 0);
|
proxy_parm_type = SwigType_lstr(stype, 0);
|
||||||
} else {
|
} else {
|
||||||
substituteResolvedType(type, tm);
|
substituteResolvedType(output_wrapper_decl, type, tm);
|
||||||
proxy_parm_type = tm;
|
proxy_parm_type = tm;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -892,7 +875,7 @@ ready:
|
||||||
Printv(call, "(", NIL);
|
Printv(call, "(", NIL);
|
||||||
|
|
||||||
// attach typemaps to cast wrapper call with proxy types
|
// attach typemaps to cast wrapper call with proxy types
|
||||||
Swig_typemap_attach_parms("cmodtype", parms, 0);
|
Swig_typemap_attach_parms("ctype", parms, 0);
|
||||||
|
|
||||||
// prepare function definition
|
// prepare function definition
|
||||||
for (p = parms, gencomma = 0; p; ) {
|
for (p = parms, gencomma = 0; p; ) {
|
||||||
|
|
@ -920,13 +903,15 @@ ready:
|
||||||
Printf(arg_name, "c%s", lname);
|
Printf(arg_name, "c%s", lname);
|
||||||
|
|
||||||
// set the appropriate type for parameter
|
// set the appropriate type for parameter
|
||||||
if ((tm = Getattr(p, "tmap:cmodtype"))) {
|
if ((tm = Getattr(p, "tmap:ctype"))) {
|
||||||
|
substituteResolvedType(output_wrapper_def, type, tm);
|
||||||
|
|
||||||
Printv(c_parm_type, NewString("("), tm, NewString(")"), NIL);
|
Printv(c_parm_type, NewString("("), tm, NewString(")"), NIL);
|
||||||
// template handling
|
// template handling
|
||||||
Replaceall(c_parm_type, "$tt", SwigType_lstr(type, 0));
|
Replaceall(c_parm_type, "$tt", SwigType_lstr(type, 0));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No cmodtype typemap defined for %s\n", SwigType_str(type, 0));
|
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(type, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
Printv(args, gencomma ? ", " : "", c_parm_type, arg_name, NIL);
|
Printv(args, gencomma ? ", " : "", c_parm_type, arg_name, NIL);
|
||||||
|
|
@ -965,7 +950,7 @@ ready:
|
||||||
// C++ function wrapper proxy code
|
// C++ function wrapper proxy code
|
||||||
bool const is_global = IS_SET_TO_ONE(n, "c:globalfun");
|
bool const is_global = IS_SET_TO_ONE(n, "c:globalfun");
|
||||||
String *wname = is_global ? Swig_name_wrapper(name) : Copy(name);
|
String *wname = is_global ? Swig_name_wrapper(name) : Copy(name);
|
||||||
String *preturn_type = get_wrapper_func_return_type(n);
|
String *preturn_type = get_wrapper_func_return_type(output_wrapper_decl, n);
|
||||||
String *pproto = get_wrapper_func_proto(n);
|
String *pproto = get_wrapper_func_proto(n);
|
||||||
String *wrapper_call = NewString("");
|
String *wrapper_call = NewString("");
|
||||||
|
|
||||||
|
|
@ -996,7 +981,7 @@ ready:
|
||||||
String *storage = Getattr(n, "storage");
|
String *storage = Getattr(n, "storage");
|
||||||
SwigType *type = Getattr(n, "type");
|
SwigType *type = Getattr(n, "type");
|
||||||
SwigType *otype = Copy(type);
|
SwigType *otype = Copy(type);
|
||||||
SwigType *return_type = functionWrapperCPPSpecificWrapperReturnTypeGet(n);
|
SwigType *return_type = get_wrapper_func_return_type(output_wrapper_def, n);
|
||||||
String *wname = IS_SET_TO_ONE(n, "c:globalfun") ? Swig_name_wrapper(name) : Copy(name);
|
String *wname = IS_SET_TO_ONE(n, "c:globalfun") ? Swig_name_wrapper(name) : Copy(name);
|
||||||
String *arg_names = NewString("");
|
String *arg_names = NewString("");
|
||||||
ParmList *parms = Getattr(n, "parms");
|
ParmList *parms = Getattr(n, "parms");
|
||||||
|
|
@ -1030,7 +1015,7 @@ ready:
|
||||||
Setattr(n, "wrap:parms", parms); //never read again?!
|
Setattr(n, "wrap:parms", parms); //never read again?!
|
||||||
|
|
||||||
// attach 'ctype' typemaps
|
// attach 'ctype' typemaps
|
||||||
Swig_typemap_attach_parms("cmodtype", parms, wrapper);
|
Swig_typemap_attach_parms("ctype", parms, wrapper);
|
||||||
|
|
||||||
// prepare function definition
|
// prepare function definition
|
||||||
for (p = parms, gencomma = 0; p; ) {
|
for (p = parms, gencomma = 0; p; ) {
|
||||||
|
|
@ -1058,13 +1043,15 @@ ready:
|
||||||
Printf(arg_name, "c%s", lname);
|
Printf(arg_name, "c%s", lname);
|
||||||
|
|
||||||
// set the appropriate type for parameter
|
// set the appropriate type for parameter
|
||||||
if ((tm = Getattr(p, "tmap:cmodtype"))) {
|
if ((tm = Getattr(p, "tmap:ctype"))) {
|
||||||
|
substituteResolvedType(output_wrapper_def, type, tm);
|
||||||
|
|
||||||
Printv(c_parm_type, tm, NIL);
|
Printv(c_parm_type, tm, NIL);
|
||||||
// template handling
|
// template handling
|
||||||
Replaceall(c_parm_type, "$tt", SwigType_lstr(type, 0));
|
Replaceall(c_parm_type, "$tt", SwigType_lstr(type, 0));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No cmodtype typemap defined for %s\n", SwigType_str(type, 0));
|
Swig_warning(WARN_C_TYPEMAP_CTYPE_UNDEF, input_file, line_number, "No ctype typemap defined for %s\n", SwigType_str(type, 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
// use proxy-type for parameter if supplied
|
// use proxy-type for parameter if supplied
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue