From 618e0eff61fe24d599cbb283d49be5900256f3ee Mon Sep 17 00:00:00 2001 From: Thien-Thi Nguyen Date: Wed, 5 Jul 2000 18:58:49 +0000 Subject: [PATCH] Add Ruby support contributed by Masaki Fukushima. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk/SWIG@518 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- Examples/GIFPlot/README | 8 +- Examples/GIFPlot/Ruby/full/Makefile | 23 + Examples/GIFPlot/Ruby/full/README | 8 + Examples/GIFPlot/Ruby/full/gifplot.i | 15 + Examples/GIFPlot/Ruby/full/runme.rb | 66 ++ Examples/GIFPlot/Ruby/simple/Makefile | 23 + Examples/GIFPlot/Ruby/simple/README | 5 + Examples/GIFPlot/Ruby/simple/runme.rb | 27 + Examples/GIFPlot/Ruby/simple/simple.i | 38 + Examples/Makefile.in | 46 + Examples/README | 2 +- Examples/index.html | 1 + Examples/ruby/constants/Makefile | 18 + Examples/ruby/constants/example.i | 24 + Examples/ruby/constants/index.html | 66 ++ Examples/ruby/constants/run.rb | 23 + Examples/ruby/index.html | 85 ++ Examples/ruby/simple/Makefile | 18 + Examples/ruby/simple/example.c | 18 + Examples/ruby/simple/example.i | 5 + Examples/ruby/simple/index.html | 99 ++ Examples/ruby/simple/run.rb | 21 + Lib/ruby/Makefile.swig | 42 + Lib/ruby/embed.i | 16 + Lib/ruby/exception.i | 27 + Lib/ruby/extconf.rb | 9 + Lib/ruby/ptrlang.i | 646 ++++++++++++ Lib/ruby/ruby.swg | 44 + Lib/ruby/rubydec.swg | 15 + Lib/ruby/rubydef.swg | 297 ++++++ Lib/ruby/typemaps.i | 501 ++++++++++ Makefile.in | 6 + Runtime/Makefile.in | 19 +- Runtime/make.sh | 2 +- Source/Modules1.1/Makefile.in | 4 +- Source/Modules1.1/ruby.cxx | 1300 +++++++++++++++++++++++++ Source/Modules1.1/ruby.h | 125 +++ Source/Modules1.1/swigmain.cxx | 7 +- configure.in | 65 ++ 39 files changed, 3754 insertions(+), 10 deletions(-) create mode 100644 Examples/GIFPlot/Ruby/full/Makefile create mode 100644 Examples/GIFPlot/Ruby/full/README create mode 100644 Examples/GIFPlot/Ruby/full/gifplot.i create mode 100644 Examples/GIFPlot/Ruby/full/runme.rb create mode 100644 Examples/GIFPlot/Ruby/simple/Makefile create mode 100644 Examples/GIFPlot/Ruby/simple/README create mode 100644 Examples/GIFPlot/Ruby/simple/runme.rb create mode 100644 Examples/GIFPlot/Ruby/simple/simple.i create mode 100644 Examples/ruby/constants/Makefile create mode 100644 Examples/ruby/constants/example.i create mode 100644 Examples/ruby/constants/index.html create mode 100644 Examples/ruby/constants/run.rb create mode 100644 Examples/ruby/index.html create mode 100644 Examples/ruby/simple/Makefile create mode 100644 Examples/ruby/simple/example.c create mode 100644 Examples/ruby/simple/example.i create mode 100644 Examples/ruby/simple/index.html create mode 100644 Examples/ruby/simple/run.rb create mode 100644 Lib/ruby/Makefile.swig create mode 100644 Lib/ruby/embed.i create mode 100644 Lib/ruby/exception.i create mode 100644 Lib/ruby/extconf.rb create mode 100644 Lib/ruby/ptrlang.i create mode 100644 Lib/ruby/ruby.swg create mode 100644 Lib/ruby/rubydec.swg create mode 100644 Lib/ruby/rubydef.swg create mode 100644 Lib/ruby/typemaps.i create mode 100644 Source/Modules1.1/ruby.cxx create mode 100644 Source/Modules1.1/ruby.h diff --git a/Examples/GIFPlot/README b/Examples/GIFPlot/README index 06880fe61..7960a6f98 100644 --- a/Examples/GIFPlot/README +++ b/Examples/GIFPlot/README @@ -4,8 +4,8 @@ GIFPlot To illustrate various SWIG features, the following examples involve building an interface to a small, but somewhat useful graphics library for creating 2D and 3D images in the form of GIF files. The Perl, -Python, and Tcl directories contain various examples specific to those -languages. +Python, Tcl, and Ruby directories contain various examples specific to +those languages. This library was originally developed as part of the SPaSM molecular dynamics project at Los Alamos National Laboratory. However, due to @@ -36,8 +36,8 @@ On Windows, you can probably just do this: Running the Examples ==================== -Once the library has been built, go the Perl, Python, or Tcl directory to see -various SWIG examples. Each example should have a README file with a +Once the library has been built, go the Perl, Python, Tcl, or Ruby directory +to see various SWIG examples. Each example should have a README file with a description. The examples are compiled using the makefile located in the top level "Examples" diff --git a/Examples/GIFPlot/Ruby/full/Makefile b/Examples/GIFPlot/Ruby/full/Makefile new file mode 100644 index 000000000..bde3899a2 --- /dev/null +++ b/Examples/GIFPlot/Ruby/full/Makefile @@ -0,0 +1,23 @@ +TOP = ../../.. +SWIG = $(TOP)/../swig +SWIGOPT = -I../../Include +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 + + diff --git a/Examples/GIFPlot/Ruby/full/README b/Examples/GIFPlot/Ruby/full/README new file mode 100644 index 000000000..22af6cb06 --- /dev/null +++ b/Examples/GIFPlot/Ruby/full/README @@ -0,0 +1,8 @@ +This example runs the entire gifplot.h header file through SWIG without +any changes. The script 'runme.rb' does something a little more +interesting. You'll have to go look at the header file to get a complete +listing of the functions. + + + + diff --git a/Examples/GIFPlot/Ruby/full/gifplot.i b/Examples/GIFPlot/Ruby/full/gifplot.i new file mode 100644 index 000000000..5a7f5008f --- /dev/null +++ b/Examples/GIFPlot/Ruby/full/gifplot.i @@ -0,0 +1,15 @@ +/* Oh what the heck, let's just grab the whole darn header file + and see what happens. */ + +%module gifplot +%{ + +/* Note: You still need this part because the %include directive + merely causes SWIG to interpret the contents of a file. It doesn't + include the right include headers for the resulting C code */ + +#include "gifplot.h" + +%} + +%include gifplot.h diff --git a/Examples/GIFPlot/Ruby/full/runme.rb b/Examples/GIFPlot/Ruby/full/runme.rb new file mode 100644 index 000000000..5c118b2fa --- /dev/null +++ b/Examples/GIFPlot/Ruby/full/runme.rb @@ -0,0 +1,66 @@ +# Plot a 3D function +require 'gifplot' +include 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 = new_ColorMap("cmap") +frame = new_FrameBuffer(500,500) +FrameBuffer_clear(frame,BLACK) + +P3 = new_Plot3D(frame,XMIN,YMIN,ZMIN,XMAX,YMAX,ZMAX) +Plot3D_lookat(P3,2*[XMAX-XMIN,YMAX-YMIN,ZMAX-ZMIN].max) +Plot3D_autoperspective(P3,40) +Plot3D_rotu(P3,60) +Plot3D_rotr(P3,30) +Plot3D_rotd(P3,10) + +def drawsolid() + Plot3D_clear(P3,BLACK) + Plot3D_start(P3) + 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 + Plot3D_solidquad(P3,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() + +FrameBuffer_writeGIF(frame,cmap,"image.gif") +puts "Wrote image.gif" diff --git a/Examples/GIFPlot/Ruby/simple/Makefile b/Examples/GIFPlot/Ruby/simple/Makefile new file mode 100644 index 000000000..c5163b8f3 --- /dev/null +++ b/Examples/GIFPlot/Ruby/simple/Makefile @@ -0,0 +1,23 @@ +TOP = ../../.. +SWIG = $(TOP)/../swig +SWIGOPT = +SRCS = +TARGET = simple +INTERFACE = simple.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 + + diff --git a/Examples/GIFPlot/Ruby/simple/README b/Examples/GIFPlot/Ruby/simple/README new file mode 100644 index 000000000..9b51038bf --- /dev/null +++ b/Examples/GIFPlot/Ruby/simple/README @@ -0,0 +1,5 @@ +This is a very minimalistic example in which just a few functions +and constants from library are wrapped and used to draw some simple +shapes. The script 'runme.rb' runs the example. + + diff --git a/Examples/GIFPlot/Ruby/simple/runme.rb b/Examples/GIFPlot/Ruby/simple/runme.rb new file mode 100644 index 000000000..e8bf5a40f --- /dev/null +++ b/Examples/GIFPlot/Ruby/simple/runme.rb @@ -0,0 +1,27 @@ +# Draw some simple shapes +puts "Drawing some basic shapes" +require 'simple' + +cmap = Simple.new_ColorMap() +f = Simple.new_FrameBuffer(400,400) + +# Clear the picture +Simple.FrameBuffer_clear(f,Simple::BLACK) + +# Make a red box +Simple.FrameBuffer_box(f,40,40,200,200,Simple::RED) + +# Make a blue circle +Simple.FrameBuffer_circle(f,200,200,40,Simple::BLUE) + +# Make green line +Simple.FrameBuffer_line(f,10,390,390,200, Simple::GREEN) + +# Write an image out to disk + +Simple.FrameBuffer_writeGIF(f,cmap,"image.gif") +puts "Wrote image.gif" + +Simple.delete_FrameBuffer(f) +Simple.delete_ColorMap(cmap) + diff --git a/Examples/GIFPlot/Ruby/simple/simple.i b/Examples/GIFPlot/Ruby/simple/simple.i new file mode 100644 index 000000000..457bc4c09 --- /dev/null +++ b/Examples/GIFPlot/Ruby/simple/simple.i @@ -0,0 +1,38 @@ +/* This example shows a very simple interface wrapping a few + primitive declarations */ + +%module simple +%{ +#include "gifplot.h" +%} + +typedef unsigned char Pixel; + +/* Here are a few useful functions */ + +ColorMap *new_ColorMap(char *filename = 0); +void delete_ColorMap(ColorMap *cmap); + +FrameBuffer *new_FrameBuffer(unsigned int width, unsigned int height); +void delete_FrameBuffer(FrameBuffer *frame); +void FrameBuffer_clear(FrameBuffer *frame, Pixel color); +void FrameBuffer_line(FrameBuffer *frame, int x1, int y1, int x2, int y2, Pixel color); +void FrameBuffer_box(FrameBuffer *frame, int x1, int y1, int x2, int y2, Pixel color); +void FrameBuffer_circle(FrameBuffer *frame, int x1, int y1, int radius, Pixel color); +int FrameBuffer_writeGIF(FrameBuffer *f, ColorMap *c, char *filename); + +/* And some useful constants */ + +#define BLACK 0 +#define WHITE 1 +#define RED 2 +#define GREEN 3 +#define BLUE 4 +#define YELLOW 5 +#define CYAN 6 +#define MAGENTA 7 + + + + + diff --git a/Examples/Makefile.in b/Examples/Makefile.in index af5b02691..0123dcc7f 100644 --- a/Examples/Makefile.in +++ b/Examples/Makefile.in @@ -337,6 +337,52 @@ mzscheme: $(SRCS) mzc --cc $(ISRCS) $(SRCS) mzc --ld $(TARGET)$(SO) $(OBJS) $(IOBJS) +################################################################## +##### RUBY ###### +################################################################## + +# Make sure these locate your Ruby installation +RUBY_INCLUDE= -DHAVE_CONFIG_H @RUBYINCLUDE@ + +# ---------------------------------------------------------------- +# Build a C dynamically loadable module +# ---------------------------------------------------------------- + +ruby: $(SRCS) + $(SWIG) -ruby $(SWIGOPT) $(INTERFACE) + $(CC) -c $(CCSHARED) $(CFLAGS) $(ISRCS) $(SRCS) $(INCLUDE) $(RUBY_INCLUDE) + $(LDSHARED) $(OBJS) $(IOBJS) $(LIBS) -o $(TARGET)$(SO) + +# ----------------------------------------------------------------- +# Build a C++ dynamically loadable module +# ----------------------------------------------------------------- + +ruby_cpp: $(SRCS) + $(SWIG) -c++ -ruby $(SWIGOPT) $(INTERFACE) + $(CXX) -c $(CCSHARED) $(CFLAGS) $(ISRCS) $(SRCS) $(INCLUDE) $(RUBY_INCLUDE) + $(CXXSHARED) $(OBJS) $(IOBJS) $(LIBS) $(CPP_DLLIBS) -o $(TARGET)$(SO) + +# ----------------------------------------------------------------- +# Build statically linked Ruby interpreter +# +# These should only be used in conjunction with the %include embed.i +# library file +# ----------------------------------------------------------------- + +RUBY_LIB = @RUBYLIB@ +RUBY_LIBOPTS = @RUBYLINK@ @LIBS@ $(SYSLIBS) + +ruby_static: $(SRCS) + $(SWIG) -ruby -lembed.i $(SWIGOPT) $(INTERFACE) + $(CC) $(CFLAGS) @LINKFORSHARED@ $(ISRCS) $(SRCS) $(INCLUDE) \ + $(RUBY_INCLUDE) $(LIBS) -L$(RUBY_LIB) $(RUBY_LIBOPTS) -o $(TARGET) + +ruby_static_cpp: $(SRCS) + $(SWIG) -c++ -ruby -lembed.i $(SWIGOPT) $(INTERFACE) + $(CXX) $(CFLAGS) $(ISRCS) $(SRCS) $(INCLUDE) \ + $(RUBY_INCLUDE) $(LIBS) -L$(RUBY_LIB) $(RUBY_LIBOPTS) -o $(TARGET) + + ################################################################## ##### SWIG ###### ################################################################## diff --git a/Examples/README b/Examples/README index a3fae68f0..98852617a 100644 --- a/Examples/README +++ b/Examples/README @@ -1,6 +1,6 @@ SWIG Examples -The "perl5", "python", "tcl", "guile", "java", and "mzscheme" +The "perl5", "python", "tcl", "guile", "java", "mzscheme", and "ruby" directories contain a very simple example. The "GIFPlot" contains a more complicated example that illustrates some of SWIG's more advanced capabilities. diff --git a/Examples/index.html b/Examples/index.html index c0e1c2507..8e2f43655 100644 --- a/Examples/index.html +++ b/Examples/index.html @@ -43,6 +43,7 @@ language:
  • Guile
  • Java
  • Mzscheme +
  • Ruby

    Real Life

    diff --git a/Examples/ruby/constants/Makefile b/Examples/ruby/constants/Makefile new file mode 100644 index 000000000..540dfbf2b --- /dev/null +++ b/Examples/ruby/constants/Makefile @@ -0,0 +1,18 @@ +TOP = ../.. +SWIG = $(TOP)/../swig +SRCS = +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 + + diff --git a/Examples/ruby/constants/example.i b/Examples/ruby/constants/example.i new file mode 100644 index 000000000..9b04ebc1d --- /dev/null +++ b/Examples/ruby/constants/example.i @@ -0,0 +1,24 @@ +/* File : example.i */ +%module example + +/* A few preprocessor macros */ + +#define ICONST 42 +#define FCONST 2.1828 +#define CCONST 'x' +#define SCONST "Hello World" + +/* This should work just fine */ +#define EXPR ICONST + 3*(FCONST) + +/* This shouldn't do anything */ +#define EXTERN extern + +/* Neither should this (BAR isn't defined) */ +#define FOO (ICONST + BAR) + +/* The following statements also produce constants */ +const int iconst = 37; +const double fconst = 3.14; + + diff --git a/Examples/ruby/constants/index.html b/Examples/ruby/constants/index.html new file mode 100644 index 000000000..b5b382a13 --- /dev/null +++ b/Examples/ruby/constants/index.html @@ -0,0 +1,66 @@ + + +SWIG:Examples:ruby:constants + + + + +SWIG/Examples/ruby/constants/ +
    + +

    Wrapping C Constants

    + +$Header$
    + +

    +When SWIG encounters C preprocessor macros and C declarations that look like constants, +it creates Ruby constants with an identical value. Click here +to see a SWIG interface with some constant declarations in it. + +

    Accessing Constants from Ruby

    + +Click here to see a script that prints out the values +of the constants contained in the above file. + +

    Key points

    + + + +
    + + + + diff --git a/Examples/ruby/constants/run.rb b/Examples/ruby/constants/run.rb new file mode 100644 index 000000000..daa2cf855 --- /dev/null +++ b/Examples/ruby/constants/run.rb @@ -0,0 +1,23 @@ +# file: run.rb + +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" + +begin + print "EXTERN = ", Example::EXTERN, " (Arg! This shouldn't print anything)\n" +rescue NameError + print "EXTERN isn't defined (good)\n" +end + +begin + print "FOO = ", Example::FOO, " (Arg! This shouldn't print anything)\n" +rescue NameError + print "FOO isn't defined (good)\n" +end diff --git a/Examples/ruby/index.html b/Examples/ruby/index.html new file mode 100644 index 000000000..a8ad5328f --- /dev/null +++ b/Examples/ruby/index.html @@ -0,0 +1,85 @@ + + +SWIG:Examples:ruby + + + +

    SWIG Ruby Examples

    + +$Header$
    + +

    +The following examples illustrate the use of SWIG with Ruby. + +

    + +

    Compilation Issues

    + + + +

    Compatibility

    + +The examples have been extensively tested on the following platforms: + + + +Your mileage may vary. If you experience a problem, please let us know by +sending a message to swig-dev@cs.uchicago.edu. + + + + diff --git a/Examples/ruby/simple/Makefile b/Examples/ruby/simple/Makefile new file mode 100644 index 000000000..38117263b --- /dev/null +++ b/Examples/ruby/simple/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 + + diff --git a/Examples/ruby/simple/example.c b/Examples/ruby/simple/example.c new file mode 100644 index 000000000..1c2af789c --- /dev/null +++ b/Examples/ruby/simple/example.c @@ -0,0 +1,18 @@ +/* File : example.c */ + +/* A global variable */ +double Foo = 3.0; + +/* Compute the greatest common divisor of positive integers */ +int gcd(int x, int y) { + int g; + g = y; + while (x > 0) { + g = x; + x = y % x; + y = g; + } + return g; +} + + diff --git a/Examples/ruby/simple/example.i b/Examples/ruby/simple/example.i new file mode 100644 index 000000000..6702abb1e --- /dev/null +++ b/Examples/ruby/simple/example.i @@ -0,0 +1,5 @@ +/* File : example.i */ +%module example + +extern int gcd(int x, int y); +extern double Foo; diff --git a/Examples/ruby/simple/index.html b/Examples/ruby/simple/index.html new file mode 100644 index 000000000..7fff03915 --- /dev/null +++ b/Examples/ruby/simple/index.html @@ -0,0 +1,99 @@ + + +SWIG:Examples:ruby:simple + + + + + +SWIG/Examples/ruby/simple/ +
    + +

    Simple Ruby Example

    + +$Header$
    + +

    +This example illustrates how you can hook Ruby to a very simple C program containing +a function and a global variable. + +

    The C Code

    + +Suppose you have the following C code: + +
    +
    +/* File : example.c */
    +
    +/* A global variable */
    +double Foo = 3.0;
    +
    +/* Compute the greatest common divisor of positive integers */
    +int gcd(int x, int y) {
    +  int g;
    +  g = y;
    +  while (x > 0) {
    +    g = x;
    +    x = y % x;
    +    y = g;
    +  }
    +  return g;
    +}
    +
    +
    + +

    The SWIG interface

    + +Here is a simple SWIG interface file: + +
    +
    +/* File: example.i */
    +%module example
    +
    +extern int gcd(int x, int y);
    +extern double Foo;
    +
    +
    + +

    Compilation

    + +
      +
    1. swig -ruby example.i +

      +

    2. Compile example_wrap.c and example.c +to create the extension example.so. +
    + +

    Using the extension

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

    Key points

    + + + +
    + + diff --git a/Examples/ruby/simple/run.rb b/Examples/ruby/simple/run.rb new file mode 100644 index 000000000..373de123c --- /dev/null +++ b/Examples/ruby/simple/run.rb @@ -0,0 +1,21 @@ +# file: run.rb + +require 'example' + +# Call our gcd() function + +x = 42 +y = 105 +g = Example.gcd(x,y) +printf "The gcd of %d and %d is %d\n",x,y,g + +# Manipulate the Foo global variable + +# Output its current value +print "Foo = ", Example.Foo, "\n" + +# Change its value +Example.Foo = 3.1415926 + +# See if the change took effect +print "Foo = ", Example.Foo, "\n" diff --git a/Lib/ruby/Makefile.swig b/Lib/ruby/Makefile.swig new file mode 100644 index 000000000..a7f3ae3d2 --- /dev/null +++ b/Lib/ruby/Makefile.swig @@ -0,0 +1,42 @@ +# File : Makefile.swig +# Makefile for a SWIG module. Use this file if you are +# producing a Ruby extension for general use or distribution. +# +# 1. Prepare extconf.rb. +# 2. Modify this file as appropriate. +# 3. Type 'make -f Makefile.swig' to generate wrapper code and Makefile. +# 4. Type 'make' to build your extension. +# 5. Type 'make install' to install your extension. +# + +MODULE = yourmodule +FEATURE = $(MODULE) +INTERFACE = $(MODULE).i +RUBY = ruby +SWIG = swig + +# for C extension +SWIGOPT = -ruby +WRAPPER = $(MODULE)_wrap.c + +## for C++ extension +#SWIGOPT = -ruby -c++ +#WRAPPER = $(MODULE)_wrap.cc + + +swigall: $(WRAPPER) Makefile + +$(WRAPPER): $(INTERFACE) + $(SWIG) $(SWIGOPT) -o $@ $(INTERFACE) + +Makefile: extconf.rb + $(RUBY) extconf.rb + @if [ -f Makefile ] ; then\ + echo "include Makefile.swig" >> Makefile;\ + fi + +swigclean: + @if [ -f Makefile ] ; then\ + make -f Makefile clean;\ + fi + rm -f Makefile $(WRAPPER) diff --git a/Lib/ruby/embed.i b/Lib/ruby/embed.i new file mode 100644 index 000000000..ad38190eb --- /dev/null +++ b/Lib/ruby/embed.i @@ -0,0 +1,16 @@ +%wrapper %{ + +#include "ruby.h" + +int +main(argc, argv) + int argc; + char **argv; +{ + ruby_init(); + ruby_options(argc, argv); + ruby_run(); + return 0; +} + +%} diff --git a/Lib/ruby/exception.i b/Lib/ruby/exception.i new file mode 100644 index 000000000..e12fd1c35 --- /dev/null +++ b/Lib/ruby/exception.i @@ -0,0 +1,27 @@ +// +// SWIG exception handling for Ruby +// +// $Header$ +// +// Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +// Copyright (C) 2000 Information-technology Promotion Agency, Japan +// +// Masaki Fukushima +// + +%{ +#define SWIG_MemoryError rb_eFatal +#define SWIG_IOError rb_eIOError +#define SWIG_RuntimeError rb_eRuntimeError +#define SWIG_IndexError rb_eIndexError +#define SWIG_TypeError rb_eTypeError +#define SWIG_DivisionByZero rb_eZeroDivError +#define SWIG_OverflowError rb_eRuntimeException +#define SWIG_SyntaxError rb_eSyntaxError +#define SWIG_ValueError rb_eArgError +#define SWIG_SystemError rb_eSystemError +#define SWIG_UnknownError rb_eRuntimeError + +#define SWIG_exception(a,b) rb_raise(a,b) + +%} diff --git a/Lib/ruby/extconf.rb b/Lib/ruby/extconf.rb new file mode 100644 index 000000000..3bac8ccc4 --- /dev/null +++ b/Lib/ruby/extconf.rb @@ -0,0 +1,9 @@ +require 'mkmf' + +dir_config('yourlib') + +if have_header('yourlib.h') and have_library('yourlib', 'yourlib_init') + # If you use swig -c option, you may have to link libswigrb. + # have_library('swigrb') + create_makefile('yourlib') +end diff --git a/Lib/ruby/ptrlang.i b/Lib/ruby/ptrlang.i new file mode 100644 index 000000000..b063545dd --- /dev/null +++ b/Lib/ruby/ptrlang.i @@ -0,0 +1,646 @@ +// +// SWIG pointer conversion and utility library for Ruby +// +// $Header$ +// +// Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +// Copyright (C) 2000 Information-technology Promotion Agency, Japan +// +// Masaki Fukushima +// +// This file is originally derived from python/ptrlang.i + +// +// SWIG pointer conversion and utility library +// +// Dave Beazley +// April 19, 1997 +// +// Python specific implementation. This file is included +// by the file ../pointer.i + +%{ + +#include + +/*------------------------------------------------------------------ + ptrcast(value,type) + + Constructs a new pointer value. Value may either be a string + or an integer. Type is a string corresponding to either the + C datatype or mangled datatype. + + ptrcast(0,"Vector *") + or + ptrcast(0,"Vector_p") + ------------------------------------------------------------------ */ + +static VALUE ptrcast(VALUE _PTRVALUE, char *type) { + + char *r,*s; + void *ptr; + VALUE obj; + char *typestr,*c; + + /* Produce a "mangled" version of the type string. */ + + typestr = (char *) xmalloc(strlen(type)+2); + + /* Go through and munge the typestring */ + + r = typestr; + *(r++) = '_'; + c = type; + while (*c) { + if (!isspace(*c)) { + if ((*c == '*') || (*c == '&')) { + *(r++) = 'p'; + } + else *(r++) = *c; + } else { + *(r++) = '_'; + } + c++; + } + *(r++) = 0; + + /* Check to see what kind of object _PTRVALUE is */ + + switch (TYPE(_PTRVALUE)) { + case T_FIXNUM: + case T_BIGNUM: + ptr = (void *) NUM2ULONG(_PTRVALUE); + /* Received a numerical value. Make a pointer out of it */ + r = (char *) xmalloc(strlen(typestr)+22); + if (ptr) { + SWIG_MakePtr(r, ptr, typestr); + } else { + sprintf(r,"_0%s",typestr); + } + obj = rb_str_new2(r); + free(r); + break; + case T_STRING: + /* Have a real pointer value now. Try to strip out the pointer + value */ + s = STR2CSTR(_PTRVALUE); + r = (char *) xmalloc(strlen(type)+22); + + /* Now extract the pointer value */ + if (!SWIG_GetPtr(s,&ptr,0)) { + if (ptr) { + SWIG_MakePtr(r,ptr,typestr); + } else { + sprintf(r,"_0%s",typestr); + } + obj = rb_str_new2(r); + } else { + obj = Qnil; + } + free(r); + break; + default: + obj = Qnil; + break; + } + free(typestr); + if (!obj) + rb_raise(rb_eTypeError,"Type error in ptrcast. Argument is not a valid pointer value."); + return obj; +} + +/*------------------------------------------------------------------ + ptrvalue(ptr,type = 0) + + Attempts to dereference a pointer value. If type is given, it + will try to use that type. Otherwise, this function will attempt + to "guess" the proper datatype by checking against all of the + builtin C datatypes. + ------------------------------------------------------------------ */ + +static VALUE ptrvalue(VALUE _PTRVALUE, int index, char *type) { + void *ptr; + char *s; + VALUE obj; + + Check_Type(_PTRVALUE, T_STRING); + s = STR2CSTR(_PTRVALUE); + if (SWIG_GetPtr(s,&ptr,0)) { + rb_raise(rb_eTypeError,"Type error in ptrvalue. Argument is not a valid pointer value."); + } + + /* If no datatype was passed, try a few common datatypes first */ + + if (!type) { + + /* No datatype was passed. Type to figure out if it's a common one */ + + if (!SWIG_GetPtr(s,&ptr,"int_p")) { + type = "int"; + } else if (!SWIG_GetPtr(s,&ptr,"double_p")) { + type = "double"; + } else if (!SWIG_GetPtr(s,&ptr,"short_p")) { + type = "short"; + } else if (!SWIG_GetPtr(s,&ptr,"long_p")) { + type = "long"; + } else if (!SWIG_GetPtr(s,&ptr,"float_p")) { + type = "float"; + } else if (!SWIG_GetPtr(s,&ptr,"char_p")) { + type = "char"; + } else if (!SWIG_GetPtr(s,&ptr,"char_pp")) { + type = "char *"; + } else { + type = "unknown"; + } + } + + if (!ptr) { + rb_raise(rb_eTypeError,"Unable to dereference NULL pointer."); + } + + /* Now we have a datatype. Try to figure out what to do about it */ + if (strcmp(type,"int") == 0) { + obj = INT2NUM(*(((int *) ptr) + index)); + } else if (strcmp(type,"double") == 0) { + obj = rb_float_new((double) *(((double *) ptr)+index)); + } else if (strcmp(type,"short") == 0) { + obj = INT2NUM(*(((short *) ptr)+index)); + } else if (strcmp(type,"long") == 0) { + obj = INT2NUM(*(((long *) ptr)+index)); + } else if (strcmp(type,"float") == 0) { + obj = rb_float_new((double) *(((float *) ptr)+index)); + } else if (strcmp(type,"char") == 0) { + obj = rb_str_new2(((char *) ptr)+index); + } else if (strcmp(type,"char *") == 0) { + char *c = *(((char **) ptr)+index); + if (c) obj = rb_str_new2(c); + else obj = rb_str_new2("NULL"); + } else { + rb_raise(rb_eTypeError,"Unable to dereference unsupported datatype."); + } + return obj; +} + +/*------------------------------------------------------------------ + ptrcreate(type,value = 0,numelements = 1) + + Attempts to create a new object of given type. Type must be + a basic C datatype. Will not create complex objects. + ------------------------------------------------------------------ */ + +static VALUE ptrcreate(char *type, VALUE _RBVALUE, int numelements) { + void *ptr; + VALUE obj; + int sz; + char *cast; + char temp[40]; + + /* Check the type string against a variety of possibilities */ + + if (strcmp(type,"int") == 0) { + sz = sizeof(int)*numelements; + cast = "int_p"; + } else if (strcmp(type,"short") == 0) { + sz = sizeof(short)*numelements; + cast = "short_p"; + } else if (strcmp(type,"long") == 0) { + sz = sizeof(long)*numelements; + cast = "long_p"; + } else if (strcmp(type,"double") == 0) { + sz = sizeof(double)*numelements; + cast = "double_p"; + } else if (strcmp(type,"float") == 0) { + sz = sizeof(float)*numelements; + cast = "float_p"; + } else if (strcmp(type,"char") == 0) { + sz = sizeof(char)*numelements; + cast = "char_p"; + } else if (strcmp(type,"char *") == 0) { + sz = sizeof(char *)*(numelements+1); + cast = "char_pp"; + } else { + rb_raise(rb_eTypeError,"Unable to create unknown datatype."); + } + + /* Create the new object */ + + ptr = (void *) xmalloc(sz); + + /* Now try to set its default value */ + + if (_RBVALUE) { + if (strcmp(type,"int") == 0) { + int *ip,i,ivalue; + ivalue = NUM2INT(_RBVALUE); + ip = (int *) ptr; + for (i = 0; i < numelements; i++) + ip[i] = ivalue; + } else if (strcmp(type,"short") == 0) { + short *ip,ivalue; + int i; + ivalue = (short) NUM2INT(_RBVALUE); + ip = (short *) ptr; + for (i = 0; i < numelements; i++) + ip[i] = ivalue; + } else if (strcmp(type,"long") == 0) { + long *ip,ivalue; + int i; + ivalue = NUM2LONG(_RBVALUE); + ip = (long *) ptr; + for (i = 0; i < numelements; i++) + ip[i] = ivalue; + } else if (strcmp(type,"double") == 0) { + double *ip,ivalue; + int i; + ivalue = (double) NUM2DBL(_RBVALUE); + ip = (double *) ptr; + for (i = 0; i < numelements; i++) + ip[i] = ivalue; + } else if (strcmp(type,"float") == 0) { + float *ip,ivalue; + int i; + ivalue = (float) NUM2DBL(_RBVALUE); + ip = (float *) ptr; + for (i = 0; i < numelements; i++) + ip[i] = ivalue; + } else if (strcmp(type,"char") == 0) { + char *ip,*ivalue; + ivalue = (char *) STR2CSTR(_RBVALUE); + ip = (char *) ptr; + strncpy(ip,ivalue,numelements-1); + } else if (strcmp(type,"char *") == 0) { + char **ip, *ivalue; + int i; + ivalue = (char *) STR2CSTR(_RBVALUE); + ip = (char **) ptr; + for (i = 0; i < numelements; i++) { + if (ivalue) { + ip[i] = (char *) xmalloc(strlen(ivalue)+1); + strcpy(ip[i],ivalue); + } else { + ip[i] = 0; + } + } + ip[numelements] = 0; + } + } + /* Create the pointer value */ + + SWIG_MakePtr(temp,ptr,cast); + obj = rb_str_new2(temp); + return obj; +} + + +/*------------------------------------------------------------------ + ptrset(ptr,value,index = 0,type = 0) + + Attempts to set the value of a pointer variable. If type is + given, we will use that type. Otherwise, we'll guess the datatype. + ------------------------------------------------------------------ */ + +static VALUE ptrset(VALUE _PTRVALUE, VALUE _RBVALUE, int index, char *type) { + void *ptr; + char *s; + VALUE obj; + + Check_Type(_PTRVALUE, T_STRING); + s = STR2CSTR(_PTRVALUE); + if (SWIG_GetPtr(s,&ptr,0)) { + rb_raise(rb_eTypeError,"Type error in ptrset. Argument is not a valid pointer value."); + } + + /* If no datatype was passed, try a few common datatypes first */ + + if (!type) { + + /* No datatype was passed. Type to figure out if it's a common one */ + + if (!SWIG_GetPtr(s,&ptr,"int_p")) { + type = "int"; + } else if (!SWIG_GetPtr(s,&ptr,"double_p")) { + type = "double"; + } else if (!SWIG_GetPtr(s,&ptr,"short_p")) { + type = "short"; + } else if (!SWIG_GetPtr(s,&ptr,"long_p")) { + type = "long"; + } else if (!SWIG_GetPtr(s,&ptr,"float_p")) { + type = "float"; + } else if (!SWIG_GetPtr(s,&ptr,"char_p")) { + type = "char"; + } else if (!SWIG_GetPtr(s,&ptr,"char_pp")) { + type = "char *"; + } else { + type = "unknown"; + } + } + + if (!ptr) { + rb_raise(rb_eTypeError,"Unable to set NULL pointer."); + } + + /* Now we have a datatype. Try to figure out what to do about it */ + if (strcmp(type,"int") == 0) { + *(((int *) ptr)+index) = NUM2INT(_RBVALUE); + } else if (strcmp(type,"double") == 0) { + *(((double *) ptr)+index) = (double) NUM2DBL(_RBVALUE); + } else if (strcmp(type,"short") == 0) { + *(((short *) ptr)+index) = (short) NUM2INT(_RBVALUE); + } else if (strcmp(type,"long") == 0) { + *(((long *) ptr)+index) = NUM2LONG(_RBVALUE); + } else if (strcmp(type,"float") == 0) { + *(((float *) ptr)+index) = (float) NUM2DBL(_RBVALUE); + } else if (strcmp(type,"char") == 0) { + char *c = STR2CSTR(_RBVALUE); + strcpy(((char *) ptr)+index, c); + } else if (strcmp(type,"char *") == 0) { + char *c = STR2CSTR(_RBVALUE); + char **ca = (char **) ptr; + if (ca[index]) free(ca[index]); + if (strcmp(c,"NULL") == 0) { + ca[index] = 0; + } else { + ca[index] = (char *) xmalloc(strlen(c)+1); + strcpy(ca[index],c); + } + } else { + rb_raise(rb_eTypeError,"Unable to set unsupported datatype."); + } + return Qnil; +} + + +/*------------------------------------------------------------------ + ptradd(ptr,offset) + + Adds a value to an existing pointer value. Will do a type-dependent + add for basic datatypes. For other datatypes, will do a byte-add. + ------------------------------------------------------------------ */ + +static VALUE ptradd(VALUE _PTRVALUE, int offset) { + + char *r,*s; + void *ptr,*junk; + VALUE obj; + char *type; + + /* Check to see what kind of object _PTRVALUE is */ + + Check_Type(_PTRVALUE, T_STRING); + + /* Have a potential pointer value now. Try to strip out the value */ + s = STR2CSTR(_PTRVALUE); + + /* Try to handle a few common datatypes first */ + + if (!SWIG_GetPtr(s,&ptr,"int_p")) { + ptr = (void *) (((int *) ptr) + offset); + } else if (!SWIG_GetPtr(s,&ptr,"double_p")) { + ptr = (void *) (((double *) ptr) + offset); + } else if (!SWIG_GetPtr(s,&ptr,"short_p")) { + ptr = (void *) (((short *) ptr) + offset); + } else if (!SWIG_GetPtr(s,&ptr,"long_p")) { + ptr = (void *) (((long *) ptr) + offset); + } else if (!SWIG_GetPtr(s,&ptr,"float_p")) { + ptr = (void *) (((float *) ptr) + offset); + } else if (!SWIG_GetPtr(s,&ptr,"char_p")) { + ptr = (void *) (((char *) ptr) + offset); + } else if (!SWIG_GetPtr(s,&ptr,0)) { + ptr = (void *) (((char *) ptr) + offset); + } else { + rb_raise(rb_eTypeError,"Type error in ptradd. Argument is not a valid pointer value."); + } + type = SWIG_GetPtr(s,&junk,"INVALID POINTER"); + r = (char *) xmalloc(strlen(type)+20); + if (ptr) { + SWIG_MakePtr(r,ptr,type); + } else { + sprintf(r,"_0%s",type); + } + obj = rb_str_new2(r); + free(r); + + return obj; +} + +/*------------------------------------------------------------------ + ptrmap(type1,type2) + + Allows a mapping between type1 and type2. (Like a typedef) + ------------------------------------------------------------------ */ + +static void ptrmap(char *type1, char *type2) { + + char *typestr1,*typestr2,*c,*r; + + /* Produce a "mangled" version of the type string. */ + + typestr1 = (char *) xmalloc(strlen(type1)+2); + + /* Go through and munge the typestring */ + + r = typestr1; + *(r++) = '_'; + c = type1; + while (*c) { + if (!isspace(*c)) { + if ((*c == '*') || (*c == '&')) { + *(r++) = 'p'; + } + else *(r++) = *c; + } else { + *(r++) = '_'; + } + c++; + } + *(r++) = 0; + + typestr2 = (char *) xmalloc(strlen(type2)+2); + + /* Go through and munge the typestring */ + + r = typestr2; + *(r++) = '_'; + c = type2; + while (*c) { + if (!isspace(*c)) { + if ((*c == '*') || (*c == '&')) { + *(r++) = 'p'; + } + else *(r++) = *c; + } else { + *(r++) = '_'; + } + c++; + } + *(r++) = 0; + SWIG_RegisterMapping(typestr1,typestr2,0); + SWIG_RegisterMapping(typestr2,typestr1,0); +} + +/*------------------------------------------------------------------ + ptrfree(ptr) + + Destroys a pointer value + ------------------------------------------------------------------ */ + +VALUE ptrfree(VALUE _PTRVALUE) { + void *ptr, *junk; + char *s; + + Check_Type(_PTRVALUE, T_STRING); + s = STR2CSTR(_PTRVALUE); + if (SWIG_GetPtr(s,&ptr,0)) { + rb_raise(rb_eTypeError,"Type error in ptrfree. Argument is not a valid pointer value."); + } + + /* Check to see if this pointer is a char ** */ + if (!SWIG_GetPtr(s,&junk,"char_pp")) { + char **c = (char **) ptr; + if (c) { + int i = 0; + while (c[i]) { + free(c[i]); + i++; + } + } + } + if (ptr) + free((char *) ptr); + + return Qnil; +} + +%} +%typemap(ruby,in) VALUE ptr, VALUE value { + $target = $source; +} + +%typemap(ruby,out) VALUE ptrcast, + VALUE ptrvalue, + VALUE ptrcreate, + VALUE ptrset, + VALUE ptradd, + VALUE ptrfree +{ + $target = $source; +} + +%typemap(ruby,ret) int ptrset { + if ($source == -1) return Qnil; +} + +VALUE ptrcast(VALUE ptr, char *type); +// Casts a pointer ptr to a new datatype given by the string type. +// type may be either the SWIG generated representation of a datatype +// or the C representation. For example : +// +// ptrcast(ptr,"double_p"); # Ruby representation +// ptrcast(ptr,"double *"); # C representation +// +// A new pointer value is returned. ptr may also be an integer +// value in which case the value will be used to set the pointer +// value. For example : +// +// a = ptrcast(0,"Vector_p"); +// +// Will create a NULL pointer of type "Vector_p" +// +// The casting operation is sensitive to formatting. As a result, +// "double *" is different than "double*". As a result of thumb, +// there should always be exactly one space between the C datatype +// and any pointer specifiers (*). + +VALUE ptrvalue(VALUE ptr, int index = 0, char *type = 0); +// Returns the value that a pointer is pointing to (ie. dereferencing). +// The type is automatically inferred by the pointer type--thus, an +// integer pointer will return an integer, a double will return a double, +// and so on. The index and type fields are optional parameters. When +// an index is specified, this function returns the value of ptr[index]. +// This allows array access. When a type is specified, it overrides +// the given pointer type. Examples : +// +// ptrvalue(a) # Returns the value *a +// ptrvalue(a,10) # Returns the value a[10] +// ptrvalue(a,10,"double") # Returns a[10] assuming a is a double * + +VALUE ptrset(VALUE ptr, VALUE value, int index = 0, char *type = 0); +// Sets the value pointed to by a pointer. The type is automatically +// inferred from the pointer type so this function will work for +// integers, floats, doubles, etc... The index and type fields are +// optional. When an index is given, it provides array access. When +// type is specified, it overrides the given pointer type. Examples : +// +// ptrset(a,3) # Sets the value *a = 3 +// ptrset(a,3,10) # Sets a[10] = 3 +// ptrset(a,3,10,"int") # Sets a[10] = 3 assuming a is a int * + +VALUE ptrcreate(char *type, VALUE value = 0, int nitems = 1); +// Creates a new object and returns a pointer to it. This function +// can be used to create various kinds of objects for use in C functions. +// type specifies the basic C datatype to create and value is an +// optional parameter that can be used to set the initial value of the +// object. nitems is an optional parameter that can be used to create +// an array. This function results in a memory allocation using +// malloc(). Examples : +// +// a = ptrcreate("double") # Create a new double, return pointer +// a = ptrcreate("int",7) # Create an integer, set value to 7 +// a = ptrcreate("int",0,1000) # Create an integer array with initial +// # values all set to zero +// +// This function only recognizes a few common C datatypes as listed below : +// +// int, short, long, float, double, char, char *, void +// +// All other datatypes will result in an error. However, other +// datatypes can be created by using the ptrcast function. For +// example: +// +// a = ptrcast(ptrcreate("int",0,100),"unsigned int *") + +VALUE ptrfree(VALUE ptr); +// Destroys the memory pointed to by ptr. This function calls free() +// and should only be used with objects created by ptrcreate(). Since +// this function calls free, it may work with other objects, but this +// is generally discouraged unless you absolutely know what you're +// doing. + +VALUE ptradd(VALUE ptr, int offset); +// Adds a value to the current pointer value. For the C datatypes of +// int, short, long, float, double, and char, the offset value is the +// number of objects and works in exactly the same manner as in C. For +// example, the following code steps through the elements of an array +// +// a = ptrcreate("double",0,100); # Create an array double a[100] +// b = a; +// for i in range(0,100): +// ptrset(b,0.0025*i); # set *b = 0.0025*i +// b = ptradd(b,1); # b++ (go to next double) +// +// In this case, adding one to b goes to the next double. +// +// For all other datatypes (including all complex datatypes), the +// offset corresponds to bytes. This function does not perform any +// bounds checking and negative offsets are perfectly legal. + +void ptrmap(char *type1, char *type2); +// This is a rarely used function that performs essentially the same +// operation as a C typedef. To manage datatypes at run-time, SWIG +// modules manage an internal symbol table of type mappings. This +// table keeps track of which types are equivalent to each other. The +// ptrmap() function provides a mechanism for scripts to add symbols +// to this table. For example : +// +// ptrmap("double_p","Real_p"); +// +// would make the types "doublePtr" and "RealPtr" equivalent to each +// other. Pointers of either type could now be used interchangably. +// +// Normally this function is not needed, but it can be used to +// circumvent SWIG's normal type-checking behavior or to work around +// weird type-handling problems. + + + + diff --git a/Lib/ruby/ruby.swg b/Lib/ruby/ruby.swg new file mode 100644 index 000000000..0497b192d --- /dev/null +++ b/Lib/ruby/ruby.swg @@ -0,0 +1,44 @@ +/* ruby.swg */ +#include "ruby.h" + +#define UINT2NUM(v) rb_uint2inum(v) +#define NUM2USHRT(n) NUM2UINT(n) +#define NUM2SHRT(n) (\ + (SHRT_MIN <= NUM2INT(n) && NUM2INT(n) <= SHRT_MAX)\ + ? (short)NUM2INT(n)\ + : (rb_raise(rb_eArgError, "integer %d out of range of `short'",\ + NUM2INT(n)), (short)0)\ +) + +#ifdef __cplusplus +# define VALUEFUNC(f) ((VALUE (*)(...))f) +# define VOIDFUNC(f) ((void (*)(...))f) +#else +# define VALUEFUNC(f) (f) +# define VOIDFUNC(f) (f) +#endif + +#if defined(_WIN32) || defined(__WIN32__) +# if defined(_MSC_VER) +# if defined(STATIC_LINKED) +# define SWIGEXPORT(a) a +# else +# define SWIGEXPORT(a) __declspec(dllexport) a +# endif +# else +# if defined(__BORLANDC__) +# define SWIGEXPORT(a) a _export +# else +# define SWIGEXPORT(a) a +# endif +#endif +#else +# define SWIGEXPORT(a) a +#endif + +#ifdef SWIG_GLOBAL +#define SWIGSTATICRUNTIME(a) SWIGEXPORT(a) +#else +#define SWIGSTATICRUNTIME(a) static a +#endif + diff --git a/Lib/ruby/rubydec.swg b/Lib/ruby/rubydec.swg new file mode 100644 index 000000000..8755a5b1d --- /dev/null +++ b/Lib/ruby/rubydec.swg @@ -0,0 +1,15 @@ +/* rubydec.swg */ +#ifdef __cplusplus +extern "C" { +#endif + +SWIGEXPORT(void) SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)); +SWIGEXPORT(void) SWIG_MakePtr(char *_c, const void *_ptr, char *type); +SWIGEXPORT(char *) SWIG_GetPtr(char *_c, void **ptr, char *_t); +SWIGEXPORT(VALUE) SWIG_NewPointerObj(void *ptr, char *type); +SWIGEXPORT(void *) SWIG_ConvertPtr(VALUE obj, char *type); + +#ifdef __cplusplus +} +#endif + diff --git a/Lib/ruby/rubydef.swg b/Lib/ruby/rubydef.swg new file mode 100644 index 000000000..0053945f6 --- /dev/null +++ b/Lib/ruby/rubydef.swg @@ -0,0 +1,297 @@ +/* rubydef.swg */ +#ifdef __cplusplus +extern "C" { +#endif + +/* SWIG pointer structure */ + +typedef struct SwigPtrType { + char *name; /* Datatype name */ + int len; /* Length (used for optimization) */ + void *(*cast)(void *); /* Pointer casting function */ + struct SwigPtrType *next; /* Linked list pointer */ +} SwigPtrType; + +/* Pointer cache structure */ + +typedef struct { + int stat; /* Status (valid) bit */ + SwigPtrType *tp; /* Pointer to type structure */ + char name[256]; /* Given datatype name */ + char mapped[256]; /* Equivalent name */ +} SwigCacheType; + +/* Some variables */ + +static int SwigPtrMax = 64; /* Max entries that can be currently held */ + /* This value may be adjusted dynamically */ +static int SwigPtrN = 0; /* Current number of entries */ +static int SwigPtrSort = 0; /* Status flag indicating sort */ +static int SwigStart[256]; /* Starting positions of types */ + +/* Pointer table */ +static SwigPtrType *SwigPtrTable = 0; /* Table containing pointer equivalences */ + +/* Cached values */ + +#define SWIG_CACHESIZE 8 +#define SWIG_CACHEMASK 0x7 +static SwigCacheType SwigCache[SWIG_CACHESIZE]; +static int SwigCacheIndex = 0; +static int SwigLastCache = 0; + +/* Sort comparison function */ +static int swigsort(const void *data1, const void *data2) { + SwigPtrType *d1 = (SwigPtrType *) data1; + SwigPtrType *d2 = (SwigPtrType *) data2; + return strcmp(d1->name,d2->name); +} + +/* Binary Search function */ +static int swigcmp(const void *key, const void *data) { + char *k = (char *) key; + SwigPtrType *d = (SwigPtrType *) data; + return strncmp(k,d->name,d->len); +} + +/* Register a new datatype with the type-checker */ + +SWIGSTATICRUNTIME(void) +SWIG_RegisterMapping(char *origtype, char *newtype, void *(*cast)(void *)) { + + int i; + SwigPtrType *t = 0,*t1; + + /* Allocate the pointer table if necessary */ + + if (!SwigPtrTable) { + SwigPtrTable = (SwigPtrType *) malloc(SwigPtrMax*sizeof(SwigPtrType)); + SwigPtrN = 0; + } + /* Grow the table */ + if (SwigPtrN >= SwigPtrMax) { + SwigPtrMax = 2*SwigPtrMax; + SwigPtrTable = (SwigPtrType *) realloc((char *) SwigPtrTable,SwigPtrMax*sizeof(SwigPtrType)); + } + for (i = 0; i < SwigPtrN; i++) + if (strcmp(SwigPtrTable[i].name,origtype) == 0) { + t = &SwigPtrTable[i]; + break; + } + if (!t) { + t = &SwigPtrTable[SwigPtrN]; + t->name = origtype; + t->len = strlen(t->name); + t->cast = 0; + t->next = 0; + SwigPtrN++; + } + + /* Check for existing entry */ + + while (t->next) { + if ((strcmp(t->name,newtype) == 0)) { + if (cast) t->cast = cast; + return; + } + t = t->next; + } + + /* Now place entry (in sorted order) */ + + t1 = (SwigPtrType *) malloc(sizeof(SwigPtrType)); + t1->name = newtype; + t1->len = strlen(t1->name); + t1->cast = cast; + t1->next = 0; + t->next = t1; + SwigPtrSort = 0; +} + +/* Make a pointer value string */ + +SWIGSTATICRUNTIME(void) +SWIG_MakePtr(char *_c, const void *_ptr, char *type) { + static char _hex[16] = + {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', + 'a', 'b', 'c', 'd', 'e', 'f'}; + unsigned long _p, _s; + char _result[20], *_r; /* Note : a 64-bit hex number = 16 digits */ + _r = _result; + _p = (unsigned long) _ptr; + if (_p > 0) { + while (_p > 0) { + _s = _p & 0xf; + *(_r++) = _hex[_s]; + _p = _p >> 4; + } + *_r = '_'; + while (_r >= _result) + *(_c++) = *(_r--); + *(_c++) = '_'; + } else { + strcpy (_c, "NULL"); + } + if (_ptr) + strcpy (_c, type); +} + +/* Define for backwards compatibility */ + +#define _swig_make_hex SWIG_MakePtr + +/* Function for getting a pointer value */ + +SWIGSTATICRUNTIME(char *) +SWIG_GetPtr(char *_c, void **ptr, char *_t) +{ + unsigned long _p; + char temp_type[256]; + char *name; + int i, len; + SwigPtrType *sp,*tp; + SwigCacheType *cache; + int start, end; + _p = 0; + + /* Pointer values must start with leading underscore */ + if (*_c == '_') { + _c++; + /* Extract hex value from pointer */ + while (*_c) { + if ((*_c >= '0') && (*_c <= '9')) + _p = (_p << 4) + (*_c - '0'); + else if ((*_c >= 'a') && (*_c <= 'f')) + _p = (_p << 4) + ((*_c - 'a') + 10); + else + break; + _c++; + } + _c++; + if (_t) { + if (strcmp(_t,_c)) { + if (!SwigPtrSort) { + qsort((void *) SwigPtrTable, SwigPtrN, sizeof(SwigPtrType), swigsort); + for (i = 0; i < 256; i++) { + SwigStart[i] = SwigPtrN; + } + for (i = SwigPtrN-1; i >= 0; i--) { + SwigStart[(int) (SwigPtrTable[i].name[1])] = i; + } + for (i = 255; i >= 1; i--) { + if (SwigStart[i-1] > SwigStart[i]) + SwigStart[i-1] = SwigStart[i]; + } + SwigPtrSort = 1; + for (i = 0; i < SWIG_CACHESIZE; i++) + SwigCache[i].stat = 0; + } + + /* First check cache for matches. Uses last cache value as starting point */ + cache = &SwigCache[SwigLastCache]; + for (i = 0; i < SWIG_CACHESIZE; i++) { + if (cache->stat) { + if (strcmp(_t,cache->name) == 0) { + if (strcmp(_c,cache->mapped) == 0) { + cache->stat++; + *ptr = (void *) _p; + if (cache->tp->cast) *ptr = (*(cache->tp->cast))(*ptr); + return (char *) 0; + } + } + } + SwigLastCache = (SwigLastCache+1) & SWIG_CACHEMASK; + if (!SwigLastCache) cache = SwigCache; + else cache++; + } + /* We have a type mismatch. Will have to look through our type + mapping table to figure out whether or not we can accept this datatype */ + + start = SwigStart[(int) _t[1]]; + end = SwigStart[(int) _t[1]+1]; + sp = &SwigPtrTable[start]; + while (start < end) { + if (swigcmp(_t,sp) == 0) break; + sp++; + start++; + } + if (start >= end) sp = 0; + /* Try to find a match for this */ + if (sp) { + while (swigcmp(_t,sp) == 0) { + name = sp->name; + len = sp->len; + tp = sp->next; + /* Try to find entry for our given datatype */ + while(tp) { + if (tp->len >= 255) { + return _c; + } + strcpy(temp_type,tp->name); + strncat(temp_type,_t+len,255-tp->len); + if (strcmp(_c,temp_type) == 0) { + + strcpy(SwigCache[SwigCacheIndex].mapped,_c); + strcpy(SwigCache[SwigCacheIndex].name,_t); + SwigCache[SwigCacheIndex].stat = 1; + SwigCache[SwigCacheIndex].tp = tp; + SwigCacheIndex = SwigCacheIndex & SWIG_CACHEMASK; + + /* Get pointer value */ + *ptr = (void *) _p; + if (tp->cast) *ptr = (*(tp->cast))(*ptr); + return (char *) 0; + } + tp = tp->next; + } + sp++; + /* Hmmm. Didn't find it this time */ + } + } + /* Didn't find any sort of match for this data. + Get the pointer value and return the received type */ + *ptr = (void *) _p; + return _c; + } else { + /* Found a match on the first try. Return pointer value */ + *ptr = (void *) _p; + return (char *) 0; + } + } else { + /* No type specified. Good luck */ + *ptr = (void *) _p; + return (char *) 0; + } + } else { + if (strcmp (_c, "NULL") == 0) { + *ptr = (void *) 0; + return (char *) 0; + } + *ptr = (void *) 0; + return _c; + } +} + +SWIGSTATICRUNTIME(VALUE) +SWIG_NewPointerObj(void *ptr, char *type) +{ + char *temp = ALLOCA_N(char, strlen(type)+22); + SWIG_MakePtr(temp, ptr, type); + return rb_str_new2(temp); +} + +SWIGSTATICRUNTIME(void *) +SWIG_ConvertPtr(VALUE obj, char *type) +{ + void *ptr; + Check_Type(obj, T_STRING); + if (SWIG_GetPtr(RSTRING(obj)->ptr, &ptr, type)) { + rb_raise(rb_eTypeError, "Expected a %s", type); + } + return ptr; +} + +#ifdef __cplusplus +} +#endif + diff --git a/Lib/ruby/typemaps.i b/Lib/ruby/typemaps.i new file mode 100644 index 000000000..cd1c533a1 --- /dev/null +++ b/Lib/ruby/typemaps.i @@ -0,0 +1,501 @@ +// +// typemaps for Ruby +// +// $Header$ +// +// Copyright (C) 2000 Network Applied Communication Laboratory, Inc. +// Copyright (C) 2000 Information-technology Promotion Agency, Japan +// +// Masaki Fukushima +// + +#ifdef AUTODOC +%section "Typemap Library (Ruby)",info,after,pre,nosort,skip=1,chop_left=3,chop_right=0,chop_top=0,chop_bottom=0 +%text %{ +%include typemaps.i + +The SWIG typemap library provides a language independent mechanism for +supporting output arguments, input values, and other C function +calling mechanisms. The primary use of the library is to provide a +better interface to certain C function--especially those involving +pointers. +%} + +#endif + +// ------------------------------------------------------------------------ +// Pointer handling +// +// These mappings provide support for input/output arguments and common +// uses for C/C++ pointers. +// ------------------------------------------------------------------------ + +// INPUT typemaps. +// These remap a C pointer to be an "INPUT" value which is passed by value +// instead of reference. + + +#ifdef AUTODOC +%subsection "Input Methods" + +%text %{ +The following methods can be applied to turn a pointer into a simple +"input" value. That is, instead of passing a pointer to an object, +you would use a real value instead. + + int *INPUT + short *INPUT + long *INPUT + unsigned int *INPUT + unsigned short *INPUT + unsigned long *INPUT + unsigned char *INPUT + float *INPUT + double *INPUT + +To use these, suppose you had a C function like this : + + double fadd(double *a, double *b) { + return *a+*b; + } + +You could wrap it with SWIG as follows : + + %include typemaps.i + double fadd(double *INPUT, double *INPUT); + +or you can use the %apply directive : + + %include typemaps.i + %apply double *INPUT { double *a, double *b }; + double fadd(double *a, double *b); + +%} +#endif + +%typemap(ruby,in) double *INPUT(double temp) +{ + temp = NUM2DBL($source); + $target = &temp; +} + +%typemap(ruby,in) float *INPUT(float temp) +{ + temp = (float) NUM2DBL($source); + $target = &temp; +} + +%typemap(ruby,in) int *INPUT(int temp) +{ + temp = NUM2INT($source); + $target = &temp; +} + +%typemap(ruby,in) short *INPUT(short temp) +{ + temp = NUM2SHRT($source); + $target = &temp; +} + +%typemap(ruby,in) long *INPUT(long temp) +{ + temp = NUM2LONG($source); + $target = &temp; +} +%typemap(ruby,in) unsigned int *INPUT(unsigned int temp) +{ + temp = NUM2UINT($source); + $target = &temp; +} +%typemap(ruby,in) unsigned short *INPUT(unsigned short temp) +{ + temp = NUM2USHRT($source); + $target = &temp; +} +%typemap(ruby,in) unsigned long *INPUT(unsigned long temp) +{ + temp = NUM2ULONG($source); + $target = &temp; +} +%typemap(ruby,in) unsigned char *INPUT(unsigned char temp) +{ + temp = (unsigned char)NUM2UINT($source); + $target = &temp; +} + +%typemap(ruby,in) signed char *INPUT(signed char temp) +{ + temp = (signed char)NUM2INT($source); + $target = &temp; +} + +// OUTPUT typemaps. These typemaps are used for parameters that +// are output only. The output value is appended to the result as +// a array element. + +#ifdef AUTODOC +%subsection "Output Methods" + +%text %{ +The following methods can be applied to turn a pointer into an "output" +value. When calling a function, no input value would be given for +a parameter, but an output value would be returned. In the case of +multiple output values, they are returned in the form of a Ruby Array. + + int *OUTPUT + short *OUTPUT + long *OUTPUT + unsigned int *OUTPUT + unsigned short *OUTPUT + unsigned long *OUTPUT + unsigned char *OUTPUT + float *OUTPUT + double *OUTPUT + +For example, suppose you were trying to wrap the modf() function in the +C math library which splits x into integral and fractional parts (and +returns the integer part in one of its parameters).K: + + double modf(double x, double *ip); + +You could wrap it with SWIG as follows : + + %include typemaps.i + double modf(double x, double *OUTPUT); + +or you can use the %apply directive : + + %include typemaps.i + %apply double *OUTPUT { double *ip }; + double modf(double x, double *ip); + +The Ruby output of the function would be a Array containing both +output values. +%} +#endif + +// Helper function for Array output + +%{ +static VALUE output_helper(VALUE target, VALUE o) { + if (NIL_P(target)) { + target = o; + } else { + if (TYPE(target) != T_ARRAY) { + VALUE o2 = target; + target = rb_ary_new(); + rb_ary_push(target, o2); + } + rb_ary_push(target, o); + } + return target; +} +%} + +// Force the argument to be ignored. + +%typemap(ruby,ignore) int *OUTPUT(int temp), + short *OUTPUT(short temp), + long *OUTPUT(long temp), + unsigned int *OUTPUT(unsigned int temp), + unsigned short *OUTPUT(unsigned short temp), + unsigned long *OUTPUT(unsigned long temp), + unsigned char *OUTPUT(unsigned char temp), + signed char *OUTPUT(signed char temp), + float *OUTPUT(float temp), + double *OUTPUT(double temp) +{ + $target = &temp; +} + +%typemap(ruby,argout) int *OUTPUT, + short *OUTPUT, + long *OUTPUT, + signed char *OUTPUT +{ + $target = output_helper($target, INT2NUM(*$source)); +} + +%typemap(ruby,argout) unsigned int *OUTPUT, + unsigned short *OUTPUT, + unsigned long *OUTPUT, + unsigned char *OUTPUT +{ + $target = output_helper($target, UINT2NUM(*$source)); +} + +%typemap(ruby,argout) float *OUTPUT, + double *OUTPUT +{ + $target = output_helper($target, rb_float_new(*$source)); +} + +// INOUT +// Mappings for an argument that is both an input and output +// parameter + + +#ifdef AUTODOC +%subsection "Input/Output Methods" + +%text %{ +The following methods can be applied to make a function parameter both +an input and output value. This combines the behavior of both the +"INPUT" and "OUTPUT" methods described earlier. Output values are +returned in the form of a Ruby array. + + int *INOUT + short *INOUT + long *INOUT + unsigned int *INOUT + unsigned short *INOUT + unsigned long *INOUT + unsigned char *INOUT + float *INOUT + double *INOUT + +For example, suppose you were trying to wrap the following function : + + void neg(double *x) { + *x = -(*x); + } + +You could wrap it with SWIG as follows : + + %include typemaps.i + void neg(double *INOUT); + +or you can use the %apply directive : + + %include typemaps.i + %apply double *INOUT { double *x }; + void neg(double *x); + +Unlike C, this mapping does not directly modify the input value (since +this makes no sense in Ruby). Rather, the modified input value shows +up as the return value of the function. Thus, to apply this function +to a Ruby variable you might do this : + + x = neg(x) + +Note : previous versions of SWIG used the symbol 'BOTH' to mark +input/output arguments. This is still supported, but will be slowly +phased out in future releases. +%} + +#endif + +%typemap(ruby,in) int *INOUT = int *INPUT; +%typemap(ruby,in) short *INOUT = short *INPUT; +%typemap(ruby,in) long *INOUT = long *INPUT; +%typemap(ruby,in) unsigned *INOUT = unsigned *INPUT; +%typemap(ruby,in) unsigned short *INOUT = unsigned short *INPUT; +%typemap(ruby,in) unsigned long *INOUT = unsigned long *INPUT; +%typemap(ruby,in) unsigned char *INOUT = unsigned char *INPUT; +%typemap(ruby,in) float *INOUT = float *INPUT; +%typemap(ruby,in) double *INOUT = double *INPUT; + +%typemap(ruby,argout) int *INOUT = int *OUTPUT; +%typemap(ruby,argout) short *INOUT = short *OUTPUT; +%typemap(ruby,argout) long *INOUT = long *OUTPUT; +%typemap(ruby,argout) unsigned *INOUT = unsigned *OUTPUT; +%typemap(ruby,argout) unsigned short *INOUT = unsigned short *OUTPUT; +%typemap(ruby,argout) unsigned long *INOUT = unsigned long *OUTPUT; +%typemap(ruby,argout) unsigned char *INOUT = unsigned char *OUTPUT; +%typemap(ruby,argout) float *INOUT = float *OUTPUT; +%typemap(ruby,argout) double *INOUT = double *OUTPUT; + +// Backwards compatibility + +%typemap(ruby,in) int *BOTH = int *INOUT; +%typemap(ruby,in) short *BOTH = short *INOUT; +%typemap(ruby,in) long *BOTH = long *INOUT; +%typemap(ruby,in) unsigned *BOTH = unsigned *INOUT; +%typemap(ruby,in) unsigned short *BOTH = unsigned short *INOUT; +%typemap(ruby,in) unsigned long *BOTH = unsigned long *INOUT; +%typemap(ruby,in) unsigned char *BOTH = unsigned char *INOUT; +%typemap(ruby,in) float *BOTH = float *INOUT; +%typemap(ruby,in) double *BOTH = double *INOUT; + +%typemap(ruby,argout) int *BOTH = int *INOUT; +%typemap(ruby,argout) short *BOTH = short *INOUT; +%typemap(ruby,argout) long *BOTH = long *INOUT; +%typemap(ruby,argout) unsigned *BOTH = unsigned *INOUT; +%typemap(ruby,argout) unsigned short *BOTH = unsigned short *INOUT; +%typemap(ruby,argout) unsigned long *BOTH = unsigned long *INOUT; +%typemap(ruby,argout) unsigned char *BOTH = unsigned char *INOUT; +%typemap(ruby,argout) float *BOTH = float *INOUT; +%typemap(ruby,argout) double *BOTH = double *INOUT; + +// -------------------------------------------------------------------- +// OUTPUT typemaps for user defined type. +// +// -------------------------------------------------------------------- + +#ifdef AUTODOC +%subsection "Output Methods for User-defined types" + +%text %{ +The following method can be applied to turn a pointer to +user-defined type returned through function aruguments into +an output value. + + User **OUTPUT + +You can use the %apply directive : + + %include typemaps.i + %apply User **OUTPUT { Foo **OUTPUT }; + int foo_func(Foo **OUTPUT); + +%} +#endif + +%typemap(ruby,ignore) User **OUTPUT(void *temp) +{ + $target = ($type)&temp; +} +%typemap(ruby,argout) User **OUTPUT +{ + $target = output_helper($target, Wrap_$basetype(*$source)); +} + + +// -------------------------------------------------------------------- +// Special types +// +// -------------------------------------------------------------------- + +#ifdef AUTODOC +%subsection "Special Methods" + +%text %{ +The typemaps.i library also provides the following mappings : + +struct timeval * +time_t + + Ruby has builtin class Time. INPUT/OUPUT typemap for timeval and + time_t is provided. + +int PROG_ARGC +char **PROG_ARGV + + Some C function receive argc and argv from C main function. + This typemap provides ignore typemap which pass Ruby ARGV contents + as argc and argv to C function. +%} + +#endif + + +// struct timeval * +%{ +#ifdef __cplusplus +extern "C" { +#endif +#ifdef HAVE_SYS_TIME_H +# include +struct timeval rb_time_timeval(VALUE); +#endif +#ifdef __cplusplus +} +#endif +%} + +%typemap(ruby,in) struct timeval *INPUT (struct timeval temp) +{ + if (NIL_P($source)) + $target = NULL; + else { + temp = rb_time_timeval($source); + $target = &temp; + } +} + +%typemap(ruby,ignore) struct timeval *OUTPUT(struct timeval temp) +{ + $target = &temp; +} + +%typemap(ruby,argout) struct timeval *OUTPUT +{ + $target = rb_time_new($source->tv_sec, $source->tv_usec); +} + +%typemap(ruby,out) struct timeval * +{ + $target = rb_time_new($source->tv_sec, $source->tv_usec); +} + +%typemap(ruby,out) struct timespec * +{ + $target = rb_time_new($source->tv_sec, $source->tv_nsec / 1000); +} + +// time_t +%typemap(ruby,in) time_t +{ + if (NIL_P($source)) + $target = (time_t)-1; + else + $target = NUM2LONG(rb_funcall($source, rb_intern("tv_sec"), 0)); +} + +%typemap(ruby,out) time_t +{ + $target = rb_time_new($source, 0); +} + +// argc and argv +%typemap(ruby,ignore) int PROG_ARGC { + $target = RARRAY(rb_argv)->len + 1; +} + +%typemap(ruby,ignore) char **PROG_ARGV { + int i, n; + VALUE ary = rb_eval_string("[$0] + ARGV"); + n = RARRAY(ary)->len; + $target = (char **)malloc(n + 1); + for (i = 0; i < n; i++) { + VALUE v = rb_obj_as_string(RARRAY(ary)->ptr[i]); + $target[i] = (char *)malloc(RSTRING(v)->len + 1); + strcpy($target[i], RSTRING(v)->ptr); + } +} + +%typemap(ruby,freearg) char **PROG_ARGV { + int i, n = RARRAY(rb_argv)->len + 1; + for (i = 0; i < n; i++) free($source[i]); + free($source); +} + +// FILE * +%{ +#ifdef __cplusplus +extern "C" { +#endif +#include "rubyio.h" +#ifdef __cplusplus +} +#endif +%} +%typemap(ruby,in) FILE *READ { + OpenFile *of; + GetOpenFile($source, of); + rb_io_check_readable(of); + $target = GetReadFile(of); + rb_read_check($target); +} +%typemap(ruby,in) FILE *READ_NOCHECK { + OpenFile *of; + GetOpenFile($source, of); + rb_io_check_readable(of); + $target = GetReadFile(of); +} +%typemap(ruby,in) FILE *WRITE { + OpenFile *of; + GetOpenFile($source, of); + rb_io_check_writable(of); + $target = GetWriteFile(of); +} diff --git a/Makefile.in b/Makefile.in index 7cc76a40a..879c794e3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -174,6 +174,12 @@ install-lib: echo "Installing Lib/mzscheme/$$i"; \ ../../$(INSTALL_DATA) $$i $(SWIG_LIB)/mzscheme/$$i; \ done; + @$(MKINSTDIRS) $(SWIG_LIB)/ruby + @cd $(srcdir)/Lib/ruby; for i in *.i *.swg Makefile.swig extconf.rb; \ + do \ + echo "Installing Lib/ruby/$$i"; \ + ../../$(INSTALL_DATA) $$i $(SWIG_LIB)/ruby/$$i; \ + done; install-runtime: @cd Runtime; $(MAKE) install diff --git a/Runtime/Makefile.in b/Runtime/Makefile.in index 968532224..342a9926c 100644 --- a/Runtime/Makefile.in +++ b/Runtime/Makefile.in @@ -13,7 +13,7 @@ VPATH = @srcdir@ CC = @CC@ LIBTOOL = ../Tools/libtool SWIGLIB = ../Lib -LIBS = libswigpl.la libswigpy.la libswigtcl8.la +LIBS = libswigpl.la libswigpy.la libswigtcl8.la libswigrb.la LIB_DIR = $(exec_prefix)/lib all: @@ -80,3 +80,20 @@ libswigpl.la: cat $(srcdir)/$(PERL5_RUNTIME) >> libperl.c $(LIBTOOL) $(CC) -c $(PERL5_INCLUDE) -DSWIG_GLOBAL -Dbool=char -Dexplicit= libperl.c $(LIBTOOL) $(CC) -o libswigpl.la libperl.lo -rpath $(LIB_DIR) -avoid-version + +# ---------------------------------------------------------------------- +# Ruby run-time library +# ---------------------------------------------------------------------- + +RUBY_INCLUDE = @RUBYINCLUDE@ +RUBY_RUNTIME = $(SWIGLIB)/ruby/ruby.swg + +# Ruby shared + +ruby: libswigrb.la + +libswigrb.la: + cp $(srcdir)/$(RUBY_RUNTIME) librb.c + cat $(SWIGLIB)/ruby/rubydef.swg >> librb.c + $(LIBTOOL) $(CC) -c $(RUBY_INCLUDE) -DSWIG_GLOBAL librb.c + $(LIBTOOL) $(CC) -o libswigrb.la librb.lo -rpath $(LIB_DIR) -avoid-version diff --git a/Runtime/make.sh b/Runtime/make.sh index b02094591..af645ea26 100644 --- a/Runtime/make.sh +++ b/Runtime/make.sh @@ -15,7 +15,7 @@ necho() { # Script that attempts to produce different run-time libraries -TARGET='perl5 python tcl' +TARGET='perl5 python tcl ruby' echo "Building the SWIG runtime libraries." echo "" diff --git a/Source/Modules1.1/Makefile.in b/Source/Modules1.1/Makefile.in index e9d01e152..d18c3df72 100644 --- a/Source/Modules1.1/Makefile.in +++ b/Source/Modules1.1/Makefile.in @@ -13,8 +13,8 @@ AR = @AR@ RANLIB = @RANLIB@ TARGET = libmodules11.a -OBJS = swigmain.o tcl8.o perl5.o python.o pycpp.o guile.o java.o mzscheme.o -SRCS = swigmain.cxx tcl8.cxx perl5.cxx python.cxx pycpp.cxx guile.cxx java.cxx mzscheme.cxx +OBJS = swigmain.o tcl8.o perl5.o python.o pycpp.o guile.o java.o mzscheme.o ruby.o +SRCS = swigmain.cxx tcl8.cxx perl5.cxx python.cxx pycpp.cxx guile.cxx java.cxx mzscheme.cxx ruby.cxx INCLUDE = -I$(srcdir)/../Include \ -I$(srcdir)/../SWIG1.1 \ -I$(srcdir)/../SWIG1.3 \ diff --git a/Source/Modules1.1/ruby.cxx b/Source/Modules1.1/ruby.cxx new file mode 100644 index 000000000..79f6643f0 --- /dev/null +++ b/Source/Modules1.1/ruby.cxx @@ -0,0 +1,1300 @@ +/******************************************************************** + * Ruby module for SWIG + * + * $Header$ + * + * Copyright (C) 2000 Network Applied Communication Laboratory, Inc. + * Copyright (C) 2000 Information-technology Promotion Agency, Japan + * + * Masaki Fukushima + * + ********************************************************************/ + +static char cvsroot[] = "$Header$"; + +#include "mod11.h" +#include "ruby.h" + +#include +#include + +static char *usage = "\ +Ruby Options\n\ + -module name - Set module name\n\ + -toplevel - Do not define module\n\ + -feature name - Set feature name (used by `require')\n"; + +#define RCLASS(hash, name) (RClass*)(Getattr(hash, name) ? Data(Getattr(hash, name)) : 0) +#define SET_RCLASS(hash, name, klass) Setattr(hash, name, NewVoid(klass, 0)) + +static String& indent(String& s, char *sp = tab4) { + sp >> s; + String rep = sp; + s.replace("\n", ("\n" >> rep).get()); + return s; +} + +// --------------------------------------------------------------------- +// RUBY::RUBY() +// +// Constructor +// --------------------------------------------------------------------- +RUBY::RUBY(void) { + module = 0; + modvar = 0; + feature = 0; + toplevel = 0; + import_file = 0; + current = NO_CPP; + klass = 0; + classes = NewHash(); + special_methods = NewHash(); + + // Python style special method name. + // Basic + Setattr(special_methods, "__repr__", "inspect"); + Setattr(special_methods, "__str__", "to_s"); + Setattr(special_methods, "__cmp__", "<=>"); + Setattr(special_methods, "__hash__", "hash"); + Setattr(special_methods, "__nonzero__", "nonzero?"); + // Callable + Setattr(special_methods, "__call__", "call"); + // Collection + Setattr(special_methods, "__len__", "length"); + Setattr(special_methods, "__getitem__", "[]"); + Setattr(special_methods, "__setitem__", "[]="); + // Numeric + Setattr(special_methods, "__add__", "+"); + Setattr(special_methods, "__sub__", "-"); + Setattr(special_methods, "__mul__", "*"); + Setattr(special_methods, "__div__", "/"); + Setattr(special_methods, "__mod__", "%"); + Setattr(special_methods, "__divmod__", "divmod"); + Setattr(special_methods, "__pow__", "**"); + Setattr(special_methods, "__lshift__", "<<"); + Setattr(special_methods, "__rshift__", ">>"); + Setattr(special_methods, "__and__", "&"); + Setattr(special_methods, "__xor__", "^"); + Setattr(special_methods, "__or__", "|"); + Setattr(special_methods, "__neg__", "-@"); + Setattr(special_methods, "__pos__", "+@"); + Setattr(special_methods, "__abs__", "abs"); + Setattr(special_methods, "__invert__", "~"); + Setattr(special_methods, "__int__", "to_i"); + Setattr(special_methods, "__float__", "to_f"); + Setattr(special_methods, "__coerce__", "coerce"); +} + +// --------------------------------------------------------------------- +// RUBY::parse_args(int argc, char *argv[]) +// +// Parse command line options and initializes variables. +// --------------------------------------------------------------------- +void RUBY::parse_args(int argc, char *argv[]) { + // Look for certain command line options + for (int i = 1; i < argc; i++) { + if (argv[i]) { + if (strcmp(argv[i],"-module") == 0) { + if (argv[i+1]) { + set_module(argv[i+1],0); + Swig_mark_arg(i); + Swig_mark_arg(i+1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i],"-feature") == 0) { + if (argv[i+1]) { + char *name = argv[i+1]; + feature = new char [strlen(name)+1]; + strcpy(feature, name); + Swig_mark_arg(i); + Swig_mark_arg(i+1); + i++; + } else { + Swig_arg_error(); + } + } else if (strcmp(argv[i],"-toplevel") == 0) { + toplevel = 1; + Swig_mark_arg(i); + } else if (strcmp(argv[i],"-help") == 0) { + fprintf(stderr,"%s\n", usage); + } + } + } + // Check consistency + if (module && toplevel) + Swig_arg_error(); + + // Set location of SWIG library + strcpy(LibDir,"ruby"); + + // Add a symbol to the parser for conditional compilation + Preprocessor_define((void *) "SWIGRUBY", 0); + + // Add typemap definitions + typemap_lang = "ruby"; +} + +// --------------------------------------------------------------------- +// RUBY::parse() +// +// Start parsing an interface file. +// --------------------------------------------------------------------- +void RUBY::parse() { + printf("Generating wrappers for Ruby\n"); + headers(); + + // typedef void *VALUE + DataType value; + strcpy(value.name, "void"); + value.type = T_VOID; + value.is_pointer = 1; + value.implicit_ptr = 0; + value.typedef_add("VALUE"); + + yyparse(); // Run the SWIG parser +} + +// --------------------------------------------------------------------- +// RUBY::set_module(char *mod_name,char **mod_list) +// +// Sets the module name. Does nothing if it's already set (so it can +// be overridden as a command line option). +// +// mod_list is a NULL-terminated list of additional modules. This +// is really only useful when building static executables. +//---------------------------------------------------------------------- + +void RUBY::set_module(char *mod_name, char **mod_list) { + if (import_file) { + fprintf(f_init, "%srb_f_require(Qnil, rb_str_new2(\"%s\"));\n", tab4, mod_name); + delete [] import_file; + import_file = 0; + } + + if (module) return; + + if (!feature) { + feature = new char[strlen(mod_name)+1]; + strcpy(feature, mod_name); + } + + module = new char[strlen(mod_name)+1]; + strcpy(module, mod_name); + // module name must be a constant. + module[0] = toupper(module[0]); + + modvar = new char[1+strlen(module)+1]; + modvar[0] = 'm'; + strcpy(modvar+1, module); + + if (mod_list) { + other_extern << "#ifdef __cplusplus\n" + << "extern \"C\" {\n" + << "#endif\n"; + for (int i = 0; mod_list[i] != NULL; i++) { + other_extern << "extern void Init_" << mod_list[i] << "(void);\n"; + other_init << tab4 << "Init_" << mod_list[i] << "();\n"; + } + other_extern << "#ifdef __cplusplus\n" + << "}\n" + << "#endif\n"; + } +} + + +static void insert_file(char *filename, FILE *file) { + if (Swig_insert_file(filename, file) == -1) { + fprintf(stderr, + "SWIG : Fatal error. " + "Unable to locate %s. (Possible installation problem).\n", + filename); + SWIG_exit(1); + } +} +// ---------------------------------------------------------------------- +// RUBY::headers(void) +// +// Generate the appropriate header files for RUBY interface. +// ---------------------------------------------------------------------- +void RUBY::headers(void) { + Swig_banner(f_header); + fprintf(f_header,"/* Implementation : RUBY */\n\n"); + fprintf(f_header,"#define SWIGRUBY\n"); + + insert_file("ruby.swg", f_header); + if (NoInclude) { + insert_file("rubydec.swg", f_header); + } else { + insert_file("rubydef.swg", f_header); + } +} + +// --------------------------------------------------------------------- +// RUBY::initialize(void) +// +// Produces an initialization function. Assumes that the module +// name has already been specified. +// --------------------------------------------------------------------- +void RUBY::initialize() { + if (!module) { + fprintf(stderr,"SWIG : *** Warning. No module name specified.\n"); + set_module("swig", NULL); // Pick a default name + } + + fprintf(f_header,"#define SWIG_init Init_%s\n", feature); + fprintf(f_header,"#define SWIG_name \"%s\"\n\n", module); + if (!toplevel) fprintf(f_header,"static VALUE %s;\n", modvar); + fprintf(f_header,"\n%s\n", (char *)other_extern.get()); + + // Start generating the initialization function + String s; + s << "\n" + << "#ifdef __cplusplus\n" + << "extern \"C\"\n" + <<"#endif\n" + << "void Init_" << feature << "(void) {\n" + << other_init; + if (!toplevel) { + s << tab4 << modvar << " = rb_define_module(\"" << module << "\");\n"; + } + s << "\n"; + fprintf(f_init, s.get()); + klass = new RClass(); +} + +// --------------------------------------------------------------------- +// RUBY::close(void) +// +// Finish the initialization function. Close any additional files and +// resources in use. +// --------------------------------------------------------------------- +void RUBY::close(void) { + // Finish off our init function + fprintf(f_init, "\n"); + emit_ptr_equivalence(f_init); + fprintf(f_init,"}\n"); +} + +// --------------------------------------------------------------------- +// RUBY::make_wrapper_name(char *cname) +// +// Creates a name for a wrapper function +// cname = Name of the C function +// --------------------------------------------------------------------- +char *RUBY::make_wrapper_name(char *cname) { + return Swig_name_wrapper(cname); +} + +// --------------------------------------------------------------------- +// RUBY::create_command(char *cname, char *iname) +// +// Creates a new command from a C function. +// cname = Name of the C function +// iname = Name of function in scripting language +// argc = Number of arguments +// --------------------------------------------------------------------- +void RUBY::create_command(char *cname, char *iname, int argc) { + String wname = make_wrapper_name(cname); + if (CPlusPlus) { + "VALUEFUNC(" >> wname << ")"; + } + if (current != NO_CPP) + iname = klass->strip(iname); + if (Getattr(special_methods, iname)) { + iname = GetChar(special_methods, iname); + } + + String s, temp; + switch (current) { + case MEMBER_FUNC: + klass->init << tab4 << "rb_define_method(" << klass->vname << ", \"" + << iname << "\", " << wname << ", " << argc << ");\n"; + break; + case CONSTRUCTOR: + s << tab4 << "rb_define_singleton_method(" << klass->vname + << ", \"new\", " << wname << ", " << argc << ");\n"; + klass->init.replace("$constructor", s.get()); + break; + case MEMBER_VAR: + temp = iname; + temp.replace("_set", "="); + temp.replace("_get", ""); + klass->init << tab4 << "rb_define_method(" << klass->vname << ", \"" + << temp << "\", " << wname << ", " << argc << ");\n"; + break; + case STATIC_FUNC: + klass->init << tab4 << "rb_define_singleton_method(" << klass->vname + << ", \"" << iname << "\", " << wname << ", " << argc + << ");\n"; + break; + default: + if (toplevel) { + s << tab4 << "rb_define_global_function(\"" + << iname << "\", " << wname << ", " << argc << ");\n"; + } else { + s << tab4 << "rb_define_module_function(" << modvar << ", \"" + << iname << "\", " << wname << ", " << argc << ");\n"; + } + fprintf(f_init, s.get()); + break; + } +} + +// --------------------------------------------------------------------- +// RUBY::create_function(char *name, char *iname, DataType *d, ParmList *l) +// +// Create a function declaration and register it with the interpreter. +// name = Name of real C function +// iname = Name of function in scripting language +// t = Return datatype +// l = Function parameters +// --------------------------------------------------------------------- +void RUBY::create_function(char *name, char *iname, DataType *t, ParmList *l) { + String source, target; + char *tm; + String cleanup, outarg; + WrapperFunction f; + + // Ruby needs no destructor wrapper + if (current == DESTRUCTOR) + return; + + char *wname = make_wrapper_name(name); + String mname, inamebuf; + int predicate = 0; + switch (current) { + case MEMBER_FUNC: + case MEMBER_VAR: + case STATIC_FUNC: + mname = klass->strip(iname); + if (Getattr(klass->predmethods, mname.get())) { + predicate = 1; + inamebuf = iname; + inamebuf << "?"; + iname = inamebuf.get(); + } + break; + } + + // Get number of arguments + int numarg = l->numarg(); + int numopt = l->numopt(); + int numignore = l->nparms - numarg; + int start = 0; + int use_self = 0; + switch (current) { + case MEMBER_FUNC: + case MEMBER_VAR: + numarg--; + start++; + use_self = 1; + break; + } + + int numreq = 0; + int numoptreal = 0; + for (int i = start; i < l->nparms; i++) { + if (!l->get(i)->ignore) { + if (i >= l->nparms - numopt) numoptreal++; + else numreq++; + } + } + int vararg = (numoptreal != 0); + + // Now write the wrapper function itself + f.def << "static VALUE\n" << wname << "("; + if (vararg) { + f.def << "int argc, VALUE *argv, VALUE self"; + } else { + f.def << "VALUE self"; + for (int i = start; i < l->nparms; i++) { + if (!l->get(i)->ignore) { + f.def << ", VALUE varg" << i; + } + } + } + f.def << ") {"; + + // Emit all of the local variables for holding arguments. + if (vararg) { + for (int i = start; i < l->nparms; i++) { + if (!l->get(i)->ignore) { + String s; + s << "varg" << i; + f.add_local("VALUE", s.get()); + } + } + } + f.add_local("VALUE", "vresult", "Qnil"); + int pcount = emit_args(t,l,f); + +#if 0 + String temp; + temp << "/* " << name << " */" << br; + temp << "/* nparms = " << l->nparms << " */" << br; + temp << "/* numarg = " << numarg << " */" << br; + temp << "/* numopt = " << numopt << " */" << br; + temp << "/* numignore = " << numignore << " */" << br; + temp << "/* numoptreal = " << numoptreal << " */" << br; + temp << "/* pcount = " << pcount << " */" << br; + temp << "/* rb_scan_args(argc, argv, \"" + << (numarg-numoptreal) << numoptreal << "\") */" << br; + temp << br; + if (numignore != 0) fprintf(stderr, temp); + f.code << temp; +#endif + // Emit count to check the number of arguments + if (vararg) { + f.code << tab4 << "rb_scan_args(argc, argv, \"" + << (numarg-numoptreal) << numoptreal << "\""; + for (int i = start; i < l->nparms; i++) { + if (!l->get(i)->ignore) { + f.code << ", &varg" << i; + } + } + f.code << ");\n"; + } + + // Now walk the function parameter list and generate code + // to get arguments + int j = 0; // Total number of non-optional arguments + + for (int i = 0; i < pcount ; i++) { + Parm &p = (*l)[i]; // Get the ith argument + source = ""; + target = ""; + + // Produce string representation of source and target arguments + int selfp = (use_self && i == 0); + if (selfp) + source << "self"; + else + source << "varg" << i; + target << "_arg" << i; + + if (!p.ignore) { + char *tab = tab4; + if (j >= (pcount-numopt)) { // Check if parsing an optional argument + f.code << tab4 << "if (argc > " << j - start << ") {\n"; + tab = tab8; + } + + // Get typemap for this argument + tm = ruby_typemap_lookup("in",p.t,p.name,source.get(),target.get(),&f); + if (tm) { + String s = tm; + f.code << indent(s, tab) << "\n"; + f.code.replace("$arg",source.get()); // Perform a variable replacement + } else { + fprintf(stderr,"%s : Line %d. No typemapping for datatype %s\n", + input_file,line_number, p.t->print_type()); + } + if (j >= (pcount-numopt)) + f.code << tab4 << "} \n"; + j++; + } + + // Check to see if there was any sort of a constaint typemap + tm = ruby_typemap_lookup("check",p.t,p.name,source.get(),target.get()); + if (tm) { + String s = tm; + f.code << indent(s) << "\n"; + f.code.replace("$arg",source.get()); + } + + // Check if there was any cleanup code (save it for later) + tm = ruby_typemap_lookup("freearg",p.t,p.name,target.get(),source.get()); + if (tm) { + String s = tm; + cleanup << indent(s) << "\n"; + cleanup.replace("$arg",source.get()); + } + + tm = ruby_typemap_lookup("argout",p.t,p.name,target.get(),"vresult"); + if (tm) { + String s = tm; + outarg << indent(s) << "\n"; + outarg.replace("$arg",source.get()); + } + } + + // Now write code to make the function call + emit_func_call(name,t,l,f); + + // Return value if necessary + if ((t->type != T_VOID) || (t->is_pointer)) { + if (predicate) { + f.code << tab4 << "vresult = (_result ? Qtrue : Qfalse);\n"; + } else { + tm = ruby_typemap_lookup("out",t,name,"_result","vresult"); + if (tm) { + String s = tm; + f.code << indent(s) << "\n"; + } else { + fprintf(stderr,"%s : Line %d. No return typemap for datatype %s\n", + input_file,line_number,t->print_type()); + } + } + } + + // Dump argument output code; + f.code << outarg; + + // Dump the argument cleanup code + f.code << cleanup; + + // Look for any remaining cleanup. This processes the %new directive + if (NewObject) { + tm = ruby_typemap_lookup("newfree",t,name,"_result",""); + if (tm) { + String s = tm; + f.code << indent(s) << "\n"; + } + } + + // free pragma + if (current == MEMBER_FUNC && Getattr(klass->freemethods, mname.get())) { + f.code << tab4 << "DATA_PTR(self) = 0;\n"; + } + + // Special processing on return value. + tm = ruby_typemap_lookup("ret",t,name,"_result",""); + if (tm) { + String s = tm; + f.code << indent(s) << "\n"; + } + + // Wrap things up (in a manner of speaking) + f.code << tab4 << "return vresult;\n}\n"; + + // Substitute the cleanup code + f.code.replace("$cleanup",cleanup.get()); + + // Emit the function + f.print(f_wrappers); + + // Now register the function with the language + create_command(name, iname, (vararg ? -1 : numarg)); +} + + +// --------------------------------------------------------------------- +// RUBY::link_variable(char *name, char *iname, DataType *t) +// +// Create a link to a C variable. +// name = Name of C variable +// iname = Name of variable in scripting language +// t = Datatype of the variable +// --------------------------------------------------------------------- +void RUBY::link_variable(char *name, char *iname, DataType *t) { + char *tm; + String getfname, setfname; + WrapperFunction getf, setf; + int mod_attr = 0; + + // module attribute? + if (current == STATIC_VAR || !toplevel) + mod_attr = 1; + + // create getter + getfname = Swig_name_get(name); + getfname.replace("::", "_"); /* FIXME: Swig_name_get bug? */ + getf.def << "static VALUE\n" << getfname << "("; + if (mod_attr) getf.def << "VALUE self"; + getf.def << ") {"; + getf.add_local("VALUE", "_val"); + tm = ruby_typemap_lookup("varout",t,name,name,"_val"); + if (!tm) + tm = ruby_typemap_lookup("out",t,name,name,"_val"); + if (tm) { + String s = tm; + getf.code << indent(s) << "\n"; + } else if (!t->is_pointer && t->type == T_USER) { + // Hack this into a pointer + t->is_pointer++; + t->remember(); + getf.code << tab4 << "_val = SWIG_NewPointerObj((void *)&" << name + << ", \"" << t->print_mangle() << "\");\n"; + t->is_pointer--; + } else { + fprintf(stderr,"%s: Line %d. Unable to link with variable type %s\n", + input_file,line_number,t->print_type()); + } + getf.code << tab4 << "return _val;\n}\n"; + getf.print(f_wrappers); + + if (Status & STAT_READONLY) { + setfname = "NULL"; + } else { + // create setter + setfname = Swig_name_set(name); + setfname.replace("::", "_"); /* FIXME: Swig_name_get bug? */ + if (mod_attr) + setf.def << "static VALUE\n" << setfname << "(VALUE self, "; + else + setf.def << "static void\n" << setfname << "("; + setf.def << "VALUE _val) {"; + tm = ruby_typemap_lookup("varin",t,name,"_val",name); + if (!tm) + tm = ruby_typemap_lookup("in",t,name,"_val",name); + if (tm) { + String s = tm; + setf.code << indent(s) << "\n"; + } else if (!t->is_pointer && t->type == T_USER) { + t->is_pointer++; + setf.add_local(t->print_type(), "temp"); + setf.code << tab4 << "temp = (" << t->print_type() << ")" + << "SWIG_ConvertPtr(_val, \"" << t->print_mangle() << "\");\n"; + setf.code << tab4 << name << " = *temp;\n"; + t->is_pointer--; + } else { + fprintf(stderr,"%s: Line %d. Unable to link with variable type %s\n", + input_file,line_number,t->print_type()); + } + if (mod_attr) + setf.code << tab4 << "return _val;\n"; + setf.code << "}\n"; + setf.print(f_wrappers); + } + + // define accessor method + if (CPlusPlus) { + "VALUEFUNC(" >> getfname << ")"; + "VALUEFUNC(" >> setfname << ")"; + } + + String s; + switch (current) { + case STATIC_VAR: + // C++ class variable + s << tab4 << "rb_define_singleton_method(" << klass->vname << ", \"" + << klass->strip(iname) << "\", " << getfname << ", 0);\n"; + if (!(Status & STAT_READONLY)) { + s << tab4 << "rb_define_singleton_method(" << klass->vname << ", \"" + << klass->strip(iname) << "=\", " << setfname << ", 1);\n"; + } + klass->init << s; + break; + default: + // C global variable + if (toplevel) { + // wrapped in Ruby global variable + s << tab4 << "rb_define_virtual_variable(\"" << iname << "\", " + << getfname << ", " << setfname << ");\n"; + } else { + // wrapped in Ruby module attribute + s << tab4 << "rb_define_singleton_method(" << modvar << ", \"" + << iname << "\", " << getfname << ", 0);\n"; + if (!(Status & STAT_READONLY)) { + s << tab4 << "rb_define_singleton_method(" << modvar << ", \"" + << iname << "=\", " << setfname << ", 1);\n"; + } + } + fputs(s.get(), f_init); + break; + } +} + + +// --------------------------------------------------------------------- +// RUBY::validate_const_name(char *name) +// +// Validate constant name. +// --------------------------------------------------------------------- +char *RUBY::validate_const_name(char *name) { + if (!name || name[0] == '\0') + return name; + + if (isupper(name[0])) + return name; + + if (islower(name[0])) { + name[0] = toupper(name[0]); + fprintf(stderr,"%s : Line %d. Wrong constant/class/module name " + "(corrected to `%s')\n", input_file, line_number, name); + return name; + } + + fprintf(stderr,"%s : Line %d. Wrong constant/class/module name\n", + input_file, line_number); + return name; +} + +// --------------------------------------------------------------------- +// RUBY::declare_const(char *name, char *iname, DataType *type, char *value) +// +// Makes a constant. +// name = Name of the constant +// iname = Scripting language name of constant +// type = Datatype of the constant +// value = Constant value (as a string) +// --------------------------------------------------------------------- +void RUBY::declare_const(char *name, char *iname, DataType *type, char *value) { + char *tm; + + if (current == CLASS_CONST) + iname = klass->strip(iname); + + tm = ruby_typemap_lookup("const",type,name,value,iname); + if (tm) { + String str = tm; + str.replace("$value",value); + if (current == CLASS_CONST) { + str.replace("$module", klass->vname.get()); + indent(str); + klass->init << str << "\n"; + } else { + if (toplevel) + str.replace("$module", "rb_cObject"); + else + str.replace("$module", modvar); + indent(str); + fprintf(f_init,"%s\n", str.get()); + } + } else { + fprintf(stderr,"%s : Line %d. Unable to create constant %s = %s\n", + input_file, line_number, type->print_type(), value); + } +} + +// --------------------------------------------------------------------- +// RUBY::ruby_typemap_lookup(char *op, DataType *type, char *pname, char *source, char *target, WrapperFunction *f = 0) +// +// Ruby specific typemap_lookup. +// op = string code for type of mapping +// type = the datatype +// pname = an optional parameter name +// source = a string with the source variable +// target = a string containing the target value +// f = a wrapper function object (optional) +// --------------------------------------------------------------------- +char *RUBY::ruby_typemap_lookup(char *op, DataType *type, char *pname, char *source, char *target, WrapperFunction *f = 0) { + static String s; + char *tm; + String target_replace = target; + target = target_replace.get(); + + RClass *cls = RCLASS(classes, type->name); + s = ""; + + if ((strcmp("out", op) == 0 || strcmp("in", op) == 0) + && strcmp(type->name, "VALUE") == 0) { + s << "$target = $source;"; + } else if (strcmp("out", op) == 0 && type->type == T_USER && + type->is_pointer == 1 && cls) { + const char *vname = (current == CONSTRUCTOR ? "self" : cls->vname.get()); + s << "$target = Wrap_" << cls->cname << "(" << vname << ", $source);"; + } else if (strcmp("in", op)==0 && type->type == T_USER && + type->is_pointer == 1 && cls) { + s << "Get_" << cls->cname << "($source, $target);"; + } else { + tm = typemap_lookup(op, typemap_lang, type, pname, source, target, f); + if (tm) { + return tm; + } + + s = ""; + if (strcmp("in", op) == 0) { + String v; + if (from_VALUE(type, "$source", v)) + s << "$target = " << v << ";"; + } else if (strcmp("out", op) == 0) { + String v; + if (to_VALUE(type, "$source", v)) + s << "$target = " << v << ";"; + } else if (strcmp("const", op) == 0) { + String v; + if (to_VALUE(type, "$value", v, 1)) { + s << "rb_define_const($module, \"$target\", " << v << ");"; + validate_const_name(target); + } + } + } + + if (strlen(s.get()) == 0) { + return NULL; + } + + if (source && strlen(source) > 0) + s.replace("$source", source); + if (target && strlen(target) > 0) + s.replace("$target", target); + s.replace("$type", type->print_type()); + return s.get(); +} + +// --------------------------------------------------------------------- +// RUBY::to_VALUE(DataType *type, char *value, literal) +// +// Makes a VALUE (as a string) +// type = Datatype of the C value +// value = C value (as a string) +// str = resulting code (as a string) +// raw = value is raw string (not quoted) ? +// --------------------------------------------------------------------- +int RUBY::to_VALUE(DataType *type, char *value, String& str, int raw = 0) { + str = ""; + if (type->is_pointer == 0) { + switch(type->type) { + case T_INT:case T_SINT: + case T_SHORT: case T_SSHORT: + case T_LONG: case T_SLONG: + case T_SCHAR: + str << "INT2NUM(" << value << ")"; + break; + case T_UINT: + case T_USHORT: + case T_ULONG: + case T_UCHAR: + str << "UINT2NUM(" << value << ")"; + break; + case T_DOUBLE: + case T_FLOAT: + str << "rb_float_new(" << value << ")"; + break; + case T_CHAR: + str << "rb_str_new(&" << value << ", 1)"; + break; + case T_BOOL: + str << "(" << value << " ? Qtrue : Qfalse)"; + break; + default: + break; + } + } else if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + if (raw) + str << "rb_str_new2(\"" << value << "\")"; + else + str << "rb_str_new2(" << value << ")"; + } else { + str << "SWIG_NewPointerObj((void *)" << value << ", \"" << type->print_mangle() << "\")"; + } + + if (strlen(str.get()) == 0) + return 0; + return 1; +} + +// --------------------------------------------------------------------- +// RUBY::from_VALUE(DataType *type, char *value) +// +// extract VALUE +// type = Datatype of the C value +// value = Ruby VALUE (as a string) +// str = resulting code (as a string) +// --------------------------------------------------------------------- +int RUBY::from_VALUE(DataType *type, char *value, String& str) { + str = ""; + if (type->is_pointer == 0) { + switch(type->type) { + case T_INT:case T_SINT: + str << "NUM2INT(" << value << ")"; + break; + case T_LONG: case T_SLONG: + str << "NUM2LONG(" << value << ")"; + break; + case T_SHORT: case T_SSHORT: + str << "NUM2SHRT(" << value << ")"; + break; + case T_UINT: + str << "NUM2UINT(" << value << ")"; + break; + case T_ULONG: + str << "NUM2ULONG(" << value << ")"; + break; + case T_USHORT: + str << "NUM2USHRT(" << value << ")"; + break; + case T_DOUBLE: + case T_FLOAT: + str << "NUM2DBL(" << value << ")"; + break; + case T_CHAR: case T_SCHAR: case T_UCHAR: + str << "NUM2CHR(" << value << ")"; + break; + case T_BOOL: + str << "RTEST(" << value << ")"; + break; + default: + break; + } + } else if ((type->type == T_CHAR) && (type->is_pointer == 1)) { + str << "STR2CSTR(" << value << ")"; + } else { + str << "SWIG_ConvertPtr(" << value << ", \"" << type->print_mangle() << "\")"; + } + + if (strlen(str.get()) == 0) + return 0; + return 1; +} + +// ---------------------------------------------------------------------- +// void RUBY::cpp_open_class(char *classname, char *classrename, char *ctype, int strip) +// +// Open a new C++ class. +// +// INPUTS: +// name = Real name of the C++ class +// rename = New name of the class (if %name was used) +// ctype = Class type (struct, class, union, etc...) +// strip = Flag indicating whether we should strip the +// class type off +// +// This function is in charge of creating a new class. The SWIG parser has +// already processed the entire class definition prior to calling this +// function (which should simplify things considerably). +// +// ---------------------------------------------------------------------- +void RUBY::cpp_open_class(char *cname, char *rename, char *ctype, int strip) { + this->Language::cpp_open_class(cname, rename, ctype, strip); + + klass = RCLASS(classes, cname); + + if (strip) { + klass->type = ""; + klass->type << klass->cname; + } else { + klass->type = ""; + klass->type << ctype << " " << klass->cname; + } + + klass->header << "\nVALUE " << klass->vname << ";\n"; + klass->init << "\n" << tab4; + if (toplevel) { + klass->init << klass->vname << " = rb_define_class(" + << "\"" << klass->name << "\", $super);\n"; + } else { + klass->init << klass->vname << " = rb_define_class_under(" << modvar + << ", \"" << klass->name << "\", $super);\n"; + } + klass->includes.replace("$class", klass->vname.get()); + klass->init << klass->includes; + klass->init << "$constructor"; + + klass->header + << "$markproto" + << "$freeproto" + << "#define Wrap_" << klass->cname << "(klass, ptr) (\\\n" + << tab4 << "(ptr) ? Data_Wrap_Struct(klass" + << ", $markfunc, $freefunc, ptr) : Qnil )\n" + << "#define Get_" << klass->cname << "(val, ptr) {\\\n" + << tab4 << "if (NIL_P(val)) ptr = NULL;\\\n" + << tab4 << "else {\\\n" + << tab8 << "if (!rb_obj_is_kind_of(val, " << klass->vname << "))\\\n" + << tab8 << tab4 << "rb_raise(rb_eTypeError, \"wrong argument type" + << " (expected " << klass->name << ")\");\\\n" + << tab8 << "Data_Get_Struct(val, " << klass->type << ", ptr);\\\n" + << tab8 << "if (!ptr) rb_raise(rb_eRuntimeError, \"" + << "This " << klass->name << " already released\");\\\n" + << tab4 << "}\\\n" + << "}\n"; +} + +// --------------------------------------------------------------------- +// void RUBY::cpp_close_class() +// +// Close the current class +// --------------------------------------------------------------------- +void RUBY::cpp_close_class() { + this->Language::cpp_close_class(); + + klass->header.replace("$markfunc", "0"); + klass->header.replace("$markproto", ""); + if (!klass->destructor_defined) { + klass->header.replace("$freefunc", "0"); + klass->header.replace("$freeproto", ""); + } + fprintf(f_header, klass->header.get()); + + klass->aliases.replace("$class", klass->vname.get()); + klass->init << klass->aliases; + + String s; + s << tab4 << "rb_undef_method(CLASS_OF(" << klass->vname + << "), \"new\");\n"; + klass->init.replace("$constructor", s.get()); + klass->init.replace("$super", "rb_cObject"); + + fprintf(f_init, klass->init.get()); + + klass = 0; +} + +// ---------------------------------------------------------------------- +// void RUBY::cpp_inherit(char **baseclass, int mode) +// +// Inherit attributes from given baseclass. +// +// INPUT: +// baseclass = NULL terminate list of baseclasses +// +// --------------------------------------------------------------------- + +void RUBY::cpp_inherit(char **baseclass, int mode) { + if (!baseclass) + return; + + for (int i = 0; baseclass[i]; i++) { + RClass *super = RCLASS(classes, baseclass[i]); + if (super) { + klass->init.replace("$super", super->vname.get()); + break; // ignore multiple inheritance + } + } +} + +// ---------------------------------------------------------------------- +// void RUBY::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) +// +// Method for adding C++ member function +// +// INPUTS: +// name - name of the member function +// iname - renaming (if given) +// t - Return datatype +// l - Parameter list +// +// By default, we're going to create a function of the form : +// +// Foo_bar(this,args) +// +// Where Foo is the classname, bar is the member name and the this pointer +// is explicitly attached to the beginning. +// +// The renaming only applies to the member function part, not the full +// classname. +// +// --------------------------------------------------------------------- +void RUBY::cpp_member_func(char *name, char *iname, DataType *t, ParmList *l) { + current = MEMBER_FUNC; + this->Language::cpp_member_func(name, iname, t, l); + current = NO_CPP; +} + +// --------------------------------------------------------------------- +// void RUBY::cpp_constructor(char *name, char *iname, ParmList *l) +// +// Method for adding C++ member constructor +// +// INPUTS: +// name - Name of the constructor (usually same as classname) +// iname - Renamed version +// l - parameters +// -------------------------------------------------------------------- +void RUBY::cpp_constructor(char *name, char *iname, ParmList *l) { + current = CONSTRUCTOR; + this->Language::cpp_constructor(name, iname, l); + current = NO_CPP; +} + +// --------------------------------------------------------------------- +// void RUBY::cpp_destructor(char *name, char *iname) +// +// Method for adding C++ member destructor +// +// INPUT: +// name - Name of the destructor (classname) +// iname - Renamed destructor +// +// -------------------------------------------------------------------- +void RUBY::cpp_destructor(char *name, char *newname) { + current = DESTRUCTOR; + this->Language::cpp_destructor(name, newname); + + String freefunc, freeproto, freebody; + freefunc << "free_" << klass->cname; + freeproto << "static void " << freefunc << "(" << klass->type << " *);\n"; + freebody << "static void\n" + << freefunc << "(" << klass->type << " *ptr) {\n" + << tab4 << Swig_name_destroy(name) << "(ptr);\n" + << "}\n"; + if (CPlusPlus) { + "VOIDFUNC(" >> freefunc << ")"; + } + + klass->header.replace("$freefunc", freefunc.get()); + klass->header.replace("$freeproto", freeproto.get()); + fprintf(f_wrappers, freebody.get()); + + klass->destructor_defined = 1; + current = NO_CPP; +} + +// --------------------------------------------------------------------- +// void RUBY::cpp_variable(char *name, char *iname, DataType *t) +// +// Wrap a C++ data member +// +// INPUTS : +// name = Name of the C++ member +// iname = Name as used in the interpreter +// t = Datatype +// +// This creates a pair of functions to set/get the variable of a member. +// -------------------------------------------------------------------- +void RUBY::cpp_variable(char *name, char *iname, DataType *t) { + current = MEMBER_VAR; + this->Language::cpp_variable(name, iname, t); + current = NO_CPP; +} + +// ----------------------------------------------------------------------- +// void RUBY::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) +// +// Wrap a static C++ function +// +// INPUTS: +// name = Real name of the function +// iname = New name in interpreter +// t = Return datatype +// l = Parameters +// ---------------------------------------------------------------------- +void RUBY::cpp_static_func(char *name, char *iname, DataType *t, ParmList *l) { + current = STATIC_FUNC; + this->Language::cpp_static_func(name, iname, t, l); + current = NO_CPP; +} + +// ---------------------------------------------------------------------- +// void RUBY::cpp_declare_const(char *name, char *iname, DataType *t, char *value) +// +// Create a C++ constant +// +// INPUTS : +// name = Real name of the constant +// iname = new name +// t = Datatype +// value = value as a string +// +// --------------------------------------------------------------------- + +void RUBY::cpp_declare_const(char *name, char *iname, DataType *type, char *value) { + current = CLASS_CONST; + this->Language::cpp_declare_const(name, iname, type, value); + current = NO_CPP; +} + +// --------------------------------------------------------------------- +// void RUBY::cpp_static_var(char *name, char *iname, DataType *t) +// +// Wrap a static C++ variable +// +// INPUT : +// name = name of the variable +// iname = interpreter name +// t = Datatype +// +// --------------------------------------------------------------------- +void RUBY::cpp_static_var(char *name, char *iname, DataType *t) { + current = STATIC_VAR; + this->Language::cpp_static_var(name, iname, t); + current = NO_CPP; +} + +// ----------------------------------------------------------------------- +// RUBY::cpp_class_decl(char *name, char *rename, char *type) +// +// A forward class declaration +// ----------------------------------------------------------------------- +void RUBY::cpp_class_decl(char *cname, char *rename, char *type) { + String valid_name = (rename ? rename : cname); + validate_const_name(valid_name.get()); + klass->set_name(cname, rename, valid_name.get()); + SET_RCLASS(classes, cname, klass); + if (type && strlen(type) > 0) { + String temp; + temp << type << " " << cname; + SET_RCLASS(classes, temp.get(), klass); + } + String s; + s << "extern VALUE " << klass->vname << ";\n"; + fprintf(f_header, s.get()); + + klass = new RClass(); +} + +// -------------------------------------------------------------------- +// void RUBY::pragma(char *target, char *var, char *value) +// +// A pragma declaration +// -------------------------------------------------------------------- +void RUBY::pragma(char *lang, char *cmd, char *value) { + if (strcmp(lang, "ruby") != 0) + return; + + if (strcmp(cmd, "free") == 0) { + char name[64]; + if (sscanf(value, " %s ", name) != 1) { + fprintf(stderr, "%s : Line %d. Invalid free pragma.\n", + input_file, line_number); + return; + } + Setattr(klass->freemethods, name, name); + } else if (strcmp(cmd, "include") == 0) { + char name[64]; + if (sscanf(value, " %s ", name) != 1) { + fprintf(stderr, "%s : Line %d. Invalid include pragma.\n", + input_file, line_number); + return; + } + klass->includes << tab4 << "rb_include_module($class, " + << "rb_eval_string(\"" << name << "\"));\n"; + } else if (strcmp(cmd, "alias") == 0) { + char alias[64], name[64]; + if (sscanf(value, " %s %s ", alias, name) != 2) { + fprintf(stderr, "%s : Line %d. Invalid alias pragma.\n", + input_file, line_number); + return; + } + klass->aliases << tab4 << "rb_define_alias($class, " + << "\"" << alias << "\", \"" << name << "\");\n"; + } else if (strcmp(cmd, "pred") == 0) { + char *tok; + tok = strtok(value, " \t"); + while (tok) { + Setattr(klass->predmethods, tok, tok); + tok = strtok(0, " \t"); + } + } else if (strcmp(cmd, "debug") == 0) { + fprintf(f_header, "/* %s */\n", value); + fprintf(f_wrappers, "/* %s */\n", value); + fprintf(f_init, "/* %s */\n", value); + fprintf(stderr, "%s\n", value); + } else { + fprintf(stderr, "%s : Line %d. Unrecognized pragma.\n", + input_file, line_number); + } +} + +// ----------------------------------------------------------------------------- +// RUBY::cpp_pragma(Pragma *plist) +// +// Handle C++ pragmas +// ----------------------------------------------------------------------------- + +void RUBY::cpp_pragma(Pragma *plist) { + while (plist) { + pragma(plist->lang.get(), plist->name.get(), plist->value.get()); + plist = plist->next; + } +} + +// --------------------------------------------------------------------- +// RUBY::import(char *filename) +// +// Imports a SWIG module as a separate file. +//---------------------------------------------------------------------- + +void RUBY::import(char *filename) { + if (import_file) delete [] import_file; + import_file = copy_string(filename); +} + +/* + * Local Variables: + * c-basic-offset: 2 + * End: + */ diff --git a/Source/Modules1.1/ruby.h b/Source/Modules1.1/ruby.h new file mode 100644 index 000000000..2c2700182 --- /dev/null +++ b/Source/Modules1.1/ruby.h @@ -0,0 +1,125 @@ +/******************************************************************** + * Ruby module for SWIG + * + * $Header$ + * + * Copyright (C) 2000 Network Applied Communication Laboratory, Inc. + * Copyright (C) 2000 Information-technology Promotion Agency, Japan + * + * Masaki Fukushima + * + ********************************************************************/ + +class RClass { + private: + String temp; + public: + String name; // class name (renamed) + String cname; // original C class/struct name + String vname; // variable name + String type; + String prefix; + String header; + String init; + + String aliases; + String includes; + DOH *freemethods; + DOH *predmethods; + int destructor_defined; + + RClass(void) { + freemethods = NewHash(); + predmethods = NewHash(); + destructor_defined = 0; + } + void set_name(char *cn, char *rn, char *valn) { + cname = cn; + name = valn; + vname << "c" << name; + prefix << (rn ? rn : cn) << "_"; + } + char *strip(char *s) { + if (strncmp(s, prefix.get(), strlen(prefix.get())) != 0) + return s; + temp = s; + temp.replace(prefix.get(), ""); + return temp.get(); + } +}; + +class RUBY : public Language { + private: + char *module; + char *modvar; + char *feature; + int toplevel; + String other_extern; + String other_init; + char *import_file; + + int current; + enum { + NO_CPP, + MEMBER_FUNC, + CONSTRUCTOR, + DESTRUCTOR, + MEMBER_VAR, + CLASS_CONST, + STATIC_FUNC, + STATIC_VAR + }; + + DOH *classes; // key=cname val=RClass + RClass *klass; // Currently processing class + DOH *special_methods; // Python style special method name table + + virtual char *make_wrapper_name(char *cname); + virtual char *validate_const_name(char *name); + virtual char *ruby_typemap_lookup(char *, DataType *, char *, char *, char *, WrapperFunction * = 0); + virtual int to_VALUE(DataType *, char *, String&, int = 0); + virtual int from_VALUE(DataType *, char *, String&); + public: + RUBY(); + + // Virtual functions required by the SWIG parser + virtual void parse_args(int, char *argv[]); + virtual void parse(); + virtual void create_function(char *, char *, DataType *, ParmList *); + virtual void link_variable(char *, char *, DataType *); + virtual void declare_const(char *, char *, DataType *, char *); + virtual void initialize(void); + virtual void headers(void); + virtual void close(void); + virtual void set_module(char *,char **); + virtual void create_command(char *, char *, int); + + // C++ language extensions. + virtual void cpp_member_func(char *name, char *iname, DataType *t, ParmList *l); + virtual void cpp_constructor(char *name, char *iname, ParmList *l); + virtual void cpp_destructor(char *name, char *newname); + virtual void cpp_open_class(char *classname, char *rname, char *ctype, int strip); + virtual void cpp_close_class(); + virtual void cpp_inherit(char **baseclass, int mode = INHERIT_ALL); + virtual void cpp_variable(char *name, char *iname, DataType *t); + virtual void cpp_static_func(char *name, char *iname, DataType *t, ParmList *l); + virtual void cpp_declare_const(char *name, char *iname, DataType *type, char *value); + virtual void cpp_static_var(char *name, char *iname, DataType *t); + + // Declaration of a class, but not a full definition + virtual void cpp_class_decl(char *, char *, char *); + + // Pragma directive + virtual void pragma(char *, char *, char *); + virtual void cpp_pragma(Pragma *); + + // Import directive + virtual void import(char *filename); + +}; + +/* + * Local Variables: + * c-basic-offset: 2 + * End: + */ diff --git a/Source/Modules1.1/swigmain.cxx b/Source/Modules1.1/swigmain.cxx index bfe7f8bce..271596824 100644 --- a/Source/Modules1.1/swigmain.cxx +++ b/Source/Modules1.1/swigmain.cxx @@ -32,6 +32,7 @@ static char cvsroot[] = "$Header$"; #include "python.h" #include "guile.h" #include "mzscheme.h" +#include "ruby.h" #include @@ -47,7 +48,8 @@ Target Language Options:\n\ -perl5 - Generate Perl5 wrappers.\n\ -java - Generate Java wrappers.\n\ -guile - Generate Guile wrappers.\n\ - -mzscheme - Generate Mzscheme wrappers.\n"; + -mzscheme - Generate Mzscheme wrappers.\n\ + -ruby - Generate Ruby wrappers.\n"; //----------------------------------------------------------------- // main() @@ -87,6 +89,9 @@ int main(int argc, char **argv) { } else if (strcmp(argv[i],"-mzscheme") == 0) { dl = new MZSCHEME; Swig_mark_arg(i); + } else if (strcmp(argv[i],"-ruby") == 0) { + dl = new RUBY; + Swig_mark_arg(i); } else if (strcmp(argv[i],"-help") == 0) { fputs(usage,stderr); Swig_mark_arg(i); diff --git a/configure.in b/configure.in index 2ba703914..794479624 100644 --- a/configure.in +++ b/configure.in @@ -594,6 +594,71 @@ AC_SUBST(GUILEINCLUDE) AC_SUBST(GUILELIB) AC_SUBST(GUILELINK) +#---------------------------------------------------------------- +# Look for Ruby +#---------------------------------------------------------------- + +RUBYBIN=nope + +AC_ARG_WITH(ruby,[ --with-ruby=path Set location of Ruby executable],[ RUBYBIN="$withval"], [RUBYBIN=nope]) + +# First figure out what the name of Ruby is + +if test "$RUBYBIN" = nope; then +AC_CHECK_PROGS(RUBY, ruby, nope) +else +RUBY="$RUBYBIN" +fi +AC_MSG_CHECKING(for Ruby header files) +if test "$RUBY" != nope; then + RUBYDIR=`($RUBY -rmkmf -e 'print $archdir') 2>/dev/null` + if test "$RUBYDIR" != ""; then + dirs="$RUBYDIR" + RUBYINCLUDE=none + for i in $dirs; do + if test -r $i/ruby.h; then + AC_MSG_RESULT($i) + RUBYINCLUDE="-I$i" + break; + fi + done + if test "$RUBYINCLUDE" = none; then + RUBYINCLUDE="-I$RUBYDIR" + AC_MSG_RESULT(could not locate ruby.h...using $RUBYINCLUDE) + fi + + AC_MSG_CHECKING(for Ruby library) + RUBYLIB=none + for i in $dirs; do + if test -r $i/libruby.a; then + AC_MSG_RESULT($i) + RUBYLIB="$i" + break; + fi + done + if test "$RUBYLIB" = none; then + RUBYLIB="$RUBYDIR" + AC_MSG_RESULT(could not locate libruby.a...using $RUBYLIB) + fi + else + AC_MSG_RESULT(unable to determine ruby configuration) + RUBYINCLUDE="-I$RUBYDIR" + RUBYLIB="$RUBYDIR" + fi + RUBYLINK=`($RUBY -rrbconfig -e 'print Config::CONFIG[["RUBY_INSTALL_NAME"]]') 2>/dev/null` + RUBYLINK="-l$RUBYLINK" + RUBYLINK="$RUBYLINK `($RUBY -rrbconfig -e 'print Config::CONFIG[["LIBS"]]') 2>/dev/null`" +else + AC_MSG_RESULT(could not figure out how to run ruby) + RUBYINCLUDE="-I/usr/local/lib/ruby/1.4/arch" + RUBYLIB="-I/usr/local/lib/ruby/1.4/arch" + RUBYLINK="-lruby -lm" +fi + +AC_SUBST(RUBYINCLUDE) +AC_SUBST(RUBYLIB) +AC_SUBST(RUBYLINK) + #---------------------------------------------------------------- # Miscellaneous