diff --git a/CHANGES.current b/CHANGES.current index 234e730c3..0c6db7c90 100644 --- a/CHANGES.current +++ b/CHANGES.current @@ -7,6 +7,17 @@ the issue number to the end of the URL: https://github.com/swig/swig/issues/ Version 4.1.0 (in progress) =========================== +2022-04-20: cminyard + Fix an issue where newlines were not properly generated + for godirectorin typemaps. If you have a virtual function + not assigned to zero, in some cases it won't generate a + newline and you will see errors: + example.go:1508:3: expected ';', found swig_r + when compiling the go code. + + Also add an example of using goin and godirectorin and add + a test for this situation. + 2022-04-11: robinst #2257 Fix new Ruby 3.2 warning "undefining the allocator of T_DATA class swig_runtime_data". diff --git a/Examples/go/check.list b/Examples/go/check.list index b3f34b306..6046c8310 100644 --- a/Examples/go/check.list +++ b/Examples/go/check.list @@ -12,3 +12,4 @@ reference simple template variables +goin diff --git a/Examples/go/goin/Makefile b/Examples/go/goin/Makefile new file mode 100644 index 000000000..f79b083cb --- /dev/null +++ b/Examples/go/goin/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIGEXE = $(TOP)/../swig +SWIG_LIB_DIR = $(TOP)/../$(TOP_BUILDDIR_TO_TOP_SRCDIR)Lib +CXXSRCS = +TARGET = example +INTERFACE = example.i +SWIGOPT = + +check: build + $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_run + +build: + $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' CXXSRCS='$(CXXSRCS)' \ + SWIG_LIB_DIR='$(SWIG_LIB_DIR)' SWIGEXE='$(SWIGEXE)' \ + SWIGOPT='$(SWIGOPT)' TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' go_cpp + +clean: + $(MAKE) -f $(TOP)/Makefile SRCDIR='$(SRCDIR)' INTERFACE='$(INTERFACE)' go_clean diff --git a/Examples/go/goin/example.i b/Examples/go/goin/example.i new file mode 100644 index 000000000..1d8289af8 --- /dev/null +++ b/Examples/go/goin/example.i @@ -0,0 +1,106 @@ + +%module(directors="1") example + +%inline %{ +// Helper functions for converting string arrays +#include +void *alloc_ptr_array(unsigned int len) +{ + return calloc(len, sizeof(void *)); +} +void set_ptr_array(void *ain, unsigned int pos, void *val) +{ + void **a = (void **) ain; + a[pos] = val; +} +void *get_ptr_array(void *ain, unsigned int pos) +{ + void **a = (void **) ain; + return a[pos]; +} +void free_ptr_array(void *ain) +{ + void **a = (void **) ain; + unsigned int i; + + if (!a) + return; + for (i = 0; a[i]; i++) { + free(a[i]); + } + free(a); +} +char *uintptr_to_string(void *in) +{ + return (char *) in; +} +void *string_to_uintptr(char *in) +{ + return strdup(in); +} +%} + +// These typemaps convert between an array of strings in Go and a +// const char** that is NULL terminated in C++. +%typemap(gotype) (const char * const *) "[]string"; +%typemap(imtype) (const char * const *) "uintptr"; +%typemap(goin) (const char * const *) { + if $input == nil || len($input) == 0 { + $result = 0 + } else { + $result = Alloc_ptr_array(uint(len($input) + 1)) + defer func() { + Free_ptr_array($result) + }() + var i uint + for i = 0; i < uint(len($input)); i++ { + Set_ptr_array($result, i, String_to_uintptr($input[i])) + } + } +} +%typemap(in) (const char * const *) { + $1 = (char **) $input; +} +%typemap(godirectorin) (const char * const *) { + if ($input == 0) { + $result = nil + } else { + var i uint + for i = 0; ; i++ { + var v uintptr = Get_ptr_array($input, i) + if v == 0 { + break + } + } + if i == 0 { + $result = nil + } else { + $result = make([]string, i) + for i = 0; ; i++ { + var v uintptr = Get_ptr_array($input, i) + if v == 0 { + break + } + $result[i] = Uintptr_to_string(v) + } + } + } +} + +%feature("director") callbacks; + +%inline %{ + class callbacks { + public: + virtual bool call1(int v, const char * const *strarray); + virtual ~callbacks() {} + }; + + bool check1(callbacks *c, int v, const char * const *strarray) { + return c->call1(v, strarray); + } + + bool callbacks::call1(int v, const char * const *strarray) { + return false; + } +%} diff --git a/Examples/go/goin/index.html b/Examples/go/goin/index.html new file mode 100644 index 000000000..852b068da --- /dev/null +++ b/Examples/go/goin/index.html @@ -0,0 +1,26 @@ + + +SWIG:Examples:go:going + + + + + +SWIG/Examples/go/goin/ +
+ +

Example of using goin and godirectorin

+ +

+This example converts between a Go []string and a "const char * const *" +in C/C++. It does this for a director and for a normal call. + +

+

+ +
+ + diff --git a/Examples/go/goin/runme.go b/Examples/go/goin/runme.go new file mode 100644 index 000000000..dfc7b0936 --- /dev/null +++ b/Examples/go/goin/runme.go @@ -0,0 +1,38 @@ +package main + +import ( + "fmt" + "swigtests/example" +) + +type mycallbacks struct { + example.Callbacks +} + +var tststrs = []string{ "A", "BCD", "EFGH" } +var tstint int = 5 + +func (v *mycallbacks) Call1(val int, strarray []string) bool { + var rv bool = true + + for i, s := range strarray { + fmt.Printf("%d: %s\n", i, s) + if s != tststrs[i] { + fmt.Printf(" ***Mismatch, expected %s\n", tststrs[i]) + rv = false + } + } + if val != tstint { + rv = false + } + return rv +} + +func main() { + cbs := &mycallbacks{} + cbs.Callbacks = example.NewDirectorCallbacks(cbs) + worked := example.Check1(cbs, tstint, tststrs) + if !worked { + panic("Data mismatch") + } +} diff --git a/Examples/go/index.html b/Examples/go/index.html index 467f4ecb7..370424c54 100644 --- a/Examples/go/index.html +++ b/Examples/go/index.html @@ -24,6 +24,7 @@ certain C declarations are turned into constants.
  • callback. C++ callbacks using directors.
  • extend. Polymorphism using directors.
  • director. Example how to utilize the director feature. +
  • director. Example how to use goin and godirectorin.

    Compilation Issues

    diff --git a/Examples/test-suite/go/go_director_inout_runme.go b/Examples/test-suite/go/go_director_inout_runme.go index f2be9d30b..55f32dfc3 100644 --- a/Examples/test-suite/go/go_director_inout_runme.go +++ b/Examples/test-suite/go/go_director_inout_runme.go @@ -34,6 +34,15 @@ func (p *GoMyClass) S3(s *string) { *s = "R3" } +func (p *GoMyClass) S4(s []string) { + if s[0] != "T1" { + panic(s) + } + if s[1] != "T2" { + panic(s) + } +} + func main() { a := wrap.NewDirectorMyClass(&GoMyClass{}) m := map[string]interface{}{ @@ -56,6 +65,8 @@ func main() { panic(str) } + a.CallS4([]string{ "T1", "T2" }) + a = wrap.NewDirectorMyClass(nil) s = a.Adjust(m) if s.Str != `{"first":"second"}` { diff --git a/Examples/test-suite/go_director_inout.i b/Examples/test-suite/go_director_inout.i index 38059ea40..b12e5da52 100644 --- a/Examples/test-suite/go_director_inout.i +++ b/Examples/test-suite/go_director_inout.i @@ -120,6 +120,92 @@ type GoRetStruct struct { $1.assign(tmp->p, tmp->p + tmp->n); } +%inline %{ +// Helper functions for converting string arrays +#include +void *alloc_ptr_array(unsigned int len) +{ + return calloc(len, sizeof(void *)); +} +void set_ptr_array(void *ain, unsigned int pos, void *val) +{ + void **a = (void **) ain; + a[pos] = val; +} +void *get_ptr_array(void *ain, unsigned int pos) +{ + void **a = (void **) ain; + return a[pos]; +} +void free_ptr_array(void *ain) +{ + void **a = (void **) ain; + unsigned int i; + + if (!a) + return; + for (i = 0; a[i]; i++) { + free(a[i]); + } + free(a); +} +char *uintptr_to_string(void *in) +{ + return (char *) in; +} +void *string_to_uintptr(char *in) +{ + return strdup(in); +} +%} + +// These typemaps convert between an array of strings in Go and a +// const char** that is NULL terminated in C++. +%typemap(gotype) (const char * const *) "[]string"; +%typemap(imtype) (const char * const *) "uintptr"; +%typemap(goin) (const char * const *) { + if $input == nil || len($input) == 0 { + $result = 0 + } else { + $result = Alloc_ptr_array(uint(len($input) + 1)) + defer func() { + Free_ptr_array($result) + }() + var i uint + for i = 0; i < uint(len($input)); i++ { + Set_ptr_array($result, i, String_to_uintptr($input[i])) + } + } +} +%typemap(in) (const char * const *) { + $1 = (char **) $input; +} +%typemap(godirectorin) (const char * const *) { + if ($input == 0) { + $result = nil + } else { + var i uint + for i = 0; ; i++ { + var v uintptr = Get_ptr_array($input, i) + if v == 0 { + break + } + } + if i == 0 { + $result = nil + } else { + $result = make([]string, i) + for i = 0; ; i++ { + var v uintptr = Get_ptr_array($input, i) + if v == 0 { + break + } + $result[i] = Uintptr_to_string(v) + } + } + } +} + %feature("director") MyClass; %inline @@ -134,9 +220,23 @@ class MyClass { return r; } - virtual void S1(std::string s) = 0; + void CallS4(const char * const *strarray); + virtual void S1(std::string s); virtual void S2(std::string& s) = 0; virtual void S3(std::string* s) = 0; + virtual void S4(const char * const *strarray); }; +void MyClass::S1(std::string s) { + throw "Base S1 called!"; +} + +void MyClass::S4(const char * const *strarray) { + throw "Base S4 called!"; +} + +void MyClass::CallS4(const char * const *strarray) { + this->S4(strarray); +} + %} diff --git a/Source/Modules/go.cxx b/Source/Modules/go.cxx index 071d39ec7..d828b00aa 100644 --- a/Source/Modules/go.cxx +++ b/Source/Modules/go.cxx @@ -3518,7 +3518,7 @@ private: goin = Copy(goin); Replaceall(goin, "$input", ln); Replaceall(goin, "$result", ivar); - Printv(f_go_wrappers, goin, NULL); + Printv(f_go_wrappers, goin, "\n", NULL); Delete(goin); } @@ -3772,7 +3772,7 @@ private: goin = Copy(goin); Replaceall(goin, "$input", ln); Replaceall(goin, "$result", ivar); - Printv(f_go_wrappers, goin, NULL); + Printv(f_go_wrappers, goin, "\n", NULL); Delete(goin); }