c2ffi4rb 0.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 86a593339fb44c53b753ecbae5120b0d3cd67363f8899b8122fa100f800d1fcc
4
+ data.tar.gz: c2a2c0ab90ce7e1307d706b268778267237691a56ce71491bfe2503b27b3f8c8
5
+ SHA512:
6
+ metadata.gz: 42260432b9a7267183c23e4ab79303257e25445c5ea5be46bcf61d7d27b43e8283144741bcf6eb95a9fd66ac7e3094067e68165648fa6fe13594459b588670f4
7
+ data.tar.gz: '08281db0ccbaedba8fb39908f343c69dbe348da5e8e49071ded01c382468962b84b308b59c6a57c707586a94dba6b5fb86937d48e0c3a1f37486ae1b52b29bdd'
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # c2ffi4rb
2
+
3
+ [c2ffi](https://github.com/rpav/c2ffi) - FFI binding generator - for Ruby
4
+
5
+ # installation
6
+
7
+ ```sh
8
+ gem install c2ffi4rb
9
+ ```
10
+
11
+ ## Usage
12
+
13
+ First, produce a `spec` file using `c2ffi`:
14
+
15
+ ```sh
16
+ c2ffi -M macros.h -o example.json example.h
17
+ c2ffi -o macros.json macros.h
18
+ ```
19
+
20
+ Now you can generate a file manually with the included tool,
21
+ `c2ffi-ruby`, as follows:
22
+
23
+ ```sh
24
+ c2ffi4rb example.json macro.json > simple.rb
25
+ ```
26
+
27
+ This produces the `simple.rb` file, as included.
28
+
29
+ ## Licence
30
+
31
+ - [LGPL-2](https://github.com/rpav/c2ffi-ruby/blob/master/c2ffi-ruby.gemspec)
data/exe/c2ffi4rb ADDED
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ ## This is meant to be more of an unsophisticated demo than a
5
+ ## production tool. Generating spec and ruby files should be part of
6
+ ## your build system. But this is how you can use it.
7
+
8
+ require 'optparse'
9
+ require 'json'
10
+ require 'c2ffi4rb'
11
+
12
+ options = {}
13
+
14
+ Version = C2FFI4RB::VERSION # Fixme
15
+
16
+ opts = OptionParser.new
17
+ opts.banner = 'Usage: c2ffi4rb [options] [file1, file2, ...]'
18
+ opts.on('-h', '--help', 'Show this message') do
19
+ puts opts
20
+ exit
21
+ end
22
+ opts.parse!
23
+
24
+ if ARGV.empty?
25
+ warn opts
26
+ exit 1
27
+ end
28
+
29
+ spec = []
30
+ ARGV.each do |file|
31
+ File.open(file) do |io|
32
+ spec += JSON.parse(io.read, Hash[:symbolize_names, true])
33
+ end
34
+ end
35
+
36
+ C2FFI4RB::Parser.parse(spec)
@@ -0,0 +1,188 @@
1
+ # frozen_string_literal: true
2
+
3
+ module C2FFI4RB
4
+ class Parser
5
+ TYPE_TABLE = {
6
+ "unsigned-int": :uint,
7
+ "unsigned-char": :uchar,
8
+ "unsigned-long": :ulong,
9
+ "function-pointer": :pointer
10
+ }.freeze
11
+
12
+ def self.parse(arr)
13
+ Parser.new.parse(arr)
14
+ end
15
+
16
+ def initialize
17
+ @struct_type = {}
18
+ @toplevels = []
19
+ @anon_counter = 0
20
+ end
21
+
22
+ def parse(arr)
23
+ arr.each do |form|
24
+ s = parse_toplevel(form)
25
+ @toplevels << s if s
26
+ end
27
+
28
+ @toplevels.each do |t|
29
+ puts
30
+ case t
31
+ when String
32
+ puts "#{t}"
33
+ when Array
34
+ t.each do |l|
35
+ puts "#{l}"
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ private
42
+
43
+ def parse_toplevel(form)
44
+ case form[:tag]
45
+ when 'typedef'
46
+ type = parse_type(form[:type])
47
+
48
+ # I don't think typedef works right with structs, so assign
49
+ if @struct_type[type]
50
+ name = add_struct(form[:name])
51
+ "#{name} = #{type}"
52
+ else
53
+ "typedef #{type}, :#{form[:name]}"
54
+ end
55
+
56
+ when 'const'
57
+ type = parse_type(form[:type])
58
+ if type == ':string'
59
+ "#{form[:name].upcase} = \"#{form[:value]}\""
60
+ else
61
+ "#{form[:name].upcase} = #{form[:value]}"
62
+ end
63
+
64
+ when 'extern'
65
+ 'attach_variable ' \
66
+ ":#{form[:name]}, :#{form[:name]}, #{parse_type(form[:type])}"
67
+
68
+ when 'function'
69
+ s = []
70
+ s << "attach_function '#{form[:name]}', ["
71
+ form[:parameters].each do |f|
72
+ s << " #{parse_type(f[:type])},"
73
+ end
74
+ s << "], #{parse_type(form['return-type'.intern])}"
75
+ # emacs doesn't like :"foo" ---^
76
+
77
+ when 'struct', 'union'
78
+ name = add_struct(form[:name])
79
+ make_struct(form)
80
+
81
+ when 'enum'
82
+ name = add_enum(form[:name])
83
+ s = []
84
+ s << "enum #{name}, ["
85
+ form[:fields].each do |f|
86
+ s << " :#{f[:name]}, #{f[:value]},"
87
+ end
88
+ s << ']'
89
+ end
90
+ end
91
+
92
+ def add_struct(name)
93
+ if name == ''
94
+ @anon_counter += 1
95
+ name = 'Anon_Type_' + @anon_counter.to_s
96
+ return name
97
+ end
98
+
99
+ name = 'C' + name if name.start_with? '_'
100
+
101
+ name = name.capitalize.gsub!(/_([a-z])/) { |m| "_#{m[1].upcase}" }
102
+ @struct_type[name] = true
103
+ name
104
+ end
105
+
106
+ def add_enum(name)
107
+ if name == ''
108
+ @anon_counter += 1
109
+ name = ':anon_type_' + @anon_counter.to_s
110
+ return name
111
+ end
112
+
113
+ if name[0] != ':'
114
+ ":#{name}"
115
+ else
116
+ name
117
+ end
118
+ end
119
+
120
+ def make_struct(form)
121
+ name = add_struct(form[:name])
122
+
123
+ type = if form[:tag] == ':struct'
124
+ 'FFI::Struct'
125
+ else
126
+ 'FFI::Union'
127
+ end
128
+
129
+ s = []
130
+ s << "class #{name} < #{type}"
131
+
132
+ if form[:fields].length.positive?
133
+ s << ' layout \\'
134
+ size = form[:fields].length
135
+ sep = ','
136
+ form[:fields].each_with_index do |f, i|
137
+ sep = '' if i >= (size - 1)
138
+ s << " :#{f[:name]}, #{parse_type(f[:type])}#{sep}"
139
+ end
140
+ end
141
+ s << 'end'
142
+ end
143
+
144
+ def parse_type(form)
145
+ tt = TYPE_TABLE[form[:tag]]
146
+ return tt if tt
147
+
148
+ case form[:tag]
149
+ when ':pointer'
150
+ pointee = parse_type(form[:type])
151
+ if [':char', ':uchar'].include?(pointee)
152
+ ':string'
153
+ elsif @struct_type[pointee]
154
+ "#{@struct_type[pointee]}.ptr"
155
+ else
156
+ ':pointer'
157
+ end
158
+
159
+ when ':array'
160
+ "[#{parse_type(form[:type])}, #{form[:size]}]"
161
+
162
+ when ':struct', ':union'
163
+ add_struct(form[:name])
164
+
165
+ when ':enum'
166
+ add_enum(form[:name])
167
+
168
+ when 'enum'
169
+ form[:name] = add_enum(form[:name])
170
+ parse_toplevel(form)
171
+ form[:name]
172
+
173
+ when 'struct', 'union'
174
+ form[:name] = add_struct(form[:name])
175
+ parse_toplevel(form)
176
+ form[:name]
177
+
178
+ else
179
+ # All non-Classy types are :-prefixed?
180
+ if form[:tag][0] != ':'
181
+ ":#{form[:tag]}"
182
+ else
183
+ form[:tag]
184
+ end
185
+ end
186
+ end
187
+ end
188
+ end
@@ -0,0 +1,3 @@
1
+ module C2FFI4RB
2
+ VERSION = '0.0.0'
3
+ end
data/lib/c2ffi4rb.rb ADDED
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'c2ffi4rb/version'
4
+ require_relative 'c2ffi4rb/parser'
5
+
6
+ module C2FFI4RB
7
+ end
metadata ADDED
@@ -0,0 +1,93 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: c2ffi4rb
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.0
5
+ platform: ruby
6
+ authors:
7
+ - kojix2
8
+ - Ryan Pavlik
9
+ autorequire:
10
+ bindir: exe
11
+ cert_chain: []
12
+ date: 2023-09-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ">="
19
+ - !ruby/object:Gem::Version
20
+ version: '0'
21
+ type: :development
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ version: '0'
28
+ - !ruby/object:Gem::Dependency
29
+ name: minitest
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :development
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: rake
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :development
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: Import C2FFI JSON to ruby/ffi
57
+ email:
58
+ - 2xijok@gmail.com
59
+ - rpavlik@gmail.com
60
+ executables:
61
+ - c2ffi4rb
62
+ extensions: []
63
+ extra_rdoc_files: []
64
+ files:
65
+ - README.md
66
+ - exe/c2ffi4rb
67
+ - lib/c2ffi4rb.rb
68
+ - lib/c2ffi4rb/parser.rb
69
+ - lib/c2ffi4rb/version.rb
70
+ homepage: https://github.com/kojix2/c2ffi4rb
71
+ licenses:
72
+ - LGPL-2
73
+ metadata: {}
74
+ post_install_message:
75
+ rdoc_options: []
76
+ require_paths:
77
+ - lib
78
+ required_ruby_version: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ requirements:
85
+ - - ">="
86
+ - !ruby/object:Gem::Version
87
+ version: '0'
88
+ requirements: []
89
+ rubygems_version: 3.4.10
90
+ signing_key:
91
+ specification_version: 4
92
+ summary: C2FFI for Ruby-FFI
93
+ test_files: []