pkcs11 0.1.0-x86-mingw32 → 0.2.0-x86-mingw32

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/.yardopts ADDED
@@ -0,0 +1,2 @@
1
+ --no-private lib/**/*.rb ext/*.c ext/*.doc
2
+
data/History.txt CHANGED
@@ -1,3 +1,26 @@
1
+ === 0.2.0 / 2011-01-18
2
+
3
+ * switch API documentation to YARD instead of RDOC
4
+ * add Ruby classes for all PKCS#11 structures
5
+ * add CopyObject
6
+ * add Get/SetOperationState
7
+ * use distinct Exception classes for different error codes
8
+ * PKCS#11 function calls don't block other ruby threads any more (only Ruby 1.9, Rubinius)
9
+ * don't wrap mechanisms any more (GetMechanismList returns plain Integers now)
10
+ * choose structs as mechanism parameter based on the given mechanism
11
+ * autogenerate many constants from C header files
12
+ * finer graded control over library loading
13
+ * several bug fixes
14
+ * more unit tests
15
+ * more documentation
16
+
17
+
1
18
  === 0.1.0 / 2010-05-03
2
19
 
3
20
  * first rubygem version
21
+ * Most functions and operations of PKCS#11 v2.2 are implemented.
22
+ * The library is based on the work of Ryosuke Kutsuna and GOTOU Yuuzou, but extended in the following ways:
23
+ - running on Unix and Windows OS
24
+ - downloadable as rubygem in source and win32 binary version
25
+ - new API, it's more ruby-like and well documented
26
+ - most functions are unit tested with help of softokn library
data/Manifest.txt CHANGED
@@ -1,10 +1,13 @@
1
1
  .autotest
2
+ .yardopts
2
3
  History.txt
3
4
  MIT-LICENSE
4
5
  Manifest.txt
5
6
  README.rdoc
6
7
  Rakefile
7
8
  ext/extconf.rb
9
+ ext/generate_structs.rb
10
+ ext/generate_thread_funcs.rb
8
11
  ext/include/cryptoki.h
9
12
  ext/include/ct-kip.h
10
13
  ext/include/otp-pkcs11.h
@@ -17,6 +20,7 @@ ext/pk11.h
17
20
  ext/pk11_const.c
18
21
  lib/pkcs11.rb
19
22
  lib/pkcs11/extensions.rb
23
+ lib/pkcs11/helper.rb
20
24
  lib/pkcs11/library.rb
21
25
  lib/pkcs11/object.rb
22
26
  lib/pkcs11/session.rb
@@ -32,3 +36,5 @@ test/test_pkcs11_crypt.rb
32
36
  test/test_pkcs11_object.rb
33
37
  test/test_pkcs11_session.rb
34
38
  test/test_pkcs11_slot.rb
39
+ test/test_pkcs11_structs.rb
40
+ test/test_pkcs11_thread.rb
data/README.rdoc CHANGED
@@ -1,7 +1,6 @@
1
1
  = PKCS #11/Ruby Interface
2
2
 
3
3
  * Homepage: http://github.com/larskanis/pkcs11
4
- * older SVN repository: http://coderepos.org/share/log/lang/ruby/pkcs11-ruby
5
4
  * API documentation: http://pkcs11.rubyforge.org/pkcs11/
6
5
 
7
6
  This module allows Ruby programs to interface with "RSA Security Inc.
@@ -20,12 +19,14 @@ This module works on the Unix like operating systems and win32.
20
19
 
21
20
  gem install pkcs11
22
21
 
22
+ This installs the PKCS#11 extension either by compiling (Unix) or by using the precompiled gem for Win32.
23
23
 
24
24
  == Usage
25
25
  Cryptoki has a reputation to be complicated to implement and use.
26
- While this seems to be true for C it isn't for Ruby.
26
+ While this seems to be true for C it shouldn't for Ruby.
27
27
 
28
- PKCS11.open requires suitable PKCS #11 implementation as UN*X *.so file or Windows-DLL.
28
+ {PKCS11.open} opens a PKCS#11 Unix *.so file or Windows-DLL. It requires
29
+ a suitable PKCS #11 implementation.
29
30
 
30
31
  require "rubygems"
31
32
  require "pkcs11"
@@ -33,19 +34,23 @@ PKCS11.open requires suitable PKCS #11 implementation as UN*X *.so file or Windo
33
34
 
34
35
  pkcs11 = PKCS11.open("/path/to/pkcs11.so")
35
36
  p pkcs11.info
36
- slot = pkcs11.active_slots.first
37
- session = slot.open
37
+ session = pkcs11.active_slots.first.open
38
38
  session.login(:USER, "1234")
39
- ...
39
+ # ... crypto operations
40
40
  session.logout
41
41
  session.close
42
42
 
43
- See PKCS11::Library for API documentation. See unit tests in the <tt>test</tt>
44
- directory of the project or gem for further examples of the usage.
43
+ This opens a {PKCS11::Session} to the first active slot of the device.
44
+ A {PKCS11::Session} can be used for all cryptographic operations
45
+ on the device.
45
46
 
46
47
  Detail information for the API specification is provided by RSA Security Inc.
47
48
  Please refer the URL: http://www.rsa.com/rsalabs/node.asp?id=2133.
48
49
 
50
+ Many usage examples can be found in the unit tests of the <tt>test</tt>
51
+ directory of the project or gem.
52
+
53
+
49
54
 
50
55
  == Cross compiling for mswin32
51
56
 
@@ -78,18 +83,18 @@ directory.
78
83
 
79
84
  == ToDo
80
85
 
81
- * unit testing (with mozilla softoken)
82
- * implement all functions/structs
83
- * sample code
86
+ * encoding support for Ruby 1.9
87
+ * support for proprietary extensions of different vendors
88
+ * PKCS#11 v2.3
84
89
 
85
90
  == Development Status
86
91
 
87
92
  STATE FUNCTION NOTE
88
93
  ------ --------------------- ----------------------------------------
89
- N/A C_Initialize called in PKCS11#initialize("/path/to/pk11lib")
90
- DONE C_Finalize called in GC
94
+ DONE C_Initialize
95
+ DONE C_Finalize
91
96
  DONE C_GetInfo
92
- N/A C_GetFunctionList internal use only
97
+ DONE C_GetFunctionList
93
98
  DONE C_GetSlotList
94
99
  DONE C_GetSlotInfo
95
100
  DONE C_GetTokenInfo
@@ -107,7 +112,7 @@ directory.
107
112
  DONE C_Login
108
113
  DONE C_Logout
109
114
  DONE C_CreateObject
110
- N/A C_CopyObject use C_GetAttributeValue and C_CreateObject
115
+ DONE C_CopyObject
111
116
  DONE C_DestroyObject
112
117
  DONE C_GetObjectSize
113
118
  DONE C_GetAttributeValue
@@ -154,3 +159,11 @@ directory.
154
159
  N/A C_GetFunctionStatus legacy function
155
160
  N/A C_CancelFunction legacy function
156
161
  DONE C_WaitForSlotEvent
162
+
163
+ == Authors
164
+ * Ryosuke Kutsuna <ryosuke@deer-n-horse.jp>
165
+ * GOTOU Yuuzou <gotoyuzo@notwork.org>
166
+ * Lars Kanis <kanis@comcard.de>
167
+
168
+ == Copying
169
+ See MIT-LICENSE included in the package.
data/Rakefile CHANGED
@@ -4,19 +4,40 @@
4
4
  require 'rubygems'
5
5
  require 'hoe'
6
6
  require 'rake/extensiontask'
7
+ require 'rbconfig'
8
+
9
+ CLEAN.include 'ext/pk11_struct_def.inc'
10
+ CLEAN.include 'ext/pk11_struct_impl.inc'
11
+ CLEAN.include 'ext/pk11_const_def.inc'
12
+ CLEAN.include 'ext/pk11_thread_funcs.h'
13
+ CLEAN.include 'ext/pk11_thread_funcs.c'
14
+ CLEAN.include 'lib/pkcs11_ext.so'
15
+ CLEAN.include 'tmp'
7
16
 
8
17
  hoe = Hoe.spec 'pkcs11' do
9
18
  developer('Ryosuke Kutsuna', 'ryosuke@deer-n-horse.jp')
10
19
  developer('GOTOU Yuuzou', 'gotoyuzo@notwork.org')
11
20
  developer('Lars Kanis', 'kanis@comcard.de')
21
+ extra_dev_deps << ['yard', '>= 0.6']
22
+ extra_dev_deps << ['rake-compiler', '>= 0.7']
23
+
12
24
  self.url = 'http://github.com/larskanis/pkcs11'
13
-
25
+ self.summary = 'PKCS#11 binding for Ruby'
26
+ self.description = 'This module allows Ruby programs to interface with "RSA Security Inc. PKCS #11 Cryptographic Token Interface (Cryptoki)".'
27
+
14
28
  self.readme_file = 'README.rdoc'
15
29
  self.extra_rdoc_files << self.readme_file << 'ext/pk11.c'
16
30
  spec_extras[:extensions] = 'ext/extconf.rb'
31
+ spec_extras[:files] = File.read_utf("Manifest.txt").split(/\r?\n\r?/)
32
+ spec_extras[:files] << 'ext/pk11_struct_impl.inc'
33
+ spec_extras[:files] << 'ext/pk11_struct_def.inc'
34
+ spec_extras[:files] << 'ext/pk11_const_def.inc'
35
+ spec_extras[:files] << 'ext/pk11_thread_funcs.h'
36
+ spec_extras[:files] << 'ext/pk11_thread_funcs.c'
37
+ spec_extras[:has_rdoc] = 'yard'
17
38
  end
18
39
 
19
- ENV['RUBY_CC_VERSION'] = '1.8.6:1.9.1'
40
+ ENV['RUBY_CC_VERSION'] ||= '1.8.6:1.9.2'
20
41
 
21
42
  Rake::ExtensionTask.new('pkcs11_ext', hoe.spec) do |ext|
22
43
  ext.ext_dir = 'ext'
@@ -24,6 +45,34 @@ Rake::ExtensionTask.new('pkcs11_ext', hoe.spec) do |ext|
24
45
  ext.cross_platform = ['i386-mswin32', 'i386-mingw32'] # forces the Windows platform instead of the default one
25
46
  end
26
47
 
48
+ file 'ext/extconf.rb' => ['ext/pk11_struct_def.inc', 'ext/pk11_thread_funcs.c']
49
+ file 'ext/pk11_struct_def.inc' => 'ext/generate_structs.rb' do
50
+ sh "#{Config::CONFIG['ruby_install_name']} ext/generate_structs.rb --def ext/pk11_struct_def.inc --impl ext/pk11_struct_impl.inc --const ext/pk11_const_def.inc --doc ext/pk11_struct.doc ext/include/pkcs11t.h"
51
+ end
52
+ file 'ext/pk11_struct_impl.inc' => 'ext/pk11_struct_def.inc'
53
+ file 'ext/pk11.c' => 'ext/pk11_struct_def.inc'
54
+ file 'ext/pk11_const.c' => 'ext/pk11_struct_def.inc'
55
+
56
+ file 'ext/pk11_thread_funcs.h' => 'ext/generate_thread_funcs.rb' do
57
+ sh "#{Config::CONFIG['ruby_install_name']} ext/generate_thread_funcs.rb --impl ext/pk11_thread_funcs.c --decl ext/pk11_thread_funcs.h ext/include/pkcs11f.h"
58
+ end
59
+ file 'ext/pk11_thread_funcs.c' => 'ext/pk11_thread_funcs.h'
60
+ file 'ext/pk11.h' => 'ext/pk11_thread_funcs.h'
61
+
62
+ desc "Generate static HTML documentation with YARD"
63
+ task :yardoc do
64
+ sh "yardoc"
65
+ end
66
+
67
+ desc "Publish YARD to wherever you want."
68
+ task :publish_yard => [:yardoc] do
69
+ rdoc_locations = hoe.rdoc_locations
70
+ warn "no rdoc_location values" if rdoc_locations.empty?
71
+ rdoc_locations.each do |dest|
72
+ sh %{rsync -av --delete doc/ #{dest}}
73
+ end
74
+ end
75
+
27
76
  # RDoc-upload task for github (currently on rubyforge)
28
77
  #
29
78
  # require 'grancher/task'
data/ext/extconf.rb CHANGED
@@ -3,4 +3,5 @@ require "mkmf"
3
3
  basedir = File.dirname(__FILE__)
4
4
  $CPPFLAGS += " -I \"#{basedir}/include\""
5
5
  have_func("rb_str_set_len")
6
+ have_func("rb_thread_blocking_region")
6
7
  create_makefile("pkcs11_ext");
@@ -0,0 +1,157 @@
1
+ #!/usr/bin/env ruby
2
+ # Quick and dirty parser for PKCS#11 structs and
3
+ # generator for Ruby wrapper classes.
4
+
5
+ require 'optparse'
6
+
7
+ options = Struct.new(:verbose, :def, :impl, :const, :doc).new
8
+ OptionParser.new do |opts|
9
+ opts.banner = "Usage: #{$0} [options] <header-file.h>*"
10
+
11
+ opts.on("-v", "--[no-]verbose", "Run verbosely", &options.method(:verbose=))
12
+ opts.on("--def FILE", "Write struct definitions to this file", &options.method(:def=))
13
+ opts.on("--impl FILE", "Write struct implementations to this file", &options.method(:impl=))
14
+ opts.on("--const FILE", "Write const implementations to this file", &options.method(:const=))
15
+ opts.on("--doc FILE", "Write documentation to this file", &options.method(:doc=))
16
+ opts.on_tail("-h", "--help", "Show this message") do
17
+ puts opts
18
+ exit
19
+ end
20
+ end.parse!
21
+
22
+ Attribute = Struct.new(:type, :name, :qual)
23
+ IgnoreStructs = %w[CK_ATTRIBUTE CK_MECHANISM]
24
+ OnlyAllocatorStructs = %w[CK_MECHANISM_INFO CK_C_INITIALIZE_ARGS CK_INFO CK_SLOT_INFO CK_TOKEN_INFO CK_SESSION_INFO]
25
+
26
+ structs = {}
27
+ File.open(options.def, "w") do |fd_def|
28
+ File.open(options.impl, "w") do |fd_impl|
29
+ File.open(options.doc, "w") do |fd_doc|
30
+ ARGV.each do |file_h|
31
+ c_src = IO.read(file_h)
32
+ c_src.scan(/struct\s+([A-Z_0-9]+)\s*\{(.*?)\}/m) do |struct|
33
+ struct_name, struct_text = $1, $2
34
+
35
+ attrs = {}
36
+ struct_text.scan(/^\s+([A-Z_0-9]+)\s+([\w_]+)\s*(\[\s*(\d+)\s*\])?/) do |elem|
37
+ attr = Attribute.new($1, $2, $4)
38
+ attrs[$1+" "+$2] = attr
39
+ # puts attr.inspect
40
+ end
41
+ structs[struct_name] = attrs
42
+
43
+ next if IgnoreStructs.include?(struct_name)
44
+
45
+ if OnlyAllocatorStructs.include?(struct_name)
46
+ fd_impl.puts "PKCS11_IMPLEMENT_ALLOCATOR(#{struct_name});"
47
+ else
48
+ fd_impl.puts "PKCS11_IMPLEMENT_STRUCT_WITH_ALLOCATOR(#{struct_name});"
49
+ end
50
+ fd_def.puts "PKCS11_DEFINE_STRUCT(#{struct_name});"
51
+ fd_doc.puts"class PKCS11::#{struct_name} < PKCS11::CStruct"
52
+ fd_doc.puts"# Size of corresponding C struct in bytes\nSIZEOF_STRUCT=Integer"
53
+ fd_doc.puts"# @return [String] Binary copy of the C struct\ndef to_s; end"
54
+ fd_doc.puts"# @return [Array<String>] Attributes of this struct\ndef members; end"
55
+
56
+ # try to find attributes belonging together
57
+ attrs.select{|key, attr| ['CK_BYTE_PTR', 'CK_VOID_PTR', 'CK_UTF8CHAR_PTR'].include?(attr.type) }.each do |key, attr|
58
+ if len_attr=attrs["CK_ULONG #{attr.name.gsub(/^p/, "ul")}Len"]
59
+ fd_impl.puts "PKCS11_IMPLEMENT_STRING_PTR_LEN_ACCESSOR(#{struct_name}, #{attr.name}, #{len_attr.name});"
60
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
61
+ fd_doc.puts"# @return [String, nil] accessor for #{attr.name} and #{len_attr.name}\nattr_accessor :#{attr.name}"
62
+ attrs.delete_if{|k,v| v==len_attr}
63
+ elsif attr.name=='pData' && (len_attr = attrs["CK_ULONG length"] || attrs["CK_ULONG ulLen"])
64
+ fd_impl.puts "PKCS11_IMPLEMENT_STRING_PTR_LEN_ACCESSOR(#{struct_name}, #{attr.name}, #{len_attr.name});"
65
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
66
+ fd_doc.puts"# @return [String, nil] accessor for #{attr.name} and #{len_attr.name}\nattr_accessor :#{attr.name}"
67
+ attrs.delete_if{|k,v| v==len_attr}
68
+ else
69
+ fd_impl.puts "PKCS11_IMPLEMENT_STRING_PTR_ACCESSOR(#{struct_name}, #{attr.name});"
70
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
71
+ fd_doc.puts"# @return [String, nil] accessor for #{attr.name}\nattr_accessor :#{attr.name}"
72
+ end
73
+ attrs.delete_if{|k,v| v==attr}
74
+ end
75
+
76
+ # standalone attributes
77
+ attrs.each do |key, attr|
78
+ if attr.qual
79
+ # Attributes with qualifier
80
+ case attr.type
81
+ when 'CK_BYTE', 'CK_UTF8CHAR', 'CK_CHAR'
82
+ fd_impl.puts "PKCS11_IMPLEMENT_STRING_ACCESSOR(#{struct_name}, #{attr.name});"
83
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
84
+ fd_doc.puts"# @return [String] accessor for #{attr.name} (max #{attr.qual} bytes)\nattr_accessor :#{attr.name}"
85
+ else
86
+ fd_impl.puts "/* unimplemented attr #{attr.type} #{attr.name} #{attr.qual} */"
87
+ fd_def.puts "/* unimplemented attr #{attr.type} #{attr.name} #{attr.qual} */"
88
+ end
89
+ else
90
+ case attr.type
91
+ when 'CK_BYTE'
92
+ fd_impl.puts "PKCS11_IMPLEMENT_BYTE_ACCESSOR(#{struct_name}, #{attr.name});"
93
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
94
+ fd_doc.puts"# @return [Integer] accessor for #{attr.name} (CK_BYTE)\nattr_accessor :#{attr.name}"
95
+ when 'CK_ULONG', 'CK_FLAGS', 'CK_SLOT_ID', 'CK_STATE', /CK_[A-Z_0-9]+_TYPE/
96
+ fd_impl.puts "PKCS11_IMPLEMENT_ULONG_ACCESSOR(#{struct_name}, #{attr.name});"
97
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
98
+ fd_doc.puts"# @return [Integer] accessor for #{attr.name} (CK_ULONG)\nattr_accessor :#{attr.name}"
99
+ when 'CK_OBJECT_HANDLE'
100
+ fd_impl.puts "PKCS11_IMPLEMENT_HANDLE_ACCESSOR(#{struct_name}, #{attr.name});"
101
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
102
+ fd_doc.puts"# @return [Integer, PKCS11::Object] Object handle (CK_ULONG)\nattr_accessor :#{attr.name}"
103
+ when 'CK_BBOOL'
104
+ fd_impl.puts "PKCS11_IMPLEMENT_BOOL_ACCESSOR(#{struct_name}, #{attr.name});"
105
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
106
+ fd_doc.puts"# @return [Boolean] Bool value\nattr_accessor :#{attr.name}"
107
+ when 'CK_ULONG_PTR'
108
+ fd_impl.puts "PKCS11_IMPLEMENT_ULONG_PTR_ACCESSOR(#{struct_name}, #{attr.name});"
109
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
110
+ fd_doc.puts"# @return [Integer, nil] accessor for #{attr.name} (CK_ULONG_PTR)\nattr_accessor :#{attr.name}"
111
+ else
112
+ # Struct attributes
113
+ if structs[attr.type]
114
+ fd_impl.puts "PKCS11_IMPLEMENT_STRUCT_ACCESSOR(#{struct_name}, #{attr.type}, #{attr.name});"
115
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
116
+ fd_doc.puts"# @return [PKCS11::#{attr.type}] inline struct\nattr_accessor :#{attr.name}"
117
+ elsif structs[attr.type.gsub(/_PTR$/,'')]
118
+ fd_impl.puts "PKCS11_IMPLEMENT_STRUCT_PTR_ACCESSOR(#{struct_name}, #{attr.type.gsub(/_PTR$/,'')}, #{attr.name});"
119
+ fd_def.puts "PKCS11_DEFINE_MEMBER(#{struct_name}, #{attr.name});"
120
+ fd_doc.puts"# @return [PKCS11::#{attr.type.gsub(/_PTR$/,'')}, nil] pointer to struct\nattr_accessor :#{attr.name}"
121
+ else
122
+ fd_impl.puts "/* unimplemented attr #{attr.type} #{attr.name} #{attr.qual} */"
123
+ fd_def.puts "/* unimplemented attr #{attr.type} #{attr.name} #{attr.qual} */"
124
+ end
125
+ end
126
+ end
127
+ end
128
+
129
+ fd_impl.puts
130
+ fd_def.puts
131
+ fd_doc.puts"end"
132
+ end
133
+ end
134
+ end
135
+ end
136
+ end
137
+
138
+ ConstTemplate = Struct.new :regexp, :def
139
+ ConstGroups = [
140
+ ConstTemplate.new(/#define\s+(CKM_[A-Z_0-9]+)\s+(\w+)/, 'PKCS11_DEFINE_MECHANISM'),
141
+ ConstTemplate.new(/#define\s+(CKA_[A-Z_0-9]+)\s+(\w+)/, 'PKCS11_DEFINE_ATTRIBUTE'),
142
+ ConstTemplate.new(/#define\s+(CKO_[A-Z_0-9]+)\s+(\w+)/, 'PKCS11_DEFINE_OBJECT_CLASS'),
143
+ ConstTemplate.new(/#define\s+(CKR_[A-Z_0-9]+)\s+(\w+)/, 'PKCS11_DEFINE_RETURN_VALUE'),
144
+ ]
145
+
146
+ File.open(options.const, "w") do |fd_const|
147
+ ARGV.each do |file_h|
148
+ c_src = IO.read(file_h)
149
+ ConstGroups.each do |const_group|
150
+ c_src.scan(const_group.regexp) do
151
+ const_name, const_value = $1, $2
152
+
153
+ fd_const.puts "#{const_group.def}(#{const_name}); /* #{const_value} */"
154
+ end
155
+ end
156
+ end
157
+ end
@@ -0,0 +1,72 @@
1
+ #!/usr/bin/env ruby
2
+ # This quick and dirty parser for PKCS#11 functions generates
3
+ # wrapper functions for using rb_thread_blocking_region()
4
+ # of Ruby 1.9.
5
+
6
+ require 'optparse'
7
+
8
+ options = Struct.new(:verbose, :impl, :decl).new
9
+ OptionParser.new do |opts|
10
+ opts.banner = "Usage: #{$0} [options] <header-file.h>*"
11
+
12
+ opts.on("-v", "--[no-]verbose", "Run verbosely", &options.method(:verbose=))
13
+ opts.on("--decl FILE", "Write declarations to this file", &options.method(:decl=))
14
+ opts.on("--impl FILE", "Write implementations to this file", &options.method(:impl=))
15
+ opts.on_tail("-h", "--help", "Show this message") do
16
+ puts opts
17
+ exit
18
+ end
19
+ end.parse!
20
+
21
+ Attribute = Struct.new(:type, :name)
22
+
23
+ File.open(options.decl, "w") do |fd_decl|
24
+ File.open(options.impl, "w") do |fd_impl|
25
+ fd_decl.puts <<-EOT
26
+ #ifndef #{options.decl.gsub(/[^\w]/, "_").upcase}
27
+ #define #{options.decl.gsub(/[^\w]/, "_").upcase}
28
+ #include "pk11.h"
29
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
30
+ EOT
31
+ fd_impl.puts <<-EOT
32
+ #include #{File.basename(options.decl).inspect}
33
+ #ifdef HAVE_RB_THREAD_BLOCKING_REGION
34
+ EOT
35
+ ARGV.each do |file_h|
36
+ c_src = IO.read(file_h)
37
+ c_src.scan(/CK_PKCS11_FUNCTION_INFO\((.+?)\).*?\((.*?)\);/m) do
38
+ func_name, func_param_list = $1, $2
39
+ func_params = []
40
+ func_param_list.scan(/^\s+([A-Z_0-9]+)\s+([\w_]+)/) do |elem|
41
+ func_params << Attribute.new($1, $2)
42
+ end
43
+ puts "func_name:#{func_name.inspect} func_params: #{func_params.inspect}" if options.verbose
44
+
45
+ fd_decl.puts <<-EOT
46
+ struct tbr_#{func_name}_params {
47
+ CK_#{func_name} func;
48
+ struct { #{ func_params.map{|f| f.type+" "+f.name+";"}.join } } params;
49
+ CK_RV retval;
50
+ };
51
+ VALUE tbf_#{func_name}( void *data );
52
+
53
+ EOT
54
+ fd_impl.puts <<-EOT
55
+ VALUE tbf_#{func_name}( void *data ){
56
+ struct tbr_#{func_name}_params *p = (struct tbr_#{func_name}_params*)data;
57
+ p->retval = p->func( #{func_params.map{|f| "p->params."+f.name}.join(",") } );
58
+ return Qnil;
59
+ }
60
+
61
+ EOT
62
+ end
63
+ end
64
+ fd_impl.puts <<-EOT
65
+ #endif
66
+ EOT
67
+ fd_decl.puts <<-EOT
68
+ #endif
69
+ #endif
70
+ EOT
71
+ end
72
+ end