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,215 @@
1
+ /* -*- C -*-
2
+ * $Id: handle.c 11708 2007-02-12 23:01:19Z shyouhei $
3
+ */
4
+
5
+ #include <ruby.h>
6
+ #include "dl.h"
7
+
8
+ VALUE rb_cDLHandle;
9
+
10
+ void
11
+ dlhandle_free(struct dl_handle *dlhandle)
12
+ {
13
+ if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) {
14
+ dlclose(dlhandle->ptr);
15
+ }
16
+ }
17
+
18
+ VALUE
19
+ rb_dlhandle_close(VALUE self)
20
+ {
21
+ struct dl_handle *dlhandle;
22
+
23
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
24
+ dlhandle->open = 0;
25
+ return INT2NUM(dlclose(dlhandle->ptr));
26
+ }
27
+
28
+ VALUE
29
+ rb_dlhandle_s_allocate(VALUE klass)
30
+ {
31
+ VALUE obj;
32
+ struct dl_handle *dlhandle;
33
+
34
+ obj = Data_Make_Struct(rb_cDLHandle, struct dl_handle, 0,
35
+ dlhandle_free, dlhandle);
36
+ dlhandle->ptr = 0;
37
+ dlhandle->open = 0;
38
+ dlhandle->enable_close = 0;
39
+
40
+ return obj;
41
+ }
42
+
43
+ VALUE
44
+ rb_dlhandle_initialize(int argc, VALUE argv[], VALUE self)
45
+ {
46
+ void *ptr;
47
+ struct dl_handle *dlhandle;
48
+ VALUE lib, flag;
49
+ char *clib = 0;
50
+ int cflag = 0;
51
+ const char *err;
52
+
53
+ switch (rb_scan_args(argc, argv, "11", &lib, &flag)) {
54
+ case 1:
55
+ clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
56
+ cflag = RTLD_LAZY | RTLD_GLOBAL;
57
+ break;
58
+ case 2:
59
+ clib = NIL_P(lib) ? NULL : StringValuePtr(lib);
60
+ cflag = NUM2INT(flag);
61
+ break;
62
+ default:
63
+ rb_bug("rb_dlhandle_new");
64
+ }
65
+
66
+ ptr = dlopen(clib, cflag);
67
+ #if defined(HAVE_DLERROR)
68
+ if (!ptr && (err = dlerror())) {
69
+ rb_raise(rb_eRuntimeError, "%s", err);
70
+ }
71
+ #else
72
+ if (!ptr) {
73
+ err = dlerror();
74
+ rb_raise(rb_eRuntimeError, "%s", err);
75
+ }
76
+ #endif
77
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
78
+ if (dlhandle->ptr && dlhandle->open && dlhandle->enable_close) {
79
+ dlclose(dlhandle->ptr);
80
+ }
81
+ dlhandle->ptr = ptr;
82
+ dlhandle->open = 1;
83
+ dlhandle->enable_close = 0;
84
+
85
+ if (rb_block_given_p()) {
86
+ rb_ensure(rb_yield, self, rb_dlhandle_close, self);
87
+ }
88
+
89
+ return Qnil;
90
+ }
91
+
92
+ VALUE
93
+ rb_dlhandle_enable_close(VALUE self)
94
+ {
95
+ struct dl_handle *dlhandle;
96
+
97
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
98
+ dlhandle->enable_close = 1;
99
+ return Qnil;
100
+ }
101
+
102
+ VALUE
103
+ rb_dlhandle_disable_close(VALUE self)
104
+ {
105
+ struct dl_handle *dlhandle;
106
+
107
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
108
+ dlhandle->enable_close = 0;
109
+ return Qnil;
110
+ }
111
+
112
+ VALUE
113
+ rb_dlhandle_to_i(VALUE self)
114
+ {
115
+ struct dl_handle *dlhandle;
116
+
117
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
118
+ return DLLONG2NUM(dlhandle);
119
+ }
120
+
121
+ VALUE
122
+ rb_dlhandle_to_ptr(VALUE self)
123
+ {
124
+ struct dl_handle *dlhandle;
125
+
126
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
127
+ return rb_dlptr_new(dlhandle, sizeof(dlhandle), 0);
128
+ }
129
+
130
+ VALUE
131
+ rb_dlhandle_sym(int argc, VALUE argv[], VALUE self)
132
+ {
133
+ VALUE sym, type;
134
+ void (*func)();
135
+ VALUE val;
136
+ struct dl_handle *dlhandle;
137
+ void *handle;
138
+ const char *name, *stype;
139
+ const char *err;
140
+
141
+ rb_secure(2);
142
+ if (rb_scan_args(argc, argv, "11", &sym, &type) == 2) {
143
+ SafeStringValue(type);
144
+ stype = StringValuePtr(type);
145
+ }
146
+ else{
147
+ stype = NULL;
148
+ }
149
+
150
+ if (sym == Qnil) {
151
+ #if defined(RTLD_NEXT)
152
+ name = RTLD_NEXT;
153
+ #else
154
+ name = NULL;
155
+ #endif
156
+ }
157
+ else{
158
+ SafeStringValue(sym);
159
+ name = StringValuePtr(sym);
160
+ }
161
+
162
+ Data_Get_Struct(self, struct dl_handle, dlhandle);
163
+ if (!dlhandle->open) {
164
+ rb_raise(rb_eRuntimeError, "closed handle");
165
+ }
166
+ handle = dlhandle->ptr;
167
+
168
+ func = dlsym(handle, name);
169
+ #if defined(HAVE_DLERROR)
170
+ if (!func && (err = dlerror()))
171
+ #else
172
+ if (!func)
173
+ #endif
174
+ {
175
+ #if defined(__CYGWIN__) || defined(WIN32) || defined(__MINGW32__)
176
+ {
177
+ int len = strlen(name);
178
+ char *name_a = (char*)dlmalloc(len+2);
179
+ strcpy(name_a, name);
180
+ name_a[len] = 'A';
181
+ name_a[len+1] = '\0';
182
+ func = dlsym(handle, name_a);
183
+ dlfree(name_a);
184
+ #if defined(HAVE_DLERROR)
185
+ if (!func && (err = dlerror()))
186
+ #else
187
+ if (!func)
188
+ #endif
189
+ {
190
+ rb_raise(rb_eRuntimeError, "unknown symbol \"%sA\"", name);
191
+ }
192
+ }
193
+ #else
194
+ rb_raise(rb_eRuntimeError, "unknown symbol \"%s\"", name);
195
+ #endif
196
+ }
197
+ val = rb_dlsym_new(func, name, stype);
198
+
199
+ return val;
200
+ }
201
+
202
+ void
203
+ Init_dlhandle()
204
+ {
205
+ rb_cDLHandle = rb_define_class_under(rb_mDL, "Handle", rb_cObject);
206
+ rb_define_alloc_func(rb_cDLHandle, rb_dlhandle_s_allocate);
207
+ rb_define_method(rb_cDLHandle, "initialize", rb_dlhandle_initialize, -1);
208
+ rb_define_method(rb_cDLHandle, "to_i", rb_dlhandle_to_i, 0);
209
+ rb_define_method(rb_cDLHandle, "to_ptr", rb_dlhandle_to_ptr, 0);
210
+ rb_define_method(rb_cDLHandle, "close", rb_dlhandle_close, 0);
211
+ rb_define_method(rb_cDLHandle, "sym", rb_dlhandle_sym, -1);
212
+ rb_define_method(rb_cDLHandle, "[]", rb_dlhandle_sym, -1);
213
+ rb_define_method(rb_cDLHandle, "disable_close", rb_dlhandle_disable_close, 0);
214
+ rb_define_method(rb_cDLHandle, "enable_close", rb_dlhandle_enable_close, 0);
215
+ }
@@ -0,0 +1,49 @@
1
+ require 'mkmf'
2
+ require 'ftools'
3
+
4
+ SO_LIBS = ["dl.so"]
5
+
6
+ $ruby_version = CONFIG['MAJOR'] + "." + CONFIG['MINOR']
7
+ $prefix = CONFIG['prefix']
8
+ $libdir = File.join($prefix,'lib')
9
+ $rubylibdir = File.join($libdir, 'ruby', $ruby_version)
10
+ $arch = CONFIG['arch']
11
+ $archdir = File.join($rubylibdir, $arch)
12
+
13
+ def find(dir, match = /./)
14
+ Dir.chdir(dir)
15
+ files = []
16
+ Dir.new(".").each{|file|
17
+ if( file != "." && file != ".." )
18
+ case File.ftype(file)
19
+ when "file"
20
+ if( file =~ match )
21
+ files.push(File.join(dir,file))
22
+ end
23
+ when "directory"
24
+ files += find(file, match).collect{|f| File.join(dir,f)}
25
+ end
26
+ end
27
+ }
28
+ Dir.chdir("..")
29
+ return files
30
+ end
31
+
32
+ def install()
33
+ rb_files = find(File.join(".","lib"), /.rb$/)
34
+
35
+ SO_LIBS.each{|f|
36
+ File.makedirs($rubylibdir, "#{$archdir}")
37
+ File.install(f, File.join($archdir,f), 0555, true)
38
+ }
39
+
40
+ rb_files.each{|f|
41
+ origfile = f
42
+ instfile = File.join($rubylibdir, origfile.sub("./lib/",""))
43
+ instdir = File.dirname(instfile)
44
+ File.makedirs(instdir)
45
+ File.install(origfile, instfile, 0644, true)
46
+ }
47
+ end
48
+
49
+ install()
@@ -0,0 +1,225 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'dl'
4
+ require 'dl/types'
5
+
6
+ module DL
7
+ module Importable
8
+ LIB_MAP = {}
9
+
10
+ module Internal
11
+ def init_types()
12
+ @types ||= ::DL::Types.new
13
+ end
14
+
15
+ def init_sym()
16
+ @SYM ||= {}
17
+ end
18
+
19
+ def [](name)
20
+ return @SYM[name.to_s][0]
21
+ end
22
+
23
+ def dlload(*libnames)
24
+ if( !defined?(@LIBS) )
25
+ @LIBS = []
26
+ end
27
+ libnames.each{|libname|
28
+ if( !LIB_MAP[libname] )
29
+ LIB_MAP[libname] = DL.dlopen(libname)
30
+ end
31
+ @LIBS.push(LIB_MAP[libname])
32
+ }
33
+ end
34
+ alias dllink :dlload
35
+
36
+ def parse_cproto(proto)
37
+ proto = proto.gsub(/\s+/, " ").strip
38
+ case proto
39
+ when /^([\d\w\*_\s]+)\(([\d\w\*_\s\,\[\]]*)\)$/
40
+ ret = $1
41
+ args = $2.strip()
42
+ ret = ret.split(/\s+/)
43
+ args = args.split(/\s*,\s*/)
44
+ func = ret.pop()
45
+ if( func =~ /^\*/ )
46
+ func.gsub!(/^\*+/,"")
47
+ ret.push("*")
48
+ end
49
+ ret = ret.join(" ")
50
+ return [func, ret, args]
51
+ else
52
+ raise(RuntimeError,"can't parse the function prototype: #{proto}")
53
+ end
54
+ end
55
+
56
+ # example:
57
+ # extern "int strlen(char*)"
58
+ #
59
+ def extern(proto)
60
+ func,ret,args = parse_cproto(proto)
61
+ return import(func, ret, args)
62
+ end
63
+
64
+ # example:
65
+ # callback "int method_name(int, char*)"
66
+ #
67
+ def callback(proto)
68
+ func,ret,args = parse_cproto(proto)
69
+
70
+ init_types()
71
+ init_sym()
72
+
73
+ rty,renc,rdec = @types.encode_return_type(ret)
74
+ if( !rty )
75
+ raise(TypeError, "unsupported type: #{ret}")
76
+ end
77
+ ty,enc,dec = encode_argument_types(args)
78
+ symty = rty + ty
79
+
80
+ module_eval("module_function :#{func}")
81
+ sym = module_eval([
82
+ "DL::callback(\"#{symty}\"){|*args|",
83
+ " sym,rdec,enc,dec = @SYM['#{func}']",
84
+ " args = enc.call(args) if enc",
85
+ " r,rs = #{func}(*args)",
86
+ " r = renc.call(r) if rdec",
87
+ " rs = dec.call(rs) if (dec && rs)",
88
+ " @retval = r",
89
+ " @args = rs",
90
+ " r",
91
+ "}",
92
+ ].join("\n"))
93
+
94
+ @SYM[func] = [sym,rdec,enc,dec]
95
+
96
+ return sym
97
+ end
98
+
99
+ # example:
100
+ # typealias("uint", "unsigned int")
101
+ #
102
+ def typealias(alias_type, ty1, enc1=nil, dec1=nil, ty2=nil, enc2=nil, dec2=nil)
103
+ init_types()
104
+ @types.typealias(alias_type, ty1, enc1, dec1,
105
+ ty2||ty1, enc2, dec2)
106
+ end
107
+
108
+ # example:
109
+ # symbol "foo_value"
110
+ # symbol "foo_func", "IIP"
111
+ #
112
+ def symbol(name, ty = nil)
113
+ sym = nil
114
+ @LIBS.each{|lib|
115
+ begin
116
+ if( ty )
117
+ sym = lib[name, ty]
118
+ else
119
+ sym = lib[name]
120
+ end
121
+ rescue
122
+ next
123
+ end
124
+ }
125
+ if( !sym )
126
+ raise(RuntimeError, "can't find the symbol `#{name}'")
127
+ end
128
+ return sym
129
+ end
130
+
131
+ # example:
132
+ # import("get_length", "int", ["void*", "int"])
133
+ #
134
+ def import(name, rettype, argtypes = nil)
135
+ init_types()
136
+ init_sym()
137
+
138
+ rty,_,rdec = @types.encode_return_type(rettype)
139
+ if( !rty )
140
+ raise(TypeError, "unsupported type: #{rettype}")
141
+ end
142
+ ty,enc,dec = encode_argument_types(argtypes)
143
+ symty = rty + ty
144
+
145
+ sym = symbol(name, symty)
146
+
147
+ mname = name.dup
148
+ if( ?A <= mname[0] && mname[0] <= ?Z )
149
+ mname[0,1] = mname[0,1].downcase
150
+ end
151
+ @SYM[mname] = [sym,rdec,enc,dec]
152
+
153
+ module_eval [
154
+ "def #{mname}(*args)",
155
+ " sym,rdec,enc,dec = @SYM['#{mname}']",
156
+ " args = enc.call(args) if enc",
157
+ if( $DEBUG )
158
+ " p \"[DL] call #{mname} with \#{args.inspect}\""
159
+ else
160
+ ""
161
+ end,
162
+ " r,rs = sym.call(*args)",
163
+ if( $DEBUG )
164
+ " p \"[DL] retval=\#{r.inspect} args=\#{rs.inspect}\""
165
+ else
166
+ ""
167
+ end,
168
+ " r = rdec.call(r) if rdec",
169
+ " rs = dec.call(rs) if dec",
170
+ " @retval = r",
171
+ " @args = rs",
172
+ " return r",
173
+ "end",
174
+ "module_function :#{mname}",
175
+ ].join("\n")
176
+
177
+ return sym
178
+ end
179
+
180
+ def _args_
181
+ return @args
182
+ end
183
+
184
+ def _retval_
185
+ return @retval
186
+ end
187
+
188
+ def encode_argument_types(tys)
189
+ init_types()
190
+ encty = []
191
+ enc = nil
192
+ dec = nil
193
+ tys.each_with_index{|ty,idx|
194
+ ty,c1,c2 = @types.encode_argument_type(ty)
195
+ if( !ty )
196
+ raise(TypeError, "unsupported type: #{ty}")
197
+ end
198
+ encty.push(ty)
199
+ if( enc )
200
+ if( c1 )
201
+ conv1 = enc
202
+ enc = proc{|v| v = conv1.call(v); v[idx] = c1.call(v[idx]); v}
203
+ end
204
+ else
205
+ if( c1 )
206
+ enc = proc{|v| v[idx] = c1.call(v[idx]); v}
207
+ end
208
+ end
209
+ if( dec )
210
+ if( c2 )
211
+ conv2 = dec
212
+ dec = proc{|v| v = conv2.call(v); v[idx] = c2.call(v[idx]); v}
213
+ end
214
+ else
215
+ if( c2 )
216
+ dec = proc{|v| v[idx] = c2.call(v[idx]); v}
217
+ end
218
+ end
219
+ }
220
+ return [encty.join, enc, dec]
221
+ end
222
+ end # end of Internal
223
+ include Internal
224
+ end # end of Importable
225
+ end