ffi_gen 0.8 → 1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (5) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +77 -0
  3. data/lib/ffi_gen.rb +195 -108
  4. data/lib/ffi_gen/clang.rb +351 -349
  5. metadata +6 -4
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Richard Musiol
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,77 @@
1
+ ffi_gen - A Generator for Ruby FFI bindings
2
+ ===========================================
3
+
4
+ *Author:* Richard Musiol
5
+ *Contributors:* Jeremy Voorhis (thanks for the initial idea)
6
+ *License:* MIT (see LICENSE)
7
+
8
+
9
+ Features
10
+ --------
11
+ * Generation of FFI methods, structures, enums and callbacks
12
+ * Generation of YARD documentation comments
13
+ * Tested with headers of the following libraries:
14
+ * Clang
15
+ * LLVM
16
+ * OpenGL
17
+
18
+
19
+ Requirements
20
+ ------------
21
+
22
+ * Ruby 1.9
23
+ * Clang 3.0 ([Download](http://llvm.org/releases/download.html#3.0), use the binaries or configure with ``--enable-shared``)
24
+
25
+ *These requirements are only for running the generator. The generated files are Ruby 1.8 compatible and do not need Clang.*
26
+
27
+
28
+ Example
29
+ -------
30
+ Use the following interface in a script or Rake task:
31
+
32
+ require "ffi_gen"
33
+
34
+ FFIGen.generate(
35
+ ruby_module: "Clang",
36
+ ffi_lib: "clang",
37
+ headers: ["clang-c/Index.h"],
38
+ cflags: `llvm-config --cflags`.split(" "),
39
+ prefixes: ["clang_", "CX"],
40
+ blacklist: ["clang_getExpansionLocation"],
41
+ output: "clang.rb"
42
+ )
43
+
44
+ Output: [clang.rb](https://github.com/neelance/ffi_gen/blob/master/lib/ffi_gen/clang.rb)
45
+
46
+
47
+ Hints
48
+ -----
49
+
50
+ You may need to set additional include directories:
51
+
52
+ export CPATH=/usr/lib/gcc/x86_64-linux-gnu/4.6.1/include
53
+
54
+ Your GCC include paths can be seen with:
55
+
56
+ `gcc -print-prog-name=cc1` -v
57
+
58
+
59
+ Projects using ffi_gen
60
+ ----------------------
61
+
62
+ * https://github.com/jvoorhis/ruby-llvm
63
+
64
+
65
+ Roadmap
66
+ -------
67
+
68
+ * Support for more libraries:
69
+ * Cairo
70
+ * (Write me if you have a whish)
71
+ * Automatic generation of object oriented wrappers
72
+ * Polish YARD documentation comments some more
73
+
74
+
75
+ Feedback
76
+ --------
77
+ Please use GitHub's issue tracker for problems or suggestions. Pull requests are welcome, too.
@@ -24,6 +24,8 @@ class Clang::String
24
24
  end
25
25
 
26
26
  class FFIGen
27
+ RUBY_KEYWORDS = %w{alias allocate and begin break case class def defined do else elsif end ensure false for if in initialize module next nil not or redo rescue retry return self super then true undef unless until when while yield}
28
+
27
29
  class Enum
28
30
  attr_reader :constants
29
31
 
@@ -34,55 +36,63 @@ class FFIGen
34
36
  @constants = []
35
37
  end
36
38
 
37
- def to_s
39
+ def write(writer)
38
40
  prefix_length = 0
39
41
  suffix_length = 0
40
42
 
41
43
  unless @constants.size < 2
42
- search_pattern = @constants.all? { |constant| constant[0].include? "_" } ? /(?<=_)/ : /[A-Z]/
43
- first_name = @constants.first[0]
44
+ search_pattern = @constants.all? { |constant| constant[:name].include? "_" } ? /(?<=_)/ : /[A-Z]/
45
+ first_name = @constants.first[:name]
44
46
 
45
47
  loop do
46
48
  position = first_name.index(search_pattern, prefix_length + 1) or break
47
49
  prefix = first_name[0...position]
48
- break if not @constants.all? { |constant| constant[0].start_with? prefix }
50
+ break if not @constants.all? { |constant| constant[:name].start_with? prefix }
49
51
  prefix_length = position
50
52
  end
51
53
 
52
54
  loop do
53
55
  position = first_name.rindex(search_pattern, first_name.size - suffix_length - 1) or break
54
56
  prefix = first_name[position..-1]
55
- break if not @constants.all? { |constant| constant[0].end_with? prefix }
57
+ break if not @constants.all? { |constant| constant[:name].end_with? prefix }
56
58
  suffix_length = first_name.size - position
57
59
  end
58
60
  end
59
61
 
60
- symbols = []
61
- definitions = []
62
- symbol_descriptions = []
63
- @constants.map do |(constant_name, constant_value, constant_comment)|
64
- symbol = ":#{@generator.to_ruby_lowercase constant_name[prefix_length..(-1 - suffix_length)]}"
65
- symbols << symbol
66
- definitions << " #{symbol}#{constant_value ? ", #{constant_value}" : ""}"
67
- symbol_descriptions << " # #{symbol} ::\n # #{@generator.create_description_comment(constant_comment, ' # ', true)}\n"
62
+ @constants.each do |constant|
63
+ constant[:symbol] = ":#{@generator.to_ruby_lowercase constant[:name][prefix_length..(-1 - suffix_length)]}"
68
64
  end
69
65
 
70
- str = ""
71
- str << @generator.create_description_comment(@comment, ' # ')
72
- str << " # \n"
73
- str << " # === Options:\n#{symbol_descriptions.join} #\n"
74
- str << " # @return [Array<Symbol>]\n"
75
- str << " def self.#{@generator.to_ruby_lowercase @name}_enum\n [#{symbols.join(', ')}]\n end\n"
76
- str << " enum :#{@generator.to_ruby_lowercase @name}, [\n#{definitions.join(",\n")}\n ]"
77
- str
66
+ writer.comment do
67
+ writer.write_description @comment
68
+ writer.puts "", "<em>This entry is only for documentation and no real method. The FFI::Enum can be accessed via #enum_type(:#{ruby_name}).</em>"
69
+ writer.puts "", "=== Options:"
70
+ @constants.each do |constant|
71
+ writer.puts "#{constant[:symbol]} ::"
72
+ writer.write_description constant[:comment], false, " ", " "
73
+ end
74
+ writer.puts "", "@method _enum_#{ruby_name}_", "@return [Symbol]", "@scope class"
75
+ end
76
+
77
+ writer.puts "enum :#{ruby_name}, ["
78
+ writer.indent do
79
+ writer.write_array @constants, "," do |constant|
80
+ "#{constant[:symbol]}#{constant[:value] ? ", #{constant[:value]}" : ''}"
81
+ end
82
+ end
83
+ writer.puts "]", ""
84
+ end
85
+
86
+ def ruby_name
87
+ @ruby_name ||= @generator.to_ruby_lowercase @name
78
88
  end
79
89
 
80
90
  def type_name(short)
81
- short ? @name : "Symbol from #{@generator.to_ruby_lowercase @name}_enum"
91
+ short ? @name : "Symbol from _enum_#{ruby_name}_"
82
92
  end
83
93
 
84
94
  def reference
85
- ":#{@generator.to_ruby_lowercase @name}"
95
+ ":#{ruby_name}"
86
96
  end
87
97
  end
88
98
 
@@ -96,31 +106,41 @@ class FFIGen
96
106
  @fields = []
97
107
  end
98
108
 
99
- def to_s
100
- field_definitions = []
101
- field_descriptions = []
102
- @fields.each do |(field_name, field_type, field_comment)|
103
- symbol = ":#{@generator.to_ruby_lowercase field_name}"
104
- field_definitions << "#{symbol}, #{@generator.to_ffi_type field_type}"
105
- field_descriptions << " # #{symbol} ::\n # (#{@generator.to_type_name field_type}) #{@generator.create_description_comment(field_comment, ' # ', true)}\n"
109
+ def write(writer)
110
+ @fields.each do |field|
111
+ field[:symbol] = ":#{@generator.to_ruby_lowercase field[:name]}"
106
112
  end
107
113
 
108
- str = ""
109
- str << @generator.create_description_comment(@comment, ' # ')
110
- str << " # \n"
111
- str << " # = Fields:\n#{field_descriptions.join} #\n"
112
- str << " class #{@generator.to_ruby_camelcase @name} < FFI::Struct\n"
113
- str << " layout #{field_definitions.join(",\n ")}\n" unless @fields.empty?
114
- str << " end"
115
- str
114
+ writer.comment do
115
+ writer.write_description @comment
116
+ unless @fields.empty?
117
+ writer.puts "", "= Fields:"
118
+ @fields.each do |field|
119
+ writer.puts "#{field[:symbol]} ::"
120
+ writer.write_description field[:comment], false, " (#{@generator.to_type_name field[:type]}) ", " "
121
+ end
122
+ end
123
+ end
124
+
125
+ writer.puts "class #{ruby_name} < FFI::Struct"
126
+ writer.indent do
127
+ writer.write_array @fields, ",", "layout ", " " do |field|
128
+ "#{field[:symbol]}, #{@generator.to_ffi_type field[:type]}"
129
+ end
130
+ end
131
+ writer.puts "end", ""
132
+ end
133
+
134
+ def ruby_name
135
+ @ruby_name ||= @generator.to_ruby_camelcase @name
116
136
  end
117
137
 
118
138
  def type_name(short)
119
- @generator.to_ruby_camelcase @name
139
+ ruby_name
120
140
  end
121
141
 
122
142
  def reference
123
- "#{type_name(false)}.by_value"
143
+ "#{ruby_name}.by_value"
124
144
  end
125
145
  end
126
146
 
@@ -136,25 +156,22 @@ class FFIGen
136
156
  @comment = comment
137
157
  end
138
158
 
139
- def to_s
140
- ruby_name = @generator.to_ruby_lowercase @name
141
- ruby_parameters = @parameters.map do |(name, type)|
142
- ruby_param_type = @generator.to_type_name type
143
- ruby_param_name = @generator.to_ruby_lowercase(name.empty? ? @generator.to_type_name(type, true) : name)
144
- [ruby_param_name, ruby_param_type, []]
159
+ def write(writer)
160
+ @parameters.each do |parameter|
161
+ parameter[:ruby_type] = @generator.to_type_name parameter[:type]
162
+ parameter[:ruby_name] = @generator.to_ruby_lowercase(parameter[:name].empty? ? @generator.to_type_name(parameter[:type], true) : parameter[:name])
163
+ parameter[:description] = []
145
164
  end
146
165
 
147
- ffi_signature = "[#{@parameters.map{ |(name, type)| @generator.to_ffi_type type }.join(', ')}], #{@generator.to_ffi_type @return_type}"
148
-
149
166
  function_description = []
150
167
  return_value_description = []
151
168
  current_description = function_description
152
169
  @comment.split("\n").map do |line|
153
- line = @generator.prepare_comment_line line
170
+ line = writer.prepare_comment_line line
154
171
  if line.gsub! /\\param (.*?) /, ''
155
- index = @parameters.index { |(name, type)| name == $1 }
156
- if index
157
- current_description = ruby_parameters[index][2]
172
+ parameter = @parameters.find { |parameter| parameter[:name] == $1 }
173
+ if parameter
174
+ current_description = parameter[:description]
158
175
  else
159
176
  current_description << "#{$1}: "
160
177
  end
@@ -163,33 +180,102 @@ class FFIGen
163
180
  current_description << line
164
181
  end
165
182
 
166
- str = ""
167
- if @is_callback
168
- str << " # <em>This is no real method. This entry is only for documentation of the callback.</em>\n"
169
- str << " # \n"
170
- end
171
- str << @generator.create_description_comment(function_description, ' # ')
172
- str << " # \n"
173
- str << " # @method #{ruby_name}#{@is_callback ? '_callback' : ''}(#{ruby_parameters.map{ |(name, type, description)| name }.join(', ')})\n"
174
- ruby_parameters.each do |(name, type, description)|
175
- str << " # @param [#{type}] #{name} #{@generator.create_description_comment(description, ' # ', true)}\n"
183
+ writer.comment do
184
+ writer.write_description function_description
185
+ writer.puts "", "<em>This entry is only for documentation and no real method.</em>" if @is_callback
186
+ writer.puts "", "@method #{@is_callback ? "_callback_#{ruby_name}_" : ruby_name}(#{@parameters.map{ |parameter| parameter[:ruby_name] }.join(', ')})"
187
+ @parameters.each do |parameter|
188
+ writer.write_description parameter[:description], false, "@param [#{parameter[:ruby_type]}] #{parameter[:ruby_name]} ", " "
189
+ end
190
+ writer.write_description return_value_description, false, "@return [#{@generator.to_type_name @return_type}] ", " "
191
+ writer.puts "@scope class"
176
192
  end
177
- str << " # @return [#{@generator.to_type_name @return_type}] #{@generator.create_description_comment(return_value_description, ' # ', true)}\n"
178
- str << " # @scope class\n"
193
+
194
+ ffi_signature = "[#{@parameters.map{ |parameter| @generator.to_ffi_type parameter[:type] }.join(', ')}], #{@generator.to_ffi_type @return_type}"
179
195
  if @is_callback
180
- str << " callback :#{ruby_name}, #{ffi_signature}"
196
+ writer.puts "callback :#{ruby_name}, #{ffi_signature}", ""
181
197
  else
182
- str << " attach_function :#{ruby_name}, :#{@name}, #{ffi_signature}"
198
+ writer.puts "attach_function :#{ruby_name}, :#{@name}, #{ffi_signature}", ""
183
199
  end
184
- str
200
+ end
201
+
202
+ def ruby_name
203
+ @ruby_name ||= @generator.to_ruby_lowercase @name, true
185
204
  end
186
205
 
187
206
  def type_name(short)
188
- "Proc(#{@generator.to_ruby_lowercase @name}_callback)"
207
+ "Proc(_callback_#{ruby_name}_)"
189
208
  end
190
209
 
191
210
  def reference
192
- ":#{@generator.to_ruby_lowercase @name}"
211
+ ":#{ruby_name}"
212
+ end
213
+ end
214
+
215
+ class Constant
216
+ def initialize(generator, name, value)
217
+ @generator = generator
218
+ @name = name
219
+ @value = value
220
+ end
221
+
222
+ def write(writer)
223
+ writer.puts "#{@generator.to_ruby_lowercase(@name, true).upcase} = #{@value}", ""
224
+ end
225
+ end
226
+
227
+ class Writer
228
+ attr_reader :output
229
+
230
+ def initialize
231
+ @indentation = ""
232
+ @output = ""
233
+ end
234
+
235
+ def indent(prefix = " ")
236
+ previous_indentation = @indentation
237
+ @indentation += prefix
238
+ yield
239
+ @indentation = previous_indentation
240
+ end
241
+
242
+ def comment(&block)
243
+ indent "# ", &block
244
+ end
245
+
246
+ def puts(*lines)
247
+ lines.each do |line|
248
+ @output << "#{@indentation}#{line}\n"
249
+ end
250
+ end
251
+
252
+ def write_array(array, separator = "", first_line_prefix = "", other_lines_prefix = "")
253
+ array.each_with_index do |entry, index|
254
+ entry = yield entry if block_given?
255
+ puts "#{index == 0 ? first_line_prefix : other_lines_prefix}#{entry}#{index < array.size - 1 ? separator : ''}"
256
+ end
257
+ end
258
+
259
+ def prepare_comment_line(line)
260
+ line = line.dup
261
+ line.sub! /\ ?\*+\/\s*$/, ''
262
+ line.sub! /^\s*\/?\*+ ?/, ''
263
+ line.gsub! /\\(brief|determine) /, ''
264
+ line.gsub! '[', '('
265
+ line.gsub! ']', ')'
266
+ line
267
+ end
268
+
269
+ def write_description(description, not_documented_message = true, first_line_prefix = "", other_lines_prefix = "")
270
+ if description.is_a? String
271
+ description = description.split("\n").map { |line| prepare_comment_line(line) }
272
+ end
273
+
274
+ description.shift while not description.empty? and description.first.strip.empty?
275
+ description.pop while not description.empty? and description.last.strip.empty?
276
+ description << (not_documented_message ? "(Not documented)" : "") if description.empty?
277
+
278
+ write_array description, "", first_line_prefix, other_lines_prefix
193
279
  end
194
280
  end
195
281
 
@@ -204,6 +290,9 @@ class FFIGen
204
290
  @blacklist = options.fetch :blacklist, []
205
291
  @output = options.fetch :output, $stdout
206
292
 
293
+ blacklist = @blacklist
294
+ @blacklist = lambda { |name| blacklist.include? name } if @blacklist.is_a? Array
295
+
207
296
  @translation_unit = nil
208
297
  @declarations = nil
209
298
  end
@@ -221,7 +310,7 @@ class FFIGen
221
310
  args_ptr.write_array_of_pointer pointers
222
311
 
223
312
  index = Clang.create_index 0, 0
224
- @translation_unit = Clang.parse_translation_unit index, File.join(File.dirname(__FILE__), "ffi_gen/empty.h"), args_ptr, args.size, nil, 0, 0
313
+ @translation_unit = Clang.parse_translation_unit index, File.join(File.dirname(__FILE__), "ffi_gen/empty.h"), args_ptr, args.size, nil, 0, Clang.enum_type(:translation_unit_flags)[:detailed_preprocessing_record]
225
314
 
226
315
  Clang.get_num_diagnostics(@translation_unit).times do |i|
227
316
  diag = Clang.get_diagnostic @translation_unit, i
@@ -257,7 +346,7 @@ class FFIGen
257
346
  next if not header_files.include? file
258
347
 
259
348
  name = Clang.get_cursor_spelling(declaration).to_s_and_dispose
260
- next if blacklist.include? name
349
+ next if @blacklist[name]
261
350
 
262
351
  comment = extract_comment translation_unit, comment_range
263
352
 
@@ -274,7 +363,7 @@ class FFIGen
274
363
  next if function_child[:kind] != :parm_decl
275
364
  param_name = Clang.get_cursor_spelling(function_child).to_s_and_dispose
276
365
  param_type = Clang.get_cursor_type function_child
277
- function.parameters << [param_name, param_type]
366
+ function.parameters << { name: param_name, type: param_type}
278
367
  end
279
368
 
280
369
  when :typedef_decl
@@ -290,10 +379,25 @@ class FFIGen
290
379
  typedef_children[1..-1].each do |param_decl|
291
380
  param_name = Clang.get_cursor_spelling(param_decl).to_s_and_dispose
292
381
  param_type = Clang.get_cursor_type param_decl
293
- callback.parameters << [param_name, param_type]
382
+ callback.parameters << { name: param_name, type: param_type }
294
383
  end
295
384
  end
385
+
386
+ when :macro_definition
387
+ tokens_ptr_ptr = FFI::MemoryPointer.new :pointer
388
+ num_tokens_ptr = FFI::MemoryPointer.new :uint
389
+ Clang.tokenize translation_unit, extent, tokens_ptr_ptr, num_tokens_ptr
390
+ num_tokens = num_tokens_ptr.read_uint
391
+ tokens_ptr = FFI::Pointer.new Clang::Token, tokens_ptr_ptr.read_pointer
296
392
 
393
+ if num_tokens == 3
394
+ token = Clang::Token.new tokens_ptr[1]
395
+ if Clang.get_token_kind(token) == :literal
396
+ value = Clang.get_token_spelling(translation_unit, token).to_s_and_dispose
397
+ @declarations[name] = Constant.new self, name, value
398
+ end
399
+ end
400
+
297
401
  end
298
402
  end
299
403
 
@@ -301,12 +405,20 @@ class FFIGen
301
405
  end
302
406
 
303
407
  def generate
304
- content = "# Generated by ffi_gen. Please do not change this file by hand.\n\nrequire 'ffi'\n\nmodule #{@ruby_module}\n extend FFI::Library\n ffi_lib '#{@ffi_lib}'\n\n#{declarations.values.join("\n\n")}\n\nend"
408
+ writer = Writer.new
409
+ writer.puts "# Generated by ffi_gen. Please do not change this file by hand.", "", "require 'ffi'", "", "module #{@ruby_module}"
410
+ writer.indent do
411
+ writer.puts "extend FFI::Library", "ffi_lib '#{@ffi_lib}'", ""
412
+ declarations.each do |name, declaration|
413
+ declaration.write writer
414
+ end
415
+ end
416
+ writer.puts "end"
305
417
  if @output.is_a? String
306
- File.open(@output, "w") { |file| file.write content }
418
+ File.open(@output, "w") { |file| file.write writer.output }
307
419
  puts "ffi_gen: #{@output}"
308
420
  else
309
- @output.write content
421
+ @output.write writer.output
310
422
  end
311
423
  end
312
424
 
@@ -340,7 +452,7 @@ class FFIGen
340
452
  constant_comment = extract_comment translation_unit, constant_comment_range
341
453
  previous_constant_location = constant_location
342
454
 
343
- enum.constants << [constant_name, constant_value, constant_comment]
455
+ enum.constants << { name: constant_name, value: constant_value, comment: constant_comment }
344
456
  end
345
457
 
346
458
  when :struct_decl
@@ -357,7 +469,7 @@ class FFIGen
357
469
  field_comment = extract_comment translation_unit, field_comment_range
358
470
  previous_field_location = field_location
359
471
 
360
- struct.fields << [field_name, field_type, field_comment]
472
+ struct.fields << { name: field_name, type: field_type, comment: field_comment }
361
473
  end
362
474
  end
363
475
  end
@@ -389,6 +501,7 @@ class FFIGen
389
501
  when :u_int then ":uint"
390
502
  when :u_long then ":ulong"
391
503
  when :u_long_long then ":ulong_long"
504
+ when :char_s, :s_char then ":char"
392
505
  when :short then ":short"
393
506
  when :int then ":int"
394
507
  when :long then ":long"
@@ -416,7 +529,7 @@ class FFIGen
416
529
  case canonical_type[:kind]
417
530
  when :void then "nil"
418
531
  when :bool then "Boolean"
419
- when :u_char, :u_short, :u_int, :u_long, :u_long_long, :short, :int, :long, :long_long then "Integer"
532
+ when :u_char, :u_short, :u_int, :u_long, :u_long_long, :char_s, :s_char, :short, :int, :long, :long_long then "Integer"
420
533
  when :float, :double then "Float"
421
534
  when :pointer
422
535
  pointee_type = Clang.get_pointee_type canonical_type
@@ -452,7 +565,7 @@ class FFIGen
452
565
  end
453
566
  end
454
567
 
455
- def to_ruby_lowercase(str)
568
+ def to_ruby_lowercase(str, avoid_keywords = false)
456
569
  str = str.dup
457
570
  str.sub! /^(#{@prefixes.join('|')})/, '' # remove prefixes
458
571
  str.gsub! /([A-Z][a-z])/, '_\1' # add underscores before word beginnings
@@ -460,6 +573,8 @@ class FFIGen
460
573
  str.sub! /^_*/, '' # remove underscores at the beginning
461
574
  str.gsub! /__+/, '_' # replace multiple underscores by only one
462
575
  str.downcase!
576
+ str.sub! /^\d/, '_\1' # fix illegal beginnings
577
+ str = "_#{str}" if avoid_keywords and RUBY_KEYWORDS.include? str
463
578
  str
464
579
  end
465
580
 
@@ -469,34 +584,6 @@ class FFIGen
469
584
  str
470
585
  end
471
586
 
472
- def prepare_comment_line(line)
473
- line = line.dup
474
- line.sub! /\ ?\*+\/\s*$/, ''
475
- line.sub! /^\s*\/?\*+ ?/, ''
476
- line.gsub! /\\(brief|determine) /, ''
477
- line.gsub! '[', '('
478
- line.gsub! ']', ')'
479
- line
480
- end
481
-
482
- def create_description_comment(description, line_prefix, inline_mode = false)
483
- if description.is_a? String
484
- description = description.split("\n").map { |line| prepare_comment_line(line) }
485
- end
486
-
487
- description.shift while not description.empty? and description.first.strip.empty?
488
- description.pop while not description.empty? and description.last.strip.empty?
489
- description << "(Not documented)" if not inline_mode and description.empty?
490
-
491
- str = ""
492
- description.each_with_index do |line, index|
493
- str << line_prefix if not inline_mode or index > 0
494
- str << line
495
- str << "\n" if not inline_mode or index < description.size - 1
496
- end
497
- str
498
- end
499
-
500
587
  def self.generate(options = {})
501
588
  self.new(options).generate
502
589
  end