diff --git a/Examples/GIFPlot/Ruby/shadow/Makefile b/Examples/GIFPlot/Ruby/shadow/Makefile new file mode 100644 index 000000000..a0f6b6325 --- /dev/null +++ b/Examples/GIFPlot/Ruby/shadow/Makefile @@ -0,0 +1,23 @@ +TOP = ../../.. +SWIG = $(TOP)/../swig +SWIGOPT = -I../../Interface +SRCS = +TARGET = gifplot +INTERFACE = gifplot.i +LIBS = -L../.. -lgifplot +INCLUDE = -I../../Include + +all:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + INCLUDE='$(INCLUDE)' LIBS='$(LIBS)' SWIGOPT='$(SWIGOPT)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby + +static:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + INCLUDE='$(INCLUDE)' LIBS='$(LIBS)' SWIGOPT='$(SWIGOPT)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core *.gif + +check: all diff --git a/Examples/GIFPlot/Ruby/shadow/README b/Examples/GIFPlot/Ruby/shadow/README new file mode 100644 index 000000000..7a33e137f --- /dev/null +++ b/Examples/GIFPlot/Ruby/shadow/README @@ -0,0 +1,5 @@ +This example illustrates Ruby shadow classes. Take a look at +the file GIFPlot/Interface/gifplot.i + +Actually Ruby module of SWIG needs no shadow class. But this example +is named "shadow" in order to be consistent with other languages. diff --git a/Examples/GIFPlot/Ruby/shadow/cmap b/Examples/GIFPlot/Ruby/shadow/cmap new file mode 100644 index 000000000..a20c331a9 Binary files /dev/null and b/Examples/GIFPlot/Ruby/shadow/cmap differ diff --git a/Examples/GIFPlot/Ruby/shadow/runme.rb b/Examples/GIFPlot/Ruby/shadow/runme.rb new file mode 100644 index 000000000..0afcceef9 --- /dev/null +++ b/Examples/GIFPlot/Ruby/shadow/runme.rb @@ -0,0 +1,66 @@ +# Plot a 3D function +require 'gifplot' +include Math + +# Here is the function to plot +def func(x,y) + return 5*cos(2*sqrt(x*x+y*y))*exp(-0.3*sqrt(x*x+y*y)) +end + +# Here are some plotting parameters +XMIN = -5.0 +XMAX = 5.0 +YMIN = -5.0 +YMAX = 5.0 +ZMIN = -5.0 +ZMAX = 5.0 + +# Grid resolution +NXPOINTS = 60 +NYPOINTS = 60 + +cmap = Gifplot::ColorMap.new("cmap") +frame = Gifplot::FrameBuffer.new(500,500) +frame.clear(Gifplot::BLACK) + +P3 = Gifplot::Plot3D.new(frame,XMIN,YMIN,ZMIN,XMAX,YMAX,ZMAX) +P3.lookat(2*[XMAX-XMIN,YMAX-YMIN,ZMAX-ZMIN].max) +P3.autoperspective(40) +P3.rotu(60) +P3.rotr(30) +P3.rotd(10) + +def drawsolid() + P3.clear(Gifplot::BLACK) + P3.start() + dx = 1.0*(XMAX-XMIN)/NXPOINTS + dy = 1.0*(YMAX-YMIN)/NYPOINTS + cscale = 240.0/(ZMAX-ZMIN) + x = XMIN + for i in 0...NXPOINTS + y = YMIN + for j in 0...NYPOINTS + z1 = func(x,y) + z2 = func(x+dx,y) + z3 = func(x+dx,y+dy) + z4 = func(x,y+dy) + c1 = cscale*(z1-ZMIN) + c2 = cscale*(z2-ZMIN) + c3 = cscale*(z3-ZMIN) + c4 = cscale*(z4-ZMIN) + c = (c1+c2+c3+c4)/4 + c = 0 if (c < 0) + c = 239 if c > 239 + P3.solidquad(x,y,z1,x+dx,y,z2,x+dx,y+dy,z3,x,y+dy,z4,c+16) + y = y + dy + end + x = x + dx + end +end + +puts "Making a nice 3D plot..." +drawsolid() + +frame.writeGIF(cmap,"image.gif") +puts "Wrote image.gif" + diff --git a/Examples/ruby/class/Makefile b/Examples/ruby/class/Makefile new file mode 100644 index 000000000..01ce757ff --- /dev/null +++ b/Examples/ruby/class/Makefile @@ -0,0 +1,19 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_cpp_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core + +check: all diff --git a/Examples/ruby/class/example.cxx b/Examples/ruby/class/example.cxx new file mode 100644 index 000000000..21582f4d1 --- /dev/null +++ b/Examples/ruby/class/example.cxx @@ -0,0 +1,28 @@ +/* File : example.c */ + +#include "example.h" +#include + +/* Move the shape to a new location */ +void Shape::move(double dx, double dy) { + x += dx; + y += dy; +} + +int Shape::nshapes = 0; + +double Circle::area() { + return M_PI*radius*radius; +} + +double Circle::perimeter() { + return 2*M_PI*radius; +} + +double Square::area() { + return width*width; +} + +double Square::perimeter() { + return 4*width; +} diff --git a/Examples/ruby/class/example.h b/Examples/ruby/class/example.h new file mode 100644 index 000000000..c0f9b1d57 --- /dev/null +++ b/Examples/ruby/class/example.h @@ -0,0 +1,39 @@ +/* File : example.h */ + +class Shape { +public: + Shape() { + nshapes++; + } + virtual ~Shape() { + nshapes--; + }; + double x, y; + void move(double dx, double dy); + virtual double area() = 0; + virtual double perimeter() = 0; + static int nshapes; +}; + +class Circle : public Shape { +private: + double radius; +public: + Circle(double r) : radius(r) { }; + virtual double area(); + virtual double perimeter(); +}; + +class Square : public Shape { +private: + double width; +public: + Square(double w) : width(w) { }; + virtual double area(); + virtual double perimeter(); +}; + + + + + diff --git a/Examples/ruby/class/example.i b/Examples/ruby/class/example.i new file mode 100644 index 000000000..75700b305 --- /dev/null +++ b/Examples/ruby/class/example.i @@ -0,0 +1,10 @@ +/* File : example.i */ +%module example + +%{ +#include "example.h" +%} + +/* Let's just grab the original header file here */ +%include "example.h" + diff --git a/Examples/ruby/class/index.html b/Examples/ruby/class/index.html new file mode 100644 index 000000000..5e8e8c852 --- /dev/null +++ b/Examples/ruby/class/index.html @@ -0,0 +1,221 @@ + + +SWIG:Examples:ruby:class + + + + + +SWIG/Examples/ruby/class/ +
+ +

Wrapping a simple C++ class

+ +$Header$
+ +

+This example illustrates C++ class wrapping performed by SWIG. +C++ classes are simply transformed into Ruby classes that provide methods to +access class members. + +

The C++ Code

+ +Suppose you have some C++ classes described by the following (and admittedly lame) +header file: + +
+
+/* File : example.h */
+
+class Shape {
+public:
+  Shape() {
+    nshapes++;
+  }
+  virtual ~Shape() {
+    nshapes--;
+  };
+  double  x, y;   
+  void    move(double dx, double dy);
+  virtual double area() = 0;
+  virtual double perimeter() = 0;
+  static  int nshapes;
+};
+
+class Circle : public Shape {
+private:
+  double radius;
+public:
+  Circle(double r) : radius(r) { };
+  virtual double area();
+  virtual double perimeter();
+};
+
+class Square : public Shape {
+private:
+  double width;
+public:
+  Square(double w) : width(w) { };
+  virtual double area();
+  virtual double perimeter();
+};
+
+
+ +

The SWIG interface

+ +A simple SWIG interface for this can be built by simply grabbing the header file +like this: + +
+
+/* File : example.i */
+%module example
+
+%{
+#include "example.h"
+%}
+
+/* Let's just grab the original header file here */
+%include "example.h"
+
+
+ +Note: when creating a C++ extension, you must run SWIG with the -c++ option like this: +
+
+% swig -c++ -ruby example.i
+
+
+ +

A sample Ruby script

+ +Click here to see a script that calls the C++ functions from Ruby. + +

Key points

+ + + +

General Comments

+ + + +
+ + diff --git a/Examples/ruby/class/runme.rb b/Examples/ruby/class/runme.rb new file mode 100644 index 000000000..de73bcd46 --- /dev/null +++ b/Examples/ruby/class/runme.rb @@ -0,0 +1,49 @@ +# file: runme.rb + +# This file illustrates the C++ interface created by SWIG. +# All of our C++ classes get converted into Ruby classes. + +require 'example' + +# ----- Object creation ----- + +print "Creating some objects:\n" +c = Example::Circle.new(10) +print " Created circle #{c}\n" +s = Example::Square.new(10) +print " Created square #{s}\n" + +# ----- Access a static member ----- + +print "\nA total of #{Example::Shape.nshapes} shapes were created\n" + +# ----- Member data access ----- + +# Set the location of the object + +# Notice how we can do this using functions specific to +# the 'Circle' class. +c.x = 20 +c.y = 30 + +# Now use the same functions in the base class +s.x = -10 +s.y = 5 + +print "\nHere is their current position:\n" +print " Circle = (", c.x, ",", c.y, ")\n" +print " Square = (", s.x, ",", s.y, ")\n" + +# ----- Call some methods ----- + +print "\nHere are some properties of the shapes:\n" +for o in [c, s] + print " #{o}\n" + print " area = ", o.area, "\n" + print " perimeter = ", o.perimeter, "\n" +end +# Notice how the Shape#area() and Shape#perimeter() functions really +# invoke the appropriate virtual method on each object. + +print "\n", Example::Shape.nshapes," shapes remain\n" +print "Goodbye\n" diff --git a/Examples/ruby/constants/example.i b/Examples/ruby/constants/example.i index 9b04ebc1d..29a1a7f11 100644 --- a/Examples/ruby/constants/example.i +++ b/Examples/ruby/constants/example.i @@ -6,7 +6,9 @@ #define ICONST 42 #define FCONST 2.1828 #define CCONST 'x' +#define CCONST2 '\n' #define SCONST "Hello World" +#define SCONST2 "\"Hello World\"" /* This should work just fine */ #define EXPR ICONST + 3*(FCONST) diff --git a/Examples/ruby/constants/run.rb b/Examples/ruby/constants/run.rb index daa2cf855..f0d5a89e7 100644 --- a/Examples/ruby/constants/run.rb +++ b/Examples/ruby/constants/run.rb @@ -2,13 +2,15 @@ require 'example' -print "ICONST = ", Example::ICONST, " (should be 42)\n" -print "FCONST = ", Example::FCONST, " (should be 2.1828)\n" -print "CCONST = ", Example::CCONST, " (should be 'x')\n" -print "SCONST = ", Example::SCONST, " (should be 'Hello World')\n" -print "EXPR = ", Example::EXPR, " (should be 48.5484)\n" -print "iconst = ", Example::Iconst, " (should be 37)\n" -print "fconst = ", Example::Fconst, " (should be 3.14)\n" +print "ICONST = ", Example::ICONST, " (should be 42)\n" +print "FCONST = ", Example::FCONST, " (should be 2.1828)\n" +print "CCONST = ", Example::CCONST, " (should be 'x')\n" +print "CCONST2 = ", Example::CCONST2, " (this should be on a new line)\n" +print "SCONST = ", Example::SCONST, " (should be 'Hello World')\n" +print "SCONST2 = ", Example::SCONST2, " (should be '\"Hello World\"')\n" +print "EXPR = ", Example::EXPR, " (should be 48.5484)\n" +print "iconst = ", Example::Iconst, " (should be 37)\n" +print "fconst = ", Example::Fconst, " (should be 3.14)\n" begin print "EXTERN = ", Example::EXTERN, " (Arg! This shouldn't print anything)\n" diff --git a/Examples/ruby/funcptr/Makefile b/Examples/ruby/funcptr/Makefile new file mode 100644 index 000000000..cd0fdf300 --- /dev/null +++ b/Examples/ruby/funcptr/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +SRCS = example.c +TARGET = example +INTERFACE = example.i + +all:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby + +static:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core + +check: all diff --git a/Examples/ruby/funcptr/example.c b/Examples/ruby/funcptr/example.c new file mode 100644 index 000000000..99583b72e --- /dev/null +++ b/Examples/ruby/funcptr/example.c @@ -0,0 +1,17 @@ +/* File : example.c */ + +int do_op(int a, int b, int (*op)(int,int)) { + return (*op)(a,b); +} + +int add(int a, int b) { + return a+b; +} + +int sub(int a, int b) { + return a-b; +} + +int mul(int a, int b) { + return a*b; +} diff --git a/Examples/ruby/funcptr/example.h b/Examples/ruby/funcptr/example.h new file mode 100644 index 000000000..58989db79 --- /dev/null +++ b/Examples/ruby/funcptr/example.h @@ -0,0 +1,7 @@ +/* file: example.h */ + +extern int do_op(int,int, int (*op)(int,int)); +extern int add(int,int); +extern int sub(int,int); +extern int mul(int,int); + diff --git a/Examples/ruby/funcptr/example.i b/Examples/ruby/funcptr/example.i new file mode 100644 index 000000000..73cc6eb8c --- /dev/null +++ b/Examples/ruby/funcptr/example.i @@ -0,0 +1,15 @@ +/* File : example.i */ +%module example +%{ +#include "example.h" +%} + +/* Wrap a function taking a pointer to a function */ +extern int do_op(int a, int b, int (*op)(int, int)); + +/* Now install a bunch of "ops" as constants */ +%constant(int (*)(int,int)) ADD = add; +%constant(int (*)(int,int)) SUB = sub; +%constant(int (*)(int,int)) MUL = mul; + + diff --git a/Examples/ruby/funcptr/index.html b/Examples/ruby/funcptr/index.html new file mode 100644 index 000000000..ff5451dbd --- /dev/null +++ b/Examples/ruby/funcptr/index.html @@ -0,0 +1,92 @@ + + +SWIG:Examples:ruby:funcptr + + + + + +SWIG/Examples/ruby/funcptr/ +
+ +

Pointers to Functions

+ +$Header$
+ +

+Okay, just what in the heck does SWIG do with a declaration like this? + +

+
+int do_op(int a, int b, int (*op)(int, int));
+
+
+ +Well, it creates a wrapper as usual. Of course, that does raise some +questions about the third argument (the pointer to a function). + +

+In this case, SWIG will wrap the function pointer as it does for all other +pointers. However, in order to actually call this function from a script, +you will need to pass some kind of C function pointer object. In C, +this is easy, you just supply a function name as an argument like this: + +

+
+/* Some callback function */
+int add(int a, int b) {
+   return a+b;
+} 
+...
+int r = do_op(x,y,add);
+
+
+ +To make this work with SWIG, you will need to do a little extra work. Specifically, +you need to create some function pointer objects using the %constant directive like this: + +
+
+%constant(int (*)(int,int)) ADD = add;
+
+
+ +Now, in a script, you would do this: + +
+
+r = do_op(x,y, ADD)
+
+
+ +

An Example

+ +Here are some files that illustrate this with a simple example: + + + +

Notes

+ + + +
+ + + + + + diff --git a/Examples/ruby/funcptr/runme.rb b/Examples/ruby/funcptr/runme.rb new file mode 100644 index 000000000..4a5b01411 --- /dev/null +++ b/Examples/ruby/funcptr/runme.rb @@ -0,0 +1,21 @@ +# file: runme.rb + +require 'example' + +a = 37 +b = 42 + +# Now call our C function with a bunch of callbacks + +print "Trying some C callback functions\n" +print " a = #{a}\n" +print " b = #{b}\n" +print " ADD(a,b) = ", Example::do_op(a,b,Example::ADD),"\n" +print " SUB(a,b) = ", Example::do_op(a,b,Example::SUB),"\n" +print " MUL(a,b) = ", Example::do_op(a,b,Example::MUL),"\n" + +print "Here is what the C callback function objects look like in Ruby\n" +print " ADD = #{Example::ADD}\n" +print " SUB = #{Example::SUB}\n" +print " MUL = #{Example::MUL}\n" + diff --git a/Examples/ruby/index.html b/Examples/ruby/index.html index a8ad5328f..53b7e8a91 100644 --- a/Examples/ruby/index.html +++ b/Examples/ruby/index.html @@ -16,6 +16,12 @@ The following examples illustrate the use of SWIG with Ruby. be used to wrap a C function, a global variable, and a constant.
  • constants. This shows how preprocessor macros and certain C declarations are turned into constants. +
  • variables. An example showing how to access C global variables from Ruby. +
  • value. How to pass and return structures by value. +
  • class. Wrapping a simple C++ class. +
  • reference. C++ references. +
  • pointer. Simple pointer handling. +
  • funcptr. Pointers to functions.

    Compilation Issues

    diff --git a/Examples/ruby/pointer/Makefile b/Examples/ruby/pointer/Makefile new file mode 100644 index 000000000..cd0fdf300 --- /dev/null +++ b/Examples/ruby/pointer/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +SRCS = example.c +TARGET = example +INTERFACE = example.i + +all:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby + +static:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core + +check: all diff --git a/Examples/ruby/pointer/example.c b/Examples/ruby/pointer/example.c new file mode 100644 index 000000000..b877d9a5b --- /dev/null +++ b/Examples/ruby/pointer/example.c @@ -0,0 +1,16 @@ +/* File : example.c */ + +void add(int *x, int *y, int *result) { + *result = *x + *y; +} + +void sub(int *x, int *y, int *result) { + *result = *x - *y; +} + +int divide(int n, int d, int *r) { + int q; + q = n/d; + *r = n - q*d; + return q; +} diff --git a/Examples/ruby/pointer/example.i b/Examples/ruby/pointer/example.i new file mode 100644 index 000000000..2ed2b5bbf --- /dev/null +++ b/Examples/ruby/pointer/example.i @@ -0,0 +1,23 @@ +/* File : example.i */ +%module example + +/* This example illustrates a couple of different techniques + for manipulating C pointers */ + +/* First we'll use the pointer library */ +extern void add(int *x, int *y, int *result); +%include pointer.i + +/* Next we'll use some typemaps */ + +%include typemaps.i +extern void sub(int *INPUT, int *INPUT, int *OUTPUT); + +/* Next we'll use typemaps and the %apply directive */ + +%apply int *OUTPUT { int *r }; +extern int divide(int n, int d, int *r); + + + + diff --git a/Examples/ruby/pointer/index.html b/Examples/ruby/pointer/index.html new file mode 100644 index 000000000..0fbe8abd4 --- /dev/null +++ b/Examples/ruby/pointer/index.html @@ -0,0 +1,173 @@ + + +SWIG:Examples:ruby:pointer + + + + +SWIG/Examples/ruby/pointer/ +
    + +

    Simple Pointer Handling

    + +$Header$
    + +

    +This example illustrates a couple of techniques for handling +simple pointers in SWIG. The prototypical example is a C function +that operates on pointers such as this: + +

    +
    +void add(int *x, int *y, int *r) { 
    +    *r = *x + *y;
    +}
    +
    +
    + +By default, SWIG wraps this function exactly as specified and creates +an interface that expects pointer objects for arguments. The only +problem is how does one go about creating these objects from a script? + +

    Possible Solutions

    + + + +

    Example

    + +The following example illustrates the use of these features for pointer +extraction. + + + +

    Notes

    + + + +
    + + diff --git a/Examples/ruby/pointer/runme.rb b/Examples/ruby/pointer/runme.rb new file mode 100644 index 000000000..b1c3af4b3 --- /dev/null +++ b/Examples/ruby/pointer/runme.rb @@ -0,0 +1,42 @@ +# file: runme.rb + +require 'example' + +# First create some objects using the pointer library. +print "Testing the pointer library\n" +a = Example::ptrcreate("int", 37) +b = Example::ptrcreate("int", 42) +c = Example::ptrcreate("int"); + +print " a = #{a}\n" +print " b = #{b}\n" +print " c = #{c}\n" + +# Call the add() function with some pointers +Example::add(a, b, c) + +# Now get the result +r = Example::ptrvalue(c) +print " 37 + 42 = #{r}\n" + +# Clean up the pointers +Example::ptrfree(a) +Example::ptrfree(b) +Example::ptrfree(c) + +# Now try the typemap library +# This should be much easier. Now how it is no longer +# necessary to manufacture pointers. + +print "Trying the typemap library\n" +r = Example::sub(37, 42) +print " 37 - 42 = #{r}\n" + +# Now try the version with multiple return values + +print "Testing multiple return values\n" +q, r = Example::divide(42, 37) +print " 42/37 = #{q} remainder #{r}\n" + + + diff --git a/Examples/ruby/reference/Makefile b/Examples/ruby/reference/Makefile new file mode 100644 index 000000000..01ce757ff --- /dev/null +++ b/Examples/ruby/reference/Makefile @@ -0,0 +1,19 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +CXXSRCS = example.cxx +TARGET = example +INTERFACE = example.i +LIBS = -lm + +all:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby_cpp + +static:: + $(MAKE) -f $(TOP)/Makefile CXXSRCS='$(CXXSRCS)' SWIG='$(SWIG)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_cpp_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core + +check: all diff --git a/Examples/ruby/reference/example.cxx b/Examples/ruby/reference/example.cxx new file mode 100644 index 000000000..384e40bb7 --- /dev/null +++ b/Examples/ruby/reference/example.cxx @@ -0,0 +1,41 @@ +/* File : example.cxx */ + +#include "example.h" +#include +#include + +Vector operator+(const Vector &a, const Vector &b) { + Vector r; + r.x = a.x + b.x; + r.y = a.y + b.y; + r.z = a.z + b.z; + return r; +} + +char *Vector::print() { + static char temp[512]; + sprintf(temp,"Vector %x (%g,%g,%g)", this, x,y,z); + return temp; +} + +VectorArray::VectorArray(int size) { + items = new Vector[size]; + maxsize = size; +} + +VectorArray::~VectorArray() { + delete [] items; +} + +Vector &VectorArray::operator[](int index) { + if ((index < 0) || (index >= maxsize)) { + printf("Panic! Array index out of bounds.\n"); + exit(1); + } + return items[index]; +} + +int VectorArray::size() { + return maxsize; +} + diff --git a/Examples/ruby/reference/example.h b/Examples/ruby/reference/example.h new file mode 100644 index 000000000..4915adb1b --- /dev/null +++ b/Examples/ruby/reference/example.h @@ -0,0 +1,26 @@ +/* File : example.h */ + +class Vector { +private: + double x,y,z; +public: + Vector() : x(0), y(0), z(0) { }; + Vector(double x, double y, double z) : x(x), y(y), z(z) { }; + friend Vector operator+(const Vector &a, const Vector &b); + char *print(); +}; + +class VectorArray { +private: + Vector *items; + int maxsize; +public: + VectorArray(int maxsize); + ~VectorArray(); + Vector &operator[](int); + int size(); +}; + + + + diff --git a/Examples/ruby/reference/example.i b/Examples/ruby/reference/example.i new file mode 100644 index 000000000..8538326f6 --- /dev/null +++ b/Examples/ruby/reference/example.i @@ -0,0 +1,46 @@ +/* File : example.i */ + +/* This file has a few "typical" uses of C++ references. */ + +%module example + +%{ +#include "example.h" +%} + +class Vector { +public: + Vector(double x, double y, double z); + ~Vector(); + char *print(); +}; + +/* This helper function calls an overloaded operator */ +%inline %{ +Vector addv(Vector &a, Vector &b) { + return a+b; +} +%} + +/* Wrapper around an array of vectors class */ + +class VectorArray { +public: + VectorArray(int maxsize); + ~VectorArray(); + int size(); + + /* This wrapper provides an alternative to the [] operator */ + %addmethods { + Vector &get(int index) { + return (*self)[index]; + } + void set(int index, Vector &a) { + (*self)[index] = a; + } + } +}; + + + + diff --git a/Examples/ruby/reference/index.html b/Examples/ruby/reference/index.html new file mode 100644 index 000000000..10218e4fd --- /dev/null +++ b/Examples/ruby/reference/index.html @@ -0,0 +1,149 @@ + + +SWIG:Examples:ruby:reference + + + + + +SWIG/Examples/ruby/reference/ +
    + +

    C++ Reference Handling

    + +$Header$
    + +

    +This example tests SWIG's handling of C++ references. Since C++ +references are closely related to pointers (as both refer to a +location in memory), SWIG simply collapses all references into +pointers when creating wrappers. + +

    Some examples

    + +References are most commonly used as function parameter. For example, +you might have an operator like this: + +
    +
    +Vector operator+(const Vector &a, const Vector &b) {
    +   Vector result;
    +   result.x = a.x + b.x;
    +   result.y = a.y + b.y;
    +   result.z = a.z + b.z;
    +   return result;
    +}
    +
    +
    + +or a function: + +
    +
    +Vector addv(const Vector &a, const Vector &b) {
    +   Vector result;
    +   result.x = a.x + b.x;
    +   result.y = a.y + b.y;
    +   result.z = a.z + b.z;
    +   return result;
    +}
    +
    +
    + +In these cases, SWIG transforms everything into a pointer and creates a wrapper +that looks like this: + +
    +
    +Vector wrap_addv(Vector *a, Vector *b) {
    +    return addv(*a,*b);
    +}
    +
    +
    + +Occasionally, a reference is used as a return value of a function +when the return result is to be used as an lvalue in an expression. +The prototypical example is an operator like this: + +
    +
    +Vector &operator[](int index);
    +
    +
    + +or a method: + +
    +
    +Vector &get(int index);
    +
    +
    + +For functions returning references, a wrapper like this is created: + +
    +
    +Vector *wrap_Object_get(Object *self, int index) {
    +    Vector &result = self->get(index);
    +    return &result;
    +}
    +
    +
    + +The following header file contains some class +definitions with some operators and use of references. + +

    SWIG Interface

    + +SWIG does NOT support overloaded operators so it can not directly build +an interface to the classes in the above file. However, a number of workarounds +can be made. For example, an overloaded operator can be stuck behind a function +call such as the addv() function above. Array access can be handled +with a pair of set/get functions like this: + +
    +
    +class VectorArray {
    +public:
    + ...
    +   %addmethods {
    +    Vector &get(int index) {
    +      return (*self)[index];
    +    }
    +    void set(int index, Vector &a) {
    +      (*self)[index] = a;
    +    }
    +   }
    +   ...
    +}
    +
    +
    + +Click here to see a SWIG interface file with these additions. + +

    Sample Ruby script

    + +Click here to see a script that manipulates some C++ references. + +

    Notes:

    + +
      +
    • C++ references primarily provide notational convenience for C++ +source code. However, Ruby only supports the 'x.a' +notation so it doesn't much matter. + +

      +

    • When a program returns a reference, a pointer is returned. +Unlike return by value, memory is not allocated to hold the +return result. + +

      +

    • SWIG has particular trouble handling various combinations of references +and pointers. This is side effect of an old parsing scheme and +type representation that will be replaced in future versions. + +
    + +
    + + diff --git a/Examples/ruby/reference/runme.rb b/Examples/ruby/reference/runme.rb new file mode 100644 index 000000000..67b76fc8a --- /dev/null +++ b/Examples/ruby/reference/runme.rb @@ -0,0 +1,60 @@ +# file: runme.rb + +# This file illustrates the manipulation of C++ references in Ruby. + +require 'example' + +# ----- Object creation ----- + +print "Creating some objects:\n" +a = Example::Vector.new(3,4,5) +b = Example::Vector.new(10,11,12) + +print " Created ", a.print, "\n" +print " Created ", b.print, "\n" + +# ----- Call an overloaded operator ----- + +# This calls the wrapper we placed around +# +# operator+(const Vector &a, const Vector &) +# +# It returns a new allocated object. + +print "Adding a+b\n" +c = Example::addv(a, b) +print " a+b = ", c.print, "\n" + +# ----- Create a vector array ----- + +print "Creating an array of vectors\n" +va = Example::VectorArray.new(10) +print " va = #{va}\n" + +# ----- Set some values in the array ----- + +# These operators copy the value of a and b to the vector array +va.set(0, a) +va.set(1, b) + +va.set(2, Example::addv(a,b)) + +c = Example::addv(a,b) +va.set(3, c) + +=begin commented out due to GC issue + +# Get some values from the array + +print "Getting some array values\n" +for i in 0...5 + print " va(#{i}) = ", va.get(i).print, "\n" +end + +# Watch under resource meter to check on this +print "Making sure we don't leak memory.\n" +for i in 0...1000000 + c = va.get(i % 10) +end + +=end diff --git a/Examples/ruby/value/Makefile b/Examples/ruby/value/Makefile new file mode 100644 index 000000000..cd0fdf300 --- /dev/null +++ b/Examples/ruby/value/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +SRCS = example.c +TARGET = example +INTERFACE = example.i + +all:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby + +static:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core + +check: all diff --git a/Examples/ruby/value/example.c b/Examples/ruby/value/example.c new file mode 100644 index 000000000..4ed2fe10a --- /dev/null +++ b/Examples/ruby/value/example.c @@ -0,0 +1,15 @@ +/* File : example.c */ + +#include "example.h" + +double dot_product(Vector a, Vector b) { + return (a.x*b.x + a.y*b.y + a.z*b.z); +} + +Vector vector_add(Vector a, Vector b) { + Vector r; + r.x = a.x + b.x; + r.y = a.y + b.y; + r.z = a.z + b.z; + return r; +} diff --git a/Examples/ruby/value/example.h b/Examples/ruby/value/example.h new file mode 100644 index 000000000..212cf4bdb --- /dev/null +++ b/Examples/ruby/value/example.h @@ -0,0 +1,5 @@ +/* File : example.h */ + +typedef struct { + double x, y, z; +} Vector; diff --git a/Examples/ruby/value/example.i b/Examples/ruby/value/example.i new file mode 100644 index 000000000..83c1f9cd6 --- /dev/null +++ b/Examples/ruby/value/example.i @@ -0,0 +1,30 @@ +// Tests SWIG's handling of pass-by-value for complex datatypes +%module example + +%{ +#include "example.h" +%} + +/* Some functions that manipulate Vectors by value */ +extern double dot_product(Vector a, Vector b); +extern Vector vector_add(Vector a, Vector b); + +/* Include this because the vector_add() function will leak memory */ +void free(void *); + +/* Some helper functions for our interface */ +%inline %{ + +Vector *new_Vector(double x, double y, double z) { + Vector *v = (Vector *) malloc(sizeof(Vector)); + v->x = x; + v->y = y; + v->z = z; + return v; +} + +void vector_print(Vector *v) { + printf("Vector %x = (%g, %g, %g)\n", v, v->x, v->y, v->z); +} +%} + diff --git a/Examples/ruby/value/index.html b/Examples/ruby/value/index.html new file mode 100644 index 000000000..fe9944c58 --- /dev/null +++ b/Examples/ruby/value/index.html @@ -0,0 +1,116 @@ + + +SWIG:Examples:ruby:value + + + + + +SWIG/Examples/ruby/value/ +
    + +

    Passing and Returning Structures by Value

    + +$Header$
    + +

    +Occasionally, a C program will manipulate structures by value such as shown in the +following code: + +

    +
    +/* File : example.c */
    +
    +typedef struct Vector {
    +   double x, y, z;
    +} Vector;
    +
    +double dot_product(Vector a, Vector b) {
    +  return (a.x*b.x + a.y*b.y + a.z*b.z);
    +}
    +
    +Vector vector_add(Vector a, Vector b) {
    +  Vector r;
    +  r.x = a.x + b.x;
    +  r.y = a.y + b.y;
    +  r.z = a.z + b.z;
    +  return r;
    +}
    +
    +
    + +Since SWIG only knows how to manage pointers to structures (not their internal +representation), the following translations are made when wrappers are +created: + +
    +
    +double wrap_dot_product(Vector *a, Vector *b) {
    +    return dot_product(*a,*b);
    +}
    +
    +Vector *wrap_vector_add(Vector *a, Vector *b) {
    +    Vector *r = (Vector *) malloc(sizeof(Vector));
    +    *r = vector_add(*a,*b);
    +    return r;
    +}
    +
    +
    + +The functions are then called using pointers from the scripting language interface. +It should also be noted that any function that returns a structure by value results +in an implicit memory allocation. This will be a memory leak unless you take steps +to free the result (see below). + +

    The SWIG interface

    + +Click here to see a SWIG interface file that +wraps these two functions. In this file, there are a few essential features: + +
      +
    • A wrapper for the free() function is created so that we +can clean up the return result created by vector_add() +function. + +

      +

    • The %inline directive is used to create a few helper functions for creating new Vector +objects and to print out the value (for debugging purposes). +
    + +

    A Ruby Script

    + +Click here to see a script that uses these functions from Ruby. + +

    Notes

    + +
      +
    • When the '-c++' option is used, the resulting wrapper code for the return value +changes to the following: + +
      +
      +Vector *wrap_vector_add(Vector *a, Vector *b) {
      +    Vector *r = new Vector(vector_add(*a,*b));
      +    return r;
      +}
      +
      +
      + +

      +

    • If you define C structure (or C++ class with '-c++' option) +in the interface file, the SWIG generated wrappers can automaticallyclean +up the result of return-by-reference by GC. + +

      +

    • Passing parameters by value like this really isn't the best C programming style. +If possible, you might change your application to use pointers. + +

      +

    • Similar translations are made when C++ references are used. + + +
    + +
    + + diff --git a/Examples/ruby/value/runme.rb b/Examples/ruby/value/runme.rb new file mode 100644 index 000000000..9372c03f4 --- /dev/null +++ b/Examples/ruby/value/runme.rb @@ -0,0 +1,32 @@ +# file: runme.rb + +require 'example' + +# Create a couple of a vectors + +v = Example::new_Vector(1, 2, 3) +w = Example::new_Vector(10, 11, 12) + +print "I just created the following vectors\n" +Example::vector_print(v) +Example::vector_print(w) + +# Now call some of our functions + +print "\nNow I'm going to compute the dot product\n" +d = Example::dot_product(v,w) +print "dot product = #{d} (should be 68)\n" + +# Add the vectors together + +print "\nNow I'm going to add the vectors together\n" +r = Example::vector_add(v,w) +Example::vector_print(r) +print "The value should be (11, 13, 15)\n" + +# Now I'd better clean up the return result r + +print "\nNow I'm going to clean up the return result\n" +Example::free(r) + +print "Good\n" diff --git a/Examples/ruby/variables/Makefile b/Examples/ruby/variables/Makefile new file mode 100644 index 000000000..cd0fdf300 --- /dev/null +++ b/Examples/ruby/variables/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +SRCS = example.c +TARGET = example +INTERFACE = example.i + +all:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='$(TARGET)' INTERFACE='$(INTERFACE)' ruby + +static:: + $(MAKE) -f $(TOP)/Makefile SRCS='$(SRCS)' SWIG='$(SWIG)' \ + TARGET='myruby' INTERFACE='$(INTERFACE)' ruby_static + +clean:: + rm -f *_wrap* *.o *~ *.so myruby .~* core + +check: all diff --git a/Examples/ruby/variables/example.c b/Examples/ruby/variables/example.c new file mode 100644 index 000000000..37e9feb33 --- /dev/null +++ b/Examples/ruby/variables/example.c @@ -0,0 +1,86 @@ +/* File : example.c */ + +/* I'm a file containing some C global variables */ + +#include +#include +#include "example.h" + +int ivar = 0; +short svar = 0; +long lvar = 0; +unsigned int uivar = 0; +unsigned short usvar = 0; +unsigned long ulvar = 0; +signed char scvar = 0; +unsigned char ucvar = 0; +char cvar = 0; +float fvar = 0; +double dvar = 0; +char *strvar = 0; +const char *cstrvar = 0; +int *iptrvar = 0; +char name[256] = "Dave"; +char path[256] = "/home/beazley"; + + +/* Global variables involving a structure */ +Point *ptptr = 0; +Point pt = { 10, 20 }; + +/* A variable that we will make read-only in the interface */ +int status = 1; + +/* A debugging function to print out their values */ + +void print_vars() { + printf("ivar = %d\n", ivar); + printf("svar = %d\n", svar); + printf("lvar = %ld\n", lvar); + printf("uivar = %u\n", uivar); + printf("usvar = %u\n", usvar); + printf("ulvar = %lu\n", ulvar); + printf("scvar = %d\n", scvar); + printf("ucvar = %u\n", ucvar); + printf("fvar = %g\n", fvar); + printf("dvar = %g\n", dvar); + printf("cvar = %c\n", cvar); + printf("strvar = %s\n", strvar ? strvar : "(null)"); + printf("cstrvar = %s\n", cstrvar ? cstrvar : "(null)"); + printf("iptrvar = %x\n", iptrvar); + printf("name = %s\n", name); + printf("ptptr = %x (%d, %d)\n", ptptr, ptptr ? ptptr->x : 0, ptptr ? ptptr->y : 0); + printf("pt = (%d, %d)\n", pt.x, pt.y); + printf("status = %d\n", status); +} + +/* A function to create an integer (to test iptrvar) */ + +int *new_int(int value) { + int *ip = (int *) malloc(sizeof(int)); + *ip = value; + return ip; +} + +/* A function to create a point */ + +Point *new_Point(int x, int y) { + Point *p = (Point *) malloc(sizeof(Point)); + p->x = x; + p->y = y; + return p; +} + +char * Point_print(Point *p) { + static char buffer[256]; + if (p) { + sprintf(buffer,"(%d,%d)", p->x,p->y); + } else { + sprintf(buffer,"null"); + } + return buffer; +} + +void pt_print() { + printf("(%d, %d)\n", pt.x, pt.y); +} diff --git a/Examples/ruby/variables/example.h b/Examples/ruby/variables/example.h new file mode 100644 index 000000000..0f7e89594 --- /dev/null +++ b/Examples/ruby/variables/example.h @@ -0,0 +1,6 @@ +/* File: example.h */ + +typedef struct { + int x,y; +} Point; + diff --git a/Examples/ruby/variables/example.i b/Examples/ruby/variables/example.i new file mode 100644 index 000000000..d62f973da --- /dev/null +++ b/Examples/ruby/variables/example.i @@ -0,0 +1,44 @@ +/* File : example.i */ +%module example +%{ +#include "example.h" +%} + +/* Some global variable declarations */ +extern int ivar; +extern short svar; +extern long lvar; +extern unsigned int uivar; +extern unsigned short usvar; +extern unsigned long ulvar; +extern signed char scvar; +extern unsigned char ucvar; +extern char cvar; +extern float fvar; +extern double dvar; +extern char *strvar; +extern const char *cstrvar; +extern int *iptrvar; +extern char name[256]; + +extern Point *ptptr; +extern Point pt; + + +/* Some read-only variables */ + +%readonly +extern int status; +extern char path[256]; +%readwrite + +/* Some helper functions to make it easier to test */ +extern void print_vars(); +extern int *new_int(int value); +extern Point *new_Point(int x, int y); +extern char *Point_print(Point *p); +extern void pt_print(); + + + + diff --git a/Examples/ruby/variables/index.html b/Examples/ruby/variables/index.html new file mode 100644 index 000000000..df144d32b --- /dev/null +++ b/Examples/ruby/variables/index.html @@ -0,0 +1,96 @@ + + +SWIG:Examples:ruby:variables + + + + +SWIG/Examples/ruby/variables/ +
    + +

    Wrapping C Global Variables

    + +$Header$
    + +

    +When a C global variable appears in an interface file, SWIG tries to +wrap it using a technique known as "variable linking." The idea is +pretty simple---we try to create a Ruby variable (actually module method) that +magically retrieves or updates the value of the underlying C variable when it is +accessed. Click here to see a SWIG interface with some variable +declarations in it. + +

    Manipulating Variables from Ruby

    + +Before going any further, it is important to understand some important +differences between C and Ruby variables. In C, a variable is +simply a name that refers to a specific location in memory. For +example, when you declare a global variable 'double a' you +know that somewhere in memory, 8 bytes have been set aside to hold a +double and that a is bound to this location for the +life of the program. In Ruby, variable creation is nothing more +than a naming operation. For example, when you say 'a = 3', +'a' becomes a name that refers to some object '3'. Later on, if you say +'a = 7.5, the name 'a' is bound to an entirely different object +containing the value '7.5' (the contents of the original object are not +changed). The end result of this is that a variable in Ruby can refer +to a virtually unlimited number of different objects (memory locations) +over the lifetime of a program. + +

    +Because of Ruby's somewhat unusual variable assignment semantics, it is not +possible to directly link a C global variable into an equivalent Ruby variable. +Instead, all C global variables are accessed as attributes of the module. +For example, if you had a global variable + +

    +
    +double foo;
    +
    +
    + +it will be accessed in the Ruby module as Example.foo. Click +here to see a script that updates and prints +out the values of the variables using this technique. + +

    Key points

    + +
      +
    • When a global variable has the type "char *", SWIG manages it as a character +string. However, whenever the value of such a variable is set from Ruby, the old +value is destroyed using free(). +
    • signed char and unsigned char are handled as small 8-bit integers. +
    • String array variables such as 'char name[256]' are managed as Ruby strings, but +when setting the value, the result is truncated to the maximum length of the array. Furthermore, the string is assumed to be null-terminated. +
    • When structures and classes are used as global variables, they are mapped into pointers. +Getting the "value" returns a pointer to the global variable. Setting the value of a structure results in a memory copy from a pointer to the global. +
    + +

    Creating read-only variables

    + +The %readonly and %readwrite directives can be used to +specify a collection of read-only variables. For example: + +
    +
    +%readonly
    +int    status;
    +double blah;
    +...
    +%readwrite
    +
    +
    + +The %readonly directive remains in effect until it is explicitly disabled +using the %readwrite directive. + +

    Comments

    +
      +
    • Management of global variables is one of the most problematic aspects +of C/C++ wrapping because the scripting interface and resulting memory management +is much trickier than simply creating a wrapper function. +
    + + + +
    \ No newline at end of file diff --git a/Examples/ruby/variables/runme.rb b/Examples/ruby/variables/runme.rb new file mode 100644 index 000000000..f4ce9cc39 --- /dev/null +++ b/Examples/ruby/variables/runme.rb @@ -0,0 +1,78 @@ +# file: runme.rb + +require 'example' + +# Try to set the values of some global variables + +Example.ivar = 42 +Example.svar = -31000 +Example.lvar = 65537 +Example.uivar = 123456 +Example.usvar = 61000 +Example.ulvar = 654321 +Example.scvar = -13 +Example.ucvar = 251 +Example.cvar = "S" +Example.fvar = 3.14159 +Example.dvar = 2.1828 +Example.strvar = "Hello World" +Example.cstrvar = "Goodbye" +Example.iptrvar= Example.new_int(37) +Example.ptptr = Example.new_Point(37,42) +Example.name = "Bill" + +# Now print out the values of the variables + +puts "Variables (values printed from Ruby)" + +print "ivar = ", Example.ivar, "\n" +print "svar = ", Example.svar, "\n" +print "lvar = ", Example.lvar, "\n" +print "uivar = ", Example.uivar, "\n" +print "usvar = ", Example.usvar, "\n" +print "ulvar = ", Example.ulvar, "\n" +print "scvar = ", Example.scvar, "\n" +print "ucvar = ", Example.ucvar, "\n" +print "fvar = ", Example.fvar, "\n" +print "dvar = ", Example.dvar, "\n" +print "cvar = ", Example.cvar, "\n" +print "strvar = ", Example.strvar, "\n" +print "cstrvar = ", Example.cstrvar, "\n" +print "iptrvar = ", Example.iptrvar, "\n" +print "name = ", Example.name, "\n" +print "ptptr = ", Example.ptptr, " ", Example.Point_print(Example.ptptr), "\n" +print "pt = ", Example.pt, " ", Example.Point_print(Example.pt), "\n" + +puts "\nVariables (values printed from C)" + +Example.print_vars() + +puts "\nNow I'm going to try and modify some read only variables"; + +puts " Tring to set 'path'"; +begin + Example.path = "Whoa!" + puts "Hey, what's going on?!?! This shouldn't work" +rescue + puts "Good." +end + +puts " Trying to set 'status'"; +begin + Example.status = 0 + puts "Hey, what's going on?!?! This shouldn't work" +rescue + puts "Good." +end + + +print "\nI'm going to try and update a structure variable.\n\n" + +Example.pt = Example.ptptr + +puts "The new value is" +Example.pt_print() +print "You should see the value ", Example.Point_print(Example.ptptr), "\n" + + +