RubyInlineWithoutZenTest 3.12.2

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.
data/lib/inline.rb ADDED
@@ -0,0 +1,902 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ ##
4
+ # Ruby Inline is a framework for writing ruby extensions in foreign
5
+ # languages.
6
+ #
7
+ # == SYNOPSIS
8
+ #
9
+ # require 'inline'
10
+ # class MyClass
11
+ # inline do |builder|
12
+ # builder.include "<math.h>"
13
+ # builder.c %q{
14
+ # long factorial(int max) {
15
+ # int i=max, result=1;
16
+ # while (i >= 2) { result *= i--; }
17
+ # return result;
18
+ # }
19
+ # }
20
+ # end
21
+ # end
22
+ #
23
+ # == DESCRIPTION
24
+ #
25
+ # Inline allows you to write foreign code within your ruby code. It
26
+ # automatically determines if the code in question has changed and
27
+ # builds it only when necessary. The extensions are then automatically
28
+ # loaded into the class/module that defines it.
29
+ #
30
+ # You can even write extra builders that will allow you to write
31
+ # inlined code in any language. Use Inline::C as a template and look
32
+ # at Module#inline for the required API.
33
+ #
34
+ # == PACKAGING
35
+ #
36
+ # To package your binaries into a gem, use hoe's INLINE and
37
+ # FORCE_PLATFORM env vars.
38
+ #
39
+ # Example:
40
+ #
41
+ # rake package INLINE=1
42
+ #
43
+ # or:
44
+ #
45
+ # rake package INLINE=1 FORCE_PLATFORM=mswin32
46
+ #
47
+ # See hoe for more details.
48
+ #
49
+
50
+ require "rbconfig"
51
+ require "digest/md5"
52
+ require 'fileutils'
53
+ require 'rubygems'
54
+ require "inline/version"
55
+ require "inline/mapping"
56
+
57
+ $TESTING = false unless defined? $TESTING
58
+
59
+ class CompilationError < RuntimeError; end
60
+
61
+ ##
62
+ # The Inline module is the top-level module used. It is responsible
63
+ # for instantiating the builder for the right language used,
64
+ # compilation/linking when needed, and loading the inlined code into
65
+ # the current namespace.
66
+
67
+ module Inline
68
+ WINDOZE = /mswin|mingw/ =~ RUBY_PLATFORM
69
+ RUBINIUS = defined? RUBY_ENGINE
70
+ DEV_NULL = (WINDOZE ? 'nul' : '/dev/null')
71
+ GEM = 'gem'
72
+ RAKE = if RUBINIUS then
73
+ File.join(Gem.bindir, 'rake')
74
+ else
75
+ "#{Gem.ruby} -S rake"
76
+ end
77
+
78
+ warn "RubyInline v #{VERSION}" if $DEBUG
79
+
80
+ def self.register cls
81
+ registered_inline_classes << cls
82
+ registered_inline_classes.uniq!
83
+ end
84
+
85
+ def self.registered_inline_classes
86
+ @@registered_inline_classes ||= []
87
+ end
88
+
89
+ # rootdir can be forced using INLINEDIR variable
90
+ # if not defined, it should store in user HOME folder
91
+ #
92
+ # Under Windows user data can be stored in several locations:
93
+ #
94
+ # HOME
95
+ # HOMEDRIVE + HOMEPATH
96
+ # APPDATA
97
+ # USERPROFILE
98
+ #
99
+ # Perform a check in that other to see if the environment is defined
100
+ # and if so, use it. only try this on Windows.
101
+
102
+ def self.rootdir
103
+ env = ENV['INLINEDIR'] || ENV['HOME']
104
+
105
+ if env.nil? and WINDOZE then
106
+ # try HOMEDRIVE + HOMEPATH combination
107
+ if ENV['HOMEDRIVE'] && ENV['HOMEPATH'] then
108
+ env = ENV['HOMEDRIVE'] + ENV['HOMEPATH']
109
+ end
110
+
111
+ # no HOMEDRIVE? use APPDATA
112
+ env = ENV['APPDATA'] if env.nil? and ENV['APPDATA']
113
+
114
+ # bummer, still no env? then fall to USERPROFILE
115
+ env = ENV['USERPROFILE'] if env.nil? and ENV['USERPROFILE']
116
+ end
117
+
118
+ if env.nil? then
119
+ abort "Define INLINEDIR or HOME in your environment and try again"
120
+ end
121
+
122
+ unless defined? @@rootdir and env == @@rootdir and test ?d, @@rootdir then
123
+ rootdir = env
124
+ Dir.mkdir rootdir, 0700 unless test ?d, rootdir
125
+ Dir.assert_secure rootdir
126
+ @@rootdir = rootdir
127
+ end
128
+
129
+ @@rootdir
130
+ end
131
+
132
+ def self.directory
133
+ unless defined? @@directory then
134
+ version = "#{Gem.ruby_engine}-#{RbConfig::CONFIG['ruby_version']}"
135
+
136
+ @@directory = File.join(self.rootdir, ".ruby_inline", version)
137
+ end
138
+
139
+ Dir.assert_secure @@directory
140
+
141
+ @@directory
142
+ end
143
+
144
+ ##
145
+ # Inline::C is the default builder used and the only one provided by
146
+ # Inline. It can be used as a template to write builders for other
147
+ # languages. It understands type-conversions for the basic types and
148
+ # can be extended as needed using #add_type_converter, #alias_type_converter
149
+ # and #remove_type_converter.
150
+
151
+ class C
152
+
153
+ include ::Inline::Mapping
154
+
155
+ MAGIC_ARITY_THRESHOLD = 15
156
+ MAGIC_ARITY = -1
157
+
158
+ ##
159
+ # Default C to ruby and ruby to C type map
160
+
161
+ TYPE_MAP = {
162
+ 'char' => [ 'NUM2CHR', 'CHR2FIX' ],
163
+
164
+ 'char *' => [ 'StringValuePtr', 'rb_str_new2' ],
165
+
166
+ 'double' => [ 'NUM2DBL', 'rb_float_new' ],
167
+
168
+ 'int' => [ "FI\X2INT", 'INT2FIX' ],
169
+ 'unsigned int' => [ 'NUM2UINT', 'UINT2NUM' ],
170
+ 'unsigned' => [ 'NUM2UINT', 'UINT2NUM' ],
171
+
172
+ 'long' => [ 'NUM2LONG', 'LONG2NUM' ],
173
+ 'unsigned long' => [ 'NUM2ULONG', 'ULONG2NUM' ],
174
+
175
+ 'long long' => [ 'NUM2LL', 'LL2NUM' ],
176
+ 'unsigned long long' => [ 'NUM2ULL', 'ULL2NUM' ],
177
+
178
+ 'off_t' => [ 'NUM2OFFT', 'OFFT2NUM' ],
179
+
180
+ 'VALUE' => [ '', '' ],
181
+ # Can't do these converters because they conflict with the above:
182
+ # ID2SYM(x), SYM2ID(x), F\IX2UINT(x)
183
+ }
184
+
185
+ def strip_comments(src)
186
+ # strip c-comments
187
+ src = src.gsub(%r%\s*/\*.*?\*/%m, '')
188
+ # strip cpp-comments
189
+ src = src.gsub(%r%^\s*//.*?\n%, '')
190
+ src = src.gsub(%r%[ \t]*//[^\n]*%, '')
191
+ src
192
+ end
193
+
194
+ def parse_signature(src, raw=false)
195
+
196
+ sig = self.strip_comments(src)
197
+ # strip preprocessor directives
198
+ sig.gsub!(/^\s*\#.*(\\\n.*)*/, '')
199
+ # strip {}s
200
+ sig.gsub!(/\{[^\}]*\}/, '{ }')
201
+ # clean and collapse whitespace
202
+ sig.gsub!(/\s+/, ' ')
203
+
204
+ unless defined? @types then
205
+ @types = 'void|' + @type_map.keys.map{|x| Regexp.escape(x)}.join('|')
206
+ end
207
+
208
+ if /(#{@types})\s*(\w+)\s*\(([^)]*)\)/ =~ sig then
209
+ return_type, function_name, arg_string = $1, $2, $3
210
+ args = []
211
+ arg_string.split(',').each do |arg|
212
+
213
+ # helps normalize into 'char * varname' form
214
+ arg = arg.gsub(/\s*\*\s*/, ' * ').strip
215
+
216
+ if /(((#{@types})\s*\*?)+)\s+(\w+)\s*$/ =~ arg then
217
+ args.push([$4, $1])
218
+ elsif arg != "void" then
219
+ warn "WAR\NING: '#{arg}' not understood"
220
+ end
221
+ end
222
+
223
+ arity = args.size
224
+ arity = MAGIC_ARITY if raw
225
+
226
+ return {
227
+ 'return' => return_type,
228
+ 'name' => function_name,
229
+ 'args' => args,
230
+ 'arity' => arity
231
+ }
232
+ end
233
+
234
+ raise SyntaxError, "Can't parse signature: #{sig}"
235
+ end # def parse_signature
236
+
237
+ def generate(src, options={})
238
+ options = {:expand_types=>options} unless Hash === options
239
+
240
+ expand_types = options[:expand_types]
241
+ singleton = options[:singleton]
242
+ result = self.strip_comments(src)
243
+
244
+ signature = parse_signature(src, !expand_types)
245
+ function_name = signature['name']
246
+ method_name = options[:method_name]
247
+ method_name ||= test_to_normal function_name
248
+ return_type = signature['return']
249
+ arity = options[:arity] || signature['arity']
250
+
251
+ raise ArgumentError, "too many arguments" if arity > MAGIC_ARITY_THRESHOLD
252
+
253
+ if expand_types then
254
+ prefix = "static VALUE #{function_name}("
255
+ if arity <= MAGIC_ARITY then
256
+ prefix += "int argc, VALUE *argv, VALUE self"
257
+ else
258
+ prefix += "VALUE self"
259
+ prefix += signature['args'].map { |arg, type| ", VALUE _#{arg}"}.join
260
+ end
261
+ prefix += ") {\n"
262
+ prefix += signature['args'].map { |arg, type|
263
+ " #{type} #{arg} = #{ruby2c(type)}(_#{arg});\n"
264
+ }.join
265
+
266
+ # replace the function signature (hopefully) with new sig (prefix)
267
+ result.sub!(/[^;\/\"\>]+#{function_name}\s*\([^\{]+\{/, "\n" + prefix)
268
+ result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
269
+ unless return_type == "void" then
270
+ raise SyntaxError, "Couldn't find return statement for #{function_name}" unless
271
+ result =~ /return/
272
+ result.gsub!(/return\s+([^\;\}]+)/) do
273
+ "return #{c2ruby(return_type)}(#{$1})"
274
+ end
275
+ else
276
+ result.sub!(/\s*\}\s*\Z/, "\nreturn Qnil;\n}")
277
+ end
278
+ else
279
+ prefix = "static #{return_type} #{function_name}("
280
+ result.sub!(/[^;\/\"\>]+#{function_name}\s*\(/, prefix)
281
+ result.sub!(/\A\n/, '') # strip off the \n in front in case we added it
282
+ end
283
+
284
+ delta = if result =~ /\A(static.*?\{)/m then
285
+ $1.split(/\n/).size
286
+ else
287
+ msg = "WAR\NING: Can't find signature in #{result.inspect}\n"
288
+ warn msg unless $TESTING
289
+ 0
290
+ end
291
+
292
+ file, line = $1, $2 if caller[1] =~ /(.*?):(\d+)/
293
+
294
+ result = "# line #{line.to_i + delta} \"#{file}\"\n" + result unless
295
+ $DEBUG and not $TESTING
296
+
297
+ @src << result
298
+ @sig[function_name] = [arity,singleton,method_name]
299
+
300
+ return result if $TESTING
301
+ end # def generate
302
+
303
+ ##
304
+ # Builds a complete C extension suitable for writing to a file and
305
+ # compiling.
306
+
307
+ def generate_ext
308
+ ext = []
309
+
310
+ if @include_ruby_first
311
+ @inc.unshift "#include \"ruby.h\""
312
+ else
313
+ @inc.push "#include \"ruby.h\""
314
+ end
315
+
316
+ ext << @inc
317
+ ext << nil
318
+ unless @pre.empty? then
319
+ ext << @pre.join("\n\n")
320
+ ext << nil
321
+ end
322
+ ext << @src.join("\n\n")
323
+ ext << nil
324
+ ext << nil
325
+ ext << "#ifdef __cplusplus"
326
+ ext << "extern \"C\" {"
327
+ ext << "#endif"
328
+ ext << " __declspec(dllexport)" if WINDOZE
329
+ ext << " void Init_#{module_name}() {"
330
+ ext << " VALUE c = rb_cObject;"
331
+
332
+ # TODO: use rb_class2path
333
+ # ext << " VALUE c = rb_path2class(#{@mod.name.inspect});"
334
+ ext << @mod.name.split("::").map { |n|
335
+ " c = rb_const_get(c, rb_intern(\"#{n}\"));"
336
+ }.join("\n")
337
+
338
+ ext << nil
339
+
340
+ @sig.keys.sort.each do |name|
341
+ method = ''
342
+ arity, singleton, method_name = @sig[name]
343
+ if singleton then
344
+ if method_name == 'allocate' then
345
+ raise "#{@mod}::allocate must have an arity of zero" if arity > 0
346
+ ext << " rb_define_alloc_func(c, (VALUE(*)(VALUE))#{name});"
347
+ next
348
+ end
349
+ method << " rb_define_singleton_method(c, \"#{method_name}\", "
350
+ else
351
+ method << " rb_define_method(c, \"#{method_name}\", "
352
+ end
353
+ method << "(VALUE(*)(ANYARGS))#{name}, #{arity});"
354
+ ext << method
355
+ end
356
+
357
+ ext << @init_extra.join("\n") unless @init_extra.empty?
358
+
359
+ ext << nil
360
+ ext << " }"
361
+ ext << "#ifdef __cplusplus"
362
+ ext << "}"
363
+ ext << "#endif"
364
+ ext << nil
365
+
366
+ ext.join "\n"
367
+ end
368
+
369
+ def module_name
370
+ unless defined? @module_name then
371
+ module_name = @mod.name.gsub('::','__')
372
+ md5 = Digest::MD5.new
373
+ @pre.each { |m| md5 << m.to_s }
374
+ @sig.keys.sort_by { |x| x.to_s }.each { |m| md5 << m.to_s }
375
+ @module_name = "Inline_#{module_name}_#{md5}"
376
+ end
377
+ @module_name
378
+ end
379
+
380
+ def so_name
381
+ unless defined? @so_name then
382
+ @so_name = "#{Inline.directory}/#{module_name}.#{RbConfig::CONFIG["DLEXT"]}"
383
+ end
384
+ @so_name
385
+ end
386
+
387
+ attr_reader :rb_file, :mod
388
+ attr_writer :mod
389
+ attr_accessor :src, :pre, :sig, :flags, :libs, :init_extra
390
+
391
+ ##
392
+ # Sets the name of the C struct for generating accessors. Used with
393
+ # #accessor, #reader, #writer.
394
+
395
+ attr_accessor :struct_name
396
+
397
+ def initialize(mod)
398
+ raise ArgumentError, "Class/Module arg is required" unless Module === mod
399
+ # new (but not on some 1.8s) -> inline -> real_caller|eval
400
+ stack = caller
401
+ meth = stack.shift until meth =~ /in .(inline|test_|setup)/ or stack.empty?
402
+ raise "Couldn't discover caller" if stack.empty?
403
+ real_caller = stack.first
404
+ real_caller = stack[3] if real_caller =~ /\(eval\)/
405
+ real_caller =~ /(.*):(\d+)/
406
+ real_caller = $1
407
+ @rb_file = File.expand_path real_caller
408
+
409
+ @mod = mod
410
+ @pre = []
411
+ @src = []
412
+ @inc = []
413
+ @sig = {}
414
+ @flags = []
415
+ @libs = []
416
+ @init_extra = []
417
+ @include_ruby_first = true
418
+ @inherited_methods = {}
419
+ @struct_name = nil
420
+
421
+ @type_map = TYPE_MAP.dup
422
+ end
423
+
424
+ ##
425
+ # Adds a #reader and #writer for a C struct member wrapped via
426
+ # Data_Wrap_Struct. +method+ is the ruby name to give the accessor,
427
+ # +type+ is the C type. Unless the C member name is overridden with
428
+ # +member+, the method name is used as the struct member.
429
+ #
430
+ # builder.struct_name = 'MyStruct'
431
+ # builder.accessor :title, 'char *'
432
+ # builder.accessor :stream_index, 'int', :index
433
+ #
434
+ # The latter accesses MyStruct->index via the stream_index method.
435
+
436
+ def accessor(method, type, member = method)
437
+ reader method, type, member
438
+ writer method, type, member
439
+ end
440
+
441
+ ##
442
+ # Adds a reader for a C struct member wrapped via Data_Wrap_Struct.
443
+ # +method+ is the ruby name to give the reader, +type+ is the C type.
444
+ # Unless the C member name is overridden with +member+, the method
445
+ # name is used as the struct member. See #accessor for an example.
446
+
447
+ def reader(method, type, member = method)
448
+ raise "struct name not set for reader #{method} #{type}" unless
449
+ @struct_name
450
+
451
+ c <<-C
452
+ VALUE #{method}() {
453
+ #{@struct_name} *pointer;
454
+
455
+ Data_Get_Struct(self, #{@struct_name}, pointer);
456
+
457
+ return #{c2ruby type}(pointer->#{member});
458
+ }
459
+ C
460
+ end
461
+
462
+ ##
463
+ # Adds a writer for a C struct member wrapped via Data_Get_Struct.
464
+ # +method+ is the ruby name to give the writer, +type+ is the C type.
465
+ # Unless the C member name is overridden with +member+, the method
466
+ # name is used as the struct member. See #accessor for an example.
467
+
468
+ def writer(method, type, member = method)
469
+ raise "struct name not set for writer #{method} #{type}" unless
470
+ @struct_name
471
+
472
+ c <<-C
473
+ VALUE #{method}_equals(VALUE value) {
474
+ #{@struct_name} *pointer;
475
+
476
+ Data_Get_Struct(self, #{@struct_name}, pointer);
477
+
478
+ pointer->#{member} = #{ruby2c type}(value);
479
+
480
+ return value;
481
+ }
482
+ C
483
+ end
484
+
485
+ ##
486
+ # Converts ruby type +type+ to a C type
487
+
488
+ def ruby2c(type)
489
+ raise ArgumentError, "Unknown type #{type.inspect}" unless @type_map.has_key? type
490
+ @type_map[type].first
491
+ end
492
+
493
+ ##
494
+ # Converts C type +type+ to a ruby type
495
+
496
+ def c2ruby(type)
497
+ raise ArgumentError, "Unknown type #{type.inspect}" unless @type_map.has_key? type
498
+ @type_map[type].last
499
+ end
500
+
501
+ ##
502
+ # Attempts to load pre-generated code returning true if it succeeds.
503
+
504
+ def load_cache
505
+ begin
506
+ file = File.join("inline", File.basename(so_name))
507
+ if require file then
508
+ dir = Inline.directory
509
+ warn "WAR\NING: #{dir} exists but is not being used" if test ?d, dir and $VERBOSE
510
+ return true
511
+ end
512
+ rescue LoadError
513
+ end
514
+ return false
515
+ end
516
+
517
+ ##
518
+ # Loads the generated code back into ruby
519
+
520
+ def load
521
+ require "#{so_name}" or raise LoadError, "require on #{so_name} failed"
522
+ end
523
+
524
+ ##
525
+ # Builds the source file, if needed, and attempts to compile it.
526
+
527
+ def build
528
+ so_name = self.so_name
529
+ so_exists = File.file? so_name
530
+ unless so_exists and File.mtime(rb_file) < File.mtime(so_name) then
531
+
532
+ unless File.directory? Inline.directory then
533
+ warn "NOTE: creating #{Inline.directory} for RubyInline" if $DEBUG
534
+ FileUtils.mkdir_p Inline.directory, :mode => 0700
535
+ end
536
+
537
+ src_name = "#{Inline.directory}/#{module_name}.c"
538
+ old_src_name = "#{src_name}.old"
539
+ should_compare = File.write_with_backup(src_name) do |io|
540
+ io.puts generate_ext
541
+ end
542
+
543
+ # recompile only if the files are different
544
+ recompile = true
545
+ if so_exists and should_compare and
546
+ FileUtils.compare_file(old_src_name, src_name) then
547
+ recompile = false
548
+
549
+ # Updates the timestamps on all the generated/compiled files.
550
+ # Prevents us from entering this conditional unless the source
551
+ # file changes again.
552
+ t = Time.now
553
+ File.utime(t, t, src_name, old_src_name, so_name)
554
+ end
555
+
556
+ if recompile then
557
+
558
+ hdrdir = %w(srcdir includedir archdir rubyhdrdir).map { |name|
559
+ RbConfig::CONFIG[name]
560
+ }.find { |dir|
561
+ dir and File.exist? File.join(dir, "ruby.h")
562
+ } or abort "ERROR: Can't find header dir for ruby. Exiting..."
563
+
564
+ flags = @flags.join(' ')
565
+ libs = @libs.join(' ')
566
+
567
+ config_hdrdir = if RUBY_VERSION > '1.9' then
568
+ "-I #{File.join hdrdir, RbConfig::CONFIG['arch']}"
569
+ else
570
+ nil
571
+ end
572
+
573
+ windoze = WINDOZE and RUBY_PLATFORM =~ /mswin/
574
+ sane = ! windoze
575
+ cmd = [ RbConfig::CONFIG['LDSHARED'],
576
+ flags,
577
+ (RbConfig::CONFIG['DLDFLAGS'] if sane),
578
+ (RbConfig::CONFIG['CCDLFLAGS'] if sane),
579
+ RbConfig::CONFIG['CFLAGS'],
580
+ (RbConfig::CONFIG['LDFLAGS'] if sane),
581
+ '-I', hdrdir,
582
+ config_hdrdir,
583
+ '-I', RbConfig::CONFIG['includedir'],
584
+ ("-L#{RbConfig::CONFIG['libdir']}" if sane),
585
+ (['-o', so_name.inspect] if sane),
586
+ File.expand_path(src_name).inspect,
587
+ libs,
588
+ crap_for_windoze,
589
+ (RbConfig::CONFIG['LDFLAGS'] if windoze),
590
+ (RbConfig::CONFIG['CCDLFLAGS'] if windoze),
591
+ ].compact.join(' ')
592
+
593
+ # strip off some makefile macros for mingw 1.9
594
+ cmd = cmd.gsub(/\$\(.*\)/, '') if RUBY_PLATFORM =~ /mingw/
595
+
596
+ # TODO: remove after osx 10.5.2
597
+ cmd += ' -flat_namespace -undefined suppress' if
598
+ RUBY_PLATFORM =~ /darwin9\.[01]/
599
+ cmd += " 2> #{DEV_NULL}" if $TESTING and not $DEBUG
600
+
601
+ warn "Building #{so_name} with '#{cmd}'" if $DEBUG
602
+
603
+ result = if WINDOZE
604
+ Dir.chdir(Inline.directory) { `#{cmd}` }
605
+ else
606
+ `#{cmd}`
607
+ end
608
+
609
+ warn "Output:\n#{result}" if $DEBUG
610
+
611
+ if $? != 0 then
612
+ bad_src_name = src_name + ".bad"
613
+ File.rename src_name, bad_src_name
614
+ raise CompilationError, "error executing #{cmd.inspect}: #{$?}\nRenamed #{src_name} to #{bad_src_name}"
615
+ end
616
+
617
+ # NOTE: manifest embedding is only required when using VC8 ruby
618
+ # build or compiler.
619
+ # Errors from this point should be ignored if RbConfig::CONFIG['arch']
620
+ # (RUBY_PLATFORM) matches 'i386-mswin32_80'
621
+ if WINDOZE and RUBY_PLATFORM =~ /_80$/ then
622
+ Dir.chdir Inline.directory do
623
+ cmd = "mt /manifest lib.so.manifest /outputresource:so.dll;#2"
624
+ warn "Embedding manifest with '#{cmd}'" if $DEBUG
625
+ result = `#{cmd}`
626
+ warn "Output:\n#{result}" if $DEBUG
627
+ if $? != 0 then
628
+ raise CompilationError, "error executing #{cmd}: #{$?}"
629
+ end
630
+ end
631
+ end
632
+
633
+ warn "Built successfully" if $DEBUG
634
+ end
635
+
636
+ else
637
+ warn "#{so_name} is up to date" if $DEBUG
638
+ end # unless (file is out of date)
639
+ end # def build
640
+
641
+ ##
642
+ # Returns extra compilation flags for windoze platforms. Ugh.
643
+
644
+ def crap_for_windoze
645
+ # gawd windoze land sucks
646
+ case RUBY_PLATFORM
647
+ when /mswin32/ then
648
+ " -link /OUT:\"#{self.so_name}\" /LIBPATH:\"#{RbConfig::CONFIG['libdir']}\" /DEFAULTLIB:\"#{RbConfig::CONFIG['LIBRUBY']}\" /INCREMENTAL:no /EXPORT:Init_#{module_name}"
649
+ when /mingw32/ then
650
+ c = RbConfig::CONFIG
651
+ " -Wl,--enable-auto-import -L#{c['libdir']} -l#{c['RUBY_SO_NAME']} -o #{so_name.inspect}"
652
+ when /i386-cygwin/ then
653
+ ' -L/usr/local/lib -lruby.dll'
654
+ else
655
+ ''
656
+ end
657
+ end
658
+
659
+ ##
660
+ # Adds compiler options to the compiler command line. No
661
+ # preprocessing is done, so you must have all your dashes and
662
+ # everything.
663
+
664
+ def add_compile_flags(*flags)
665
+ @flags.push(*flags)
666
+ end
667
+
668
+ ##
669
+ # Registers a static id_name for the symbol :name.
670
+
671
+ def add_id name
672
+ self.add_static "id_#{name}", "rb_intern(\"#{name}\")"
673
+ end
674
+
675
+ ##
676
+ # Adds linker flags to the link command line. No preprocessing is
677
+ # done, so you must have all your dashes and everything.
678
+
679
+ def add_link_flags(*flags)
680
+ @libs.push(*flags)
681
+ end
682
+
683
+ ##
684
+ # Create a static variable and initialize it to a value.
685
+
686
+ def add_static name, init, type = "VALUE"
687
+ prefix "static #{type} #{name};"
688
+ add_to_init "#{name} = #{init};"
689
+ end
690
+
691
+ ##
692
+ # Adds custom content to the end of the init function.
693
+
694
+ def add_to_init(*src)
695
+ @init_extra.push(*src)
696
+ end
697
+
698
+ ##
699
+ # Registers C type-casts +r2c+ and +c2r+ for +type+.
700
+
701
+ def add_type_converter(type, r2c, c2r)
702
+ warn "WAR\NING: overridding #{type} on #{caller[0]}" if @type_map.has_key? type
703
+ @type_map[type] = [r2c, c2r]
704
+ end
705
+
706
+ ##
707
+ # Registers C type +alias_type+ as an alias of +existing_type+
708
+
709
+ def alias_type_converter(existing_type, alias_type)
710
+ warn "WAR\NING: overridding #{type} on #{caller[0]}" if
711
+ @type_map.has_key? alias_type
712
+
713
+ @type_map[alias_type] = @type_map[existing_type]
714
+ end
715
+
716
+ ##
717
+ # Unregisters C type-casts for +type+.
718
+
719
+ def remove_type_converter(type)
720
+ @type_map.delete type
721
+ end
722
+
723
+ ##
724
+ # Maps RubyConstants to cRubyConstants.
725
+
726
+ def map_ruby_const(*names)
727
+ names.each do |name|
728
+ self.prefix "static VALUE c#{name};"
729
+ self.add_to_init " c#{name} = rb_const_get(c, rb_intern(#{name.to_s.inspect}));"
730
+ end
731
+ end
732
+
733
+ ##
734
+ # Maps a C constant to ruby. +names_and_types+ is a hash that maps the
735
+ # name of the constant to its C type.
736
+ #
737
+ # builder.map_c_const :C_NAME => :int
738
+ #
739
+ # If you wish to give the constant a different ruby name:
740
+ #
741
+ # builder.map_c_const :C_NAME => [:int, :RUBY_NAME]
742
+
743
+ def map_c_const(names_and_types)
744
+ names_and_types.each do |name, typ|
745
+ typ, ruby_name = Array === typ ? typ : [typ, name]
746
+ self.add_to_init " rb_define_const(c, #{ruby_name.to_s.inspect}, #{c2ruby(typ.to_s)}(#{name}));"
747
+ end
748
+ end
749
+
750
+ ##
751
+ # Adds an include to the top of the file. Don't forget to use
752
+ # quotes or angle brackets.
753
+
754
+ def include(header)
755
+ @inc << "#include #{header}"
756
+ end
757
+
758
+ ##
759
+ # Specifies that the the ruby.h header should be included *after* custom
760
+ # header(s) instead of before them.
761
+
762
+ def include_ruby_last
763
+ @include_ruby_first = false
764
+ end
765
+
766
+ ##
767
+ # Adds any amount of text/code to the source
768
+
769
+ def prefix(code)
770
+ @pre << code
771
+ end
772
+
773
+ ##
774
+ # Adds a C function to the source, including performing automatic
775
+ # type conversion to arguments and the return value. The Ruby
776
+ # method name can be overridden by providing method_name. Unknown
777
+ # type conversions can be extended by using +add_type_converter+.
778
+
779
+ def c src, options = {}
780
+ options = {
781
+ :expand_types => true,
782
+ }.merge options
783
+ self.generate src, options
784
+ end
785
+
786
+ ##
787
+ # Same as +c+, but adds a class function.
788
+
789
+ def c_singleton src, options = {}
790
+ options = {
791
+ :expand_types => true,
792
+ :singleton => true,
793
+ }.merge options
794
+ self.generate src, options
795
+ end
796
+
797
+ ##
798
+ # Adds a raw C function to the source. This version does not
799
+ # perform any type conversion and must conform to the ruby/C
800
+ # coding conventions. The Ruby method name can be overridden
801
+ # by providing method_name.
802
+
803
+ def c_raw src, options = {}
804
+ self.generate src, options
805
+ end
806
+
807
+ ##
808
+ # Same as +c_raw+, but adds a class function.
809
+
810
+ def c_raw_singleton src, options = {}
811
+ options = {
812
+ :singleton => true,
813
+ }.merge options
814
+ self.generate src, options
815
+ end
816
+
817
+ end # class Inline::C
818
+ end # module Inline
819
+
820
+ class Module
821
+ ##
822
+ # Extends the Module class to have an inline method. The default
823
+ # language/builder used is C, but can be specified with the +lang+
824
+ # parameter.
825
+
826
+ def inline(lang = :C, options={})
827
+ Inline.register self
828
+
829
+ case options
830
+ when TrueClass, FalseClass then
831
+ warn "WAR\NING: 2nd argument to inline is now a hash, changing to {:testing=>#{options}}" unless options
832
+ options = { :testing => options }
833
+ when Hash
834
+ options[:testing] ||= false
835
+ else
836
+ raise ArgumentError, "BLAH"
837
+ end
838
+
839
+ builder_class = begin
840
+ Inline.const_get(lang)
841
+ rescue NameError
842
+ require "inline/#{lang}"
843
+ Inline.const_get(lang)
844
+ end
845
+
846
+ builder = builder_class.new self
847
+
848
+ yield builder
849
+
850
+ unless options[:testing] then
851
+ unless builder.load_cache then
852
+ builder.build
853
+ builder.load
854
+ end
855
+ end
856
+ end
857
+ end
858
+
859
+ class File
860
+
861
+ ##
862
+ # Equivalent to +File::open+ with an associated block, but moves
863
+ # any existing file with the same name to the side first.
864
+
865
+ def self.write_with_backup(path) # returns true if file already existed
866
+
867
+ # move previous version to the side if it exists
868
+ renamed = false
869
+ if test ?f, path then
870
+ renamed = true
871
+ File.rename path, path + ".old"
872
+ end
873
+
874
+ File.open(path, "w") do |io|
875
+ yield(io)
876
+ end
877
+
878
+ return renamed
879
+ end
880
+ end # class File
881
+
882
+ class Dir
883
+
884
+ ##
885
+ # +assert_secure+ checks that if a +path+ exists it has minimally
886
+ # writable permissions. If not, it prints an error and exits. It
887
+ # only works on +POSIX+ systems. Patches for other systems are
888
+ # welcome.
889
+
890
+ def self.assert_secure(path)
891
+ mode = File.stat(path).mode
892
+ unless ((mode % 01000) & 0022) == 0 then
893
+ if $TESTING then
894
+ raise SecurityError, "Directory #{path} is insecure"
895
+ else
896
+ abort "#{path} is insecure (#{'%o' % mode}). It may not be group or world writable. Exiting."
897
+ end
898
+ end
899
+ rescue Errno::ENOENT
900
+ # If it ain't there, it's certainly secure
901
+ end
902
+ end