c2ffi4rb 0.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +31 -0
- data/exe/c2ffi4rb +36 -0
- data/lib/c2ffi4rb/parser.rb +188 -0
- data/lib/c2ffi4rb/version.rb +3 -0
- data/lib/c2ffi4rb.rb +7 -0
- metadata +93 -0
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
|
data/lib/c2ffi4rb.rb
ADDED
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: []
|