Re-enable spec/library for full CI runs.
[rbx.git] / lib / ffi / types_generator.rb
blobc832a17e967e3a2673d29580bdb479eb6542e8af
1 require 'tempfile'
3 module FFI
4   class TypesGenerator
6     ##
7     # Maps different C types to the C type representations we use
9     TYPE_MAP = {
10                "char" => :char,
11         "signed char" => :char,
12       "__signed char" => :char,
13       "unsigned char" => :uchar,
15                "short"     => :short,
16         "signed short"     => :short,
17         "signed short int" => :short,
18       "unsigned short"     => :ushort,
19       "unsigned short int" => :ushort,
21                "int" => :int,
22         "signed int" => :int,
23       "unsigned int" => :uint,
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,
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,
40       "char *" => :string,
41       "void *" => :pointer,
42     }
44     def self.generate
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
53         io.close
55         typedefs = `cpp -D_DARWIN_USE_64_BIT_INODE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 #{io.path}`
56       end
58       code = ""
60       typedefs.each do |type|
61         # We only care about single line typedef
62         next unless type =~ /typedef/
63         # Ignore unions or structs
64         next if type =~ /union|struct/
65         
66         # strip off the starting typedef and ending ;
67         type.gsub!(/^(.*typedef\s*)/, "")
68         type.gsub!(/\s*;\s*$/, "")
69     
70         parts = type.split(/\s+/)
71         def_type   = parts.join(" ")
73         # GCC does mapping with __attribute__ stuf, also see
74         # http://hal.cs.berkeley.edu/cil/cil016.html section 16.2.7.  Problem
75         # with this is that the __attribute__ stuff can either occur before or
76         # after the new type that is defined...
77         if type =~ /__attribute__/
78           if parts.last =~ /__QI__|__HI__|__SI__|__DI__|__word__/
80             # In this case, the new type is BEFORE __attribute__ we need to
81             # find the final_type as the type before the part that starts with
82             # __attribute__
83             final_type = ""
84             parts.each do |p|
85               break if p =~ /__attribute__/
86               final_type = p
87             end
88           else
89             final_type = parts.pop
90           end
91           
92           def_type = case type
93                      when /__QI__/   then "char"
94                      when /__HI__/   then "short"
95                      when /__SI__/   then "int"
96                      when /__DI__/   then "long long"
97                      when /__word__/ then "long"
98                      else                 "int"
99                      end
101           def_type = "unsigned #{def_type}" if type =~ /unsigned/
102         else
103           final_type = parts.pop
104           def_type   = parts.join(" ")
105         end
106         
107         if type = TYPE_MAP[def_type]
108           code << "rbx.platform.typedef.#{final_type} = #{type}\n"
109           TYPE_MAP[final_type] = TYPE_MAP[def_type]
110         else
111           # Fallback to an ordinary pointer if we don't know the type
112           if def_type =~ /\*/
113             code << "rbx.platform.typedef.#{final_type} = pointer\n"
114             TYPE_MAP[final_type] = :pointer
115           end
116         end
117       end
119       code
120     end
122   end