c2ffi4rb 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: []