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.
- checksums.yaml +7 -0
- data/.gitignore +0 -1
- data/.travis.yml +8 -0
- data/README.md +2 -2
- data/Rakefile +0 -1
- data/ext/rubysl/dl/depend +46 -0
- data/ext/rubysl/dl/dl.c +742 -0
- data/ext/rubysl/dl/dl.def +59 -0
- data/ext/rubysl/dl/dl.h +313 -0
- data/ext/rubysl/dl/extconf.rb +193 -0
- data/ext/rubysl/dl/h2rb +500 -0
- data/ext/rubysl/dl/handle.c +215 -0
- data/ext/rubysl/dl/install.rb +49 -0
- data/ext/rubysl/dl/lib/dl/import.rb +225 -0
- data/ext/rubysl/dl/lib/dl/struct.rb +149 -0
- data/ext/rubysl/dl/lib/dl/types.rb +245 -0
- data/ext/rubysl/dl/lib/dl/win32.rb +25 -0
- data/ext/rubysl/dl/mkcall.rb +69 -0
- data/ext/rubysl/dl/mkcallback.rb +63 -0
- data/ext/rubysl/dl/mkcbtable.rb +25 -0
- data/ext/rubysl/dl/ptr.c +1062 -0
- data/ext/rubysl/dl/sample/c++sample.C +35 -0
- data/ext/rubysl/dl/sample/c++sample.rb +60 -0
- data/ext/rubysl/dl/sample/drives.rb +70 -0
- data/ext/rubysl/dl/sample/getch.rb +5 -0
- data/ext/rubysl/dl/sample/libc.rb +69 -0
- data/ext/rubysl/dl/sample/msgbox.rb +19 -0
- data/ext/rubysl/dl/sample/msgbox2.rb +18 -0
- data/ext/rubysl/dl/sample/stream.rb +87 -0
- data/ext/rubysl/dl/sym.c +993 -0
- data/ext/rubysl/dl/test/libtest.def +28 -0
- data/ext/rubysl/dl/test/test.c +247 -0
- data/ext/rubysl/dl/test/test.rb +306 -0
- data/ext/rubysl/dl/type.rb +115 -0
- data/lib/dl.rb +1 -0
- data/lib/rubysl/dl.rb +2 -0
- data/lib/rubysl/dl/version.rb +5 -0
- data/rubysl-dl.gemspec +20 -18
- metadata +109 -87
- data/lib/rubysl-dl.rb +0 -7
- data/lib/rubysl-dl/version.rb +0 -5
@@ -0,0 +1,149 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'dl'
|
4
|
+
require 'dl/import'
|
5
|
+
|
6
|
+
module DL
|
7
|
+
module Importable
|
8
|
+
module Internal
|
9
|
+
def define_struct(contents)
|
10
|
+
init_types()
|
11
|
+
Struct.new(@types, contents)
|
12
|
+
end
|
13
|
+
alias struct define_struct
|
14
|
+
|
15
|
+
def define_union(contents)
|
16
|
+
init_types()
|
17
|
+
Union.new(@types, contents)
|
18
|
+
end
|
19
|
+
alias union define_union
|
20
|
+
|
21
|
+
class Memory
|
22
|
+
def initialize(ptr, names, ty, len, enc, dec)
|
23
|
+
@ptr = ptr
|
24
|
+
@names = names
|
25
|
+
@ty = ty
|
26
|
+
@len = len
|
27
|
+
@enc = enc
|
28
|
+
@dec = dec
|
29
|
+
|
30
|
+
# define methods
|
31
|
+
@names.each{|name|
|
32
|
+
instance_eval [
|
33
|
+
"def #{name}",
|
34
|
+
" v = @ptr[\"#{name}\"]",
|
35
|
+
" if( @len[\"#{name}\"] )",
|
36
|
+
" v = v.collect{|x| @dec[\"#{name}\"] ? @dec[\"#{name}\"].call(x) : x }",
|
37
|
+
" else",
|
38
|
+
" v = @dec[\"#{name}\"].call(v) if @dec[\"#{name}\"]",
|
39
|
+
" end",
|
40
|
+
" return v",
|
41
|
+
"end",
|
42
|
+
"def #{name}=(v)",
|
43
|
+
" if( @len[\"#{name}\"] )",
|
44
|
+
" v = v.collect{|x| @enc[\"#{name}\"] ? @enc[\"#{name}\"].call(x) : x }",
|
45
|
+
" else",
|
46
|
+
" v = @enc[\"#{name}\"].call(v) if @enc[\"#{name}\"]",
|
47
|
+
" end",
|
48
|
+
" @ptr[\"#{name}\"] = v",
|
49
|
+
" return v",
|
50
|
+
"end",
|
51
|
+
].join("\n")
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
def to_ptr
|
56
|
+
return @ptr
|
57
|
+
end
|
58
|
+
|
59
|
+
def size
|
60
|
+
return @ptr.size
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class Struct
|
65
|
+
def initialize(types, contents)
|
66
|
+
@names = []
|
67
|
+
@ty = {}
|
68
|
+
@len = {}
|
69
|
+
@enc = {}
|
70
|
+
@dec = {}
|
71
|
+
@size = 0
|
72
|
+
@tys = ""
|
73
|
+
@types = types
|
74
|
+
parse(contents)
|
75
|
+
end
|
76
|
+
|
77
|
+
def size
|
78
|
+
return @size
|
79
|
+
end
|
80
|
+
|
81
|
+
def members
|
82
|
+
return @names
|
83
|
+
end
|
84
|
+
|
85
|
+
# ptr must be a PtrData object.
|
86
|
+
def new(ptr)
|
87
|
+
ptr.struct!(@tys, *@names)
|
88
|
+
mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec)
|
89
|
+
return mem
|
90
|
+
end
|
91
|
+
|
92
|
+
def malloc(size = nil)
|
93
|
+
if( !size )
|
94
|
+
size = @size
|
95
|
+
end
|
96
|
+
ptr = DL::malloc(size)
|
97
|
+
return new(ptr)
|
98
|
+
end
|
99
|
+
|
100
|
+
def parse(contents)
|
101
|
+
contents.each{|elem|
|
102
|
+
name,ty,num,enc,dec = parse_elem(elem)
|
103
|
+
@names.push(name)
|
104
|
+
@ty[name] = ty
|
105
|
+
@len[name] = num
|
106
|
+
@enc[name] = enc
|
107
|
+
@dec[name] = dec
|
108
|
+
if( num )
|
109
|
+
@tys += "#{ty}#{num}"
|
110
|
+
else
|
111
|
+
@tys += ty
|
112
|
+
end
|
113
|
+
}
|
114
|
+
@size = DL.sizeof(@tys)
|
115
|
+
end
|
116
|
+
|
117
|
+
def parse_elem(elem)
|
118
|
+
elem.strip!
|
119
|
+
case elem
|
120
|
+
when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)$/
|
121
|
+
ty = ($1 + $2).strip
|
122
|
+
name = $3
|
123
|
+
num = nil;
|
124
|
+
when /^([\w\d_\*]+)([\*\s]+)([\w\d_]+)\[(\d+)\]$/
|
125
|
+
ty = ($1 + $2).strip
|
126
|
+
name = $3
|
127
|
+
num = $4.to_i
|
128
|
+
else
|
129
|
+
raise(RuntimeError, "invalid element: #{elem}")
|
130
|
+
end
|
131
|
+
ty,enc,dec = @types.encode_struct_type(ty)
|
132
|
+
if( !ty )
|
133
|
+
raise(TypeError, "unsupported type: #{ty}")
|
134
|
+
end
|
135
|
+
return [name,ty,num,enc,dec]
|
136
|
+
end
|
137
|
+
end # class Struct
|
138
|
+
|
139
|
+
class Union < Struct
|
140
|
+
def new
|
141
|
+
ptr = DL::malloc(@size)
|
142
|
+
ptr.union!(@tys, *@names)
|
143
|
+
mem = Memory.new(ptr, @names, @ty, @len, @enc, @dec)
|
144
|
+
return mem
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end # module Internal
|
148
|
+
end # module Importable
|
149
|
+
end # module DL
|
@@ -0,0 +1,245 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'dl'
|
4
|
+
|
5
|
+
module DL
|
6
|
+
class Types
|
7
|
+
TYPES = [
|
8
|
+
# FORMAT:
|
9
|
+
# ["alias name",
|
10
|
+
# "type name", encoding_method, decoding_method, for function prototypes
|
11
|
+
# "type name", encoding_method, decoding_method] for structures (not implemented)
|
12
|
+
|
13
|
+
# for Windows
|
14
|
+
["DWORD", "unsigned long", nil, nil,
|
15
|
+
"unsigned long", nil, nil],
|
16
|
+
["PDWORD", "unsigned long *", nil, nil,
|
17
|
+
"unsigned long *", nil, nil],
|
18
|
+
["WORD", "unsigned short", nil, nil,
|
19
|
+
"unsigned short", nil, nil],
|
20
|
+
["PWORD", "unsigned int *", nil, nil,
|
21
|
+
"unsigned int *", nil, nil],
|
22
|
+
["BYTE", "unsigned char", nil, nil,
|
23
|
+
"unsigned char", nil, nil],
|
24
|
+
["PBYTE", "unsigned char *", nil, nil,
|
25
|
+
"unsigned char *", nil, nil],
|
26
|
+
["BOOL", "ibool", nil, nil,
|
27
|
+
"ibool", nil, nil],
|
28
|
+
["ATOM", "int", nil, nil,
|
29
|
+
"int", nil, nil],
|
30
|
+
["BYTE", "unsigned char", nil, nil,
|
31
|
+
"unsigned char", nil, nil],
|
32
|
+
["PBYTE", "unsigned char *", nil, nil,
|
33
|
+
"unsigned char *", nil, nil],
|
34
|
+
["UINT", "unsigned int", nil, nil,
|
35
|
+
"unsigned int", nil, nil],
|
36
|
+
["ULONG", "unsigned long", nil, nil,
|
37
|
+
"unsigned long", nil, nil],
|
38
|
+
["UCHAR", "unsigned char", nil, nil,
|
39
|
+
"unsigned char", nil, nil],
|
40
|
+
["HANDLE", "unsigned long", nil, nil,
|
41
|
+
"unsigned long", nil, nil],
|
42
|
+
["PHANDLE","void*", nil, nil,
|
43
|
+
"void*", nil, nil],
|
44
|
+
["PVOID", "void*", nil, nil,
|
45
|
+
"void*", nil, nil],
|
46
|
+
["LPCSTR", "char*", nil, nil,
|
47
|
+
"char*", nil, nil],
|
48
|
+
["HDC", "unsigned int", nil, nil,
|
49
|
+
"unsigned int", nil, nil],
|
50
|
+
["HWND", "unsigned int", nil, nil,
|
51
|
+
"unsigned int", nil, nil],
|
52
|
+
|
53
|
+
# Others
|
54
|
+
["uint", "unsigned int", nil, nil,
|
55
|
+
"unsigned int", nil, nil],
|
56
|
+
["u_int", "unsigned int", nil, nil,
|
57
|
+
"unsigned int", nil, nil],
|
58
|
+
["ulong", "unsigned long", nil, nil,
|
59
|
+
"unsigned long", nil, nil],
|
60
|
+
["u_long", "unsigned long", nil, nil,
|
61
|
+
"unsigned long", nil, nil],
|
62
|
+
|
63
|
+
# DL::Importable primitive types
|
64
|
+
["ibool",
|
65
|
+
"I",
|
66
|
+
proc{|v| v ? 1 : 0},
|
67
|
+
proc{|v| (v != 0) ? true : false},
|
68
|
+
"I",
|
69
|
+
proc{|v| v ? 1 : 0 },
|
70
|
+
proc{|v| (v != 0) ? true : false} ],
|
71
|
+
["cbool",
|
72
|
+
"C",
|
73
|
+
proc{|v| v ? 1 : 0},
|
74
|
+
proc{|v| (v != 0) ? true : false},
|
75
|
+
"C",
|
76
|
+
proc{|v,len| v ? 1 : 0},
|
77
|
+
proc{|v,len| (v != 0) ? true : false}],
|
78
|
+
["lbool",
|
79
|
+
"L",
|
80
|
+
proc{|v| v ? 1 : 0},
|
81
|
+
proc{|v| (v != 0) ? true : false},
|
82
|
+
"L",
|
83
|
+
proc{|v,len| v ? 1 : 0},
|
84
|
+
proc{|v,len| (v != 0) ? true : false}],
|
85
|
+
["unsigned char",
|
86
|
+
"C",
|
87
|
+
proc{|v| [v].pack("C").unpack("c")[0]},
|
88
|
+
proc{|v| [v].pack("c").unpack("C")[0]},
|
89
|
+
"C",
|
90
|
+
proc{|v| [v].pack("C").unpack("c")[0]},
|
91
|
+
proc{|v| [v].pack("c").unpack("C")[0]}],
|
92
|
+
["unsigned short",
|
93
|
+
"H",
|
94
|
+
proc{|v| [v].pack("S").unpack("s")[0]},
|
95
|
+
proc{|v| [v].pack("s").unpack("S")[0]},
|
96
|
+
"H",
|
97
|
+
proc{|v| [v].pack("S").unpack("s")[0]},
|
98
|
+
proc{|v| [v].pack("s").unpack("S")[0]}],
|
99
|
+
["unsigned int",
|
100
|
+
"I",
|
101
|
+
proc{|v| [v].pack("I").unpack("i")[0]},
|
102
|
+
proc{|v| [v].pack("i").unpack("I")[0]},
|
103
|
+
"I",
|
104
|
+
proc{|v| [v].pack("I").unpack("i")[0]},
|
105
|
+
proc{|v| [v].pack("i").unpack("I")[0]}],
|
106
|
+
["unsigned long",
|
107
|
+
"L",
|
108
|
+
proc{|v| [v].pack("L").unpack("l")[0]},
|
109
|
+
proc{|v| [v].pack("l").unpack("L")[0]},
|
110
|
+
"L",
|
111
|
+
proc{|v| [v].pack("L").unpack("l")[0]},
|
112
|
+
proc{|v| [v].pack("l").unpack("L")[0]}],
|
113
|
+
["unsigned char ref",
|
114
|
+
"c",
|
115
|
+
proc{|v| [v].pack("C").unpack("c")[0]},
|
116
|
+
proc{|v| [v].pack("c").unpack("C")[0]},
|
117
|
+
nil, nil, nil],
|
118
|
+
["unsigned int ref",
|
119
|
+
"i",
|
120
|
+
proc{|v| [v].pack("I").unpack("i")[0]},
|
121
|
+
proc{|v| [v].pack("i").unpack("I")[0]},
|
122
|
+
nil, nil, nil],
|
123
|
+
["unsigned long ref",
|
124
|
+
"l",
|
125
|
+
proc{|v| [v].pack("L").unpack("l")[0]},
|
126
|
+
proc{|v| [v].pack("l").unpack("L")[0]},
|
127
|
+
nil, nil, nil],
|
128
|
+
["char ref", "c", nil, nil,
|
129
|
+
nil, nil, nil],
|
130
|
+
["short ref", "h", nil, nil,
|
131
|
+
nil, nil, nil],
|
132
|
+
["int ref", "i", nil, nil,
|
133
|
+
nil, nil, nil],
|
134
|
+
["long ref", "l", nil, nil,
|
135
|
+
nil, nil, nil],
|
136
|
+
["float ref", "f", nil, nil,
|
137
|
+
nil, nil, nil],
|
138
|
+
["double ref","d", nil, nil,
|
139
|
+
nil, nil, nil],
|
140
|
+
["char", "C", nil, nil,
|
141
|
+
"C", nil, nil],
|
142
|
+
["short", "H", nil, nil,
|
143
|
+
"H", nil, nil],
|
144
|
+
["int", "I", nil, nil,
|
145
|
+
"I", nil, nil],
|
146
|
+
["long", "L", nil, nil,
|
147
|
+
"L", nil, nil],
|
148
|
+
["float", "F", nil, nil,
|
149
|
+
"F", nil, nil],
|
150
|
+
["double", "D", nil, nil,
|
151
|
+
"D", nil, nil],
|
152
|
+
[/^char\s*\*$/,"s",nil, nil,
|
153
|
+
"S",nil, nil],
|
154
|
+
[/^const char\s*\*$/,"S",nil, nil,
|
155
|
+
"S",nil, nil],
|
156
|
+
[/^.+\*$/, "P", nil, nil,
|
157
|
+
"P", nil, nil],
|
158
|
+
[/^.+\[\]$/, "a", nil, nil,
|
159
|
+
"a", nil, nil],
|
160
|
+
["void", "0", nil, nil,
|
161
|
+
nil, nil, nil],
|
162
|
+
]
|
163
|
+
|
164
|
+
def initialize
|
165
|
+
init_types()
|
166
|
+
end
|
167
|
+
|
168
|
+
def typealias(ty1, ty2, enc=nil, dec=nil, ty3=nil, senc=nil, sdec=nil)
|
169
|
+
@TYDEFS.unshift([ty1, ty2, enc, dec, ty3, senc, sdec])
|
170
|
+
end
|
171
|
+
|
172
|
+
def init_types
|
173
|
+
@TYDEFS = TYPES.dup
|
174
|
+
end
|
175
|
+
|
176
|
+
def encode_argument_type(alias_type)
|
177
|
+
proc_encode = nil
|
178
|
+
proc_decode = nil
|
179
|
+
@TYDEFS.each{|aty,ty,enc,dec,_,_,_|
|
180
|
+
if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) )
|
181
|
+
alias_type = alias_type.gsub(aty,ty) if ty
|
182
|
+
alias_type.strip! if alias_type
|
183
|
+
if( proc_encode )
|
184
|
+
if( enc )
|
185
|
+
conv1 = proc_encode
|
186
|
+
proc_encode = proc{|v| enc.call(conv1.call(v))}
|
187
|
+
end
|
188
|
+
else
|
189
|
+
if( enc )
|
190
|
+
proc_encode = enc
|
191
|
+
end
|
192
|
+
end
|
193
|
+
if( proc_decode )
|
194
|
+
if( dec )
|
195
|
+
conv2 = proc_decode
|
196
|
+
proc_decode = proc{|v| dec.call(conv2.call(v))}
|
197
|
+
end
|
198
|
+
else
|
199
|
+
if( dec )
|
200
|
+
proc_decode = dec
|
201
|
+
end
|
202
|
+
end
|
203
|
+
end
|
204
|
+
}
|
205
|
+
return [alias_type, proc_encode, proc_decode]
|
206
|
+
end
|
207
|
+
|
208
|
+
def encode_return_type(ty)
|
209
|
+
ty, enc, dec = encode_argument_type(ty)
|
210
|
+
return [ty, enc, dec]
|
211
|
+
end
|
212
|
+
|
213
|
+
def encode_struct_type(alias_type)
|
214
|
+
proc_encode = nil
|
215
|
+
proc_decode = nil
|
216
|
+
@TYDEFS.each{|aty,_,_,_,ty,enc,dec|
|
217
|
+
if( (aty.is_a?(Regexp) && (aty =~ alias_type)) || (aty == alias_type) )
|
218
|
+
alias_type = alias_type.gsub(aty,ty) if ty
|
219
|
+
alias_type.strip! if alias_type
|
220
|
+
if( proc_encode )
|
221
|
+
if( enc )
|
222
|
+
conv1 = proc_encode
|
223
|
+
proc_encode = proc{|v| enc.call(conv1.call(v))}
|
224
|
+
end
|
225
|
+
else
|
226
|
+
if( enc )
|
227
|
+
proc_encode = enc
|
228
|
+
end
|
229
|
+
end
|
230
|
+
if( proc_decode )
|
231
|
+
if( dec )
|
232
|
+
conv2 = proc_decode
|
233
|
+
proc_decode = proc{|v| dec.call(conv2.call(v))}
|
234
|
+
end
|
235
|
+
else
|
236
|
+
if( dec )
|
237
|
+
proc_decode = dec
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
}
|
242
|
+
return [alias_type, proc_encode, proc_decode]
|
243
|
+
end
|
244
|
+
end # end of Types
|
245
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'dl'
|
4
|
+
|
5
|
+
class Win32API
|
6
|
+
DLL = {}
|
7
|
+
|
8
|
+
def initialize(dllname, func, import, export = "0")
|
9
|
+
prototype = (export + import.to_s).tr("VPpNnLlIi", "0SSI").sub(/^(.)0*$/, '\1')
|
10
|
+
handle = DLL[dllname] ||= DL::Handle.new(dllname)
|
11
|
+
@sym = handle.sym(func, prototype)
|
12
|
+
end
|
13
|
+
|
14
|
+
def call(*args)
|
15
|
+
import = @sym.proto.split("", 2)[1]
|
16
|
+
args.each_with_index do |x, i|
|
17
|
+
args[i] = nil if x == 0 and import[i] == ?S
|
18
|
+
args[i], = [x].pack("I").unpack("i") if import[i] == ?I
|
19
|
+
end
|
20
|
+
ret, = @sym.call(*args)
|
21
|
+
return ret || 0
|
22
|
+
end
|
23
|
+
|
24
|
+
alias Call call
|
25
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'mkmf'
|
4
|
+
$:.unshift File.dirname(__FILE__)
|
5
|
+
require 'type'
|
6
|
+
require 'dlconfig'
|
7
|
+
|
8
|
+
if name = ARGV.shift
|
9
|
+
OUTPUT = File.open name, "wb"
|
10
|
+
at_exit { OUTPUT.close }
|
11
|
+
else
|
12
|
+
OUTPUT = STDOUT
|
13
|
+
end
|
14
|
+
|
15
|
+
def output_arg(x,i)
|
16
|
+
"args[#{i}].#{DLTYPE[x][:stmem]}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def output_args(types)
|
20
|
+
t = []
|
21
|
+
types[1..-1].each_with_index{|x,i| t.push(output_arg(x,i))}
|
22
|
+
t.join(",")
|
23
|
+
end
|
24
|
+
|
25
|
+
def output_callfunc(types)
|
26
|
+
t = types[0]
|
27
|
+
stmem = DLTYPE[t][:stmem]
|
28
|
+
ctypes = types2ctypes(types)
|
29
|
+
if( t == VOID )
|
30
|
+
callstm = "(*f)(#{output_args(types)})"
|
31
|
+
else
|
32
|
+
callstm = "ret.#{stmem} = (*f)(#{output_args(types)})"
|
33
|
+
end
|
34
|
+
[ "{",
|
35
|
+
"#{ctypes[0]} (*f)(#{ctypes[1..-1].join(',')}) = func;",
|
36
|
+
"#{callstm};",
|
37
|
+
"}"].join(" ")
|
38
|
+
end
|
39
|
+
|
40
|
+
def output_case(types)
|
41
|
+
num = types2num(types)
|
42
|
+
callfunc_stm = output_callfunc(types)
|
43
|
+
<<EOF
|
44
|
+
case #{num}:
|
45
|
+
#ifdef DEBUG
|
46
|
+
OUTPUT.printf("#{callfunc_stm}\\n");
|
47
|
+
#endif
|
48
|
+
#{callfunc_stm};
|
49
|
+
break;
|
50
|
+
EOF
|
51
|
+
end
|
52
|
+
|
53
|
+
def rec_output(types = [VOID])
|
54
|
+
OUTPUT.print output_case(types)
|
55
|
+
if( types.length <= MAX_ARG )
|
56
|
+
DLTYPE.keys.sort.each{|t|
|
57
|
+
if( t != VOID && DLTYPE[t][:sym] )
|
58
|
+
rec_output(types + [t])
|
59
|
+
end
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
DLTYPE.keys.sort.each{|t|
|
65
|
+
if( DLTYPE[t][:sym] )
|
66
|
+
$stderr.printf(" #{DLTYPE[t][:ctype]}\n")
|
67
|
+
rec_output([t])
|
68
|
+
end
|
69
|
+
}
|