1#include <fiddle.h>
2
3VALUE mFiddle;
4VALUE rb_eFiddleError;
5
6#ifndef TYPE_SSIZE_T
7# if SIZEOF_SIZE_T == SIZEOF_INT
8#   define TYPE_SSIZE_T TYPE_INT
9# elif SIZEOF_SIZE_T == SIZEOF_LONG
10#   define TYPE_SSIZE_T TYPE_LONG
11# elif defined HAVE_LONG_LONG && SIZEOF_SIZE_T == SIZEOF_LONG_LONG
12#   define TYPE_SSIZE_T TYPE_LONG_LONG
13# endif
14#endif
15#define TYPE_SIZE_T (-1*SIGNEDNESS_OF_SIZE_T*TYPE_SSIZE_T)
16
17#ifndef TYPE_PTRDIFF_T
18# if SIZEOF_PTRDIFF_T == SIZEOF_INT
19#   define TYPE_PTRDIFF_T TYPE_INT
20# elif SIZEOF_PTRDIFF_T == SIZEOF_LONG
21#   define TYPE_PTRDIFF_T TYPE_LONG
22# elif defined HAVE_LONG_LONG && SIZEOF_PTRDIFF_T == SIZEOF_LONG_LONG
23#   define TYPE_PTRDIFF_T TYPE_LONG_LONG
24# endif
25#endif
26
27#ifndef TYPE_INTPTR_T
28# if SIZEOF_INTPTR_T == SIZEOF_INT
29#   define TYPE_INTPTR_T TYPE_INT
30# elif SIZEOF_INTPTR_T == SIZEOF_LONG
31#   define TYPE_INTPTR_T TYPE_LONG
32# elif defined HAVE_LONG_LONG && SIZEOF_INTPTR_T == SIZEOF_LONG_LONG
33#   define TYPE_INTPTR_T TYPE_LONG_LONG
34# endif
35#endif
36#define TYPE_UINTPTR_T (-TYPE_INTPTR_T)
37
38void Init_fiddle_pointer(void);
39
40/*
41 * call-seq: Fiddle.malloc(size)
42 *
43 * Allocate +size+ bytes of memory and return the integer memory address
44 * for the allocated memory.
45 */
46static VALUE
47rb_fiddle_malloc(VALUE self, VALUE size)
48{
49    void *ptr;
50
51    rb_secure(4);
52    ptr = (void*)ruby_xmalloc(NUM2INT(size));
53    return PTR2NUM(ptr);
54}
55
56/*
57 * call-seq: Fiddle.realloc(addr, size)
58 *
59 * Change the size of the memory allocated at the memory location +addr+ to
60 * +size+ bytes.  Returns the memory address of the reallocated memory, which
61 * may be different than the address passed in.
62 */
63static VALUE
64rb_fiddle_realloc(VALUE self, VALUE addr, VALUE size)
65{
66    void *ptr = NUM2PTR(addr);
67
68    rb_secure(4);
69    ptr = (void*)ruby_xrealloc(ptr, NUM2INT(size));
70    return PTR2NUM(ptr);
71}
72
73/*
74 * call-seq: Fiddle.free(addr)
75 *
76 * Free the memory at address +addr+
77 */
78VALUE
79rb_fiddle_free(VALUE self, VALUE addr)
80{
81    void *ptr = NUM2PTR(addr);
82
83    rb_secure(4);
84    ruby_xfree(ptr);
85    return Qnil;
86}
87
88/*
89 * call-seq: Fiddle.dlunwrap(addr)
90 *
91 * Returns the hexadecimal representation of a memory pointer address +addr+
92 *
93 * Example:
94 *
95 *   lib = Fiddle.dlopen('/lib64/libc-2.15.so')
96 *   => #<Fiddle::Handle:0x00000001342460>
97 *
98 *   lib['strcpy'].to_s(16)
99 *   => "7f59de6dd240"
100 *
101 *   Fiddle.dlunwrap(Fiddle.dlwrap(lib['strcpy'].to_s(16)))
102 *   => "7f59de6dd240"
103 */
104VALUE
105rb_fiddle_ptr2value(VALUE self, VALUE addr)
106{
107    rb_secure(4);
108    return (VALUE)NUM2PTR(addr);
109}
110
111/*
112 * call-seq: Fiddle.dlwrap(val)
113 *
114 * Returns a memory pointer of a function's hexadecimal address location +val+
115 *
116 * Example:
117 *
118 *   lib = Fiddle.dlopen('/lib64/libc-2.15.so')
119 *   => #<Fiddle::Handle:0x00000001342460>
120 *
121 *   Fiddle.dlwrap(lib['strcpy'].to_s(16))
122 *   => 25522520
123 */
124static VALUE
125rb_fiddle_value2ptr(VALUE self, VALUE val)
126{
127    return PTR2NUM((void*)val);
128}
129
130void Init_fiddle_handle(void);
131
132void
133Init_fiddle(void)
134{
135    /*
136     * Document-module: Fiddle
137     *
138     * A libffi wrapper for Ruby.
139     *
140     * == Description
141     *
142     * Fiddle is an extension to translate a foreign function interface (FFI)
143     * with ruby.
144     *
145     * It wraps {libffi}[http://sourceware.org/libffi/], a popular C library
146     * which provides a portable interface that allows code written in one
147     * language to clal code written in another language.
148     *
149     * == Example
150     *
151     * Here we will use Fiddle::Function to wrap {floor(3) from
152     * libm}[http://linux.die.net/man/3/floor]
153     *
154     *	    require 'fiddle'
155     *
156     *	    libm = Fiddle.dlopen('/lib/libm.so.6')
157     *
158     *	    floor = Fiddle::Function.new(
159     *	      libm['floor'],
160     *	      [Fiddle::TYPE_DOUBLE],
161     *	      Fiddle::TYPE_DOUBLE
162     *	    )
163     *
164     *	    puts floor.call(3.14159) #=> 3.0
165     *
166     *
167     */
168    mFiddle = rb_define_module("Fiddle");
169
170    /*
171     * Document-class: Fiddle::DLError
172     *
173     * standard dynamic load exception
174     */
175    rb_eFiddleError = rb_define_class_under(mFiddle, "DLError", rb_eStandardError);
176
177    /* Document-const: TYPE_VOID
178     *
179     * C type - void
180     */
181    rb_define_const(mFiddle, "TYPE_VOID",      INT2NUM(TYPE_VOID));
182
183    /* Document-const: TYPE_VOIDP
184     *
185     * C type - void*
186     */
187    rb_define_const(mFiddle, "TYPE_VOIDP",     INT2NUM(TYPE_VOIDP));
188
189    /* Document-const: TYPE_CHAR
190     *
191     * C type - char
192     */
193    rb_define_const(mFiddle, "TYPE_CHAR",      INT2NUM(TYPE_CHAR));
194
195    /* Document-const: TYPE_SHORT
196     *
197     * C type - short
198     */
199    rb_define_const(mFiddle, "TYPE_SHORT",     INT2NUM(TYPE_SHORT));
200
201    /* Document-const: TYPE_INT
202     *
203     * C type - int
204     */
205    rb_define_const(mFiddle, "TYPE_INT",       INT2NUM(TYPE_INT));
206
207    /* Document-const: TYPE_LONG
208     *
209     * C type - long
210     */
211    rb_define_const(mFiddle, "TYPE_LONG",      INT2NUM(TYPE_LONG));
212
213#if HAVE_LONG_LONG
214    /* Document-const: TYPE_LONG_LONG
215     *
216     * C type - long long
217     */
218    rb_define_const(mFiddle, "TYPE_LONG_LONG", INT2NUM(TYPE_LONG_LONG));
219#endif
220
221    /* Document-const: TYPE_FLOAT
222     *
223     * C type - float
224     */
225    rb_define_const(mFiddle, "TYPE_FLOAT",     INT2NUM(TYPE_FLOAT));
226
227    /* Document-const: TYPE_DOUBLE
228     *
229     * C type - double
230     */
231    rb_define_const(mFiddle, "TYPE_DOUBLE",    INT2NUM(TYPE_DOUBLE));
232
233    /* Document-const: TYPE_SIZE_T
234     *
235     * C type - size_t
236     */
237    rb_define_const(mFiddle, "TYPE_SIZE_T",   INT2NUM(TYPE_SIZE_T));
238
239    /* Document-const: TYPE_SSIZE_T
240     *
241     * C type - ssize_t
242     */
243    rb_define_const(mFiddle, "TYPE_SSIZE_T",   INT2NUM(TYPE_SSIZE_T));
244
245    /* Document-const: TYPE_PTRDIFF_T
246     *
247     * C type - ptrdiff_t
248     */
249    rb_define_const(mFiddle, "TYPE_PTRDIFF_T", INT2NUM(TYPE_PTRDIFF_T));
250
251    /* Document-const: TYPE_INTPTR_T
252     *
253     * C type - intptr_t
254     */
255    rb_define_const(mFiddle, "TYPE_INTPTR_T",  INT2NUM(TYPE_INTPTR_T));
256
257    /* Document-const: TYPE_UINTPTR_T
258     *
259     * C type - uintptr_t
260     */
261    rb_define_const(mFiddle, "TYPE_UINTPTR_T",  INT2NUM(TYPE_UINTPTR_T));
262
263    /* Document-const: ALIGN_VOIDP
264     *
265     * The alignment size of a void*
266     */
267    rb_define_const(mFiddle, "ALIGN_VOIDP", INT2NUM(ALIGN_VOIDP));
268
269    /* Document-const: ALIGN_CHAR
270     *
271     * The alignment size of a char
272     */
273    rb_define_const(mFiddle, "ALIGN_CHAR",  INT2NUM(ALIGN_CHAR));
274
275    /* Document-const: ALIGN_SHORT
276     *
277     * The alignment size of a short
278     */
279    rb_define_const(mFiddle, "ALIGN_SHORT", INT2NUM(ALIGN_SHORT));
280
281    /* Document-const: ALIGN_INT
282     *
283     * The alignment size of an int
284     */
285    rb_define_const(mFiddle, "ALIGN_INT",   INT2NUM(ALIGN_INT));
286
287    /* Document-const: ALIGN_LONG
288     *
289     * The alignment size of a long
290     */
291    rb_define_const(mFiddle, "ALIGN_LONG",  INT2NUM(ALIGN_LONG));
292
293#if HAVE_LONG_LONG
294    /* Document-const: ALIGN_LONG_LONG
295     *
296     * The alignment size of a long long
297     */
298    rb_define_const(mFiddle, "ALIGN_LONG_LONG",  INT2NUM(ALIGN_LONG_LONG));
299#endif
300
301    /* Document-const: ALIGN_FLOAT
302     *
303     * The alignment size of a float
304     */
305    rb_define_const(mFiddle, "ALIGN_FLOAT", INT2NUM(ALIGN_FLOAT));
306
307    /* Document-const: ALIGN_DOUBLE
308     *
309     * The alignment size of a double
310     */
311    rb_define_const(mFiddle, "ALIGN_DOUBLE",INT2NUM(ALIGN_DOUBLE));
312
313    /* Document-const: ALIGN_SIZE_T
314     *
315     * The alignment size of a size_t
316     */
317    rb_define_const(mFiddle, "ALIGN_SIZE_T", INT2NUM(ALIGN_OF(size_t)));
318
319    /* Document-const: ALIGN_SSIZE_T
320     *
321     * The alignment size of a ssize_t
322     */
323    rb_define_const(mFiddle, "ALIGN_SSIZE_T", INT2NUM(ALIGN_OF(size_t))); /* same as size_t */
324
325    /* Document-const: ALIGN_PTRDIFF_T
326     *
327     * The alignment size of a ptrdiff_t
328     */
329    rb_define_const(mFiddle, "ALIGN_PTRDIFF_T", INT2NUM(ALIGN_OF(ptrdiff_t)));
330
331    /* Document-const: ALIGN_INTPTR_T
332     *
333     * The alignment size of a intptr_t
334     */
335    rb_define_const(mFiddle, "ALIGN_INTPTR_T", INT2NUM(ALIGN_OF(intptr_t)));
336
337    /* Document-const: ALIGN_UINTPTR_T
338     *
339     * The alignment size of a uintptr_t
340     */
341    rb_define_const(mFiddle, "ALIGN_UINTPTR_T", INT2NUM(ALIGN_OF(uintptr_t)));
342
343    /* Document-const: WINDOWS
344     *
345     * Returns a boolean regarding whether the host is WIN32
346     */
347#if defined(_WIN32)
348    rb_define_const(mFiddle, "WINDOWS", Qtrue);
349#else
350    rb_define_const(mFiddle, "WINDOWS", Qfalse);
351#endif
352
353    /* Document-const: SIZEOF_VOIDP
354     *
355     * size of a void*
356     */
357    rb_define_const(mFiddle, "SIZEOF_VOIDP", INT2NUM(sizeof(void*)));
358
359    /* Document-const: SIZEOF_CHAR
360     *
361     * size of a char
362     */
363    rb_define_const(mFiddle, "SIZEOF_CHAR",  INT2NUM(sizeof(char)));
364
365    /* Document-const: SIZEOF_SHORT
366     *
367     * size of a short
368     */
369    rb_define_const(mFiddle, "SIZEOF_SHORT", INT2NUM(sizeof(short)));
370
371    /* Document-const: SIZEOF_INT
372     *
373     * size of an int
374     */
375    rb_define_const(mFiddle, "SIZEOF_INT",   INT2NUM(sizeof(int)));
376
377    /* Document-const: SIZEOF_LONG
378     *
379     * size of a long
380     */
381    rb_define_const(mFiddle, "SIZEOF_LONG",  INT2NUM(sizeof(long)));
382
383#if HAVE_LONG_LONG
384    /* Document-const: SIZEOF_LONG_LONG
385     *
386     * size of a long long
387     */
388    rb_define_const(mFiddle, "SIZEOF_LONG_LONG",  INT2NUM(sizeof(LONG_LONG)));
389#endif
390
391    /* Document-const: SIZEOF_FLOAT
392     *
393     * size of a float
394     */
395    rb_define_const(mFiddle, "SIZEOF_FLOAT", INT2NUM(sizeof(float)));
396
397    /* Document-const: SIZEOF_DOUBLE
398     *
399     * size of a double
400     */
401    rb_define_const(mFiddle, "SIZEOF_DOUBLE",INT2NUM(sizeof(double)));
402
403    /* Document-const: SIZEOF_SIZE_T
404     *
405     * size of a size_t
406     */
407    rb_define_const(mFiddle, "SIZEOF_SIZE_T",  INT2NUM(sizeof(size_t)));
408
409    /* Document-const: SIZEOF_SSIZE_T
410     *
411     * size of a ssize_t
412     */
413    rb_define_const(mFiddle, "SIZEOF_SSIZE_T",  INT2NUM(sizeof(size_t))); /* same as size_t */
414
415    /* Document-const: SIZEOF_PTRDIFF_T
416     *
417     * size of a ptrdiff_t
418     */
419    rb_define_const(mFiddle, "SIZEOF_PTRDIFF_T",  INT2NUM(sizeof(ptrdiff_t)));
420
421    /* Document-const: SIZEOF_INTPTR_T
422     *
423     * size of a intptr_t
424     */
425    rb_define_const(mFiddle, "SIZEOF_INTPTR_T",  INT2NUM(sizeof(intptr_t)));
426
427    /* Document-const: SIZEOF_UINTPTR_T
428     *
429     * size of a uintptr_t
430     */
431    rb_define_const(mFiddle, "SIZEOF_UINTPTR_T",  INT2NUM(sizeof(uintptr_t)));
432
433    /* Document-const: RUBY_FREE
434     *
435     * Address of the ruby_xfree() function
436     */
437    rb_define_const(mFiddle, "RUBY_FREE", PTR2NUM(ruby_xfree));
438
439    /* Document-const: BUILD_RUBY_PLATFORM
440     *
441     * Platform built against (i.e. "x86_64-linux", etc.)
442     *
443     * See also RUBY_PLATFORM
444     */
445    rb_define_const(mFiddle, "BUILD_RUBY_PLATFORM", rb_str_new2(RUBY_PLATFORM));
446
447    rb_define_module_function(mFiddle, "dlwrap", rb_fiddle_value2ptr, 1);
448    rb_define_module_function(mFiddle, "dlunwrap", rb_fiddle_ptr2value, 1);
449    rb_define_module_function(mFiddle, "malloc", rb_fiddle_malloc, 1);
450    rb_define_module_function(mFiddle, "realloc", rb_fiddle_realloc, 2);
451    rb_define_module_function(mFiddle, "free", rb_fiddle_free, 1);
452
453    Init_fiddle_function();
454    Init_fiddle_closure();
455    Init_fiddle_handle();
456    Init_fiddle_pointer();
457}
458/* vim: set noet sws=4 sw=4: */
459