ffi 1.15.5-x64-mingw-ucrt
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +338 -0
- data/COPYING +49 -0
- data/Gemfile +14 -0
- data/LICENSE +24 -0
- data/LICENSE.SPECS +22 -0
- data/README.md +136 -0
- data/Rakefile +191 -0
- data/ffi.gemspec +42 -0
- data/lib/3.1/ffi_c.so +0 -0
- data/lib/ffi/abstract_memory.rb +44 -0
- data/lib/ffi/autopointer.rb +203 -0
- data/lib/ffi/buffer.rb +4 -0
- data/lib/ffi/callback.rb +4 -0
- data/lib/ffi/data_converter.rb +67 -0
- data/lib/ffi/enum.rb +296 -0
- data/lib/ffi/errno.rb +43 -0
- data/lib/ffi/ffi.rb +47 -0
- data/lib/ffi/io.rb +62 -0
- data/lib/ffi/library.rb +592 -0
- data/lib/ffi/managedstruct.rb +84 -0
- data/lib/ffi/memorypointer.rb +1 -0
- data/lib/ffi/platform/aarch64-darwin/types.conf +130 -0
- data/lib/ffi/platform/aarch64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/aarch64-freebsd12/types.conf +181 -0
- data/lib/ffi/platform/aarch64-linux/types.conf +104 -0
- data/lib/ffi/platform/aarch64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/arm-freebsd/types.conf +152 -0
- data/lib/ffi/platform/arm-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/arm-linux/types.conf +132 -0
- data/lib/ffi/platform/i386-cygwin/types.conf +3 -0
- data/lib/ffi/platform/i386-darwin/types.conf +100 -0
- data/lib/ffi/platform/i386-freebsd/types.conf +152 -0
- data/lib/ffi/platform/i386-freebsd12/types.conf +152 -0
- data/lib/ffi/platform/i386-gnu/types.conf +107 -0
- data/lib/ffi/platform/i386-linux/types.conf +103 -0
- data/lib/ffi/platform/i386-netbsd/types.conf +126 -0
- data/lib/ffi/platform/i386-openbsd/types.conf +128 -0
- data/lib/ffi/platform/i386-solaris/types.conf +122 -0
- data/lib/ffi/platform/i386-windows/types.conf +52 -0
- data/lib/ffi/platform/ia64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips-linux/types.conf +102 -0
- data/lib/ffi/platform/mips64-linux/types.conf +104 -0
- data/lib/ffi/platform/mips64el-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsel-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa32r6el-linux/types.conf +102 -0
- data/lib/ffi/platform/mipsisa64r6-linux/types.conf +104 -0
- data/lib/ffi/platform/mipsisa64r6el-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc-aix/types.conf +180 -0
- data/lib/ffi/platform/powerpc-darwin/types.conf +100 -0
- data/lib/ffi/platform/powerpc-linux/types.conf +130 -0
- data/lib/ffi/platform/powerpc-openbsd/types.conf +156 -0
- data/lib/ffi/platform/powerpc64-linux/types.conf +104 -0
- data/lib/ffi/platform/powerpc64le-linux/types.conf +100 -0
- data/lib/ffi/platform/riscv64-linux/types.conf +104 -0
- data/lib/ffi/platform/s390-linux/types.conf +102 -0
- data/lib/ffi/platform/s390x-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-linux/types.conf +102 -0
- data/lib/ffi/platform/sparc-solaris/types.conf +128 -0
- data/lib/ffi/platform/sparc64-linux/types.conf +102 -0
- data/lib/ffi/platform/sparcv9-openbsd/types.conf +156 -0
- data/lib/ffi/platform/sparcv9-solaris/types.conf +128 -0
- data/lib/ffi/platform/x86_64-cygwin/types.conf +3 -0
- data/lib/ffi/platform/x86_64-darwin/types.conf +130 -0
- data/lib/ffi/platform/x86_64-dragonflybsd/types.conf +130 -0
- data/lib/ffi/platform/x86_64-freebsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-freebsd12/types.conf +158 -0
- data/lib/ffi/platform/x86_64-haiku/types.conf +117 -0
- data/lib/ffi/platform/x86_64-linux/types.conf +132 -0
- data/lib/ffi/platform/x86_64-msys/types.conf +119 -0
- data/lib/ffi/platform/x86_64-netbsd/types.conf +128 -0
- data/lib/ffi/platform/x86_64-openbsd/types.conf +134 -0
- data/lib/ffi/platform/x86_64-solaris/types.conf +122 -0
- data/lib/ffi/platform/x86_64-windows/types.conf +52 -0
- data/lib/ffi/platform.rb +185 -0
- data/lib/ffi/pointer.rb +167 -0
- data/lib/ffi/struct.rb +316 -0
- data/lib/ffi/struct_by_reference.rb +72 -0
- data/lib/ffi/struct_layout.rb +96 -0
- data/lib/ffi/struct_layout_builder.rb +227 -0
- data/lib/ffi/tools/const_generator.rb +232 -0
- data/lib/ffi/tools/generator.rb +105 -0
- data/lib/ffi/tools/generator_task.rb +32 -0
- data/lib/ffi/tools/struct_generator.rb +195 -0
- data/lib/ffi/tools/types_generator.rb +137 -0
- data/lib/ffi/types.rb +194 -0
- data/lib/ffi/union.rb +43 -0
- data/lib/ffi/variadic.rb +69 -0
- data/lib/ffi/version.rb +3 -0
- data/lib/ffi.rb +27 -0
- data/rakelib/ffi_gem_helper.rb +65 -0
- data/samples/getlogin.rb +8 -0
- data/samples/getpid.rb +8 -0
- data/samples/gettimeofday.rb +18 -0
- data/samples/hello.rb +8 -0
- data/samples/inotify.rb +60 -0
- data/samples/pty.rb +75 -0
- data/samples/qsort.rb +20 -0
- metadata +207 -0
data/lib/ffi/types.rb
ADDED
@@ -0,0 +1,194 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2008-2010 Wayne Meissner
|
3
|
+
# Copyright (c) 2007, 2008 Evan Phoenix
|
4
|
+
#
|
5
|
+
# This file is part of ruby-ffi.
|
6
|
+
#
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
11
|
+
#
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
13
|
+
# list of conditions and the following disclaimer.
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this software
|
19
|
+
# without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
|
33
|
+
# see {file:README}
|
34
|
+
module FFI
|
35
|
+
|
36
|
+
# @param [Type, DataConverter, Symbol] old type definition used by {FFI.find_type}
|
37
|
+
# @param [Symbol] add new type definition's name to add
|
38
|
+
# @return [Type]
|
39
|
+
# Add a definition type to type definitions.
|
40
|
+
def self.typedef(old, add)
|
41
|
+
TypeDefs[add] = self.find_type(old)
|
42
|
+
end
|
43
|
+
|
44
|
+
# (see FFI.typedef)
|
45
|
+
def self.add_typedef(old, add)
|
46
|
+
typedef old, add
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# @param [Type, DataConverter, Symbol] name
|
51
|
+
# @param [Hash] type_map if nil, {FFI::TypeDefs} is used
|
52
|
+
# @return [Type]
|
53
|
+
# Find a type in +type_map+ ({FFI::TypeDefs}, by default) from
|
54
|
+
# a type objet, a type name (symbol). If +name+ is a {DataConverter},
|
55
|
+
# a new {Type::Mapped} is created.
|
56
|
+
def self.find_type(name, type_map = nil)
|
57
|
+
if name.is_a?(Type)
|
58
|
+
name
|
59
|
+
|
60
|
+
elsif type_map && type_map.has_key?(name)
|
61
|
+
type_map[name]
|
62
|
+
|
63
|
+
elsif TypeDefs.has_key?(name)
|
64
|
+
TypeDefs[name]
|
65
|
+
|
66
|
+
elsif name.is_a?(DataConverter)
|
67
|
+
(type_map || TypeDefs)[name] = Type::Mapped.new(name)
|
68
|
+
else
|
69
|
+
raise TypeError, "unable to resolve type '#{name}'"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# List of type definitions
|
74
|
+
TypeDefs.merge!({
|
75
|
+
# The C void type; only useful for function return types
|
76
|
+
:void => Type::VOID,
|
77
|
+
|
78
|
+
# C boolean type
|
79
|
+
:bool => Type::BOOL,
|
80
|
+
|
81
|
+
# C nul-terminated string
|
82
|
+
:string => Type::STRING,
|
83
|
+
|
84
|
+
# C signed char
|
85
|
+
:char => Type::CHAR,
|
86
|
+
# C unsigned char
|
87
|
+
:uchar => Type::UCHAR,
|
88
|
+
|
89
|
+
# C signed short
|
90
|
+
:short => Type::SHORT,
|
91
|
+
# C unsigned short
|
92
|
+
:ushort => Type::USHORT,
|
93
|
+
|
94
|
+
# C signed int
|
95
|
+
:int => Type::INT,
|
96
|
+
# C unsigned int
|
97
|
+
:uint => Type::UINT,
|
98
|
+
|
99
|
+
# C signed long
|
100
|
+
:long => Type::LONG,
|
101
|
+
|
102
|
+
# C unsigned long
|
103
|
+
:ulong => Type::ULONG,
|
104
|
+
|
105
|
+
# C signed long long integer
|
106
|
+
:long_long => Type::LONG_LONG,
|
107
|
+
|
108
|
+
# C unsigned long long integer
|
109
|
+
:ulong_long => Type::ULONG_LONG,
|
110
|
+
|
111
|
+
# C single precision float
|
112
|
+
:float => Type::FLOAT,
|
113
|
+
|
114
|
+
# C double precision float
|
115
|
+
:double => Type::DOUBLE,
|
116
|
+
|
117
|
+
# C long double
|
118
|
+
:long_double => Type::LONGDOUBLE,
|
119
|
+
|
120
|
+
# Native memory address
|
121
|
+
:pointer => Type::POINTER,
|
122
|
+
|
123
|
+
# 8 bit signed integer
|
124
|
+
:int8 => Type::INT8,
|
125
|
+
# 8 bit unsigned integer
|
126
|
+
:uint8 => Type::UINT8,
|
127
|
+
|
128
|
+
# 16 bit signed integer
|
129
|
+
:int16 => Type::INT16,
|
130
|
+
# 16 bit unsigned integer
|
131
|
+
:uint16 => Type::UINT16,
|
132
|
+
|
133
|
+
# 32 bit signed integer
|
134
|
+
:int32 => Type::INT32,
|
135
|
+
# 32 bit unsigned integer
|
136
|
+
:uint32 => Type::UINT32,
|
137
|
+
|
138
|
+
# 64 bit signed integer
|
139
|
+
:int64 => Type::INT64,
|
140
|
+
# 64 bit unsigned integer
|
141
|
+
:uint64 => Type::UINT64,
|
142
|
+
|
143
|
+
:buffer_in => Type::BUFFER_IN,
|
144
|
+
:buffer_out => Type::BUFFER_OUT,
|
145
|
+
:buffer_inout => Type::BUFFER_INOUT,
|
146
|
+
|
147
|
+
# Used in function prototypes to indicate the arguments are variadic
|
148
|
+
:varargs => Type::VARARGS,
|
149
|
+
})
|
150
|
+
|
151
|
+
# This will convert a pointer to a Ruby string (just like `:string`), but
|
152
|
+
# also allow to work with the pointer itself. This is useful when you want
|
153
|
+
# a Ruby string already containing a copy of the data, but also the pointer
|
154
|
+
# to the data for you to do something with it, like freeing it, in case the
|
155
|
+
# library handed the memory off to the caller (Ruby-FFI).
|
156
|
+
#
|
157
|
+
# It's {typedef}'d as +:strptr+.
|
158
|
+
class StrPtrConverter
|
159
|
+
extend DataConverter
|
160
|
+
native_type Type::POINTER
|
161
|
+
|
162
|
+
# @param [Pointer] val
|
163
|
+
# @param ctx not used
|
164
|
+
# @return [Array(String, Pointer)]
|
165
|
+
# Returns a [ String, Pointer ] tuple so the C memory for the string can be freed
|
166
|
+
def self.from_native(val, ctx)
|
167
|
+
[ val.null? ? nil : val.get_string(0), val ]
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
typedef(StrPtrConverter, :strptr)
|
172
|
+
|
173
|
+
# @param type +type+ is an instance of class accepted by {FFI.find_type}
|
174
|
+
# @return [Numeric]
|
175
|
+
# Get +type+ size, in bytes.
|
176
|
+
def self.type_size(type)
|
177
|
+
find_type(type).size
|
178
|
+
end
|
179
|
+
|
180
|
+
# Load all the platform dependent types
|
181
|
+
begin
|
182
|
+
File.open(File.join(Platform::CONF_DIR, 'types.conf'), "r") do |f|
|
183
|
+
prefix = "rbx.platform.typedef."
|
184
|
+
f.each_line { |line|
|
185
|
+
if line.index(prefix) == 0
|
186
|
+
new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
|
187
|
+
typedef(orig_type.to_sym, new_type.to_sym)
|
188
|
+
end
|
189
|
+
}
|
190
|
+
end
|
191
|
+
typedef :pointer, :caddr_t
|
192
|
+
rescue Errno::ENOENT
|
193
|
+
end
|
194
|
+
end
|
data/lib/ffi/union.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2009 Andrea Fazzi <andrea.fazzi@alcacoop.it>
|
3
|
+
#
|
4
|
+
# This file is part of ruby-ffi.
|
5
|
+
#
|
6
|
+
# All rights reserved.
|
7
|
+
#
|
8
|
+
# Redistribution and use in source and binary forms, with or without
|
9
|
+
# modification, are permitted provided that the following conditions are met:
|
10
|
+
#
|
11
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
12
|
+
# list of conditions and the following disclaimer.
|
13
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
14
|
+
# this list of conditions and the following disclaimer in the documentation
|
15
|
+
# and/or other materials provided with the distribution.
|
16
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
17
|
+
# may be used to endorse or promote products derived from this software
|
18
|
+
# without specific prior written permission.
|
19
|
+
#
|
20
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
21
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
22
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
23
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
24
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
25
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
26
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
27
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
28
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
29
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
30
|
+
#
|
31
|
+
|
32
|
+
require 'ffi/struct'
|
33
|
+
|
34
|
+
module FFI
|
35
|
+
|
36
|
+
class Union < FFI::Struct
|
37
|
+
def self.builder
|
38
|
+
b = StructLayoutBuilder.new
|
39
|
+
b.union = true
|
40
|
+
b
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
data/lib/ffi/variadic.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
#
|
2
|
+
# Copyright (C) 2008, 2009 Wayne Meissner
|
3
|
+
# Copyright (C) 2009 Luc Heinrich
|
4
|
+
#
|
5
|
+
# This file is part of ruby-ffi.
|
6
|
+
#
|
7
|
+
# All rights reserved.
|
8
|
+
#
|
9
|
+
# Redistribution and use in source and binary forms, with or without
|
10
|
+
# modification, are permitted provided that the following conditions are met:
|
11
|
+
#
|
12
|
+
# * Redistributions of source code must retain the above copyright notice, this
|
13
|
+
# list of conditions and the following disclaimer.
|
14
|
+
# * Redistributions in binary form must reproduce the above copyright notice
|
15
|
+
# this list of conditions and the following disclaimer in the documentation
|
16
|
+
# and/or other materials provided with the distribution.
|
17
|
+
# * Neither the name of the Ruby FFI project nor the names of its contributors
|
18
|
+
# may be used to endorse or promote products derived from this software
|
19
|
+
# without specific prior written permission.
|
20
|
+
#
|
21
|
+
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
22
|
+
# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
23
|
+
# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
24
|
+
# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
|
25
|
+
# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
26
|
+
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
27
|
+
# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
28
|
+
# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
29
|
+
# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
30
|
+
# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
31
|
+
#
|
32
|
+
|
33
|
+
module FFI
|
34
|
+
class VariadicInvoker
|
35
|
+
def call(*args, &block)
|
36
|
+
param_types = Array.new(@fixed)
|
37
|
+
param_values = Array.new
|
38
|
+
@fixed.each_with_index do |t, i|
|
39
|
+
param_values << args[i]
|
40
|
+
end
|
41
|
+
i = @fixed.length
|
42
|
+
while i < args.length
|
43
|
+
param_types << FFI.find_type(args[i], @type_map)
|
44
|
+
param_values << args[i + 1]
|
45
|
+
i += 2
|
46
|
+
end
|
47
|
+
invoke(param_types, param_values, &block)
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Attach the invoker to module +mod+ as +mname+
|
52
|
+
#
|
53
|
+
def attach(mod, mname)
|
54
|
+
invoker = self
|
55
|
+
params = "*args"
|
56
|
+
call = "call"
|
57
|
+
mod.module_eval <<-code
|
58
|
+
@@#{mname} = invoker
|
59
|
+
def self.#{mname}(#{params})
|
60
|
+
@@#{mname}.#{call}(#{params})
|
61
|
+
end
|
62
|
+
def #{mname}(#{params})
|
63
|
+
@@#{mname}.#{call}(#{params})
|
64
|
+
end
|
65
|
+
code
|
66
|
+
invoker
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ffi/version.rb
ADDED
data/lib/ffi.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
if RUBY_ENGINE == 'ruby'
|
2
|
+
begin
|
3
|
+
require RUBY_VERSION.split('.')[0, 2].join('.') + '/ffi_c'
|
4
|
+
rescue Exception
|
5
|
+
require 'ffi_c'
|
6
|
+
end
|
7
|
+
|
8
|
+
require 'ffi/ffi'
|
9
|
+
|
10
|
+
elsif RUBY_ENGINE == 'jruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [9, 2, 20]) >= 0
|
11
|
+
JRuby::Util.load_ext("org.jruby.ext.ffi.FFIService")
|
12
|
+
require 'ffi/ffi'
|
13
|
+
|
14
|
+
elsif RUBY_ENGINE == 'truffleruby' && (RUBY_ENGINE_VERSION.split('.').map(&:to_i) <=> [20, 1, 0]) >= 0
|
15
|
+
require 'truffleruby/ffi_backend'
|
16
|
+
require 'ffi/ffi'
|
17
|
+
|
18
|
+
else
|
19
|
+
# Remove the ffi gem dir from the load path, then reload the internal ffi implementation
|
20
|
+
$LOAD_PATH.delete(File.dirname(__FILE__))
|
21
|
+
$LOAD_PATH.delete(File.join(File.dirname(__FILE__), 'ffi'))
|
22
|
+
unless $LOADED_FEATURES.nil?
|
23
|
+
$LOADED_FEATURES.delete(__FILE__)
|
24
|
+
$LOADED_FEATURES.delete('ffi.rb')
|
25
|
+
end
|
26
|
+
require 'ffi.rb'
|
27
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'bundler/gem_helper'
|
3
|
+
|
4
|
+
class FfiGemHelper < Bundler::GemHelper
|
5
|
+
attr_accessor :cross_platforms
|
6
|
+
|
7
|
+
def install
|
8
|
+
super
|
9
|
+
|
10
|
+
task "release:guard_clean" => ["release:update_history"]
|
11
|
+
|
12
|
+
task "release:update_history" do
|
13
|
+
update_history
|
14
|
+
end
|
15
|
+
|
16
|
+
task "release:rubygem_push" => ["gem:native", "gem:java"]
|
17
|
+
end
|
18
|
+
|
19
|
+
def hfile
|
20
|
+
"CHANGELOG.md"
|
21
|
+
end
|
22
|
+
|
23
|
+
def headline
|
24
|
+
'([^\w]*)(\d+\.\d+\.\d+(?:\.\w+)?)([^\w]+)([2Y][0Y][0-9Y][0-9Y]-[0-1M][0-9M]-[0-3D][0-9D])([^\w]*|$)'
|
25
|
+
end
|
26
|
+
|
27
|
+
def reldate
|
28
|
+
Time.now.strftime("%Y-%m-%d")
|
29
|
+
end
|
30
|
+
|
31
|
+
def update_history
|
32
|
+
hin = File.read(hfile)
|
33
|
+
hout = hin.sub(/#{headline}/) do
|
34
|
+
raise "#{hfile} isn't up-to-date for version #{version}" unless $2==version.to_s
|
35
|
+
$1 + $2 + $3 + reldate + $5
|
36
|
+
end
|
37
|
+
if hout != hin
|
38
|
+
Bundler.ui.confirm "Updating #{hfile} for release."
|
39
|
+
File.write(hfile, hout)
|
40
|
+
Rake::FileUtilsExt.sh "git", "commit", hfile, "-m", "Update release date in #{hfile}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def tag_version
|
45
|
+
Bundler.ui.confirm "Tag release with annotation:"
|
46
|
+
m = File.read(hfile).match(/(?<annotation>#{headline}.*?)#{headline}/m) || raise("Unable to find release notes in #{hfile}")
|
47
|
+
Bundler.ui.info(m[:annotation].gsub(/^/, " "))
|
48
|
+
IO.popen(["git", "tag", "--file=-", version_tag], "w") do |fd|
|
49
|
+
fd.write m[:annotation]
|
50
|
+
end
|
51
|
+
yield if block_given?
|
52
|
+
rescue
|
53
|
+
Bundler.ui.error "Untagging #{version_tag} due to error."
|
54
|
+
sh_with_code "git tag -d #{version_tag}"
|
55
|
+
raise
|
56
|
+
end
|
57
|
+
|
58
|
+
def rubygem_push(path)
|
59
|
+
cross_platforms.each do |ruby_platform|
|
60
|
+
super(path.gsub(/\.gem\z/, "-#{ruby_platform}.gem"))
|
61
|
+
end
|
62
|
+
super(path.gsub(/\.gem\z/, "-java.gem"))
|
63
|
+
super(path)
|
64
|
+
end
|
65
|
+
end
|
data/samples/getlogin.rb
ADDED
data/samples/getpid.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
require 'rbconfig'
|
3
|
+
|
4
|
+
class Timeval < FFI::Struct
|
5
|
+
layout tv_sec: :ulong, tv_usec: :ulong
|
6
|
+
end
|
7
|
+
module LibC
|
8
|
+
extend FFI::Library
|
9
|
+
if FFI::Platform.windows?
|
10
|
+
ffi_lib RbConfig::CONFIG["LIBRUBY_SO"]
|
11
|
+
else
|
12
|
+
ffi_lib FFI::Library::LIBC
|
13
|
+
end
|
14
|
+
attach_function :gettimeofday, [ :pointer, :pointer ], :int
|
15
|
+
end
|
16
|
+
t = Timeval.new
|
17
|
+
LibC.gettimeofday(t.pointer, nil)
|
18
|
+
puts "t.tv_sec=#{t[:tv_sec]} t.tv_usec=#{t[:tv_usec]}"
|
data/samples/hello.rb
ADDED
data/samples/inotify.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module Inotify
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
class Event < FFI::Struct
|
7
|
+
layout \
|
8
|
+
:wd, :int,
|
9
|
+
:mask, :uint,
|
10
|
+
:cookie, :uint,
|
11
|
+
:len, :uint
|
12
|
+
end
|
13
|
+
attach_function :init, :inotify_init, [ ], :int
|
14
|
+
attach_function :add_watch, :inotify_add_watch, [ :int, :string, :uint ], :int
|
15
|
+
attach_function :rm_watch, :inotify_rm_watch, [ :int, :uint ], :int
|
16
|
+
attach_function :read, [ :int, :buffer_out, :uint ], :int
|
17
|
+
IN_ACCESS=0x00000001
|
18
|
+
IN_MODIFY=0x00000002
|
19
|
+
IN_ATTRIB=0x00000004
|
20
|
+
IN_CLOSE_WRITE=0x00000008
|
21
|
+
IN_CLOSE_NOWRITE=0x00000010
|
22
|
+
IN_CLOSE=(IN_CLOSE_WRITE | IN_CLOSE_NOWRITE)
|
23
|
+
IN_OPEN=0x00000020
|
24
|
+
IN_MOVED_FROM=0x00000040
|
25
|
+
IN_MOVED_TO=0x00000080
|
26
|
+
IN_MOVE= (IN_MOVED_FROM | IN_MOVED_TO)
|
27
|
+
IN_CREATE=0x00000100
|
28
|
+
IN_DELETE=0x00000200
|
29
|
+
IN_DELETE_SELF=0x00000400
|
30
|
+
IN_MOVE_SELF=0x00000800
|
31
|
+
# Events sent by the kernel.
|
32
|
+
IN_UNMOUNT=0x00002000
|
33
|
+
IN_Q_OVERFLOW=0x00004000
|
34
|
+
IN_IGNORED=0x00008000
|
35
|
+
IN_ONLYDIR=0x01000000
|
36
|
+
IN_DONT_FOLLOW=0x02000000
|
37
|
+
IN_MASK_ADD=0x20000000
|
38
|
+
IN_ISDIR=0x40000000
|
39
|
+
IN_ONESHOT=0x80000000
|
40
|
+
IN_ALL_EVENTS=(IN_ACCESS | IN_MODIFY | IN_ATTRIB | IN_CLOSE_WRITE \
|
41
|
+
| IN_CLOSE_NOWRITE | IN_OPEN | IN_MOVED_FROM \
|
42
|
+
| IN_MOVED_TO | IN_CREATE | IN_DELETE \
|
43
|
+
| IN_DELETE_SELF | IN_MOVE_SELF)
|
44
|
+
|
45
|
+
end
|
46
|
+
if $0 == __FILE__
|
47
|
+
fd = Inotify.init
|
48
|
+
puts "fd=#{fd}"
|
49
|
+
wd = Inotify.add_watch(fd, "/tmp/", Inotify::IN_ALL_EVENTS)
|
50
|
+
fp = FFI::IO.for_fd(fd)
|
51
|
+
puts "wfp=#{fp}"
|
52
|
+
while true
|
53
|
+
buf = FFI::Buffer.alloc_out(Inotify::Event.size + 4096, 1, false)
|
54
|
+
ev = Inotify::Event.new buf
|
55
|
+
ready = IO.select([ fp ], nil, nil, nil)
|
56
|
+
n = Inotify.read(fd, buf, buf.total)
|
57
|
+
puts "Read #{n} bytes from inotify fd"
|
58
|
+
puts "event.wd=#{ev[:wd]} mask=#{ev[:mask]} len=#{ev[:len]} name=#{ev[:len] > 0 ? buf.get_string(16) : 'unknown'}"
|
59
|
+
end
|
60
|
+
end
|
data/samples/pty.rb
ADDED
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module PTY
|
4
|
+
private
|
5
|
+
module LibC
|
6
|
+
extend FFI::Library
|
7
|
+
ffi_lib FFI::Library::LIBC
|
8
|
+
attach_function :forkpty, [ :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
|
9
|
+
attach_function :openpty, [ :buffer_out, :buffer_out, :buffer_out, :buffer_in, :buffer_in ], :int
|
10
|
+
attach_function :login_tty, [ :int ], :int
|
11
|
+
attach_function :close, [ :int ], :int
|
12
|
+
attach_function :strerror, [ :int ], :string
|
13
|
+
attach_function :fork, [], :int
|
14
|
+
attach_function :execv, [ :string, :buffer_in ], :int
|
15
|
+
attach_function :execvp, [ :string, :buffer_in ], :int
|
16
|
+
attach_function :dup2, [ :int, :int ], :int
|
17
|
+
attach_function :dup, [ :int ], :int
|
18
|
+
end
|
19
|
+
Buffer = FFI::Buffer
|
20
|
+
def self.build_args(args)
|
21
|
+
cmd = args.shift
|
22
|
+
cmd_args = args.map do |arg|
|
23
|
+
MemoryPointer.from_string(arg)
|
24
|
+
end
|
25
|
+
exec_args = MemoryPointer.new(:pointer, 1 + cmd_args.length + 1)
|
26
|
+
exec_cmd = MemoryPointer.from_string(cmd)
|
27
|
+
exec_args[0].put_pointer(0, exec_cmd)
|
28
|
+
cmd_args.each_with_index do |arg, i|
|
29
|
+
exec_args[i + 1].put_pointer(0, arg)
|
30
|
+
end
|
31
|
+
[ cmd, exec_args ]
|
32
|
+
end
|
33
|
+
public
|
34
|
+
def self.getpty(*args)
|
35
|
+
mfdp = Buffer.new :int
|
36
|
+
name = Buffer.new 1024
|
37
|
+
#
|
38
|
+
# All the execv setup is done in the parent, since doing anything other than
|
39
|
+
# execv in the child after fork is really flakey
|
40
|
+
#
|
41
|
+
exec_cmd, exec_args = build_args(args)
|
42
|
+
pid = LibC.forkpty(mfdp, name, nil, nil)
|
43
|
+
raise "forkpty failed: #{LibC.strerror(FFI.errno)}" if pid < 0
|
44
|
+
if pid == 0
|
45
|
+
LibC.execvp(exec_cmd, exec_args)
|
46
|
+
exit 1
|
47
|
+
end
|
48
|
+
masterfd = mfdp.get_int(0)
|
49
|
+
rfp = FFI::IO.for_fd(masterfd, "r")
|
50
|
+
wfp = FFI::IO.for_fd(LibC.dup(masterfd), "w")
|
51
|
+
if block_given?
|
52
|
+
yield rfp, wfp, pid
|
53
|
+
rfp.close unless rfp.closed?
|
54
|
+
wfp.close unless wfp.closed?
|
55
|
+
else
|
56
|
+
[ rfp, wfp, pid ]
|
57
|
+
end
|
58
|
+
end
|
59
|
+
def self.spawn(*args, &block)
|
60
|
+
self.getpty("/bin/sh", "-c", args[0], &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
module LibC
|
64
|
+
extend FFI::Library
|
65
|
+
attach_function :close, [ :int ], :int
|
66
|
+
attach_function :write, [ :int, :buffer_in, :ulong ], :long
|
67
|
+
attach_function :read, [ :int, :buffer_out, :ulong ], :long
|
68
|
+
end
|
69
|
+
PTY.getpty("/bin/ls", "-alR", "/") { |rfd, wfd, pid|
|
70
|
+
#PTY.spawn("ls -laR /") { |rfd, wfd, pid|
|
71
|
+
puts "child pid=#{pid}"
|
72
|
+
while !rfd.eof? && (buf = rfd.gets)
|
73
|
+
puts "child: '#{buf.strip}'"
|
74
|
+
end
|
75
|
+
}
|
data/samples/qsort.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'ffi'
|
2
|
+
|
3
|
+
module LibC
|
4
|
+
extend FFI::Library
|
5
|
+
ffi_lib FFI::Library::LIBC
|
6
|
+
callback :qsort_cmp, [ :pointer, :pointer ], :int
|
7
|
+
attach_function :qsort, [ :pointer, :ulong, :ulong, :qsort_cmp ], :int
|
8
|
+
end
|
9
|
+
|
10
|
+
p = FFI::MemoryPointer.new(:int, 2)
|
11
|
+
p.put_array_of_int32(0, [ 2, 1 ])
|
12
|
+
puts "ptr=#{p.inspect}"
|
13
|
+
puts "Before qsort #{p.get_array_of_int32(0, 2).join(', ')}"
|
14
|
+
LibC.qsort(p, 2, 4) do |p1, p2|
|
15
|
+
i1 = p1.get_int32(0)
|
16
|
+
i2 = p2.get_int32(0)
|
17
|
+
puts "In block: comparing #{i1} and #{i2}"
|
18
|
+
i1 < i2 ? -1 : i1 > i2 ? 1 : 0
|
19
|
+
end
|
20
|
+
puts "After qsort #{p.get_array_of_int32(0, 2).join(', ')}"
|