ffi 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of ffi might be problematic. Click here for more details.

Files changed (62) hide show
  1. data/Rakefile +52 -29
  2. data/ext/AbstractMemory.c +72 -28
  3. data/ext/AutoPointer.c +54 -0
  4. data/ext/AutoPointer.h +18 -0
  5. data/ext/Buffer.c +21 -17
  6. data/ext/Callback.c +81 -43
  7. data/ext/Callback.h +1 -1
  8. data/ext/Invoker.c +465 -108
  9. data/ext/MemoryPointer.c +25 -90
  10. data/ext/NativeLibrary.c +90 -0
  11. data/ext/NativeLibrary.h +22 -0
  12. data/ext/Platform.c +21 -2
  13. data/ext/Pointer.c +107 -0
  14. data/ext/Pointer.h +21 -0
  15. data/ext/Types.c +16 -5
  16. data/ext/Types.h +3 -1
  17. data/ext/compat.h +14 -0
  18. data/ext/extconf.rb +13 -1
  19. data/ext/ffi.c +11 -1
  20. data/ext/ffi.mk +3 -3
  21. data/ext/libffi.darwin.mk +19 -8
  22. data/gen/Rakefile +12 -0
  23. data/lib/ffi/autopointer.rb +61 -0
  24. data/lib/ffi/errno.rb +8 -0
  25. data/lib/ffi/ffi.rb +38 -201
  26. data/lib/ffi/io.rb +7 -0
  27. data/lib/ffi/library.rb +116 -0
  28. data/lib/ffi/managedstruct.rb +55 -0
  29. data/lib/ffi/memorypointer.rb +3 -96
  30. data/lib/ffi/platform.rb +8 -5
  31. data/lib/ffi/pointer.rb +105 -0
  32. data/lib/ffi/struct.rb +97 -42
  33. data/lib/ffi/tools/const_generator.rb +177 -0
  34. data/lib/ffi/tools/generator.rb +58 -0
  35. data/lib/ffi/tools/generator_task.rb +35 -0
  36. data/lib/ffi/tools/struct_generator.rb +194 -0
  37. data/lib/ffi/tools/types_generator.rb +123 -0
  38. data/lib/ffi/types.rb +150 -0
  39. data/lib/ffi/variadic.rb +30 -0
  40. data/nbproject/Makefile-Default.mk +6 -3
  41. data/nbproject/Makefile-impl.mk +5 -5
  42. data/nbproject/Package-Default.bash +72 -0
  43. data/nbproject/configurations.xml +139 -25
  44. data/nbproject/private/configurations.xml +1 -1
  45. data/nbproject/project.xml +4 -0
  46. data/samples/gettimeofday.rb +6 -2
  47. data/samples/inotify.rb +59 -0
  48. data/samples/pty.rb +75 -0
  49. data/specs/buffer_spec.rb +64 -9
  50. data/specs/callback_spec.rb +308 -4
  51. data/specs/errno_spec.rb +13 -0
  52. data/specs/library_spec.rb +55 -0
  53. data/specs/managed_struct_spec.rb +40 -0
  54. data/specs/number_spec.rb +183 -0
  55. data/specs/pointer_spec.rb +126 -0
  56. data/specs/rbx/memory_pointer_spec.rb +7 -7
  57. data/specs/spec_helper.rb +7 -0
  58. data/specs/string_spec.rb +34 -0
  59. data/specs/struct_spec.rb +223 -0
  60. data/specs/typedef_spec.rb +48 -0
  61. data/specs/variadic_spec.rb +84 -0
  62. metadata +270 -237
@@ -0,0 +1,123 @@
1
+ require 'tempfile'
2
+
3
+ module FFI
4
+ class TypesGenerator
5
+
6
+ ##
7
+ # Maps different C types to the C type representations we use
8
+
9
+ TYPE_MAP = {
10
+ "char" => :char,
11
+ "signed char" => :char,
12
+ "__signed char" => :char,
13
+ "unsigned char" => :uchar,
14
+
15
+ "short" => :short,
16
+ "signed short" => :short,
17
+ "signed short int" => :short,
18
+ "unsigned short" => :ushort,
19
+ "unsigned short int" => :ushort,
20
+
21
+ "int" => :int,
22
+ "signed int" => :int,
23
+ "unsigned int" => :uint,
24
+
25
+ "long" => :long,
26
+ "long int" => :long,
27
+ "signed long" => :long,
28
+ "signed long int" => :long,
29
+ "unsigned long" => :ulong,
30
+ "unsigned long int" => :ulong,
31
+ "long unsigned int" => :ulong,
32
+
33
+ "long long" => :long_long,
34
+ "long long int" => :long_long,
35
+ "signed long long" => :long_long,
36
+ "signed long long int" => :long_long,
37
+ "unsigned long long" => :ulong_long,
38
+ "unsigned long long int" => :ulong_long,
39
+
40
+ "char *" => :string,
41
+ "void *" => :pointer,
42
+ }
43
+
44
+ def self.generate(options = {})
45
+ typedefs = nil
46
+ Tempfile.open 'ffi_types_generator' do |io|
47
+ io.puts <<-C
48
+ #include <sys/types.h>
49
+ #include <sys/socket.h>
50
+ #include <sys/resource.h>
51
+ C
52
+
53
+ io.close
54
+ typedefs = `gcc -E -x c #{options[:cppflags]} -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -c #{io.path}`
55
+ end
56
+
57
+ code = ""
58
+
59
+ typedefs.each_line do |type|
60
+ # We only care about single line typedef
61
+ next unless type =~ /typedef/
62
+ # Ignore unions or structs
63
+ next if type =~ /union|struct/
64
+
65
+ # strip off the starting typedef and ending ;
66
+ type.gsub!(/^(.*typedef\s*)/, "")
67
+ type.gsub!(/\s*;\s*$/, "")
68
+
69
+ parts = type.split(/\s+/)
70
+ def_type = parts.join(" ")
71
+
72
+ # GCC does mapping with __attribute__ stuf, also see
73
+ # http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7. Problem
74
+ # with this is that the __attribute__ stuff can either occur before or
75
+ # after the new type that is defined...
76
+ if type =~ /__attribute__/
77
+ if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/
78
+
79
+ # In this case, the new type is BEFORE __attribute__ we need to
80
+ # find the final_type as the type before the part that starts with
81
+ # __attribute__
82
+ final_type = ""
83
+ parts.each do |p|
84
+ break if p =~ /__attribute__/
85
+ final_type = p
86
+ end
87
+ else
88
+ final_type = parts.pop
89
+ end
90
+
91
+ def_type = case type
92
+ when /__QI__/ then "char"
93
+ when /__HI__/ then "short"
94
+ when /__SI__/ then "int"
95
+ when /__DI__/ then "long long"
96
+ when /__word__/ then "long"
97
+ else "int"
98
+ end
99
+
100
+ def_type = "unsigned #{def_type}" if type =~ /unsigned/
101
+ else
102
+ final_type = parts.pop
103
+ def_type = parts.join(" ")
104
+ end
105
+
106
+ if type = TYPE_MAP[def_type]
107
+ code << "rbx.platform.typedef.#{final_type} = #{type}\n"
108
+ TYPE_MAP[final_type] = TYPE_MAP[def_type]
109
+ else
110
+ # Fallback to an ordinary pointer if we don't know the type
111
+ if def_type =~ /\*/
112
+ code << "rbx.platform.typedef.#{final_type} = pointer\n"
113
+ TYPE_MAP[final_type] = :pointer
114
+ end
115
+ end
116
+ end
117
+
118
+ code
119
+ end
120
+
121
+ end
122
+ end
123
+
@@ -0,0 +1,150 @@
1
+ module FFI
2
+ TypeDefs = Hash.new
3
+ def self.add_typedef(current, add)
4
+ if current.kind_of? Integer
5
+ code = current
6
+ else
7
+ code = TypeDefs[current]
8
+ raise TypeError, "Unable to resolve type '#{current}'" unless code
9
+ end
10
+
11
+ TypeDefs[add] = code
12
+ end
13
+ def self.find_type(name, type_map = nil)
14
+ type_map = TypeDefs if type_map.nil?
15
+ code = type_map[name]
16
+ code = name if !code && name.kind_of?(Integer)
17
+ code = name if !code && name.kind_of?(FFI::CallbackInfo)
18
+ raise TypeError, "Unable to resolve type '#{name}'" unless code
19
+ return code
20
+ end
21
+
22
+ # Converts a char
23
+ add_typedef(NativeType::INT8, :char)
24
+
25
+ # Converts an unsigned char
26
+ add_typedef(NativeType::UINT8, :uchar)
27
+
28
+ # Converts an 8 bit int
29
+ add_typedef(NativeType::INT8, :int8)
30
+
31
+ # Converts an unsigned char
32
+ add_typedef(NativeType::UINT8, :uint8)
33
+
34
+ # Converts a short
35
+ add_typedef(NativeType::INT16, :short)
36
+
37
+ # Converts an unsigned short
38
+ add_typedef(NativeType::UINT16, :ushort)
39
+
40
+ # Converts a 16bit int
41
+ add_typedef(NativeType::INT16, :int16)
42
+
43
+ # Converts an unsigned 16 bit int
44
+ add_typedef(NativeType::UINT16, :uint16)
45
+
46
+ # Converts an int
47
+ add_typedef(NativeType::INT32, :int)
48
+
49
+ # Converts an unsigned int
50
+ add_typedef(NativeType::UINT32, :uint)
51
+
52
+ # Converts a 32 bit int
53
+ add_typedef(NativeType::INT32, :int32)
54
+
55
+ # Converts an unsigned 16 bit int
56
+ add_typedef(NativeType::UINT32, :uint32)
57
+
58
+ # Converts a long
59
+ add_typedef(NativeType::LONG, :long)
60
+
61
+ # Converts an unsigned long
62
+ add_typedef(NativeType::ULONG, :ulong)
63
+
64
+ # Converts a 64 bit int
65
+ add_typedef(NativeType::INT64, :int64)
66
+
67
+ # Converts an unsigned 64 bit int
68
+ add_typedef(NativeType::UINT64, :uint64)
69
+
70
+ # Converts a long long
71
+ add_typedef(NativeType::INT64, :long_long)
72
+
73
+ # Converts an unsigned long long
74
+ add_typedef(NativeType::UINT64, :ulong_long)
75
+
76
+ # Converts a float
77
+ add_typedef(NativeType::FLOAT32, :float)
78
+
79
+ # Converts a double
80
+ add_typedef(NativeType::FLOAT64, :double)
81
+
82
+ # Converts a pointer to opaque data
83
+ add_typedef(NativeType::POINTER, :pointer)
84
+
85
+ # For when a function has no return value
86
+ add_typedef(NativeType::VOID, :void)
87
+
88
+ # Converts NUL-terminated C strings
89
+ add_typedef(NativeType::STRING, :string)
90
+
91
+ # Converts FFI::Buffer objects
92
+ add_typedef(NativeType::BUFFER_IN, :buffer_in)
93
+ add_typedef(NativeType::BUFFER_OUT, :buffer_out)
94
+ add_typedef(NativeType::BUFFER_INOUT, :buffer_inout)
95
+ add_typedef(NativeType::VARARGS, :varargs)
96
+
97
+ # Use for a C struct with a char [] embedded inside.
98
+ add_typedef(NativeType::CHAR_ARRAY, :char_array)
99
+
100
+ TypeSizes = {
101
+ 1 => :char,
102
+ 2 => :short,
103
+ 4 => :int,
104
+ 8 => :long_long,
105
+ }
106
+ SizeTypes = {
107
+ NativeType::INT8 => 1,
108
+ NativeType::UINT8 => 1,
109
+ NativeType::INT16 => 2,
110
+ NativeType::UINT16 => 2,
111
+ NativeType::INT32 => 4,
112
+ NativeType::UINT32 => 4,
113
+ NativeType::INT64 => 8,
114
+ NativeType::UINT64 => 8,
115
+ NativeType::FLOAT32 => 4,
116
+ NativeType::FLOAT64 => 8,
117
+ NativeType::LONG => FFI::Platform::LONG_SIZE / 8,
118
+ NativeType::ULONG => FFI::Platform::LONG_SIZE / 8,
119
+ NativeType::POINTER => FFI::Platform::ADDRESS_SIZE / 8,
120
+ }
121
+
122
+ def self.size_to_type(size)
123
+ if sz = TypeSizes[size]
124
+ return sz
125
+ end
126
+
127
+ # Be like C, use int as the default type size.
128
+ return :int
129
+ end
130
+ def self.type_size(type)
131
+ if sz = SizeTypes[find_type(type)]
132
+ return sz
133
+ end
134
+ raise ArgumentError, "Unknown native type"
135
+ end
136
+
137
+ # Load all the platform dependent types
138
+ begin
139
+ File.open(File.join(FFI::Platform::CONF_DIR, 'types.conf'), "r") do |f|
140
+ prefix = "rbx.platform.typedef."
141
+ f.each_line { |line|
142
+ if line.index(prefix) == 0
143
+ new_type, orig_type = line.chomp.slice(prefix.length..-1).split(/\s*=\s*/)
144
+ add_typedef(orig_type.to_sym, new_type.to_sym)
145
+ end
146
+ }
147
+ end
148
+ rescue Errno::ENOENT
149
+ end
150
+ end
@@ -0,0 +1,30 @@
1
+ module FFI
2
+ class VariadicInvoker
3
+ def VariadicInvoker.new(library, function, arg_types, ret_type, options)
4
+ invoker = self.__new(library, function, ret_type, options[:convention].to_s)
5
+ invoker.init(arg_types, options[:type_map])
6
+ invoker
7
+ end
8
+ def init(arg_types, type_map)
9
+ @fixed = Array.new
10
+ @type_map = type_map
11
+ arg_types.each_with_index do |type, i|
12
+ @fixed << type unless type == FFI::NativeType::VARARGS
13
+ end
14
+ end
15
+ def call(*args, &block)
16
+ param_types = Array.new(@fixed)
17
+ param_values = Array.new
18
+ @fixed.each_with_index do |t, i|
19
+ param_values << args[i]
20
+ end
21
+ i = @fixed.length
22
+ while i < args.length
23
+ param_types << FFI.find_type(args[i], @type_map)
24
+ param_values << args[i + 1]
25
+ i += 2
26
+ end
27
+ invoke(param_types, param_values, &block)
28
+ end
29
+ end
30
+ end
@@ -17,11 +17,14 @@ CCC=g++
17
17
  CXX=g++
18
18
  FC=
19
19
 
20
+ # Macros
21
+ PLATFORM=GNU-MacOSX
22
+
20
23
  # Include project Makefile
21
24
  include ruby-ffi-Makefile.mk
22
25
 
23
26
  # Object Directory
24
- OBJECTDIR=build/Default/GNU-MacOSX
27
+ OBJECTDIR=build/Default/${PLATFORM}
25
28
 
26
29
  # Object Files
27
30
  OBJECTFILES=
@@ -41,14 +44,14 @@ LDLIBSOPTIONS=
41
44
 
42
45
  # Build Targets
43
46
  .build-conf: ${BUILD_SUBPROJECTS}
44
- cd . && make -f Makefile
47
+ cd . && rake compile
45
48
 
46
49
  # Subprojects
47
50
  .build-subprojects:
48
51
 
49
52
  # Clean Targets
50
53
  .clean-conf:
51
- cd . && make -f Makefile clean
54
+ cd . && rake clean
52
55
 
53
56
  # Subprojects
54
57
  .clean-subprojects:
@@ -35,19 +35,19 @@ ALLCONFS=Default
35
35
 
36
36
 
37
37
  # build
38
- .build-impl: .validate-impl .depcheck-impl
38
+ .build-impl: .build-pre .validate-impl .depcheck-impl
39
39
  @#echo "=> Running $@... Configuration=$(CONF)"
40
40
  ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .build-conf
41
41
 
42
42
 
43
43
  # clean
44
- .clean-impl: .validate-impl .depcheck-impl
44
+ .clean-impl: .clean-pre .validate-impl .depcheck-impl
45
45
  @#echo "=> Running $@... Configuration=$(CONF)"
46
46
  ${MAKE} -f nbproject/Makefile-${CONF}.mk SUBPROJECTS=${SUBPROJECTS} .clean-conf
47
47
 
48
48
 
49
49
  # clobber
50
- .clobber-impl: .depcheck-impl
50
+ .clobber-impl: .clobber-pre .depcheck-impl
51
51
  @#echo "=> Running $@..."
52
52
  for CONF in ${ALLCONFS}; \
53
53
  do \
@@ -55,7 +55,7 @@ ALLCONFS=Default
55
55
  done
56
56
 
57
57
  # all
58
- .all-impl: .depcheck-impl
58
+ .all-impl: .all-pre .depcheck-impl
59
59
  @#echo "=> Running $@..."
60
60
  for CONF in ${ALLCONFS}; \
61
61
  do \
@@ -92,7 +92,7 @@ ALLCONFS=Default
92
92
 
93
93
 
94
94
  # help
95
- .help-impl:
95
+ .help-impl: .help-pre
96
96
  @echo "This makefile supports the following configurations:"
97
97
  @echo " ${ALLCONFS}"
98
98
  @echo ""
@@ -0,0 +1,72 @@
1
+ #!/bin/bash -x
2
+
3
+ #
4
+ # Generated - do not edit!
5
+ #
6
+
7
+ # Macros
8
+ TOP=`pwd`
9
+ PLATFORM=GNU-MacOSX
10
+ TMPDIR=build/Default/${PLATFORM}/tmp-packaging
11
+ TMPDIRNAME=tmp-packaging
12
+ OUTPUT_PATH=MissingOutputInProject
13
+ OUTPUT_BASENAME=MissingOutputInProject
14
+ PACKAGE_TOP_DIR=ruby-ffi/
15
+
16
+ # Functions
17
+ function checkReturnCode
18
+ {
19
+ rc=$?
20
+ if [ $rc != 0 ]
21
+ then
22
+ exit $rc
23
+ fi
24
+ }
25
+ function makeDirectory
26
+ # $1 directory path
27
+ # $2 permission (optional)
28
+ {
29
+ mkdir -p "$1"
30
+ checkReturnCode
31
+ if [ "$2" != "" ]
32
+ then
33
+ chmod $2 "$1"
34
+ checkReturnCode
35
+ fi
36
+ }
37
+ function copyFileToTmpDir
38
+ # $1 from-file path
39
+ # $2 to-file path
40
+ # $3 permission
41
+ {
42
+ cp "$1" "$2"
43
+ checkReturnCode
44
+ if [ "$3" != "" ]
45
+ then
46
+ chmod $3 "$2"
47
+ checkReturnCode
48
+ fi
49
+ }
50
+
51
+ # Setup
52
+ cd "${TOP}"
53
+ mkdir -p dist/Default/${PLATFORM}/package
54
+ rm -rf ${TMPDIR}
55
+ mkdir -p ${TMPDIR}
56
+
57
+ # Copy files and create directories and links
58
+ cd "${TOP}"
59
+ makeDirectory ${TMPDIR}/ruby-ffi/bin
60
+ copyFileToTmpDir "${OUTPUT_PATH}" "${TMPDIR}/${PACKAGE_TOP_DIR}bin/${OUTPUT_BASENAME}" 0755
61
+
62
+
63
+ # Generate tar file
64
+ cd "${TOP}"
65
+ rm -f dist/Default/${PLATFORM}/package/ruby-ffi.tar
66
+ cd ${TMPDIR}
67
+ tar -vcf ../../../../dist/Default/${PLATFORM}/package/ruby-ffi.tar *
68
+ checkReturnCode
69
+
70
+ # Cleanup
71
+ cd "${TOP}"
72
+ rm -rf ${TMPDIR}