rubysl-dl 0.0.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+ }