rubysl-dl 0.0.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,35 @@
1
+ #include <stdio.h>
2
+
3
+ class Person {
4
+ private:
5
+ const char *name;
6
+ int age;
7
+
8
+ public:
9
+ Person(const char *name, int age);
10
+ const char * get_name();
11
+ int get_age();
12
+ void set_age(int i);
13
+ };
14
+
15
+ Person::Person(const char *name, int age)
16
+ : name(name), age(age)
17
+ {
18
+ /* empty */
19
+ }
20
+
21
+ const char *
22
+ Person::get_name()
23
+ {
24
+ return name;
25
+ }
26
+
27
+ int
28
+ Person::get_age(){
29
+ return age;
30
+ }
31
+
32
+ void
33
+ Person::set_age(int i){
34
+ age = i;
35
+ }
@@ -0,0 +1,60 @@
1
+ =begin
2
+ This script shows how to deal with C++ classes using Ruby/DL.
3
+ You must build a dynamic loadable library using "c++sample.C"
4
+ to run this script as follows:
5
+ $ g++ -o libsample.so -shared c++sample.C
6
+ =end
7
+
8
+ require 'dl'
9
+ require 'dl/import'
10
+ require 'dl/struct'
11
+
12
+ # Give a name of dynamic loadable library
13
+ LIBNAME = ARGV[0] || "libsample.so"
14
+
15
+ class Person
16
+ module Core
17
+ extend DL::Importable
18
+
19
+ dlload LIBNAME
20
+
21
+ # mangled symbol names
22
+ extern "void __6PersonPCci(void *, const char *, int)"
23
+ extern "const char *get_name__6Person(void *)"
24
+ extern "int get_age__6Person(void *)"
25
+ extern "void set_age__6Personi(void *, int)"
26
+
27
+ Data = struct [
28
+ "char *name",
29
+ "int age",
30
+ ]
31
+ end
32
+
33
+ def initialize(name, age)
34
+ @ptr = Core::Data.alloc
35
+ Core::__6PersonPCci(@ptr, name, age)
36
+ end
37
+
38
+ def get_name()
39
+ str = Core::get_name__6Person(@ptr)
40
+ if( str )
41
+ str.to_s
42
+ else
43
+ nil
44
+ end
45
+ end
46
+
47
+ def get_age()
48
+ Core::get_age__6Person(@ptr)
49
+ end
50
+
51
+ def set_age(age)
52
+ Core::set_age__6Personi(@ptr, age)
53
+ end
54
+ end
55
+
56
+ obj = Person.new("ttate", 1)
57
+ p obj.get_name()
58
+ p obj.get_age()
59
+ obj.set_age(10)
60
+ p obj.get_age()
@@ -0,0 +1,70 @@
1
+ # -*- ruby -*-
2
+ # drives.rb -- find existing drives and show the drive type.
3
+
4
+ require 'dl'
5
+ require 'dl/import'
6
+
7
+ module Kernel32
8
+ extend DL::Importable
9
+
10
+ dlload "kernel32"
11
+
12
+ extern "long GetLogicalDrives()"
13
+ extern "int GetDriveType(char*)"
14
+ extern "long GetDiskFreeSpace(char*, long ref, long ref, long ref, long ref)"
15
+ end
16
+
17
+ include Kernel32
18
+
19
+ buff = Kernel32.getLogicalDrives()
20
+
21
+ i = 0
22
+ ds = []
23
+ while( i < 26 )
24
+ mask = (1 << i)
25
+ if( buff & mask > 0 )
26
+ ds.push((65+i).chr)
27
+ end
28
+ i += 1
29
+ end
30
+
31
+ =begin
32
+ From the cygwin's /usr/include/w32api/winbase.h:
33
+ #define DRIVE_UNKNOWN 0
34
+ #define DRIVE_NO_ROOT_DIR 1
35
+ #define DRIVE_REMOVABLE 2
36
+ #define DRIVE_FIXED 3
37
+ #define DRIVE_REMOTE 4
38
+ #define DRIVE_CDROM 5
39
+ #define DRIVE_RAMDISK 6
40
+ =end
41
+
42
+ types = [
43
+ "unknown",
44
+ "no root dir",
45
+ "Removable",
46
+ "Fixed",
47
+ "Remote",
48
+ "CDROM",
49
+ "RAM",
50
+ ]
51
+ print("Drive : Type (Free Space/Available Space)\n")
52
+ ds.each{|d|
53
+ t = Kernel32.getDriveType(d + ":\\")
54
+ Kernel32.getDiskFreeSpace(d + ":\\", 0, 0, 0, 0)
55
+ _,sec_per_clus,byte_per_sec,free_clus,total_clus = Kernel32._args_
56
+ fbytes = sec_per_clus * byte_per_sec * free_clus
57
+ tbytes = sec_per_clus * byte_per_sec * total_clus
58
+ unit = "B"
59
+ if( fbytes > 1024 && tbytes > 1024 )
60
+ fbytes = fbytes / 1024
61
+ tbytes = tbytes / 1024
62
+ unit = "K"
63
+ end
64
+ if( fbytes > 1024 && tbytes > 1024 )
65
+ fbytes = fbytes / 1024
66
+ tbytes = tbytes / 1024
67
+ unit = "M"
68
+ end
69
+ print("#{d} : #{types[t]} (#{fbytes} #{unit}/#{tbytes} #{unit})\n")
70
+ }
@@ -0,0 +1,5 @@
1
+ require 'dl'
2
+
3
+ crtdll = DL::dlopen("crtdll")
4
+ getch = crtdll['_getch', 'L']
5
+ print(getch.call, "\n")
@@ -0,0 +1,69 @@
1
+ require "dl/import"
2
+ require "dl/struct"
3
+
4
+ module LIBC
5
+ extend DL::Importable
6
+
7
+ begin
8
+ dlload "libc.so.6"
9
+ rescue
10
+ dlload "libc.so.5"
11
+ end
12
+
13
+ extern "int atoi(char*)"
14
+ extern "ibool isdigit(int)"
15
+ extern "int gettimeofday(struct timeval *, struct timezone *)"
16
+ extern "char* strcat(char*, char*)"
17
+ extern "FILE* fopen(char*, char*)"
18
+ extern "int fclose(FILE*)"
19
+ extern "int fgetc(FILE*)"
20
+ extern "int strlen(char*)"
21
+ extern "void qsort(void*, int, int, void*)"
22
+
23
+ def str_qsort(ary, comp)
24
+ len = ary.length
25
+ r,rs = qsort(ary, len, DL.sizeof('P'), comp)
26
+ return rs[0].to_a('S', len)
27
+ end
28
+
29
+ Timeval = struct [
30
+ "long tv_sec",
31
+ "long tv_usec",
32
+ ]
33
+
34
+ Timezone = struct [
35
+ "int tz_minuteswest",
36
+ "int tz_dsttime",
37
+ ]
38
+
39
+ def my_compare(ptr1, ptr2)
40
+ ptr1.ptr.to_s <=> ptr2.ptr.to_s
41
+ end
42
+ COMPARE = callback("int my_compare(char**, char**)")
43
+ end
44
+
45
+
46
+ $cb1 = DL.callback('IPP'){|ptr1, ptr2|
47
+ str1 = ptr1.ptr.to_s
48
+ str2 = ptr2.ptr.to_s
49
+ str1 <=> str2
50
+ }
51
+
52
+ p LIBC.atoi("10")
53
+
54
+ p LIBC.isdigit(?1)
55
+
56
+ p LIBC.isdigit(?a)
57
+
58
+ p LIBC.strcat("a", "b")
59
+
60
+ ary = ["a","c","b"]
61
+ ptr = ary.to_ptr
62
+ LIBC.qsort(ptr, ary.length, DL.sizeof('P'), LIBC::COMPARE)
63
+ p ptr.to_a('S', ary.length)
64
+
65
+ tv = LIBC::Timeval.malloc
66
+ tz = LIBC::Timezone.malloc
67
+ LIBC.gettimeofday(tv, tz)
68
+
69
+ p Time.at(tv.tv_sec)
@@ -0,0 +1,19 @@
1
+ # This script works on Windows.
2
+
3
+ require 'dl'
4
+
5
+ User32 = DL.dlopen("user32")
6
+ Kernel32 = DL.dlopen("kernel32")
7
+
8
+ MB_OK = 0
9
+ MB_OKCANCEL = 1
10
+
11
+ message_box = User32['MessageBoxA', 'ILSSI']
12
+ r,rs = message_box.call(0, 'ok?', 'error', MB_OKCANCEL)
13
+
14
+ case r
15
+ when 1
16
+ print("OK!\n")
17
+ when 2
18
+ print("Cancel!\n")
19
+ end
@@ -0,0 +1,18 @@
1
+ # This script works on Windows.
2
+
3
+ require 'dl/win32'
4
+
5
+ MB_OK = 0
6
+ MB_OKCANCEL = 1
7
+
8
+ message_box = Win32API.new("user32",'MessageBoxA', 'ISSI', 'I')
9
+ r = message_box.call(0, 'ok?', 'error', MB_OKCANCEL)
10
+
11
+ case r
12
+ when 1
13
+ print("OK!\n")
14
+ when 2
15
+ print("Cancel!\n")
16
+ else
17
+ p r
18
+ end
@@ -0,0 +1,87 @@
1
+ # -*- ruby -*-
2
+ # Display a file name and stream names of a file with those size.
3
+
4
+ require 'dl'
5
+ require 'dl/import'
6
+
7
+ module NTFS
8
+ extend DL::Importable
9
+
10
+ dlload "kernel32.dll"
11
+
12
+ OPEN_EXISTING = 3
13
+ GENERIC_READ = 0x80000000
14
+ BACKUP_DATA = 0x00000001
15
+ BACKUP_ALTERNATE_DATA = 0x00000004
16
+ FILE_SHARE_READ = 0x00000001
17
+ FILE_FLAG_BACKUP_SEMANTICS = 0x02000000
18
+
19
+ typealias "LPSECURITY_ATTRIBUTES", "void*"
20
+
21
+ extern "BOOL BackupRead(HANDLE, PBYTE, DWORD, PDWORD, BOOL, BOOL, PVOID)"
22
+ extern "BOOL BackupSeek(HANDLE, DWORD, DWORD, PDWORD, PDWORD, PVOID)"
23
+ extern "BOOL CloseHandle(HANDLE)"
24
+ extern "HANDLE CreateFile(LPCSTR, DWORD, DWORD, LPSECURITY_ATTRIBUTES,
25
+ DWORD, DWORD, HANDLE)"
26
+
27
+ module_function
28
+
29
+ def streams(filename)
30
+ status = []
31
+ h = createFile(filename,GENERIC_READ,FILE_SHARE_READ,nil,
32
+ OPEN_EXISTING,FILE_FLAG_BACKUP_SEMANTICS,0)
33
+ if( h != 0 )
34
+ begin
35
+ # allocate the memory for backup data used in backupRead().
36
+ data = DL.malloc(DL.sizeof("L5"))
37
+ data.struct!("LLLLL", :id, :attrs, :size_low, :size_high, :name_size)
38
+
39
+ # allocate memories for references to long values used in backupRead().
40
+ context = DL.malloc(DL.sizeof("L"))
41
+ lval = DL.malloc(DL.sizeof("L"))
42
+
43
+ while( backupRead(h, data, data.size, lval, false, false, context) )
44
+ size = data[:size_low] + (data[:size_high] << (DL.sizeof("I") * 8))
45
+ case data[:id]
46
+ when BACKUP_ALTERNATE_DATA
47
+ stream_name = DL.malloc(data[:name_size])
48
+ backupRead(h, stream_name, stream_name.size,
49
+ lval, false, false, context)
50
+ name = stream_name[0, stream_name.size]
51
+ name.tr!("\000","")
52
+ if( name =~ /^:(.*?):.*$/ )
53
+ status.push([$1,size])
54
+ end
55
+ when BACKUP_DATA
56
+ status.push([nil,size])
57
+ else
58
+ raise(RuntimeError, "unknown data type #{data[:id]}.")
59
+ end
60
+ l1 = DL.malloc(DL.sizeof("L"))
61
+ l2 = DL.malloc(DL.sizeof("L"))
62
+ if( !backupSeek(h, data[:size_low], data[:size_high], l1, l2, context) )
63
+ break
64
+ end
65
+ end
66
+ ensure
67
+ backupRead(h, nil, 0, lval, true, false, context)
68
+ closeHandle(h)
69
+ end
70
+ return status
71
+ else
72
+ raise(RuntimeError, "can't open #{filename}.\n")
73
+ end
74
+ end
75
+ end
76
+
77
+ ARGV.each{|filename|
78
+ if( File.exist?(filename) )
79
+ NTFS.streams(filename).each{|name,size|
80
+ if( name )
81
+ print("#{filename}:#{name}\t#{size}bytes\n")
82
+ else
83
+ print("#{filename}\t#{size}bytes\n")
84
+ end
85
+ }
86
+ end
87
+ }
@@ -0,0 +1,993 @@
1
+ /* -*- C -*-
2
+ * $Id: sym.c 18479 2008-08-11 00:37:21Z shyouhei $
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include <errno.h>
7
+ #include "dl.h"
8
+
9
+ VALUE rb_cDLSymbol;
10
+
11
+ static const char *
12
+ char2type(int ch)
13
+ {
14
+ switch (ch) {
15
+ case '0':
16
+ return "void";
17
+ case 'P':
18
+ return "void *";
19
+ case 'p':
20
+ return "void *";
21
+ case 'C':
22
+ return "char";
23
+ case 'c':
24
+ return "char *";
25
+ case 'H':
26
+ return "short";
27
+ case 'h':
28
+ return "short *";
29
+ case 'I':
30
+ return "int";
31
+ case 'i':
32
+ return "int *";
33
+ case 'L':
34
+ return "long";
35
+ case 'l':
36
+ return "long *";
37
+ case 'F':
38
+ return "double";
39
+ case 'f':
40
+ return "double *";
41
+ case 'D':
42
+ return "double";
43
+ case 'd':
44
+ return "double *";
45
+ case 'S':
46
+ return "const char *";
47
+ case 's':
48
+ return "char *";
49
+ case 'A':
50
+ return "[]";
51
+ case 'a':
52
+ return "[]"; /* ?? */
53
+ }
54
+ return NULL;
55
+ }
56
+
57
+ void
58
+ dlsym_free(struct sym_data *data)
59
+ {
60
+ if( data->name ){
61
+ DEBUG_CODE({
62
+ printf("dlsym_free(): free(data->name:%s)\n",data->name);
63
+ });
64
+ free(data->name);
65
+ }
66
+ if( data->type ){
67
+ DEBUG_CODE({
68
+ printf("dlsym_free(): free(data->type:%s)\n",data->type);
69
+ });
70
+ free(data->type);
71
+ }
72
+ }
73
+
74
+ VALUE
75
+ rb_dlsym_new(void (*func)(), const char *name, const char *type)
76
+ {
77
+ VALUE val;
78
+ struct sym_data *data;
79
+ const char *ptype;
80
+
81
+ rb_secure(4);
82
+ if( !type || !type[0] ){
83
+ return rb_dlptr_new((void*)func, 0, 0);
84
+ }
85
+
86
+ for( ptype = type; *ptype; ptype ++ ){
87
+ if( ! char2type(*ptype) ){
88
+ rb_raise(rb_eDLTypeError, "unknown type specifier '%c'", *ptype);
89
+ }
90
+ }
91
+
92
+ if( func ){
93
+ val = Data_Make_Struct(rb_cDLSymbol, struct sym_data, 0, dlsym_free, data);
94
+ data->func = func;
95
+ data->name = name ? strdup(name) : NULL;
96
+ data->type = type ? strdup(type) : NULL;
97
+ data->len = type ? strlen(type) : 0;
98
+ #if !(defined(DLSTACK))
99
+ if( data->len - 1 > MAX_ARG ){
100
+ rb_raise(rb_eDLError, "maximum number of arguments is %d.", MAX_ARG);
101
+ }
102
+ #endif
103
+ }
104
+ else{
105
+ val = Qnil;
106
+ }
107
+
108
+ return val;
109
+ }
110
+
111
+ freefunc_t
112
+ rb_dlsym2csym(VALUE val)
113
+ {
114
+ struct sym_data *data;
115
+ freefunc_t func;
116
+
117
+ if( rb_obj_is_kind_of(val, rb_cDLSymbol) ){
118
+ Data_Get_Struct(val, struct sym_data, data);
119
+ func = data->func;
120
+ }
121
+ else if( val == Qnil ){
122
+ func = NULL;
123
+ }
124
+ else{
125
+ rb_raise(rb_eTypeError, "DL::Symbol was expected");
126
+ }
127
+
128
+ return func;
129
+ }
130
+
131
+ VALUE
132
+ rb_dlsym_s_allocate(VALUE klass)
133
+ {
134
+ VALUE obj;
135
+ struct sym_data *data;
136
+
137
+ obj = Data_Make_Struct(klass, struct sym_data, 0, dlsym_free, data);
138
+ data->func = 0;
139
+ data->name = 0;
140
+ data->type = 0;
141
+ data->len = 0;
142
+
143
+ return obj;
144
+ }
145
+
146
+ VALUE
147
+ rb_dlsym_initialize(int argc, VALUE argv[], VALUE self)
148
+ {
149
+ VALUE addr, name, type;
150
+ struct sym_data *data;
151
+ void *saddr;
152
+ const char *sname, *stype;
153
+
154
+ rb_scan_args(argc, argv, "12", &addr, &name, &type);
155
+
156
+ saddr = (void*)(DLNUM2LONG(rb_Integer(addr)));
157
+ if (!NIL_P(name)) StringValue(name);
158
+ stype = NIL_P(type) ? NULL : StringValuePtr(type);
159
+ sname = NIL_P(name) ? NULL : RSTRING(name)->ptr;
160
+
161
+ if( saddr ){
162
+ Data_Get_Struct(self, struct sym_data, data);
163
+ if( data->name ) free(data->name);
164
+ if( data->type ) free(data->type);
165
+ data->func = saddr;
166
+ data->name = sname ? strdup(sname) : 0;
167
+ data->type = stype ? strdup(stype) : 0;
168
+ data->len = stype ? strlen(stype) : 0;
169
+ }
170
+
171
+ return Qnil;
172
+ }
173
+
174
+ VALUE
175
+ rb_s_dlsym_char2type(VALUE self, VALUE ch)
176
+ {
177
+ const char *type;
178
+
179
+ type = char2type(StringValuePtr(ch)[0]);
180
+
181
+ if (type == NULL)
182
+ return Qnil;
183
+ else
184
+ return rb_str_new2(type);
185
+ }
186
+
187
+ VALUE
188
+ rb_dlsym_name(VALUE self)
189
+ {
190
+ struct sym_data *sym;
191
+
192
+ Data_Get_Struct(self, struct sym_data, sym);
193
+ return sym->name ? rb_tainted_str_new2(sym->name) : Qnil;
194
+ }
195
+
196
+ VALUE
197
+ rb_dlsym_proto(VALUE self)
198
+ {
199
+ struct sym_data *sym;
200
+
201
+ Data_Get_Struct(self, struct sym_data, sym);
202
+ return sym->type ? rb_tainted_str_new2(sym->type) : Qnil;
203
+ }
204
+
205
+ VALUE
206
+ rb_dlsym_cproto(VALUE self)
207
+ {
208
+ struct sym_data *sym;
209
+ const char *ptype, *typestr;
210
+ size_t len;
211
+ VALUE val;
212
+
213
+ Data_Get_Struct(self, struct sym_data, sym);
214
+
215
+ ptype = sym->type;
216
+
217
+ if( ptype ){
218
+ typestr = char2type(*ptype++);
219
+ len = strlen(typestr);
220
+
221
+ val = rb_tainted_str_new(typestr, len);
222
+ if (typestr[len - 1] != '*')
223
+ rb_str_cat(val, " ", 1);
224
+
225
+ if( sym->name ){
226
+ rb_str_cat2(val, sym->name);
227
+ }
228
+ else{
229
+ rb_str_cat2(val, "(null)");
230
+ }
231
+ rb_str_cat(val, "(", 1);
232
+
233
+ while (*ptype) {
234
+ const char *ty = char2type(*ptype++);
235
+ rb_str_cat2(val, ty);
236
+ if (*ptype)
237
+ rb_str_cat(val, ", ", 2);
238
+ }
239
+
240
+ rb_str_cat(val, ");", 2);
241
+ }
242
+ else{
243
+ val = rb_tainted_str_new2("void (");
244
+ if( sym->name ){
245
+ rb_str_cat2(val, sym->name);
246
+ }
247
+ else{
248
+ rb_str_cat2(val, "(null)");
249
+ }
250
+ rb_str_cat2(val, ")()");
251
+ }
252
+
253
+ return val;
254
+ }
255
+
256
+ VALUE
257
+ rb_dlsym_inspect(VALUE self)
258
+ {
259
+ VALUE proto;
260
+ VALUE val;
261
+ char *str;
262
+ int str_size;
263
+ struct sym_data *sym;
264
+
265
+ Data_Get_Struct(self, struct sym_data, sym);
266
+ proto = rb_dlsym_cproto(self);
267
+
268
+ str_size = RSTRING(proto)->len + 100;
269
+ str = dlmalloc(str_size);
270
+ snprintf(str, str_size - 1,
271
+ "#<DL::Symbol:0x%lx func=0x%lx '%s'>",
272
+ (long unsigned)sym, (long unsigned)sym->func, RSTRING(proto)->ptr);
273
+ val = rb_tainted_str_new2(str);
274
+ dlfree(str);
275
+
276
+ return val;
277
+ }
278
+
279
+ static int
280
+ stack_size(struct sym_data *sym)
281
+ {
282
+ int i;
283
+ int size;
284
+
285
+ size = 0;
286
+ for( i=1; i < sym->len; i++ ){
287
+ switch(sym->type[i]){
288
+ case 'C':
289
+ case 'H':
290
+ case 'I':
291
+ case 'L':
292
+ size += sizeof(long);
293
+ break;
294
+ case 'F':
295
+ size += sizeof(float);
296
+ break;
297
+ case 'D':
298
+ size += sizeof(double);
299
+ break;
300
+ case 'c':
301
+ case 'h':
302
+ case 'i':
303
+ case 'l':
304
+ case 'f':
305
+ case 'd':
306
+ case 'p':
307
+ case 'P':
308
+ case 's':
309
+ case 'S':
310
+ case 'a':
311
+ case 'A':
312
+ size += sizeof(void*);
313
+ break;
314
+ default:
315
+ return -(sym->type[i]);
316
+ }
317
+ }
318
+ return size;
319
+ }
320
+
321
+ static ID rb_dl_id_DLErrno;
322
+
323
+ static VALUE
324
+ rb_dl_get_last_error(VALUE self)
325
+ {
326
+ return rb_thread_local_aref(rb_thread_current(), rb_dl_id_DLErrno);
327
+ }
328
+
329
+ static VALUE
330
+ rb_dl_set_last_error(VALUE self, VALUE val)
331
+ {
332
+ errno = NUM2INT(val);
333
+ rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, val);
334
+ return Qnil;
335
+ }
336
+
337
+ #ifdef HAVE_WINDOWS_H
338
+ #include <windows.h>
339
+ static ID rb_dl_id_DLW32Error;
340
+
341
+ static VALUE
342
+ rb_dl_win32_get_last_error(VALUE self)
343
+ {
344
+ return rb_thread_local_aref(rb_thread_current(), rb_dl_id_DLW32Error);
345
+ }
346
+
347
+ static VALUE
348
+ rb_dl_win32_set_last_error(VALUE self, VALUE val)
349
+ {
350
+ SetLastError(NUM2INT(val));
351
+ rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, val);
352
+ return Qnil;
353
+ }
354
+ #endif
355
+
356
+ #ifdef DLSTACK_GUARD
357
+ # ifdef __MSVC_RUNTIME_CHECKS
358
+ # pragma runtime_checks("s", off)
359
+ # endif
360
+ # if _MSC_VER >= 1300
361
+ __declspec(noinline)
362
+ # endif
363
+ static int
364
+ rb_dlsym_guardcall(char type, ANY_TYPE *ret, long *stack, void *func)
365
+ {
366
+ char *volatile guard = ALLOCA_N(char, 1); /* guard stack pointer */
367
+ switch(type){
368
+ case '0':
369
+ {
370
+ void (*f)(DLSTACK_PROTO) = func;
371
+ f(DLSTACK_ARGS);
372
+ }
373
+ break;
374
+ case 'P':
375
+ case 'p':
376
+ {
377
+ void * (*f)(DLSTACK_PROTO) = func;
378
+ ret->p = f(DLSTACK_ARGS);
379
+ }
380
+ break;
381
+ case 'C':
382
+ case 'c':
383
+ {
384
+ char (*f)(DLSTACK_PROTO) = func;
385
+ ret->c = f(DLSTACK_ARGS);
386
+ }
387
+ break;
388
+ case 'H':
389
+ case 'h':
390
+ {
391
+ short (*f)(DLSTACK_PROTO) = func;
392
+ ret->h = f(DLSTACK_ARGS);
393
+ }
394
+ break;
395
+ case 'I':
396
+ case 'i':
397
+ {
398
+ int (*f)(DLSTACK_PROTO) = func;
399
+ ret->i = f(DLSTACK_ARGS);
400
+ }
401
+ break;
402
+ case 'L':
403
+ case 'l':
404
+ {
405
+ long (*f)(DLSTACK_PROTO) = func;
406
+ ret->l = f(DLSTACK_ARGS);
407
+ }
408
+ break;
409
+ case 'F':
410
+ case 'f':
411
+ {
412
+ float (*f)(DLSTACK_PROTO) = func;
413
+ ret->f = f(DLSTACK_ARGS);
414
+ }
415
+ break;
416
+ case 'D':
417
+ case 'd':
418
+ {
419
+ double (*f)(DLSTACK_PROTO) = func;
420
+ ret->d = f(DLSTACK_ARGS);
421
+ }
422
+ break;
423
+ case 'S':
424
+ case 's':
425
+ {
426
+ char * (*f)(DLSTACK_PROTO) = func;
427
+ ret->s = f(DLSTACK_ARGS);
428
+ }
429
+ break;
430
+ default:
431
+ return 0;
432
+ }
433
+ return 1;
434
+ }
435
+ # ifdef __MSVC_RUNTIME_CHECKS
436
+ # pragma runtime_checks("s", restore)
437
+ # endif
438
+ #endif /* defined(DLSTACK_GUARD) */
439
+
440
+ VALUE
441
+ rb_dlsym_call(int argc, VALUE argv[], VALUE self)
442
+ {
443
+ struct sym_data *sym;
444
+ ANY_TYPE *args;
445
+ ANY_TYPE *dargs;
446
+ ANY_TYPE ret;
447
+ int *dtypes;
448
+ VALUE val;
449
+ VALUE dvals;
450
+ int i;
451
+ long ftype;
452
+ void *func;
453
+
454
+ rb_secure_update(self);
455
+ Data_Get_Struct(self, struct sym_data, sym);
456
+ DEBUG_CODE({
457
+ printf("rb_dlsym_call(): type = '%s', func = 0x%x\n", sym->type, sym->func);
458
+ });
459
+ if( (sym->len - 1) != argc ){
460
+ rb_raise(rb_eArgError, "%d arguments are needed", sym->len - 1);
461
+ }
462
+
463
+ ftype = 0;
464
+ dvals = Qnil;
465
+
466
+ args = ALLOC_N(ANY_TYPE, sym->len - 1);
467
+ dargs = ALLOC_N(ANY_TYPE, sym->len - 1);
468
+ dtypes = ALLOC_N(int, sym->len - 1);
469
+ #define FREE_ARGS {xfree(args); xfree(dargs); xfree(dtypes);}
470
+
471
+ for( i = sym->len - 2; i >= 0; i-- ){
472
+ dtypes[i] = 0;
473
+
474
+ switch( sym->type[i+1] ){
475
+ case 'p':
476
+ dtypes[i] = 'p';
477
+ case 'P':
478
+ {
479
+ struct ptr_data *data;
480
+ VALUE pval;
481
+
482
+ if( argv[i] == Qnil ){
483
+ ANY2P(args[i]) = DLVOIDP(0);
484
+ }
485
+ else{
486
+ if( rb_obj_is_kind_of(argv[i], rb_cDLPtrData) ){
487
+ pval = argv[i];
488
+ }
489
+ else{
490
+ pval = rb_funcall(argv[i], rb_intern("to_ptr"), 0);
491
+ if( !rb_obj_is_kind_of(pval, rb_cDLPtrData) ){
492
+ rb_raise(rb_eDLTypeError, "unexpected type of argument #%d", i);
493
+ }
494
+ }
495
+ rb_check_safe_obj(pval);
496
+ Data_Get_Struct(pval, struct ptr_data, data);
497
+ ANY2P(args[i]) = DLVOIDP(data->ptr);
498
+ }
499
+ }
500
+ PUSH_P(ftype);
501
+ break;
502
+ case 'a':
503
+ dtypes[i] = 'a';
504
+ case 'A':
505
+ if( argv[i] == Qnil ){
506
+ ANY2P(args[i]) = DLVOIDP(0);
507
+ }
508
+ else{
509
+ ANY2P(args[i]) = DLVOIDP(rb_ary2cary(0, argv[i], NULL));
510
+ }
511
+ PUSH_P(ftype);
512
+ break;
513
+ case 'C':
514
+ ANY2C(args[i]) = DLCHAR(NUM2CHR(argv[i]));
515
+ PUSH_C(ftype);
516
+ break;
517
+ case 'c':
518
+ ANY2C(dargs[i]) = DLCHAR(NUM2CHR(argv[i]));
519
+ ANY2P(args[i]) = DLVOIDP(&(ANY2C(dargs[i])));
520
+ dtypes[i] = 'c';
521
+ PUSH_P(ftype);
522
+ break;
523
+ case 'H':
524
+ ANY2H(args[i]) = DLSHORT(NUM2INT(argv[i]));
525
+ PUSH_C(ftype);
526
+ break;
527
+ case 'h':
528
+ ANY2H(dargs[i]) = DLSHORT(NUM2INT(argv[i]));
529
+ ANY2P(args[i]) = DLVOIDP(&(ANY2H(dargs[i])));
530
+ dtypes[i] = 'h';
531
+ PUSH_P(ftype);
532
+ break;
533
+ case 'I':
534
+ ANY2I(args[i]) = DLINT(NUM2INT(argv[i]));
535
+ PUSH_I(ftype);
536
+ break;
537
+ case 'i':
538
+ ANY2I(dargs[i]) = DLINT(NUM2INT(argv[i]));
539
+ ANY2P(args[i]) = DLVOIDP(&(ANY2I(dargs[i])));
540
+ dtypes[i] = 'i';
541
+ PUSH_P(ftype);
542
+ break;
543
+ case 'L':
544
+ ANY2L(args[i]) = DLNUM2LONG(argv[i]);
545
+ PUSH_L(ftype);
546
+ break;
547
+ case 'l':
548
+ ANY2L(dargs[i]) = DLNUM2LONG(argv[i]);
549
+ ANY2P(args[i]) = DLVOIDP(&(ANY2L(dargs[i])));
550
+ dtypes[i] = 'l';
551
+ PUSH_P(ftype);
552
+ break;
553
+ case 'F':
554
+ Check_Type(argv[i], T_FLOAT);
555
+ ANY2F(args[i]) = DLFLOAT(RFLOAT(argv[i])->value);
556
+ PUSH_F(ftype);
557
+ break;
558
+ case 'f':
559
+ Check_Type(argv[i], T_FLOAT);
560
+ ANY2F(dargs[i]) = DLFLOAT(RFLOAT(argv[i])->value);
561
+ ANY2P(args[i]) = DLVOIDP(&(ANY2F(dargs[i])));
562
+ dtypes[i] = 'f';
563
+ PUSH_P(ftype);
564
+ break;
565
+ case 'D':
566
+ Check_Type(argv[i], T_FLOAT);
567
+ ANY2D(args[i]) = RFLOAT(argv[i])->value;
568
+ PUSH_D(ftype);
569
+ break;
570
+ case 'd':
571
+ Check_Type(argv[i], T_FLOAT);
572
+ ANY2D(dargs[i]) = RFLOAT(argv[i])->value;
573
+ ANY2P(args[i]) = DLVOIDP(&(ANY2D(dargs[i])));
574
+ dtypes[i] = 'd';
575
+ PUSH_P(ftype);
576
+ break;
577
+ case 'S':
578
+ if( argv[i] == Qnil ){
579
+ ANY2S(args[i]) = DLSTR(0);
580
+ }
581
+ else{
582
+ VALUE str = argv[i];
583
+ SafeStringValue(str);
584
+ ANY2S(args[i]) = DLSTR(RSTRING(str)->ptr);
585
+ }
586
+ PUSH_P(ftype);
587
+ break;
588
+ case 's':
589
+ {
590
+ VALUE str = argv[i];
591
+ SafeStringValue(str);
592
+ ANY2S(args[i]) = DLSTR(dlmalloc(RSTRING(str)->len + 1));
593
+ memcpy((char*)(ANY2S(args[i])), RSTRING(str)->ptr, RSTRING(str)->len + 1);
594
+ dtypes[i] = 's';
595
+ }
596
+ PUSH_P(ftype);
597
+ break;
598
+ default:
599
+ FREE_ARGS;
600
+ rb_raise(rb_eDLTypeError,
601
+ "unknown type '%c' of the return value.",
602
+ sym->type[i+1]);
603
+ }
604
+ }
605
+
606
+ switch( sym->type[0] ){
607
+ case '0':
608
+ PUSH_0(ftype);
609
+ break;
610
+ case 'P':
611
+ case 'p':
612
+ case 'S':
613
+ case 's':
614
+ case 'A':
615
+ case 'a':
616
+ PUSH_P(ftype);
617
+ break;
618
+ case 'C':
619
+ case 'c':
620
+ PUSH_C(ftype);
621
+ break;
622
+ case 'H':
623
+ case 'h':
624
+ PUSH_H(ftype);
625
+ break;
626
+ case 'I':
627
+ case 'i':
628
+ PUSH_I(ftype);
629
+ break;
630
+ case 'L':
631
+ case 'l':
632
+ PUSH_L(ftype);
633
+ break;
634
+ case 'F':
635
+ case 'f':
636
+ PUSH_F(ftype);
637
+ break;
638
+ case 'D':
639
+ case 'd':
640
+ PUSH_D(ftype);
641
+ break;
642
+ default:
643
+ FREE_ARGS;
644
+ rb_raise(rb_eDLTypeError,
645
+ "unknown type `%c' of the return value.",
646
+ sym->type[0]);
647
+ }
648
+
649
+ func = sym->func;
650
+
651
+ #if defined(DLSTACK)
652
+ {
653
+ #if defined(DLSTACK_SIZE)
654
+ int stk_size;
655
+ long stack[DLSTACK_SIZE];
656
+ long *sp;
657
+
658
+ sp = stack;
659
+ stk_size = stack_size(sym);
660
+ if( stk_size < 0 ){
661
+ FREE_ARGS;
662
+ rb_raise(rb_eDLTypeError, "unknown type '%c'.", -stk_size);
663
+ }
664
+ else if( stk_size > (int)(DLSTACK_SIZE) ){
665
+ FREE_ARGS;
666
+ rb_raise(rb_eArgError, "too many arguments.");
667
+ }
668
+ #endif
669
+
670
+ DLSTACK_START(sym);
671
+
672
+ #if defined(DLSTACK_REVERSE)
673
+ for( i = sym->len - 2; i >= 0; i-- )
674
+ #else
675
+ for( i = 0; i <= sym->len -2; i++ )
676
+ #endif
677
+ {
678
+ switch( sym->type[i+1] ){
679
+ case 'p':
680
+ case 'P':
681
+ DLSTACK_PUSH_P(ANY2P(args[i]));
682
+ break;
683
+ case 'a':
684
+ case 'A':
685
+ DLSTACK_PUSH_P(ANY2P(args[i]));
686
+ break;
687
+ case 'C':
688
+ DLSTACK_PUSH_C(ANY2C(args[i]));
689
+ break;
690
+ case 'c':
691
+ DLSTACK_PUSH_P(ANY2P(args[i]));
692
+ break;
693
+ case 'H':
694
+ DLSTACK_PUSH_H(ANY2H(args[i]));
695
+ break;
696
+ case 'h':
697
+ DLSTACK_PUSH_P(ANY2P(args[i]));
698
+ break;
699
+ case 'I':
700
+ DLSTACK_PUSH_I(ANY2I(args[i]));
701
+ break;
702
+ case 'i':
703
+ DLSTACK_PUSH_P(ANY2P(args[i]));
704
+ break;
705
+ case 'L':
706
+ DLSTACK_PUSH_L(ANY2L(args[i]));
707
+ break;
708
+ case 'l':
709
+ DLSTACK_PUSH_P(ANY2P(args[i]));
710
+ break;
711
+ case 'F':
712
+ DLSTACK_PUSH_F(ANY2F(args[i]));
713
+ break;
714
+ case 'f':
715
+ DLSTACK_PUSH_P(ANY2P(args[i]));
716
+ break;
717
+ case 'D':
718
+ DLSTACK_PUSH_D(ANY2D(args[i]));
719
+ break;
720
+ case 'd':
721
+ DLSTACK_PUSH_P(ANY2P(args[i]));
722
+ break;
723
+ case 'S':
724
+ case 's':
725
+ DLSTACK_PUSH_P(ANY2S(args[i]));
726
+ break;
727
+ }
728
+ }
729
+ DLSTACK_END(sym->type);
730
+
731
+ #ifdef DLSTACK_GUARD
732
+ if(!rb_dlsym_guardcall(sym->type[0], &ret, stack, func)) {
733
+ FREE_ARGS;
734
+ rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
735
+ }
736
+ #else /* defined(DLSTACK_GUARD) */
737
+ {
738
+ switch( sym->type[0] ){
739
+ case '0':
740
+ {
741
+ void (*f)(DLSTACK_PROTO) = func;
742
+ f(DLSTACK_ARGS);
743
+ }
744
+ break;
745
+ case 'P':
746
+ case 'p':
747
+ {
748
+ void * (*f)(DLSTACK_PROTO) = func;
749
+ ret.p = f(DLSTACK_ARGS);
750
+ }
751
+ break;
752
+ case 'C':
753
+ case 'c':
754
+ {
755
+ char (*f)(DLSTACK_PROTO) = func;
756
+ ret.c = f(DLSTACK_ARGS);
757
+ }
758
+ break;
759
+ case 'H':
760
+ case 'h':
761
+ {
762
+ short (*f)(DLSTACK_PROTO) = func;
763
+ ret.h = f(DLSTACK_ARGS);
764
+ }
765
+ break;
766
+ case 'I':
767
+ case 'i':
768
+ {
769
+ int (*f)(DLSTACK_PROTO) = func;
770
+ ret.i = f(DLSTACK_ARGS);
771
+ }
772
+ break;
773
+ case 'L':
774
+ case 'l':
775
+ {
776
+ long (*f)(DLSTACK_PROTO) = func;
777
+ ret.l = f(DLSTACK_ARGS);
778
+ }
779
+ break;
780
+ case 'F':
781
+ case 'f':
782
+ {
783
+ float (*f)(DLSTACK_PROTO) = func;
784
+ ret.f = f(DLSTACK_ARGS);
785
+ }
786
+ break;
787
+ case 'D':
788
+ case 'd':
789
+ {
790
+ double (*f)(DLSTACK_PROTO) = func;
791
+ ret.d = f(DLSTACK_ARGS);
792
+ }
793
+ break;
794
+ case 'S':
795
+ case 's':
796
+ {
797
+ char * (*f)(DLSTACK_PROTO) = func;
798
+ ret.s = f(DLSTACK_ARGS);
799
+ }
800
+ break;
801
+ default:
802
+ FREE_ARGS;
803
+ rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
804
+ }
805
+ }
806
+ #endif /* defubed(DLSTACK_GUARD) */
807
+
808
+ {
809
+ /*
810
+ * We should get the value of errno/GetLastError() before calling another functions.
811
+ */
812
+ int last_errno = errno;
813
+ #ifdef _WIN32
814
+ DWORD win32_last_err = GetLastError();
815
+ #endif
816
+
817
+ rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLErrno, INT2NUM(last_errno));
818
+ #ifdef _WIN32
819
+ rb_thread_local_aset(rb_thread_current(), rb_dl_id_DLW32Error, INT2NUM(win32_last_err));
820
+ #endif
821
+ }
822
+
823
+ }
824
+ #else /* defined(DLSTACK) */
825
+ switch(ftype){
826
+ #include "call.func"
827
+ default:
828
+ FREE_ARGS;
829
+ rb_raise(rb_eDLTypeError, "unsupported function type `%s'", sym->type);
830
+ }
831
+ #endif /* defined(DLSTACK) */
832
+
833
+ switch( sym->type[0] ){
834
+ case '0':
835
+ val = Qnil;
836
+ break;
837
+ case 'P':
838
+ val = rb_dlptr_new((void*)(ANY2P(ret)), 0, 0);
839
+ break;
840
+ case 'p':
841
+ val = rb_dlptr_new((void*)(ANY2P(ret)), 0, dlfree);
842
+ break;
843
+ case 'C':
844
+ case 'c':
845
+ val = CHR2FIX((char)(ANY2C(ret)));
846
+ break;
847
+ case 'H':
848
+ case 'h':
849
+ val = INT2NUM((short)(ANY2H(ret)));
850
+ break;
851
+ case 'I':
852
+ case 'i':
853
+ val = INT2NUM((int)(ANY2I(ret)));
854
+ break;
855
+ case 'L':
856
+ case 'l':
857
+ val = DLLONG2NUM((long)(ANY2L(ret)));
858
+ break;
859
+ case 'F':
860
+ case 'f':
861
+ val = rb_float_new((double)(ANY2F(ret)));
862
+ break;
863
+ case 'D':
864
+ case 'd':
865
+ val = rb_float_new((double)(ANY2D(ret)));
866
+ break;
867
+ case 'S':
868
+ if( ANY2S(ret) ){
869
+ val = rb_tainted_str_new2((char*)(ANY2S(ret)));
870
+ }
871
+ else{
872
+ val = Qnil;
873
+ }
874
+ break;
875
+ case 's':
876
+ if( ANY2S(ret) ){
877
+ val = rb_tainted_str_new2((char*)(ANY2S(ret)));
878
+ DEBUG_CODE({
879
+ printf("dlfree(%s)\n",(char*)(ANY2S(ret)));
880
+ });
881
+ dlfree((void*)(ANY2S(ret)));
882
+ }
883
+ else{
884
+ val = Qnil;
885
+ }
886
+ break;
887
+ default:
888
+ FREE_ARGS;
889
+ rb_raise(rb_eDLTypeError, "unknown type `%c'", sym->type[0]);
890
+ }
891
+
892
+ dvals = rb_ary_new();
893
+ for( i = 0; i <= sym->len - 2; i++ ){
894
+ if( dtypes[i] ){
895
+ switch( dtypes[i] ){
896
+ case 'c':
897
+ rb_ary_push(dvals, CHR2FIX(*((char*)(ANY2P(args[i])))));
898
+ break;
899
+ case 'h':
900
+ rb_ary_push(dvals, INT2NUM(*((short*)(ANY2P(args[i])))));
901
+ break;
902
+ case 'i':
903
+ rb_ary_push(dvals, INT2NUM(*((int*)(ANY2P(args[i])))));
904
+ break;
905
+ case 'l':
906
+ rb_ary_push(dvals, DLLONG2NUM(*((long*)(ANY2P(args[i])))));
907
+ break;
908
+ case 'f':
909
+ rb_ary_push(dvals, rb_float_new(*((float*)(ANY2P(args[i])))));
910
+ break;
911
+ case 'd':
912
+ rb_ary_push(dvals, rb_float_new(*((double*)(ANY2P(args[i])))));
913
+ break;
914
+ case 'p':
915
+ rb_ary_push(dvals, rb_dlptr_new((void*)(ANY2P(args[i])), 0, 0));
916
+ break;
917
+ case 'a':
918
+ rb_ary_push(dvals, rb_dlptr_new((void*)ANY2P(args[i]), 0, 0));
919
+ break;
920
+ case 's':
921
+ rb_ary_push(dvals, rb_tainted_str_new2((char*)ANY2S(args[i])));
922
+ DEBUG_CODE({
923
+ printf("dlfree(%s)\n",(char*)ANY2S(args[i]));
924
+ });
925
+ dlfree((void*)ANY2S(args[i]));
926
+ break;
927
+ default:
928
+ {
929
+ char c = dtypes[i];
930
+ FREE_ARGS;
931
+ rb_raise(rb_eRuntimeError, "unknown argument type '%c'", i, c);
932
+ }
933
+ }
934
+ }
935
+ else{
936
+ switch( sym->type[i+1] ){
937
+ case 'A':
938
+ dlfree((void*)ANY2P(args[i]));
939
+ break;
940
+ }
941
+ rb_ary_push(dvals, argv[i]);
942
+ }
943
+ }
944
+
945
+ FREE_ARGS;
946
+ #undef FREE_ARGS
947
+ return rb_assoc_new(val,dvals);
948
+ }
949
+
950
+ VALUE
951
+ rb_dlsym_to_i(VALUE self)
952
+ {
953
+ struct sym_data *sym;
954
+
955
+ Data_Get_Struct(self, struct sym_data, sym);
956
+ return DLLONG2NUM(sym);
957
+ }
958
+
959
+ VALUE
960
+ rb_dlsym_to_ptr(VALUE self)
961
+ {
962
+ struct sym_data *sym;
963
+
964
+ Data_Get_Struct(self, struct sym_data, sym);
965
+ return rb_dlptr_new(sym->func, sizeof(freefunc_t), 0);
966
+ }
967
+
968
+ void
969
+ Init_dlsym()
970
+ {
971
+ rb_cDLSymbol = rb_define_class_under(rb_mDL, "Symbol", rb_cObject);
972
+ rb_define_alloc_func(rb_cDLSymbol, rb_dlsym_s_allocate);
973
+ rb_define_singleton_method(rb_cDLSymbol, "char2type", rb_s_dlsym_char2type, 1);
974
+ rb_define_method(rb_cDLSymbol, "initialize", rb_dlsym_initialize, -1);
975
+ rb_define_method(rb_cDLSymbol, "call", rb_dlsym_call, -1);
976
+ rb_define_method(rb_cDLSymbol, "[]", rb_dlsym_call, -1);
977
+ rb_define_method(rb_cDLSymbol, "name", rb_dlsym_name, 0);
978
+ rb_define_method(rb_cDLSymbol, "proto", rb_dlsym_proto, 0);
979
+ rb_define_method(rb_cDLSymbol, "cproto", rb_dlsym_cproto, 0);
980
+ rb_define_method(rb_cDLSymbol, "inspect", rb_dlsym_inspect, 0);
981
+ rb_define_method(rb_cDLSymbol, "to_s", rb_dlsym_cproto, 0);
982
+ rb_define_method(rb_cDLSymbol, "to_ptr", rb_dlsym_to_ptr, 0);
983
+ rb_define_method(rb_cDLSymbol, "to_i", rb_dlsym_to_i, 0);
984
+
985
+ rb_dl_id_DLErrno = rb_intern("DLErrno");
986
+ rb_define_singleton_method(rb_mDL, "last_error", rb_dl_get_last_error, 0);
987
+ rb_define_singleton_method(rb_mDL, "last_error=", rb_dl_set_last_error, 1);
988
+ #ifdef _WIN32
989
+ rb_dl_id_DLW32Error = rb_intern("DLW32Error");
990
+ rb_define_singleton_method(rb_mDL, "win32_last_error", rb_dl_win32_get_last_error, 0);
991
+ rb_define_singleton_method(rb_mDL, "win32_last_error=", rb_dl_win32_set_last_error, 1);
992
+ #endif
993
+ }