├── .gitignore ├── Gemfile ├── README.md ├── Rakefile.rb ├── api.md ├── apr_functions.txt ├── build_config.rb ├── doc.erb ├── include ├── mruby_APR.h ├── mruby_APR_boxing.h ├── mruby_APR_classes.h └── mruby_APR_functions.h ├── lib └── win │ └── apr-1_md.lib ├── mrbgem.rake ├── mrblib ├── APR_ext.rb ├── addinfo.rb ├── basic_socket.rb ├── cruby_lib │ ├── fileutils.rb │ ├── find.rb │ ├── forwardable.rb │ ├── observer.rb │ ├── ostruct.rb │ └── shellwords.rb ├── dir.rb ├── env.rb ├── file.rb ├── file_stat.rb ├── filetest.rb ├── glob.rb ├── globals.rb ├── io.rb ├── io_error.rb ├── ipsocket.rb ├── kernel.rb ├── monkey_patches │ ├── module.rb │ └── string.rb ├── mrb_apr_gem_init.rb ├── mruby_backport_utils.rb ├── pathname.rb ├── pipe.rb ├── process.rb ├── process_status.rb ├── signal.rb ├── socket_constants.rb ├── socket_error.rb ├── system_call_error.rb ├── tcpserver.rb ├── tcpsocket.rb └── udpsocket.rb ├── mruby-bindings.in ├── ctypes.rb ├── dummy_decls.h └── includes.h ├── rakelib └── mruby-bindings.rake ├── refactor.rb ├── sandbox ├── bin_write_text_read.txt ├── echo_out.txt ├── empty_file.txt ├── file_for_writing.txt ├── shell.rb ├── test.txt ├── two_line_file.txt ├── windows print three args.c └── windows print three args.exe ├── spec.md ├── specs ├── README.md ├── apr_dir.rb ├── apr_file_io.rb ├── apr_proc.rb ├── apr_socket.rb ├── apr_time.rb ├── fixture.rb ├── helpers │ ├── tcp_client.rb │ └── tcp_server.rb ├── ruby_dir.rb ├── ruby_file.rb ├── ruby_file_stat.rb ├── ruby_forwardable.rb ├── ruby_io.rb ├── ruby_kernel.rb ├── ruby_process.rb ├── ruby_tcpsocket.rb └── ruby_udpsocket.rb └── src ├── mruby_APR.c ├── mruby_APR_boxing.c ├── mruby_APR_enum_constants.c ├── mruby_APR_macro_constants.c ├── mruby_APR_macro_constants_errnos.h ├── mruby_APR_native_ext.c ├── mruby_apr_dir_t.c ├── mruby_apr_file_t.c ├── mruby_apr_finfo_t.c ├── mruby_apr_global_mutex_t.c ├── mruby_apr_hdtr_t.c ├── mruby_apr_ipsubnet_t.c ├── mruby_apr_other_child_rec_t.c ├── mruby_apr_pool_t.c ├── mruby_apr_proc_mutex_t.c ├── mruby_apr_proc_t.c ├── mruby_apr_procattr_t.c ├── mruby_apr_sockaddr_t.c ├── mruby_apr_socket_t.c ├── mruby_apr_thread_once_t.c ├── mruby_apr_thread_t.c ├── mruby_apr_threadattr_t.c ├── mruby_apr_threadkey_t.c └── mruby_apr_time_exp_t.c /.gitignore: -------------------------------------------------------------------------------- 1 | .bundle/ 2 | bin/ 3 | build/ 4 | vendor/ 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | source "https://rubygems.org" 3 | 4 | gem 'mruby-rake-tasks', git: 'https://github.com/jbreeden/mruby-rake-tasks' 5 | gem 'rake' 6 | 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | mruby-apr 2 | ========= 3 | 4 | [![Join the chat at https://gitter.im/jbreeden/mruby-apr](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jbreeden/mruby-apr?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) 5 | 6 | A cross-platform MRuby port of the core system libraries from CRuby: 7 | 8 | - IO (read, write, pipe, popen) 9 | - File, FileTest, File::Stat 10 | - Dir 11 | - BasicSocket, UDPSocket, TCPSocket, TCPServer 12 | - ENV 13 | - Kernel ( \`backticks\`, system, spawn, & load) 14 | - Process (spawn & wait) 15 | - Process::Status (including the global $?) 16 | - Forwardable 17 | - Observer 18 | - OpenStruct 19 | - Pathname 20 | - Shellwords 21 | 22 | Specs 23 | ----- 24 | 25 | [See the ruby/spec results](https://googledrive.com/host/0B0NNQZ6fVYyiSzNlREV1ODZIWEU) 26 | 27 | - [mruby-spec](https://github.com/jbreeden/mruby-spec) is used to run relevant portions of [ruby/spec](https://github.com/ruby/spec) 28 | against [mruby](https://github.com/mruby/mruby). 29 | - The original `mruby-apr` specs are [here](./specs). 30 | 31 | Building 32 | -------- 33 | 34 | ### Mac and Linux 35 | 36 | **1. Setup the dependencies** 37 | - Download libapr version 1.5.2 from [Apache's website](https://apr.apache.org/download.cgi) 38 | - Download `mruby-apr` [here](https://github.com/jbreeden/mruby-apr). 39 | - Add the following lines to your MRuby build_config.rb file. 40 | ```Ruby 41 | spec.cc.flags << '-DMRB_INT64' 42 | conf.gem 'path/to/mruby-apr' 43 | ``` 44 | **2. Make & Rake** 45 | ``` 46 | cd /path/to/apr 47 | configure && make && sudo make install 48 | cd /path/to/mruby 49 | rake 50 | ``` 51 | 52 | _Note: APR uses the off64_t type. If you're running 32-bit Linux and get errors like "Unknown type name off64_t" 53 | you'll need to define the preprocessor macro `_LARGEFILE64_SOURCE`._ 54 | 55 | ### Windows 56 | 57 | **1. Setup the dependencies** 58 | - Download libapr version 1.5.2 from [Apache's website](https://apr.apache.org/download.cgi) 59 | - Download `mruby-apr` [here](https://github.com/jbreeden/mruby-apr). 60 | - Add the following lines to your MRuby build_config.rb file. 61 | ```Ruby 62 | spec.cc.flags << '-DMRB_INT64' 63 | ENV['APR_HOME'] = "/path/to/your/libapr/build/dir" 64 | conf.gem '/path/to/mruby-apr' 65 | ``` 66 | *Notice that on windows, you must set APR_HOME to tell this gem where to find headers & lib files* 67 | 68 | **2. CMake & Rake** 69 | 70 | APR comes with `cmake` scripts. You can use `cmake` to generate different kinds of project files for building APR. 71 | To name a few, Visual Studio, MinGW, and NMake are supported. Just use the same compiler you're using for MRuby. 72 | 73 | Once APR is built 74 | 75 | ``` 76 | cd /path/to/mruby 77 | rake 78 | ``` 79 | 80 | Platform Support 81 | ---------------- 82 | 83 | Primary development and testing done on Windows, Mac, Ubuntu, and Raspbian. However, it should work anywhere you can compile [Apache APR](https://apr.apache.org). 84 | 85 | Implementation Details 86 | ---------------------- 87 | 88 | Apache APR provides a cross platform runtime library for C, allowing portable access to system resources 89 | (eg processes, files, sockets, etc.). `mruby-apr` provides bindings to this library to bring these capabilities 90 | to mruby, without having to code the cross-platform logic over again. 91 | 92 | These bindings are provided at 2 distinct levels: 93 | 94 | 1. Direct bindings to libapr are provided in the `APR` module. 95 | + These bindings provide a nearly identical api to libapr from mruby as is available in C. 96 | + The main point of difference is that out-parameters in the C API correspond to multiple return values in the mruby API. 97 | 2. The direct bindings are used to implement portions of the CRuby standard library, purely in mruby. 98 | + This provides a familiar and idiomatic API to system resources for ruby programmers. 99 | + As with the Rubinius implementation, this should make it easier for Ruby programmers to hack on the stdlib. 100 | -------------------------------------------------------------------------------- /Rakefile.rb: -------------------------------------------------------------------------------- 1 | require 'mruby/rake/tasks' 2 | 3 | # Util Functions 4 | # -------------- 5 | 6 | def each_test_file(&block) 7 | Dir['specs/*.rb'].reject { |f| File.basename(f) == 'fixture.rb' }.each(&block) 8 | end 9 | 10 | def test_file_name(test_file) 11 | File.basename(test_file).sub(/\.rb$/, '') 12 | end 13 | 14 | # Tasks 15 | # ----- 16 | 17 | desc "Print the supported functions" 18 | task "tell_functions" do 19 | File.open('include/mruby_APR.h', 'r') do |f| 20 | regex = /BIND_(.*)_FUNCTION TRUE/ 21 | f.each_line do |l| 22 | puts l[regex, 1] if l =~ regex 23 | end 24 | end 25 | end 26 | 27 | namespace :docs do 28 | run = proc { |ruby_cmd| system "echo \"puts ERB.new(File.read('doc.erb'), nil, '-').result\" | #{ruby_cmd}" } 29 | desc 'Print the MRuby APIs' 30 | task :mruby do 31 | run["mruby"] 32 | end 33 | desc 'Print the CRuby APIs' 34 | task :cruby do 35 | run["ruby -r erb"] 36 | end 37 | end 38 | 39 | namespace :test do 40 | 41 | each_test_file do |test_file| 42 | test = test_file_name(test_file) 43 | desc "Run the #{test} tests" 44 | task (test) do 45 | Dir.chdir 'specs' do 46 | system "mruby #{test_file.sub(/^specs\//, '')}" 47 | end 48 | end 49 | end 50 | 51 | desc "Run all of the tests" 52 | task :all do 53 | Dir.chdir 'specs' do 54 | Dir['*.rb'].reject { |f| File.basename(f) == 'specs/fixture.rb' }.sort.each do |f| 55 | system "mruby #{f}" 56 | end 57 | end 58 | end 59 | 60 | desc "Run all the tests and print a summary" 61 | task :summary do 62 | IO.popen("rake test:all", "r") do |io| 63 | while s = io.gets 64 | puts s if /(^[a-z])|tests failed/i =~ s 65 | end 66 | end 67 | end 68 | 69 | end 70 | 71 | desc "Generate method stubs for a ruby class" 72 | task :gen_rb do 73 | c = eval(ENV['CLASS']) 74 | unless c.class == Class 75 | $stderr.puts "#{ENV['CLASS']} does not refer to a Ruby class" 76 | end 77 | c.singleton_methods(false).sort.each do |m| 78 | puts "def self.#{m}(*args)\n raise NotImplementedError.new\nend\n\n" 79 | end 80 | c.public_instance_methods(false).sort.each do |m| 81 | puts "def #{m}(*args)\n raise NotImplementedError.new\nend\n\n" 82 | end 83 | end 84 | -------------------------------------------------------------------------------- /api.md: -------------------------------------------------------------------------------- 1 | MRuby-APR 2 | ========= 3 | 4 | BasicSocket 5 | ----------- 6 | 7 | Ancestors: `IO` 8 | 9 | Instance Methods: 10 | - `#assert_can_read` 11 | - `#assert_can_write` 12 | - `#close` 13 | - `#close_read` 14 | - `#close_write` 15 | - `#eof?` 16 | - `#initialize` 17 | - `#read` 18 | - `#recv` 19 | - `#send` 20 | - `#shutdown` 21 | - `#write` 22 | 23 | Dir 24 | --- 25 | 26 | Class Methods: 27 | - `::[]` 28 | - `::chdir` 29 | - `::delete` 30 | - `::entries` 31 | - `::exist?` 32 | - `::exists?` 33 | - `::foreach` 34 | - `::getwd` 35 | - `::glob` 36 | - `::home` 37 | - `::mkdir` 38 | - `::mktmpdir` 39 | - `::pwd` 40 | - `::rmdir` 41 | - `::tmpdir` 42 | - `::unlink` 43 | 44 | 45 | File 46 | ---- 47 | 48 | Ancestors: `IO` 49 | 50 | Class Methods: 51 | - `::absolute_path` 52 | - `::atime` 53 | - `::basename` 54 | - `::ctime` 55 | - `::delete` 56 | - `::dirname` 57 | - `::expand_path` 58 | - `::extname` 59 | - `::join` 60 | - `::open` 61 | - `::read` 62 | - `::unlink` 63 | 64 | Instance Methods: 65 | - `#assert_can_read` 66 | - `#assert_can_write` 67 | - `#close` 68 | - `#closed?` 69 | - `#eof` 70 | - `#eof?` 71 | - `#flock` 72 | - `#flush` 73 | - `#getbyte` 74 | - `#getc` 75 | - `#initialize` 76 | - `#native_file` 77 | - `#read` 78 | - `#seek` 79 | - `#ungetbyte` 80 | - `#ungetc` 81 | - `#write` 82 | 83 | File::Stat 84 | ---------- 85 | 86 | Instance Methods: 87 | - `#atime` 88 | - `#blockdev?` 89 | - `#chardev?` 90 | - `#ctime` 91 | - `#directory?` 92 | - `#file?` 93 | - `#ftype` 94 | - `#initialize` 95 | - `#mtime` 96 | - `#name` 97 | - `#nlink` 98 | - `#pipe?` 99 | - `#size` 100 | - `#size?` 101 | - `#socket?` 102 | - `#symlink?` 103 | - `#zero?` 104 | 105 | FileTest 106 | -------- 107 | 108 | Class Methods: 109 | - `::is_type?` 110 | 111 | Instance Methods: 112 | - `#blockdev?` 113 | - `#chardev?` 114 | - `#directory?` 115 | - `#exist?` 116 | - `#exists?` 117 | - `#file?` 118 | - `#pipe?` 119 | - `#size` 120 | - `#size?` 121 | - `#socket?` 122 | - `#symlink?` 123 | - `#zero?` 124 | 125 | Forwardable 126 | ----------- 127 | 128 | Class Methods: 129 | - `::debug` 130 | - `::debug=` 131 | 132 | Instance Methods: 133 | - `#def_delegator` 134 | - `#def_delegators` 135 | - `#def_instance_delegator` 136 | - `#def_instance_delegators` 137 | - `#delegate` 138 | - `#instance_delegate` 139 | 140 | IO 141 | -- 142 | 143 | Class Methods: 144 | - `::pipe` 145 | - `::popen` 146 | 147 | Instance Methods: 148 | - `#<<` 149 | - `#each` 150 | - `#each_byte` 151 | - `#each_char` 152 | - `#each_line` 153 | - `#eof` 154 | - `#getbyte` 155 | - `#getc` 156 | - `#gets` 157 | - `#print` 158 | - `#puts` 159 | - `#seek` 160 | 161 | IPSocket 162 | -------- 163 | 164 | Ancestors: `BasicSocket`, `IO` 165 | 166 | Instance Methods: 167 | - `#recvfrom` 168 | 169 | Kernel 170 | ------ 171 | 172 | Instance Methods: 173 | - \` (Backtick) 174 | - `#load` 175 | - `#sleep` 176 | - `#spawn` 177 | - `#system` 178 | 179 | Observable 180 | ---------- 181 | 182 | Instance Methods: 183 | - `#add_observer` 184 | - `#changed` 185 | - `#changed?` 186 | - `#count_observers` 187 | - `#delete_observer` 188 | - `#delete_observers` 189 | - `#notify_observers` 190 | 191 | OpenStruct 192 | ---------- 193 | 194 | Instance Methods: 195 | - `#==` 196 | - `#[]` 197 | - `#[]=` 198 | - `#delete_field` 199 | - `#each_pair` 200 | - `#eql?` 201 | - `#hash` 202 | - `#initialize` 203 | - `#initialize_copy` 204 | - `#inspect` 205 | - `#marshal_dump` 206 | - `#marshal_load` 207 | - `#method_missing` 208 | - `#modifiable` 209 | - `#new_ostruct_member` 210 | - `#table` 211 | - `#to_h` 212 | - `#to_s` 213 | 214 | Shellwords 215 | ---------- 216 | 217 | Class Methods: 218 | - `::escape` 219 | - `::join` 220 | - `::shellescape` 221 | - `::shelljoin` 222 | - `::shellsplit` 223 | - `::shellwords` 224 | - `::split` 225 | 226 | Instance Methods: 227 | - `#shellescape` 228 | - `#shelljoin` 229 | - `#shellsplit` 230 | - `#shellwords` 231 | 232 | IO::Pipe 233 | -------- 234 | 235 | Ancestors: `File`, `IO` 236 | 237 | Instance Methods: 238 | - `#initialize` 239 | 240 | Process 241 | ------- 242 | 243 | Class Methods: 244 | - `::pid` 245 | - `::spawn` 246 | - `::wait` 247 | 248 | 249 | Socket 250 | ------ 251 | 252 | 253 | Process::Status 254 | --------------- 255 | 256 | Instance Methods: 257 | - `#coredump?` 258 | - `#exited?` 259 | - `#exitstatus` 260 | - `#initialize` 261 | - `#pid` 262 | - `#signaled?` 263 | - `#success?` 264 | 265 | TCPServer 266 | --------- 267 | 268 | Ancestors: `TCPSocket`, `IPSocket`, `BasicSocket`, `IO` 269 | 270 | Instance Methods: 271 | - `#accept` 272 | - `#initialize` 273 | - `#listen` 274 | 275 | TCPSocket 276 | --------- 277 | 278 | Ancestors: `IPSocket`, `BasicSocket`, `IO` 279 | 280 | Instance Methods: 281 | - `#initialize` 282 | 283 | UDPSocket 284 | --------- 285 | 286 | Ancestors: `IPSocket`, `BasicSocket`, `IO` 287 | 288 | Instance Methods: 289 | - `#bind` 290 | - `#connect` 291 | - `#initialize` 292 | - `#read` 293 | -------------------------------------------------------------------------------- /apr_functions.txt: -------------------------------------------------------------------------------- 1 | apr_ctime 2 | apr_dir_close 3 | apr_dir_make 4 | apr_dir_make_recursive 5 | apr_dir_open 6 | apr_dir_read 7 | apr_dir_remove 8 | apr_dir_rewind 9 | apr_env_delete 10 | apr_env_get 11 | apr_env_set 12 | apr_file_append 13 | apr_file_attrs_set 14 | apr_file_buffer_size_get 15 | apr_file_close 16 | apr_file_copy 17 | apr_file_datasync 18 | apr_file_eof 19 | apr_file_flags_get 20 | apr_file_flush 21 | apr_file_getc 22 | apr_file_gets 23 | apr_file_info_get 24 | apr_file_inherit_unset 25 | apr_file_link 26 | apr_file_lock 27 | apr_file_namedpipe_create 28 | apr_file_open 29 | apr_file_open_flags_stderr 30 | apr_file_open_flags_stdin 31 | apr_file_open_flags_stdout 32 | apr_file_open_stderr 33 | apr_file_open_stdin 34 | apr_file_open_stdout 35 | apr_file_perms_set 36 | apr_file_pipe_create 37 | apr_file_puts 38 | apr_file_read 39 | apr_file_remove 40 | apr_file_rename 41 | apr_file_seek 42 | apr_file_sync 43 | apr_file_trunc 44 | apr_file_ungetc 45 | apr_file_unlock 46 | apr_file_write 47 | apr_filepath_name_get 48 | apr_fnmatch 49 | apr_fnmatch_test 50 | apr_gethostname 51 | apr_getnameinfo 52 | apr_initialize 53 | apr_os_default_encoding 54 | apr_os_locale_encoding 55 | apr_pool_clear 56 | apr_pool_create 57 | apr_pool_destroy 58 | apr_proc_create 59 | apr_proc_detach 60 | apr_proc_wait 61 | apr_procattr_addrspace_set 62 | apr_procattr_child_err_set 63 | apr_procattr_child_in_set 64 | apr_procattr_child_out_set 65 | apr_procattr_cmdtype_set 66 | apr_procattr_create 67 | apr_procattr_detach_set 68 | apr_procattr_dir_set 69 | apr_procattr_error_check_set 70 | apr_procattr_group_set 71 | apr_procattr_io_set 72 | apr_procattr_user_set 73 | apr_sleep 74 | apr_sockaddr_equal 75 | apr_sockaddr_info_get 76 | apr_sockaddr_ip_get 77 | apr_sockaddr_is_wildcard 78 | apr_socket_accept 79 | apr_socket_addr_get 80 | apr_socket_atreadeof 81 | apr_socket_bind 82 | apr_socket_close 83 | apr_socket_connect 84 | apr_socket_create 85 | apr_socket_listen 86 | apr_socket_opt_get 87 | apr_socket_opt_set 88 | apr_socket_protocol_get 89 | apr_socket_recv 90 | apr_socket_recvfrom 91 | apr_socket_send 92 | apr_socket_sendto 93 | apr_socket_shutdown 94 | apr_socket_timeout_get 95 | apr_socket_timeout_set 96 | apr_socket_type_get 97 | apr_stat 98 | apr_strerror 99 | apr_to_os_error 100 | apr_temp_dir_get 101 | apr_terminate 102 | apr_terminate2 103 | apr_time_now 104 | apr_time_sec 105 | apr_tokenize_to_argv 106 | -------------------------------------------------------------------------------- /build_config.rb: -------------------------------------------------------------------------------- 1 | MRuby::Build.new do |conf| 2 | # load specific toolchain settings 3 | 4 | # Gets set by the VS command prompts. 5 | if ENV['VisualStudioVersion'] || ENV['VSINSTALLDIR'] 6 | toolchain :visualcpp 7 | else 8 | toolchain :gcc 9 | end 10 | 11 | conf.gembox 'full-core' 12 | 13 | conf.cc.flags << '-DMRB_INT64' 14 | 15 | # Include this gem from source 16 | conf.gem File.dirname(__FILE__) 17 | end 18 | -------------------------------------------------------------------------------- /doc.erb: -------------------------------------------------------------------------------- 1 | <% 2 | classes = [ 3 | # [Addrinfo, "Addrinfo"], 4 | BasicSocket, 5 | Dir, 6 | File, 7 | File::Stat, 8 | FileTest, 9 | Forwardable, 10 | IO, 11 | IPSocket, 12 | Kernel, 13 | Observable, 14 | OpenStruct, 15 | Shellwords, 16 | IO::Pipe, 17 | Process, 18 | Socket, 19 | Process::Status, 20 | TCPServer, 21 | TCPSocket, 22 | UDPSocket 23 | ] 24 | -%> 25 | MRuby-APR 26 | ========= 27 | 28 | <% classes.each do |cls| -%> 29 | <%= cls %> 30 | <%= '-' * cls.to_s.length %> 31 | 32 | <% ancestors = cls.ancestors[1...-3] 33 | unless ancestors.empty? -%> 34 | Ancestors: <%= ancestors.map { |m| "`#{m}`"}.join(', ') %> 35 | 36 | <% end -%> 37 | <% unless cls.methods(false).empty? -%> 38 | Class Methods: 39 | <% cls.methods(false).sort.each do |meth| -%> 40 | - `::<%= meth %>` 41 | <% end -%> 42 | 43 | <% end -%> 44 | <% unless cls.instance_methods(false).empty? -%> 45 | Instance Methods: 46 | <% cls.instance_methods(false).sort.each do |meth| -%> 47 | - `#<%= meth %>` 48 | <% end -%> 49 | <% end -%> 50 | 51 | <% end -%> 52 | -------------------------------------------------------------------------------- /include/mruby_APR.h: -------------------------------------------------------------------------------- 1 | #ifndef APR_HEADER 2 | #define APR_HEADER 3 | 4 | /* 5 | * Header Files 6 | * ------------ 7 | * 8 | * These are the header files that defined the 9 | * classes and functions for which bindings have 10 | * been generated. If any of these are not needed 11 | * they should be commented out. 12 | * 13 | * TODO: ONLY the filename is inserted here automatically. 14 | * If the file is not directly on the include path, 15 | * you will need to prepend the relative path. 16 | */ 17 | 18 | /* MRUBY_BINDING: pre_includes */ 19 | /* sha: user_defined */ 20 | #if defined(_WIN32) || defined(_WIN64) 21 | /* Actually much larger than Window's max path length, but whatevs */ 22 | #define PATH_MAX 1024 23 | #include 24 | #define getcwd _getcwd 25 | #define chdir _chdir 26 | #else 27 | #include 28 | #include 29 | #if !defined(PATH_MAX) && defined(MRUBY_APR_LINUX) 30 | #include 31 | #endif 32 | #endif 33 | /* MRUBY_BINDING_END */ 34 | 35 | /* MRUBY_BINDING: includes */ 36 | /* sha: aabfd2e62a48e757b23f6c2143509287038c61a867f179b46d5a4cb271304ba9 */ 37 | #include 38 | #include "mruby.h" 39 | #include "mruby/array.h" 40 | #include "mruby/class.h" 41 | #include "mruby/compile.h" 42 | #include "mruby/data.h" 43 | #include "mruby/string.h" 44 | #include "mruby/value.h" 45 | #include "mruby/variable.h" 46 | 47 | #include "apr.h" 48 | #include "apr_env.h" 49 | #include "apr_errno.h" 50 | #include "apr_file_info.h" 51 | #include "apr_file_io.h" 52 | #include "apr_fnmatch.h" 53 | #include "apr_general.h" 54 | #include "apr_global_mutex.h" 55 | #include "apr_network_io.h" 56 | #include "apr_pools.h" 57 | #include "apr_proc_mutex.h" 58 | #include "apr_signal.h" 59 | #include "apr_strings.h" 60 | #include "apr_thread_proc.h" 61 | #include "apr_time.h" 62 | 63 | 64 | #include "mruby_APR_functions.h" 65 | #include "mruby_APR_classes.h" 66 | #include "mruby_APR_boxing.h" 67 | /* MRUBY_BINDING_END */ 68 | 69 | /* MRUBY_BINDING: post_includes */ 70 | /* sha: user_defined */ 71 | void mruby_APR_init_native_ext(mrb_state * mrb); 72 | /* MRUBY_BINDING_END */ 73 | 74 | /* 75 | * RClass Macros 76 | * ------------- 77 | * 78 | * Macros for retrieving the RClass*'s defined by this gem. 79 | */ 80 | 81 | /* MRUBY_BINDING: pre_class_macros */ 82 | /* sha: user_defined */ 83 | 84 | /* MRUBY_BINDING_END */ 85 | 86 | /* MRUBY_BINDING: class_macros */ 87 | /* sha: 2ca34a3fd1c59e54ea70663b4692fae30b241463cb5c67bc780256d63c87569e */ 88 | #define APR_module(mrb) mrb_module_get(mrb, "APR") 89 | #define Dir_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Dir") 90 | #define File_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "File") 91 | #define Finfo_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Finfo") 92 | #define GlobalMutex_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "GlobalMutex") 93 | #define Hdtr_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Hdtr") 94 | #define Ipsubnet_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Ipsubnet") 95 | #define OtherChildRec_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "OtherChildRec") 96 | #define Pool_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Pool") 97 | #define Proc_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Proc") 98 | #define Procattr_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Procattr") 99 | #define ProcMutex_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "ProcMutex") 100 | #define Sockaddr_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Sockaddr") 101 | #define Socket_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Socket") 102 | #define Thread_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Thread") 103 | #define Threadattr_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Threadattr") 104 | #define Threadkey_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "Threadkey") 105 | #define ThreadOnce_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "ThreadOnce") 106 | #define TimeExp_class(mrb) mrb_class_get_under(mrb, APR_module(mrb), "TimeExp") 107 | /* MRUBY_BINDING_END */ 108 | 109 | /* MRUBY_BINDING: post_class_macros */ 110 | /* sha: user_defined */ 111 | 112 | /* MRUBY_BINDING_END */ 113 | 114 | /* 115 | * Class initialization function declarations 116 | * ------------------------------------------ 117 | */ 118 | 119 | /* MRUBY_BINDING: pre_class_init_decls */ 120 | /* sha: user_defined */ 121 | 122 | /* MRUBY_BINDING_END */ 123 | 124 | /* MRUBY_BINDING: pre_class_init_decls */ 125 | /* sha: 2704c36aefe9e99647dbb00d403d031cd881bb76fdc62c143ff0c42282fdbd5e */ 126 | #if BIND_Dir_TYPE 127 | void mrb_APR_Dir_init(mrb_state* mrb); 128 | #endif 129 | #if BIND_File_TYPE 130 | void mrb_APR_File_init(mrb_state* mrb); 131 | #endif 132 | #if BIND_Finfo_TYPE 133 | void mrb_APR_Finfo_init(mrb_state* mrb); 134 | #endif 135 | #if BIND_GlobalMutex_TYPE 136 | void mrb_APR_GlobalMutex_init(mrb_state* mrb); 137 | #endif 138 | #if BIND_Hdtr_TYPE 139 | void mrb_APR_Hdtr_init(mrb_state* mrb); 140 | #endif 141 | #if BIND_Ipsubnet_TYPE 142 | void mrb_APR_Ipsubnet_init(mrb_state* mrb); 143 | #endif 144 | #if BIND_OtherChildRec_TYPE 145 | void mrb_APR_OtherChildRec_init(mrb_state* mrb); 146 | #endif 147 | #if BIND_Pool_TYPE 148 | void mrb_APR_Pool_init(mrb_state* mrb); 149 | #endif 150 | #if BIND_Proc_TYPE 151 | void mrb_APR_Proc_init(mrb_state* mrb); 152 | #endif 153 | #if BIND_Procattr_TYPE 154 | void mrb_APR_Procattr_init(mrb_state* mrb); 155 | #endif 156 | #if BIND_ProcMutex_TYPE 157 | void mrb_APR_ProcMutex_init(mrb_state* mrb); 158 | #endif 159 | #if BIND_Sockaddr_TYPE 160 | void mrb_APR_Sockaddr_init(mrb_state* mrb); 161 | #endif 162 | #if BIND_Socket_TYPE 163 | void mrb_APR_Socket_init(mrb_state* mrb); 164 | #endif 165 | #if BIND_Thread_TYPE 166 | void mrb_APR_Thread_init(mrb_state* mrb); 167 | #endif 168 | #if BIND_Threadattr_TYPE 169 | void mrb_APR_Threadattr_init(mrb_state* mrb); 170 | #endif 171 | #if BIND_Threadkey_TYPE 172 | void mrb_APR_Threadkey_init(mrb_state* mrb); 173 | #endif 174 | #if BIND_ThreadOnce_TYPE 175 | void mrb_APR_ThreadOnce_init(mrb_state* mrb); 176 | #endif 177 | #if BIND_TimeExp_TYPE 178 | void mrb_APR_TimeExp_init(mrb_state* mrb); 179 | #endif 180 | /* MRUBY_BINDING_END */ 181 | 182 | /* MRUBY_BINDING: post_class_init_decls */ 183 | /* sha: user_defined */ 184 | 185 | /* MRUBY_BINDING_END */ 186 | 187 | /* 188 | * Macro & Enum definition function declarations 189 | * --------------------------------------------- 190 | */ 191 | void mruby_APR_define_macro_constants(mrb_state* mrb); 192 | void mruby_APR_define_enum_constants(mrb_state* mrb); 193 | 194 | #endif 195 | -------------------------------------------------------------------------------- /include/mruby_APR_classes.h: -------------------------------------------------------------------------------- 1 | #ifndef MRUBY_APR_CLASSES_HEADER 2 | #define MRUBY_APR_CLASSES_HEADER 3 | 4 | #define BIND_Dir_TYPE TRUE 5 | #define BIND_Dir_INITIALIZE TRUE 6 | 7 | #define BIND_File_TYPE TRUE 8 | #define BIND_File_INITIALIZE TRUE 9 | 10 | #define BIND_Finfo_TYPE TRUE 11 | 12 | #define BIND_GlobalMutex_TYPE TRUE 13 | #define BIND_GlobalMutex_INITIALIZE TRUE 14 | 15 | #define BIND_Hdtr_TYPE TRUE 16 | #define BIND_Hdtr_INITIALIZE TRUE 17 | #define BIND_Hdtr_headers_FIELD_READER FALSE 18 | #define BIND_Hdtr_headers_FIELD_WRITER FALSE 19 | #define BIND_Hdtr_numheaders_FIELD_READER TRUE 20 | #define BIND_Hdtr_numheaders_FIELD_WRITER TRUE 21 | #define BIND_Hdtr_trailers_FIELD_READER FALSE 22 | #define BIND_Hdtr_trailers_FIELD_WRITER FALSE 23 | #define BIND_Hdtr_numtrailers_FIELD_READER TRUE 24 | #define BIND_Hdtr_numtrailers_FIELD_WRITER TRUE 25 | 26 | #define BIND_Ipsubnet_TYPE TRUE 27 | #define BIND_Ipsubnet_INITIALIZE TRUE 28 | 29 | #define BIND_OtherChildRec_TYPE TRUE 30 | #define BIND_OtherChildRec_INITIALIZE TRUE 31 | 32 | #define BIND_Pool_TYPE TRUE 33 | #define BIND_Pool_INITIALIZE TRUE 34 | 35 | #define BIND_ProcMutex_TYPE TRUE 36 | #define BIND_ProcMutex_INITIALIZE TRUE 37 | 38 | #define BIND_Proc_TYPE TRUE 39 | 40 | #define BIND_Procattr_TYPE TRUE 41 | #define BIND_Procattr_INITIALIZE TRUE 42 | 43 | #define BIND_Sockaddr_TYPE TRUE 44 | #define BIND_Sockaddr_INITIALIZE TRUE 45 | #define BIND_Sockaddr_pool_FIELD_READER TRUE 46 | #define BIND_Sockaddr_pool_FIELD_WRITER TRUE 47 | #define BIND_Sockaddr_hostname_FIELD_READER FALSE 48 | #define BIND_Sockaddr_hostname_FIELD_WRITER FALSE 49 | #define BIND_Sockaddr_servname_FIELD_READER FALSE 50 | #define BIND_Sockaddr_servname_FIELD_WRITER FALSE 51 | #define BIND_Sockaddr_port_FIELD_READER TRUE 52 | #define BIND_Sockaddr_port_FIELD_WRITER TRUE 53 | #define BIND_Sockaddr_family_FIELD_READER TRUE 54 | #define BIND_Sockaddr_family_FIELD_WRITER TRUE 55 | #define BIND_Sockaddr_salen_FIELD_READER FALSE 56 | #define BIND_Sockaddr_salen_FIELD_WRITER FALSE 57 | #define BIND_Sockaddr_ipaddr_len_FIELD_READER TRUE 58 | #define BIND_Sockaddr_ipaddr_len_FIELD_WRITER TRUE 59 | #define BIND_Sockaddr_addr_str_len_FIELD_READER TRUE 60 | #define BIND_Sockaddr_addr_str_len_FIELD_WRITER TRUE 61 | #define BIND_Sockaddr_ipaddr_ptr_FIELD_READER FALSE 62 | #define BIND_Sockaddr_ipaddr_ptr_FIELD_WRITER FALSE 63 | #define BIND_Sockaddr_next_FIELD_READER TRUE 64 | #define BIND_Sockaddr_next_FIELD_WRITER TRUE 65 | #define BIND_Sockaddr_sa_FIELD_READER FALSE 66 | #define BIND_Sockaddr_sa_FIELD_WRITER FALSE 67 | 68 | #define BIND_Socket_TYPE TRUE 69 | #define BIND_Socket_INITIALIZE TRUE 70 | 71 | #define BIND_ThreadOnce_TYPE TRUE 72 | #define BIND_ThreadOnce_INITIALIZE TRUE 73 | 74 | #define BIND_Thread_TYPE TRUE 75 | #define BIND_Thread_INITIALIZE TRUE 76 | 77 | #define BIND_Threadattr_TYPE TRUE 78 | #define BIND_Threadattr_INITIALIZE TRUE 79 | 80 | #define BIND_Threadkey_TYPE TRUE 81 | #define BIND_Threadkey_INITIALIZE TRUE 82 | 83 | #define BIND_TimeExp_TYPE TRUE 84 | #define BIND_TimeExp_INITIALIZE TRUE 85 | #define BIND_TimeExp_tm_usec_FIELD_READER TRUE 86 | #define BIND_TimeExp_tm_usec_FIELD_WRITER TRUE 87 | #define BIND_TimeExp_tm_sec_FIELD_READER TRUE 88 | #define BIND_TimeExp_tm_sec_FIELD_WRITER TRUE 89 | #define BIND_TimeExp_tm_min_FIELD_READER TRUE 90 | #define BIND_TimeExp_tm_min_FIELD_WRITER TRUE 91 | #define BIND_TimeExp_tm_hour_FIELD_READER TRUE 92 | #define BIND_TimeExp_tm_hour_FIELD_WRITER TRUE 93 | #define BIND_TimeExp_tm_mday_FIELD_READER TRUE 94 | #define BIND_TimeExp_tm_mday_FIELD_WRITER TRUE 95 | #define BIND_TimeExp_tm_mon_FIELD_READER TRUE 96 | #define BIND_TimeExp_tm_mon_FIELD_WRITER TRUE 97 | #define BIND_TimeExp_tm_year_FIELD_READER TRUE 98 | #define BIND_TimeExp_tm_year_FIELD_WRITER TRUE 99 | #define BIND_TimeExp_tm_wday_FIELD_READER TRUE 100 | #define BIND_TimeExp_tm_wday_FIELD_WRITER TRUE 101 | #define BIND_TimeExp_tm_yday_FIELD_READER TRUE 102 | #define BIND_TimeExp_tm_yday_FIELD_WRITER TRUE 103 | #define BIND_TimeExp_tm_isdst_FIELD_READER TRUE 104 | #define BIND_TimeExp_tm_isdst_FIELD_WRITER TRUE 105 | #define BIND_TimeExp_tm_gmtoff_FIELD_READER TRUE 106 | #define BIND_TimeExp_tm_gmtoff_FIELD_WRITER TRUE 107 | 108 | #endif 109 | -------------------------------------------------------------------------------- /lib/win/apr-1_md.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbreeden/mruby-apr/98d47bbd40bba9be13224c190caf6228dc08ec8b/lib/win/apr-1_md.lib -------------------------------------------------------------------------------- /mrbgem.rake: -------------------------------------------------------------------------------- 1 | $APR_GEM_DIR = File.dirname(__FILE__) 2 | $APR_HOME = ENV['APR_HOME'] 3 | 4 | def configure_mruby_apr_win(spec) 5 | # TODO: This default is here because of this mrbgem's origins in rubium. 6 | # Should update rubium's build_config to set ENV['APR_HOME'] instead. 7 | apr_home = ($APR_HOME && Dir.exists?($APR_HOME)) ? $APR_HOME : "#{$APR_GEM_DIR}/../../apr_source/apr-1.5.2/build" 8 | unless Dir.exists?(apr_home) 9 | $stderr.puts "On Windows, APR_HOME env variable should be set to libapr build directory." 10 | raise 'APR not found' 11 | end 12 | 13 | spec.cc.include_paths << apr_home 14 | spec.cxx.include_paths << apr_home 15 | 16 | # Pre-built libraries are held under "#{$APR_GEM_DIR}/lib/PLATFORM" 17 | spec.linker.library_paths << "#{apr_home}/x64/Release" 18 | 19 | spec.linker.libraries << "apr-1" 20 | spec.linker.libraries << "Rpcrt4" 21 | spec.linker.libraries << "Ws2_32" 22 | spec.linker.libraries << "Advapi32" 23 | spec.linker.libraries << "Shell32" 24 | spec.linker.libraries << "Mswsock" 25 | end 26 | 27 | def configure_mruby_apr_lin(spec) 28 | apr_1_config = '/usr/local/apr/bin/apr-1-config' 29 | global_apr_1_config = `which apr-1-config`.strip 30 | 31 | if File.exists?(global_apr_1_config) 32 | apr_1_config = global_apr_1_config 33 | end 34 | 35 | unless File.exists?(apr_1_config) 36 | $stderr.puts 'Could not find apr-1-config executable on PATH or in /usr/local/apr/bin (the default make install target).' 37 | $stderr.puts 'Please download and install APR. (Or build from source with a `configure && make && sudo make install`.)' 38 | raise 'APR not found' 39 | end 40 | 41 | apr_include_dir = `#{apr_1_config} --includes`.sub('-I', '').strip 42 | spec.cc.include_paths << apr_include_dir 43 | spec.cxx.include_paths << apr_include_dir 44 | 45 | apr_ldflags = `#{apr_1_config} --link-ld --libs`.strip 46 | spec.linker.flags_after_libraries << apr_ldflags 47 | end 48 | 49 | def configure_mruby_apr(spec) 50 | # This gem is only setup to build with the static apr lib. 51 | # To use the static lib, you need to declare this preprocessor macro. 52 | spec.cc.defines << "APR_DECLARE_STATIC" 53 | spec.cxx.defines << "APR_DECLARE_STATIC" 54 | 55 | if ENV['OS'] =~ /windows/i 56 | configure_mruby_apr_win(spec) 57 | else 58 | configure_mruby_apr_lin(spec) 59 | end 60 | end 61 | 62 | MRuby::Gem::Specification.new('mruby-apr') do |spec| 63 | spec.license = 'Apache Version 2' 64 | spec.author = 'Jared Breeden' 65 | spec.summary = 'Bindings to the APR libraries' 66 | spec.add_dependency('mruby-regexp-pcre', ">= 0.0.0", github: "iij/mruby-regexp-pcre") 67 | 68 | # Gather cflags from various locations and check for MRB_INT64 69 | # TODO: There should be a better way to communicate this requirement 70 | # to the user. 71 | set_flags = spec.build.cc.flags.dup.concat((ENV['CFLAGS'] || '').split).flatten 72 | 73 | if !(/true/i =~ ENV['MRUBY_APR_IGNORE_INT_SIZE']) && set_flags.select { |f| f =~ /-D.*MRB_INT64/i }.empty? 74 | $stderr.puts <<-EOS 75 | ERROR: 76 | mruby-apr requires 64 bit integers. 77 | Please define the MRB_INT64 macro before building. 78 | Options: 79 | 1. Set `spec.cc.flags << '-DMRB_INT64'` in build_config.rb 80 | 2. Invoke rake as `rake CLFAGS=-DMRB_INT64 ...` when building mruby 81 | Workaround: 82 | If you think you're seeing this message in error, 83 | set ENV['MRUBY_APR_IGNORE_INT_SIZE'] = 'true' to bypass 84 | this check (and consider submitting a bug report!) 85 | EOS 86 | raise "MRuby-APR requires MRB_INT64 to be set" 87 | end 88 | 89 | spec.rbfiles = %w[ 90 | mruby_backport_utils 91 | io 92 | file 93 | dir 94 | glob 95 | basic_socket 96 | ipsocket 97 | tcpsocket 98 | tcpserver 99 | udpsocket 100 | socket_error 101 | kernel 102 | ].map { |name| "#{$APR_GEM_DIR}/mrblib/#{name}.rb" } 103 | .concat(Dir["#{$APR_GEM_DIR}/mrblib/**/*.rb"]) 104 | .map { |f| File.expand_path(f) } 105 | .uniq 106 | 107 | # Need the gem init file to be compiled last, so push it on the end of the file list 108 | gem_init_rb = File.expand_path("#{spec.dir}/mrblib/mrb_apr_gem_init.rb") 109 | spec.rbfiles.delete(gem_init_rb) 110 | spec.rbfiles.push(gem_init_rb) 111 | 112 | configure_mruby_apr(spec) 113 | end 114 | -------------------------------------------------------------------------------- /mrblib/APR_ext.rb: -------------------------------------------------------------------------------- 1 | # APR.rb is auto generated. 2 | # This file contains hand-written extensions to the module. 3 | 4 | module APR 5 | # If apr_errno is an error code, and it doesn't appear in `opt[:ignore]`, 6 | # raise it as a Ruby exception. 7 | def self.raise_apr_errno(apr_errno, opt = {ignore: []}) 8 | [opt[:ignore]].flatten.each do |err| 9 | return if apr_errno == err 10 | end 11 | if apr_errno != APR::APR_SUCCESS 12 | raise SystemCallError.new(APR.strerror(apr_errno), APR.to_os_error(apr_errno)) 13 | end 14 | end 15 | 16 | # Use this method to get a pool via the 'loan' pattern. 17 | def self.with_pool(&block) 18 | err, pool = APR.pool_create(nil) 19 | return block[pool] 20 | end 21 | 22 | # Creating pools is slow. If you don't need to keep any native handles 23 | # from the pool around, use this method instead. It re-uses a pool, 24 | # clearing the contents after each use. 25 | def self.with_stack_pool(&block) 26 | @stack_pool_handle ||= stack_pool 27 | stack_pool_enter 28 | result = yield @stack_pool_handle 29 | stack_pool_leave 30 | result 31 | end 32 | 33 | # APR_FINFO_* Flags 34 | # ----------------- 35 | # 36 | # For quick reference, the flags made available by APR are listed here. 37 | # Below this listing, predefined combinations of flags are defined 38 | # 39 | # ### Standard flags 40 | # 41 | # define APR_FINFO_LINK 0x00000001 /**< Stat the link not the file itself if it is a link */ 42 | # define APR_FINFO_MTIME 0x00000010 /**< Modification Time */ 43 | # define APR_FINFO_CTIME 0x00000020 /**< Creation or inode-changed time */ 44 | # define APR_FINFO_ATIME 0x00000040 /**< Access Time */ 45 | # define APR_FINFO_SIZE 0x00000100 /**< Size of the file */ 46 | # define APR_FINFO_CSIZE 0x00000200 /**< Storage size consumed by the file */ 47 | # define APR_FINFO_DEV 0x00001000 /**< Device */ 48 | # define APR_FINFO_INODE 0x00002000 /**< Inode */ 49 | # define APR_FINFO_NLINK 0x00004000 /**< Number of links */ 50 | # define APR_FINFO_TYPE 0x00008000 /**< Type */ 51 | # define APR_FINFO_USER 0x00010000 /**< User */ 52 | # define APR_FINFO_GROUP 0x00020000 /**< Group */ 53 | # define APR_FINFO_UPROT 0x00100000 /**< User protection bits */ 54 | # define APR_FINFO_GPROT 0x00200000 /**< Group protection bits */ 55 | # define APR_FINFO_WPROT 0x00400000 /**< World protection bits */ 56 | # define APR_FINFO_ICASE 0x01000000 /**< if dev is case insensitive */ 57 | # define APR_FINFO_NAME 0x02000000 /**< ->name in proper case */ 58 | # 59 | # ### Aggregate Flags 60 | # 61 | # define APR_FINFO_MIN 0x00008170 /**< type, mtime, ctime, atime, size */ 62 | # define APR_FINFO_IDENT 0x00003000 /**< dev and inode */ 63 | # define APR_FINFO_OWNER 0x00030000 /**< user and group */ 64 | # define APR_FINFO_PROT 0x00700000 /**< all protections */ 65 | # define APR_FINFO_NORM 0x0073b170 /**< an atomic unix apr_stat() */ 66 | # define APR_FINFO_DIRENT 0x02000000 /**< an atomic unix apr_dir_read() */ 67 | 68 | # Default file info fields "want" flags 69 | APR_FINFO_DEFAULT = APR_FINFO_MTIME | 70 | APR_FINFO_CTIME | 71 | APR_FINFO_ATIME | 72 | APR_FINFO_SIZE | 73 | APR_FINFO_TYPE | 74 | APR_FINFO_USER | 75 | APR_FINFO_GROUP | 76 | APR_FINFO_UPROT | 77 | APR_FINFO_GPROT | 78 | APR_FINFO_WPROT | 79 | APR_FINFO_NAME 80 | 81 | # Info fields "want" flags for statusing a link instead of the file itself 82 | APR_FINFO_LINK = APR_FINFO_DEFAULT | APR_FINFO_LINK 83 | 84 | module Convert 85 | # Convert an APR representation of time 86 | # into a Ruby Time object. 87 | def self.apr_time_to_rb(apr_time) 88 | Time.at(APR.time_sec(apr_time)) 89 | end 90 | end 91 | end 92 | -------------------------------------------------------------------------------- /mrblib/addinfo.rb: -------------------------------------------------------------------------------- 1 | class Addrinfo 2 | 3 | # def self.foreach 4 | # end 5 | # 6 | # def self.getaddrinfo 7 | # end 8 | # 9 | # def self.ip 10 | # end 11 | # 12 | # def self.tcp 13 | # end 14 | # 15 | # def self.udp 16 | # end 17 | # 18 | # def self.unix 19 | # end 20 | 21 | # def initialize(sockaddr, family, socktype, protocol) 22 | # end 23 | 24 | # def afamily 25 | # end 26 | # 27 | # def bind 28 | # end 29 | # 30 | # def canonname 31 | # end 32 | # 33 | # def connect 34 | # end 35 | # 36 | # def connect_from 37 | # end 38 | # 39 | # def connect_to 40 | # end 41 | # 42 | # def family_addrinfo 43 | # end 44 | # 45 | # def getnameinfo 46 | # end 47 | # 48 | # def inspect 49 | # end 50 | # 51 | # def inspect_sockaddr 52 | # end 53 | # 54 | # def ip? 55 | # end 56 | # 57 | # def ip_address 58 | # end 59 | # 60 | # def ip_port 61 | # end 62 | # 63 | # def ip_unpack 64 | # end 65 | # 66 | # def ipv4? 67 | # end 68 | # 69 | # def ipv4_loopback? 70 | # end 71 | # 72 | # def ipv4_multicast? 73 | # end 74 | # 75 | # def ipv4_private? 76 | # end 77 | # 78 | # def ipv6? 79 | # end 80 | # 81 | # def ipv6_linklocal? 82 | # end 83 | # 84 | # def ipv6_loopback? 85 | # end 86 | # 87 | # def ipv6_mc_global? 88 | # end 89 | # 90 | # def ipv6_mc_linklocal? 91 | # end 92 | # 93 | # def ipv6_mc_nodelocal? 94 | # end 95 | # 96 | # def ipv6_mc_orglocal? 97 | # end 98 | # 99 | # def ipv6_mc_sitelocal? 100 | # end 101 | # 102 | # def ipv6_multicast? 103 | # end 104 | # 105 | # def ipv6_sitelocal? 106 | # end 107 | # 108 | # def ipv6_to_ipv4 109 | # end 110 | # 111 | # def ipv6_unique_local? 112 | # end 113 | # 114 | # def ipv6_unspecified? 115 | # end 116 | # 117 | # def ipv6_v4compat? 118 | # end 119 | # 120 | # def ipv6_v4mapped? 121 | # end 122 | # 123 | # def listen 124 | # end 125 | # 126 | # def marshal_dump 127 | # end 128 | # 129 | # def marshal_load 130 | # end 131 | # 132 | # def pfamily 133 | # end 134 | # 135 | # def protocol 136 | # end 137 | # 138 | # def socktype 139 | # end 140 | # 141 | # def to_s 142 | # end 143 | # 144 | # def to_sockaddr 145 | # end 146 | # 147 | # def unix? 148 | # end 149 | # 150 | # def unix_path 151 | # end 152 | 153 | end 154 | -------------------------------------------------------------------------------- /mrblib/basic_socket.rb: -------------------------------------------------------------------------------- 1 | class BasicSocket < IO 2 | 3 | # BasicSocket Subclass Contract 4 | # ----------------------------- 5 | 6 | # A subclass of BasicSocket must provide the following instance variables: 7 | # - @apr_socket: An APR::Socket instance 8 | 9 | def initialize 10 | # Sockets always open in duplex mode. 11 | # When the client calls `close`, `close_read`, or `close_write` 12 | # these values will be overwritten. 13 | @can_read = true 14 | @can_write = true 15 | end 16 | 17 | # IO Subclass Contract Implementation 18 | # ----------------------------------- 19 | 20 | def assert_can_read 21 | raise IOError.new("Not open for reading") unless @can_read 22 | end 23 | 24 | def assert_can_write 25 | raise IOError.new("Not open for writing") unless @can_write 26 | end 27 | 28 | def read(length=nil) 29 | assert_can_read 30 | 31 | msg = "" 32 | 33 | if length 34 | err, msg = APR.socket_recv(@apr_socket, length) 35 | APR::raise_apr_errno(err, ignore: APR::APR_EOF) 36 | else 37 | err = nil 38 | msg = "" 39 | while err != APR::APR_EOF 40 | err, part = APR.socket_recv(@apr_socket, 100) 41 | APR::raise_apr_errno(err, ignore: APR::APR_EOF) 42 | msg += part 43 | end 44 | end 45 | 46 | if length.nil? 47 | # should be "" if nothing was read (EOF hit) 48 | msg 49 | elsif length == 0 50 | # Per ruby documents, return "" on length == 0 51 | "" 52 | else 53 | # length was provided non-zero, so return nil if nothing read 54 | msg == "" ? nil : msg 55 | end 56 | end 57 | 58 | def write(str) 59 | assert_can_write 60 | 61 | # Todo: check for socket connection 62 | str = str.to_s unless str.class == String 63 | err, bytes_sent = APR.socket_send(@apr_socket, str, str.length) 64 | APR.raise_apr_errno(err) 65 | bytes_sent 66 | end 67 | 68 | def eof? 69 | err, at_eof = APR.socket_atreadeof(@apr_socket) 70 | APR.raise_apr_errno(err) 71 | at_eof 72 | end 73 | 74 | # Semi-Private Utility Methods 75 | # ----------------------- 76 | 77 | module Util 78 | def self.to_apr_address_family(af) 79 | case af 80 | when Socket::AF_INET, :INET, :AF_INET, 'INET', 'AF_INET' 81 | APR::APR_INET 82 | when Socket::AF_INET6, :INET6, :AF_INET6, 'INET6', 'AF_INET6' 83 | APR::APR_INET6 84 | else 85 | raise SocketError("Unrecognized socket type: #{af}") 86 | end 87 | end 88 | 89 | def self.to_apr_socket_type(st) 90 | case st 91 | when :STREAM, :SOCK_STREAM, 'STREAM', 'SOCK_STREAM' 92 | APR::SOCK_STREAM 93 | when :DGRAM, :SOCK_DGRAM, 'DGRAM', 'SOCK_DGRAM' 94 | APR::SOCK_DGRAM 95 | when :RAW, :SOCK_RAW, 'RAW', 'SOCK_RAW' 96 | APR::SOCK_RAW 97 | when :SEQPACKET, :SOCK_SEQPACKET, 'SEQPACKET', 'SOCK_SEQPACKET' 98 | APR::SOCK_SEQPACKET 99 | when :RDM, :SOCK_RDM, 'RDM', 'SOCK_RDM' 100 | APR::SOCK_RDM 101 | else 102 | raise SocketError("Unrecognized socket type: #{st}") 103 | end 104 | end 105 | 106 | def self.address_family_to_s(af) 107 | case af 108 | when Socket::AF_APPLETALK 109 | 'AF_APPLETALK' 110 | when Socket::AF_CCITT 111 | 'AF_CCITT' 112 | when Socket::AF_CHAOS 113 | 'AF_CHAOS' 114 | when Socket::AF_CNT 115 | 'AF_CNT' 116 | when Socket::AF_COIP 117 | 'AF_COIP' 118 | when Socket::AF_DATAKIT 119 | 'AF_DATAKIT' 120 | when Socket::AF_DLI 121 | 'AF_DLI' 122 | when Socket::AF_E164 123 | 'AF_E164' 124 | when Socket::AF_ECMA 125 | 'AF_ECMA' 126 | when Socket::AF_HYLINK 127 | 'AF_HYLINK' 128 | when Socket::AF_IMPLINK 129 | 'AF_IMPLINK' 130 | when Socket::AF_INET 131 | 'AF_INET' 132 | when Socket::AF_INET6 133 | 'AF_INET6' 134 | when Socket::AF_IPX 135 | 'AF_IPX' 136 | when Socket::AF_ISDN 137 | 'AF_ISDN' 138 | when Socket::AF_ISO 139 | 'AF_ISO' 140 | when Socket::AF_LAT 141 | 'AF_LAT' 142 | when Socket::AF_LINK 143 | 'AF_LINK' 144 | when Socket::AF_LOCAL 145 | 'AF_LOCAL' 146 | when Socket::AF_MAX 147 | 'AF_MAX' 148 | when Socket::AF_NATM 149 | 'AF_NATM' 150 | when Socket::AF_NDRV 151 | 'AF_NDRV' 152 | when Socket::AF_NETBIOS 153 | 'AF_NETBIOS' 154 | when Socket::AF_NS 155 | 'AF_NS' 156 | when Socket::AF_OSI 157 | 'AF_OSI' 158 | when Socket::AF_PPP 159 | 'AF_PPP' 160 | when Socket::AF_PUP 161 | 'AF_PUP' 162 | when Socket::AF_ROUTE 163 | 'AF_ROUTE' 164 | when Socket::AF_SIP 165 | 'AF_SIP' 166 | when Socket::AF_SNA 167 | 'AF_SNA' 168 | when Socket::AF_SYSTEM 169 | 'AF_SYSTEM' 170 | when Socket::AF_UNIX 171 | 'AF_UNIX' 172 | when Socket::AF_UNSPEC 173 | 'AF_UNSPEC' 174 | else 175 | raise ArgumentError.new("Unrecognized APR address family constant") 176 | end 177 | end 178 | end 179 | 180 | # Instance Methods 181 | # ---------------- 182 | 183 | def close 184 | assert_can_read 185 | @can_read = false 186 | @can_write = false 187 | ignored_err = APR.socket_close(@apr_socket) 188 | end 189 | 190 | def close_read 191 | assert_can_read 192 | @can_read = false 193 | ignored_err = APR.socket_shutdown(@apr_socket, APR::ShutdownHow::APR_SHUTDOWN_READ) 194 | end 195 | 196 | def close_write 197 | assert_can_write 198 | @can_write = false 199 | ignored_err = APR.socket_shutdown(@apr_socket, APR::ShutdownHow::APR_SHUTDOWN_WRITE) 200 | end 201 | 202 | def closed? 203 | !(@can_read || @can_write) 204 | end 205 | 206 | def read_closed? 207 | !@can_read 208 | end 209 | 210 | def write_closed? 211 | !@can_write 212 | end 213 | 214 | # def connect_address 215 | # 216 | # end 217 | # 218 | # def do_not_reverse_lookup 219 | # 220 | # end 221 | # 222 | # def do_not_reverse_lookup= 223 | # 224 | # end 225 | # 226 | # def getpeereid 227 | # 228 | # end 229 | # 230 | # def getpeername 231 | # 232 | # end 233 | # 234 | # def getsockname 235 | # 236 | # end 237 | # 238 | # def getsockopt 239 | # 240 | # end 241 | # 242 | # def local_address 243 | # 244 | # end 245 | 246 | def recv(maxlen) 247 | err, msg = APR.socket_recv(@apr_socket, maxlen) 248 | APR.raise_apr_errno(err, ignore: APR::APR_EOF) 249 | msg 250 | end 251 | 252 | # def recv_nonblock 253 | # 254 | # end 255 | # 256 | # def recvmsg 257 | # 258 | # end 259 | # 260 | # def recvmsg_nonblock 261 | # 262 | # end 263 | # 264 | # def remote_address 265 | # 266 | # end 267 | 268 | def send(msg) 269 | assert_can_write 270 | 271 | msg = msg.to_s unless msg.class == String 272 | err, bytes_sent = APR.socket_send(@apr_socket, msg, msg.length) 273 | APR.raise_apr_errno(err) 274 | bytes_sent 275 | end 276 | 277 | # def sendmsg 278 | # 279 | # end 280 | # 281 | # def sendmsg_nonblock 282 | # 283 | # end 284 | # 285 | # def setsockopt 286 | # 287 | # end 288 | 289 | def shutdown(how = Socket::SHUT_RDWR) 290 | case how 291 | when Socket::SHUT_RDWR, :RDWR, :SHUT_RDWR, 'RDWR', 'SHUT_RDWR' 292 | close_read 293 | close_write 294 | when Socket::SHUT_RD, :RD, :SHUT_RD, 'RD', 'SHUT_RD' 295 | close_read 296 | when Socket::SHUT_WR, :WR, :SHUT_WR, 'WR', 'SHUT_WR' 297 | close_write 298 | else 299 | raise SocketError.new("Unrecognized `how` parameter to BasicSocket#shutdown: #{how}") 300 | end 301 | end 302 | end 303 | -------------------------------------------------------------------------------- /mrblib/cruby_lib/find.rb: -------------------------------------------------------------------------------- 1 | module Find 2 | def find(*paths) 3 | ignore_error = false 4 | if [true, false].include?(paths.last) 5 | ignore_error = paths.pop 6 | end 7 | 8 | block_given? or return enum_for(__method__, *paths, ignore_error) 9 | 10 | paths.map { |path| 11 | raise SystemCallError.new("No such file or directory #{d}") unless File.exist?(path) 12 | path.dup 13 | }.each do |path| 14 | path = path.to_path if path.respond_to? :to_path 15 | paths = [path] 16 | while file = paths.shift 17 | begin 18 | yield file.dup 19 | begin 20 | is_directory = File.directory?(file) 21 | rescue SystemCallError 22 | raise unless ignore_error 23 | next 24 | end 25 | if is_directory 26 | begin 27 | files = Dir.entries(file) 28 | rescue SystemCallError 29 | raise unless ignore_error 30 | next 31 | end 32 | files.sort! 33 | files.reverse_each {|f| 34 | next if f == "." or f == ".." 35 | f = File.join(file, f) 36 | paths.unshift f 37 | } 38 | end 39 | rescue Prune 40 | # Just Continue 41 | end 42 | end 43 | end 44 | nil 45 | end 46 | 47 | class Prune < StandardError; end 48 | def prune 49 | raise Prune.new 50 | end 51 | 52 | module_function :find 53 | module_function :prune 54 | end 55 | -------------------------------------------------------------------------------- /mrblib/cruby_lib/observer.rb: -------------------------------------------------------------------------------- 1 | # Implementation of the _Observer_ object-oriented design pattern. The 2 | # following documentation is copied, with modifications, from "Programming 3 | # Ruby", by Hunt and Thomas; http://www.ruby-doc.org/docs/ProgrammingRuby/html/lib_patterns.html. 4 | # 5 | # See Observable for more info. 6 | 7 | # The Observer pattern (also known as publish/subscribe) provides a simple 8 | # mechanism for one object to inform a set of interested third-party objects 9 | # when its state changes. 10 | # 11 | # == Mechanism 12 | # 13 | # The notifying class mixes in the +Observable+ 14 | # module, which provides the methods for managing the associated observer 15 | # objects. 16 | # 17 | # The observable object must: 18 | # * assert that it has +#changed+ 19 | # * call +#notify_observers+ 20 | # 21 | # An observer subscribes to updates using Observable#add_observer, which also 22 | # specifies the method called via #notify_observers. The default method for 23 | # #notify_observers is #update. 24 | # 25 | # === Example 26 | # 27 | # The following example demonstrates this nicely. A +Ticker+, when run, 28 | # continually receives the stock +Price+ for its @symbol. A +Warner+ 29 | # is a general observer of the price, and two warners are demonstrated, a 30 | # +WarnLow+ and a +WarnHigh+, which print a warning if the price is below or 31 | # above their set limits, respectively. 32 | # 33 | # The +update+ callback allows the warners to run without being explicitly 34 | # called. The system is set up with the +Ticker+ and several observers, and the 35 | # observers do their duty without the top-level code having to interfere. 36 | # 37 | # Note that the contract between publisher and subscriber (observable and 38 | # observer) is not declared or enforced. The +Ticker+ publishes a time and a 39 | # price, and the warners receive that. But if you don't ensure that your 40 | # contracts are correct, nothing else can warn you. 41 | # 42 | # require "observer" 43 | # 44 | # class Ticker ### Periodically fetch a stock price. 45 | # include Observable 46 | # 47 | # def initialize(symbol) 48 | # @symbol = symbol 49 | # end 50 | # 51 | # def run 52 | # last_price = nil 53 | # loop do 54 | # price = Price.fetch(@symbol) 55 | # print "Current price: #{price}\n" 56 | # if price != last_price 57 | # changed # notify observers 58 | # last_price = price 59 | # notify_observers(Time.now, price) 60 | # end 61 | # sleep 1 62 | # end 63 | # end 64 | # end 65 | # 66 | # class Price ### A mock class to fetch a stock price (60 - 140). 67 | # def self.fetch(symbol) 68 | # 60 + rand(80) 69 | # end 70 | # end 71 | # 72 | # class Warner ### An abstract observer of Ticker objects. 73 | # def initialize(ticker, limit) 74 | # @limit = limit 75 | # ticker.add_observer(self) 76 | # end 77 | # end 78 | # 79 | # class WarnLow < Warner 80 | # def update(time, price) # callback for observer 81 | # if price < @limit 82 | # print "--- #{time.to_s}: Price below #@limit: #{price}\n" 83 | # end 84 | # end 85 | # end 86 | # 87 | # class WarnHigh < Warner 88 | # def update(time, price) # callback for observer 89 | # if price > @limit 90 | # print "+++ #{time.to_s}: Price above #@limit: #{price}\n" 91 | # end 92 | # end 93 | # end 94 | # 95 | # ticker = Ticker.new("MSFT") 96 | # WarnLow.new(ticker, 80) 97 | # WarnHigh.new(ticker, 120) 98 | # ticker.run 99 | # 100 | # Produces: 101 | # 102 | # Current price: 83 103 | # Current price: 75 104 | # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 75 105 | # Current price: 90 106 | # Current price: 134 107 | # +++ Sun Jun 09 00:10:25 CDT 2002: Price above 120: 134 108 | # Current price: 134 109 | # Current price: 112 110 | # Current price: 79 111 | # --- Sun Jun 09 00:10:25 CDT 2002: Price below 80: 79 112 | module Observable 113 | 114 | # 115 | # Add +observer+ as an observer on this object. so that it will receive 116 | # notifications. 117 | # 118 | # +observer+:: the object that will be notified of changes. 119 | # +func+:: Symbol naming the method that will be called when this Observable 120 | # has changes. 121 | # 122 | # This method must return true for +observer.respond_to?+ and will 123 | # receive *arg when #notify_observers is called, where 124 | # *arg is the value passed to #notify_observers by this 125 | # Observable 126 | def add_observer(observer, func=:update) 127 | @observer_peers ||= {} 128 | unless observer.respond_to? func 129 | raise NoMethodError, "observer does not respond to `#{func}'" 130 | end 131 | @observer_peers[observer] = func 132 | end 133 | 134 | # 135 | # Remove +observer+ as an observer on this object so that it will no longer 136 | # receive notifications. 137 | # 138 | # +observer+:: An observer of this Observable 139 | def delete_observer(observer) 140 | @observer_peers.delete observer if @observer_peers.respond_to?(:delete) 141 | end 142 | 143 | # 144 | # Remove all observers associated with this object. 145 | # 146 | def delete_observers 147 | @observer_peers.clear if @observer_peers.respond_to?(:clear) 148 | end 149 | 150 | # 151 | # Return the number of observers associated with this object. 152 | # 153 | def count_observers 154 | if @observer_peers.respond_to?(:size) 155 | @observer_peers.size 156 | else 157 | 0 158 | end 159 | end 160 | 161 | # 162 | # Set the changed state of this object. Notifications will be sent only if 163 | # the changed +state+ is +true+. 164 | # 165 | # +state+:: Boolean indicating the changed state of this Observable. 166 | # 167 | def changed(state=true) 168 | @observer_state = state 169 | end 170 | 171 | # 172 | # Returns true if this object's state has been changed since the last 173 | # #notify_observers call. 174 | # 175 | def changed? 176 | !!@observer_state 177 | end 178 | 179 | # 180 | # Notify observers of a change in state *if* this object's changed state is 181 | # +true+. 182 | # 183 | # This will invoke the method named in #add_observer, passing *arg. 184 | # The changed state is then set to +false+. 185 | # 186 | # *arg:: Any arguments to pass to the observers. 187 | def notify_observers(*arg) 188 | if @observer_state 189 | (@observer_peers || []).each do |k, v| 190 | k.send v, *arg 191 | end 192 | @observer_state = false 193 | end 194 | end 195 | 196 | end 197 | -------------------------------------------------------------------------------- /mrblib/cruby_lib/ostruct.rb: -------------------------------------------------------------------------------- 1 | class OpenStruct 2 | # 3 | # Creates a new OpenStruct object. By default, the resulting OpenStruct 4 | # object will have no attributes. 5 | # 6 | # The optional +hash+, if given, will generate attributes and values 7 | # (can be a Hash, an OpenStruct or a Struct). 8 | # For example: 9 | # 10 | # require 'ostruct' 11 | # hash = { "country" => "Australia", :population => 20_000_000 } 12 | # data = OpenStruct.new(hash) 13 | # 14 | # p data # -> 15 | # 16 | def initialize(hash=nil) 17 | @table = {} 18 | if hash 19 | hash.each_pair do |k, v| 20 | k = k.to_sym 21 | @table[k] = v 22 | new_ostruct_member(k) 23 | end 24 | end 25 | end 26 | 27 | # Duplicate an OpenStruct object members. 28 | def initialize_copy(orig) 29 | super 30 | @table = @table.dup 31 | @table.each_key{|key| new_ostruct_member(key)} 32 | end 33 | 34 | # 35 | # Converts the OpenStruct to a hash with keys representing 36 | # each attribute (as symbols) and their corresponding values 37 | # Example: 38 | # 39 | # require 'ostruct' 40 | # data = OpenStruct.new("country" => "Australia", :population => 20_000_000) 41 | # data.to_h # => {:country => "Australia", :population => 20000000 } 42 | # 43 | def to_h 44 | @table.dup 45 | end 46 | 47 | # 48 | # Yields all attributes (as a symbol) along with the corresponding values 49 | # or returns an enumerator if not block is given. 50 | # Example: 51 | # 52 | # require 'ostruct' 53 | # data = OpenStruct.new("country" => "Australia", :population => 20_000_000) 54 | # data.each_pair.to_a # => [[:country, "Australia"], [:population, 20000000]] 55 | # 56 | def each_pair 57 | return to_enum(__method__) { @table.size } unless block_given? 58 | @table.each_pair{|p| yield p} 59 | end 60 | 61 | # 62 | # Provides marshalling support for use by the Marshal library. 63 | # 64 | def marshal_dump 65 | @table 66 | end 67 | 68 | # 69 | # Provides marshalling support for use by the Marshal library. 70 | # 71 | def marshal_load(x) 72 | @table = x 73 | @table.each_key{|key| new_ostruct_member(key)} 74 | end 75 | 76 | # 77 | # Used internally to check if the OpenStruct is able to be 78 | # modified before granting access to the internal Hash table to be modified. 79 | # 80 | def modifiable 81 | begin 82 | @modifiable = true 83 | rescue 84 | raise RuntimeError, "can't modify frozen #{self.class}", caller(3) 85 | end 86 | @table 87 | end 88 | protected :modifiable 89 | 90 | # 91 | # Used internally to defined properties on the 92 | # OpenStruct. It does this by using the metaprogramming function 93 | # define_singleton_method for both the getter method and the setter method. 94 | # 95 | def new_ostruct_member(name) 96 | name = name.to_sym 97 | unless respond_to?(name) 98 | define_singleton_method(name) { @table[name] } 99 | define_singleton_method("#{name}=") { |x| modifiable[name] = x } 100 | end 101 | name 102 | end 103 | protected :new_ostruct_member 104 | 105 | def method_missing(mid, *args) # :nodoc: 106 | len = args.length 107 | mid_s = mid.to_s 108 | if mid_s.end_with? '=' 109 | mname = mid_s[0..(mid_s.length - 2)] 110 | if len != 1 111 | raise ArgumentError, "wrong number of arguments (#{len} for 1)", caller(1) 112 | end 113 | modifiable[new_ostruct_member(mname)] = args[0] 114 | elsif len == 0 115 | @table[mid] 116 | else 117 | err = NoMethodError.new "undefined method `#{mid}' for #{self}", mid, args 118 | err.set_backtrace caller(1) 119 | raise err 120 | end 121 | end 122 | 123 | # Returns the value of a member. 124 | # 125 | # person = OpenStruct.new('name' => 'John Smith', 'age' => 70) 126 | # person[:age] # => 70, same as ostruct.age 127 | # 128 | def [](name) 129 | @table[name.to_sym] 130 | end 131 | 132 | # 133 | # Sets the value of a member. 134 | # 135 | # person = OpenStruct.new('name' => 'John Smith', 'age' => 70) 136 | # person[:age] = 42 # => equivalent to ostruct.age = 42 137 | # person.age # => 42 138 | # 139 | def []=(name, value) 140 | modifiable[new_ostruct_member(name)] = value 141 | end 142 | 143 | # 144 | # Remove the named field from the object. Returns the value that the field 145 | # contained if it was defined. 146 | # 147 | # require 'ostruct' 148 | # 149 | # person = OpenStruct.new('name' => 'John Smith', 'age' => 70) 150 | # 151 | # person.delete_field('name') # => 'John Smith' 152 | # 153 | def delete_field(name) 154 | sym = name.to_sym 155 | singleton_class.__send__(:remove_method, sym, "#{sym}=") 156 | @table.delete sym 157 | end 158 | 159 | # MRuby Patch: 160 | # Change behavior since MRuby doesn't have threads. 161 | # Leaving the conditional fallback in case MRuby gets threads. 162 | if Object.const_defined?(:Thread) 163 | InspectKey = :__inspect_key__ # :nodoc: 164 | else 165 | InspectIds = [] 166 | end 167 | 168 | # 169 | # Returns a string containing a detailed summary of the keys and values. 170 | # 171 | def inspect 172 | str = "#<#{self.class}" 173 | 174 | # MRuby Patch: 175 | # Change behavior since MRuby doesn't have threads. 176 | # Leaving the conditional fallback in case MRuby gets threads. 177 | ids = nil 178 | if Object.const_defined?(:Thread) 179 | ids = (Thread.current[InspectKey] ||= []) 180 | else 181 | ids = InspectIds 182 | end 183 | 184 | if ids.include?(object_id) 185 | return str << ' ...>' 186 | end 187 | 188 | ids << object_id 189 | begin 190 | first = true 191 | for k,v in @table 192 | str << "," unless first 193 | first = false 194 | str << " #{k}=#{v.inspect}" 195 | end 196 | return str << '>' 197 | ensure 198 | ids.pop 199 | end 200 | end 201 | alias :to_s :inspect 202 | 203 | attr_reader :table # :nodoc: 204 | protected :table 205 | 206 | # 207 | # Compares this object and +other+ for equality. An OpenStruct is equal to 208 | # +other+ when +other+ is an OpenStruct and the two objects' Hash tables are 209 | # equal. 210 | # 211 | def ==(other) 212 | return false unless other.kind_of?(OpenStruct) 213 | @table == other.table 214 | end 215 | 216 | # 217 | # Compares this object and +other+ for equality. An OpenStruct is eql? to 218 | # +other+ when +other+ is an OpenStruct and the two objects' Hash tables are 219 | # eql?. 220 | # 221 | def eql?(other) 222 | return false unless other.kind_of?(OpenStruct) 223 | @table.eql?(other.table) 224 | end 225 | 226 | # Compute a hash-code for this OpenStruct. 227 | # Two hashes with the same content will have the same hash code 228 | # (and will be eql?). 229 | def hash 230 | @table.hash 231 | end 232 | end 233 | -------------------------------------------------------------------------------- /mrblib/cruby_lib/shellwords.rb: -------------------------------------------------------------------------------- 1 | ## 2 | # == Manipulates strings like the UNIX Bourne shell 3 | # 4 | # This module manipulates strings according to the word parsing rules 5 | # of the UNIX Bourne shell. 6 | # 7 | # The shellwords() function was originally a port of shellwords.pl, 8 | # but modified to conform to POSIX / SUSv3 (IEEE Std 1003.1-2001 [1]). 9 | # 10 | # === Usage 11 | # 12 | # You can use shellwords to parse a string into a Bourne shell friendly Array. 13 | # 14 | # require 'shellwords' 15 | # 16 | # argv = Shellwords.split('three blind "mice"') 17 | # argv #=> ["three", "blind", "mice"] 18 | # 19 | # Once you've required Shellwords, you can use the #split alias 20 | # String#shellsplit. 21 | # 22 | # argv = "see how they run".shellsplit 23 | # argv #=> ["see", "how", "they", "run"] 24 | # 25 | # Be careful you don't leave a quote unmatched. 26 | # 27 | # argv = "they all ran after the farmer's wife".shellsplit 28 | # #=> ArgumentError: Unmatched double quote: ... 29 | # 30 | # In this case, you might want to use Shellwords.escape, or it's alias 31 | # String#shellescape. 32 | # 33 | # This method will escape the String for you to safely use with a Bourne shell. 34 | # 35 | # argv = Shellwords.escape("special's.txt") 36 | # argv #=> "special\\s.txt" 37 | # system("cat " + argv) 38 | # 39 | # Shellwords also comes with a core extension for Array, Array#shelljoin. 40 | # 41 | # argv = %w{ls -lta lib} 42 | # system(argv.shelljoin) 43 | # 44 | # You can use this method to create an escaped string out of an array of tokens 45 | # separated by a space. In this example we'll use the literal shortcut for 46 | # Array.new. 47 | # 48 | # === Authors 49 | # * Wakou Aoyama 50 | # * Akinori MUSHA 51 | # 52 | # === Contact 53 | # * Akinori MUSHA (current maintainer) 54 | # 55 | # === Resources 56 | # 57 | # 1: {IEEE Std 1003.1-2004}[http://pubs.opengroup.org/onlinepubs/009695399/toc.htm] 58 | 59 | module Shellwords 60 | # Splits a string into an array of tokens in the same way the UNIX 61 | # Bourne shell does. 62 | # 63 | # argv = Shellwords.split('here are "two words"') 64 | # argv #=> ["here", "are", "two words"] 65 | # 66 | # String#shellsplit is a shortcut for this function. 67 | # 68 | # argv = 'here are "two words"'.shellsplit 69 | # argv #=> ["here", "are", "two words"] 70 | def shellsplit(line) 71 | words = [] 72 | field = '' 73 | line.scan(/\G\s*(?>([^\s\\\'\"]+)|'([^\']*)'|"((?:[^\"\\]|\\.)*)"|(\\.?)|(\S))(\s|\z)?/m) do 74 | |word, sq, dq, esc, garbage, sep| 75 | raise ArgumentError, "Unmatched double quote: #{line.inspect}" if garbage 76 | field << (word || sq || (dq || esc).gsub(/\\(.)/, '\\1')) 77 | if sep 78 | words << field 79 | field = '' 80 | end 81 | end 82 | words 83 | end 84 | 85 | alias shellwords shellsplit 86 | 87 | module_function :shellsplit, :shellwords 88 | 89 | class << self 90 | alias split shellsplit 91 | end 92 | 93 | # Escapes a string so that it can be safely used in a Bourne shell 94 | # command line. +str+ can be a non-string object that responds to 95 | # +to_s+. 96 | # 97 | # Note that a resulted string should be used unquoted and is not 98 | # intended for use in double quotes nor in single quotes. 99 | # 100 | # argv = Shellwords.escape("It's better to give than to receive") 101 | # argv #=> "It\\'s\\ better\\ to\\ give\\ than\\ to\\ receive" 102 | # 103 | # String#shellescape is a shorthand for this function. 104 | # 105 | # argv = "It's better to give than to receive".shellescape 106 | # argv #=> "It\\'s\\ better\\ to\\ give\\ than\\ to\\ receive" 107 | # 108 | # # Search files in lib for method definitions 109 | # pattern = "^[ \t]*def " 110 | # open("| grep -Ern #{pattern.shellescape} lib") { |grep| 111 | # grep.each_line { |line| 112 | # file, lineno, matched_line = line.split(':', 3) 113 | # # ... 114 | # } 115 | # } 116 | # 117 | # It is the caller's responsibility to encode the string in the right 118 | # encoding for the shell environment where this string is used. 119 | # 120 | # Multibyte characters are treated as multibyte characters, not bytes. 121 | # 122 | # Returns an empty quoted String if +str+ has a length of zero. 123 | def shellescape(str) 124 | str = str.to_s 125 | 126 | # An empty argument will be skipped, so return empty quotes. 127 | return "''" if str.empty? 128 | 129 | str = str.dup 130 | 131 | # Treat multibyte characters as is. It is caller's responsibility 132 | # to encode the string in the right encoding for the shell 133 | # environment. 134 | str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/, "\\\\\\1") 135 | 136 | # A LF cannot be escaped with a backslash because a backslash + LF 137 | # combo is regarded as line continuation and simply ignored. 138 | str.gsub!(/\n/, "'\n'") 139 | 140 | return str 141 | end 142 | 143 | module_function :shellescape 144 | 145 | class << self 146 | alias escape shellescape 147 | end 148 | 149 | # Builds a command line string from an argument list, +array+. 150 | # 151 | # All elements are joined into a single string with fields separated by a 152 | # space, where each element is escaped for Bourne shell and stringified using 153 | # +to_s+. 154 | # 155 | # ary = ["There's", "a", "time", "and", "place", "for", "everything"] 156 | # argv = Shellwords.join(ary) 157 | # argv #=> "There\\'s a time and place for everything" 158 | # 159 | # Array#shelljoin is a shortcut for this function. 160 | # 161 | # ary = ["Don't", "rock", "the", "boat"] 162 | # argv = ary.shelljoin 163 | # argv #=> "Don\\'t rock the boat" 164 | # 165 | # You can also mix non-string objects in the elements as allowed in Array#join. 166 | # 167 | # output = `#{['ps', '-p', $$].shelljoin}` 168 | # 169 | def shelljoin(array) 170 | array.map { |arg| shellescape(arg) }.join(' ') 171 | end 172 | 173 | module_function :shelljoin 174 | 175 | class << self 176 | alias join shelljoin 177 | end 178 | end 179 | 180 | class String 181 | # call-seq: 182 | # str.shellsplit => array 183 | # 184 | # Splits +str+ into an array of tokens in the same way the UNIX 185 | # Bourne shell does. 186 | # 187 | # See Shellwords.shellsplit for details. 188 | def shellsplit 189 | Shellwords.split(self) 190 | end 191 | 192 | # call-seq: 193 | # str.shellescape => string 194 | # 195 | # Escapes +str+ so that it can be safely used in a Bourne shell 196 | # command line. 197 | # 198 | # See Shellwords.shellescape for details. 199 | def shellescape 200 | Shellwords.escape(self) 201 | end 202 | end 203 | 204 | class Array 205 | # call-seq: 206 | # array.shelljoin => string 207 | # 208 | # Builds a command line string from an argument list +array+ joining 209 | # all elements escaped for Bourne shell and separated by a space. 210 | # 211 | # See Shellwords.shelljoin for details. 212 | def shelljoin 213 | Shellwords.join(self) 214 | end 215 | end 216 | -------------------------------------------------------------------------------- /mrblib/dir.rb: -------------------------------------------------------------------------------- 1 | class Dir 2 | include Enumerable 3 | 4 | module Private 5 | # Replaces alternate path separators with the normalized version in `path` 6 | def self.normalize_path(path) 7 | if File::ALT_SEPARATOR 8 | path.gsub!(File::ALT_SEPARATOR, File::SEPARATOR) 9 | end 10 | path 11 | end 12 | end 13 | 14 | def initialize(path) 15 | err, @pool = APR.pool_create(nil) 16 | APR.raise_apr_errno(err) 17 | @path = File::Private.to_path_str(path) 18 | err, @native_dir = APR.dir_open @path, @pool 19 | APR.raise_apr_errno(err) 20 | @closed = false 21 | @pos = 0 22 | end 23 | 24 | def self.open(path, &block) 25 | instance = self.new(path) 26 | if block_given? 27 | result = nil 28 | begin 29 | result = block[instance] 30 | ensure 31 | instance.close 32 | end 33 | result 34 | else 35 | instance 36 | end 37 | end 38 | 39 | def assert_open 40 | raise IOError.new('Closed directory') if @closed 41 | end 42 | 43 | def close 44 | assert_open 45 | err = APR.dir_close(@native_dir) 46 | APR.raise_apr_errno(err) 47 | @closed = true 48 | end 49 | 50 | def each(&block) 51 | assert_open 52 | if block_given? 53 | while entry = read 54 | block[entry] 55 | end 56 | self 57 | else 58 | self.class.entries(@path).enum_for(:each) 59 | end 60 | end 61 | 62 | def read 63 | assert_open 64 | err, finfo = APR.dir_read APR::APR_FINFO_NAME, @native_dir 65 | APR.raise_apr_errno(err, ignore: [APR::APR_INCOMPLETE, APR::APR_ENOENT]) 66 | @pos += 1 67 | (err == APR::APR_ENOENT || finfo.nil?) ? nil : finfo.name 68 | end 69 | 70 | def rewind 71 | assert_open 72 | @pos = 0 73 | err = APR.dir_rewind(@native_dir) 74 | APR.raise_apr_errno(err) 75 | end 76 | 77 | def tell 78 | assert_open 79 | @pos 80 | end 81 | alias pos tell 82 | 83 | def self.chdir(path = nil, &block) 84 | path = Dir.home unless path 85 | path = File::Private.to_path_str(path) 86 | if block.nil? 87 | err = APR.dir_chdir(path) 88 | APR.raise_apr_errno(err) 89 | 0 90 | else 91 | prev = pwd 92 | begin 93 | chdir path 94 | block[] 95 | ensure 96 | chdir prev 97 | end 98 | end 99 | end 100 | 101 | # def self.chroot 102 | # 103 | # end 104 | 105 | def self.delete(path) 106 | path = File::Private.to_path_str(path) 107 | APR.with_stack_pool do |pool| 108 | err = APR.dir_remove(path, pool) 109 | APR.raise_apr_errno(err) 110 | end 111 | 0 112 | end 113 | class << self 114 | alias rmdir delete 115 | alias unlink rmdir 116 | end 117 | 118 | 119 | class << self 120 | alias native_entries entries 121 | end 122 | def self.entries(path) 123 | native_entries(File::Private.to_path_str(path, true)) 124 | end 125 | 126 | def self.exists?(path) 127 | path = File::Private.to_path_str(path) 128 | File.directory?(path) 129 | end 130 | class << self 131 | alias exist? exists? 132 | end 133 | 134 | def self.foreach(path, &block) 135 | path = File::Private.to_path_str(path) 136 | files = entries(path) 137 | if block.nil? 138 | self.to_enum :foreach, path 139 | else 140 | files.each(&block) 141 | end 142 | end 143 | 144 | def self.getwd 145 | err, path = APR.dir_getcwd 146 | APR.raise_apr_errno(err) # Why would this ever happen? 147 | Private.normalize_path(path) 148 | end 149 | class << self 150 | alias pwd getwd 151 | end 152 | 153 | def self.home 154 | if APR::OS == 'Windows' 155 | Private.normalize_path(ENV['HOMEPATH']) 156 | else 157 | Private.normalize_path(ENV['HOME']) 158 | end 159 | end 160 | 161 | def self.mkdir(path) 162 | path = File::Private.to_path_str(path) 163 | APR.with_stack_pool do |pool| 164 | err = APR.dir_make path, APR::APR_FPROT_OS_DEFAULT, pool 165 | APR.raise_apr_errno(err) 166 | end 167 | end 168 | 169 | def self.tmpdir 170 | APR.with_stack_pool do |pool| 171 | err, dirname = APR.temp_dir_get(pool) 172 | Private.normalize_path(dirname) 173 | end 174 | end 175 | 176 | def self.mktmpdir(prefix_suffix = nil, parent = nil) 177 | if block_given? 178 | raise "Cannot securely delete temp dir contents, so mktmpdir does not yet support a block parameter" 179 | # Need FileUtils::remove_entry_secure to fix 180 | end 181 | 182 | prefix_suffix = case prefix_suffix 183 | when NilClass 184 | ['d', ''] 185 | when String 186 | [prefix_suffix, ''] 187 | when Array 188 | prefix_suffix 189 | else 190 | raise ArgumentError.new("Invalid first parameter to Dir.mktmpdir") 191 | end 192 | 193 | parent = case parent 194 | when String 195 | parent[parent.length - 1] == '/' ? parent : "#{parent}/" 196 | when NilClass 197 | Dir.tmpdir 198 | else 199 | raise ArgumentError.new("Invalid second parameter to Dir.mktmpdir") 200 | end 201 | 202 | now = Time.now 203 | random_string = (0..5).map { (rand(26) + 'a'.ord).chr }.join('') 204 | 205 | dirname = "%{parent}%{prefix}%{date}-%{pid}-%{rand}%{suffix}" % { 206 | parent: parent, 207 | prefix: prefix_suffix.first, 208 | date: now.year.to_s + ('%02d' % now.month) + ('%02d' % now.day), 209 | pid: Process.pid, 210 | rand: random_string, 211 | suffix: prefix_suffix.last 212 | } 213 | 214 | self.mkdir(dirname) 215 | dirname 216 | end 217 | end 218 | -------------------------------------------------------------------------------- /mrblib/env.rb: -------------------------------------------------------------------------------- 1 | ENV = Object.new 2 | 3 | class << ENV 4 | def [](key) 5 | err, value = ::APR.env_get(key, pool) 6 | if err != 0 7 | nil 8 | else 9 | value 10 | end 11 | end 12 | 13 | def []=(key, value) 14 | err = ::APR.env_set(key, value, pool) 15 | ::APR.raise_apr_errno(err) 16 | value 17 | end 18 | 19 | def delete(key) 20 | value = self[key] 21 | ::APR.env_delete(key, pool) 22 | value 23 | end 24 | 25 | def pool 26 | unless @pool 27 | err, env_pool = ::APR.pool_create(nil) 28 | @pool = env_pool 29 | end 30 | @pool 31 | end 32 | end 33 | -------------------------------------------------------------------------------- /mrblib/file_stat.rb: -------------------------------------------------------------------------------- 1 | class File 2 | class Stat 3 | def initialize(file_name, apr_wanted=nil) 4 | APR.with_stack_pool do |pool| 5 | APR.raise_apr_errno(APR::APR_ENOENT) unless File.exists?(file_name) 6 | err, native_finfo = APR.stat(file_name, apr_wanted || APR::APR_FINFO_DEFAULT, pool) 7 | APR.raise_apr_errno(err, ignore: APR::APR_INCOMPLETE) 8 | 9 | @atime = APR::Convert.apr_time_to_rb(native_finfo.atime) if (native_finfo.valid & APR::APR_FINFO_ATIME) != 0 10 | @ctime = APR::Convert.apr_time_to_rb(native_finfo.ctime) if (native_finfo.valid & APR::APR_FINFO_CTIME) != 0 11 | @mtime = APR::Convert.apr_time_to_rb(native_finfo.mtime) if (native_finfo.valid & APR::APR_FINFO_MTIME) != 0 12 | 13 | @name = native_finfo.name if (native_finfo.valid & APR::APR_FINFO_NAME) != 0 14 | @nlink = native_finfo.nlink if (native_finfo.valid & APR::APR_FINFO_NLINK) != 0 15 | @size = native_finfo.size if (native_finfo.valid & APR::APR_FINFO_SIZE) != 0 16 | @protection = native_finfo.protection if (native_finfo.valid & APR::APR_FINFO_PROT) != 0 17 | @filetype = native_finfo.filetype if (native_finfo.valid & APR::APR_FINFO_PROT) != 0 18 | end 19 | end 20 | 21 | # def <=> 22 | # raise NotImplementedError.new('File::Stat#<=> is not yet implemented') 23 | # end 24 | 25 | attr_reader :atime 26 | attr_reader :ctime 27 | attr_reader :mtime 28 | attr_reader :name 29 | attr_reader :nlink 30 | attr_reader :size 31 | alias size? size 32 | 33 | # def blksize 34 | # raise NotImplementedError.new('File::Stat#blksize is not yet implemented') 35 | # end 36 | 37 | def blockdev? 38 | @filetype == APR::Filetype::APR_BLK 39 | end 40 | 41 | # def blocks 42 | # raise NotImplementedError.new('File::Stat#blocks is not yet implemented') 43 | # end 44 | 45 | def chardev? 46 | @filetype == APR::Filetype::APR_CHR 47 | end 48 | 49 | # def dev 50 | # raise NotImplementedError.new('File::Stat#dev is not yet implemented') 51 | # end 52 | # 53 | # def dev_major 54 | # raise NotImplementedError.new('File::Stat#dev_major is not yet implemented') 55 | # end 56 | # 57 | # def dev_minor 58 | # raise NotImplementedError.new('File::Stat#dev_minor is not yet implemented') 59 | # end 60 | 61 | def directory? 62 | @filetype == APR::Filetype::APR_DIR 63 | end 64 | 65 | # def executable? 66 | # raise NotImplementedError.new('File::Stat#executable? is not yet implemented') 67 | # end 68 | # 69 | # def executable_real? 70 | # raise NotImplementedError.new('File::Stat#executable_real? is not yet implemented') 71 | # end 72 | 73 | def file? 74 | @filetype == APR::Filetype::APR_REG 75 | end 76 | 77 | def ftype 78 | if file? 79 | "file" 80 | elsif directory? 81 | "directory" 82 | elsif chardev? 83 | "characterSpecial" 84 | elsif blockdev? 85 | "blockSpecial" 86 | elsif pipe? 87 | "fifo" 88 | elsif symlink? 89 | "link" 90 | elsif socket? 91 | "socket" 92 | else 93 | "unkown" 94 | end 95 | end 96 | 97 | # def gid 98 | # raise NotImplementedError.new('File::Stat#gid is not yet implemented') 99 | # end 100 | # 101 | # def grpowned? 102 | # raise NotImplementedError.new('File::Stat#grpowned? is not yet implemented') 103 | # end 104 | # 105 | # def ino 106 | # raise NotImplementedError.new('File::Stat#ino is not yet implemented') 107 | # end 108 | # 109 | # def mode 110 | # raise NotImplementedError.new('File::Stat#mode is not yet implemented') 111 | # end 112 | # 113 | # def owned? 114 | # raise NotImplementedError.new('File::Stat#owned? is not yet implemented') 115 | # end 116 | 117 | def pipe? 118 | @filetype == APR::Filetype::APR_PIPE 119 | end 120 | 121 | # def rdev 122 | # raise NotImplementedError.new('File::Stat#rdev is not yet implemented') 123 | # end 124 | # 125 | # def rdev_major 126 | # raise NotImplementedError.new('File::Stat#rdev_major is not yet implemented') 127 | # end 128 | # 129 | # def rdev_minor 130 | # raise NotImplementedError.new('File::Stat#rdev_minor is not yet implemented') 131 | # end 132 | # 133 | # def readable? 134 | # raise NotImplementedError.new('File::Stat#readable? is not yet implemented') 135 | # end 136 | # 137 | # def readable_real? 138 | # raise NotImplementedError.new('File::Stat#readable_real? is not yet implemented') 139 | # end 140 | # 141 | # def setgid? 142 | # raise NotImplementedError.new('File::Stat#setgid? is not yet implemented') 143 | # end 144 | # 145 | # def setuid? 146 | # raise NotImplementedError.new('File::Stat#setuid? is not yet implemented') 147 | # end 148 | 149 | def socket? 150 | @filetype == APR::Filetype::APR_SOCKET 151 | end 152 | 153 | # def sticky? 154 | # raise NotImplementedError.new('File::Stat#sticky? is not yet implemented') 155 | # end 156 | 157 | def symlink? 158 | @filetype == APR::Filetype::APR_LNK 159 | end 160 | 161 | # def uid 162 | # raise NotImplementedError.new('File::Stat#uid is not yet implemented') 163 | # end 164 | # 165 | # def world_readable? 166 | # raise NotImplementedError.new('File::Stat#world_readable? is not yet implemented') 167 | # end 168 | # 169 | # def world_writable? 170 | # raise NotImplementedError.new('File::Stat#world_writable? is not yet implemented') 171 | # end 172 | # 173 | # def writable? 174 | # raise NotImplementedError.new('File::Stat#writable? is not yet implemented') 175 | # end 176 | # 177 | # def writable_real? 178 | # raise NotImplementedError.new('File::Stat#writable_real? is not yet implemented') 179 | # end 180 | # 181 | def zero? 182 | size == 0 183 | end 184 | end 185 | end 186 | -------------------------------------------------------------------------------- /mrblib/filetest.rb: -------------------------------------------------------------------------------- 1 | module FileTest 2 | ## OPTIMIZATION: Converted to C 3 | # module Util 4 | # # OPTIMIZATION: This is much faster than creating a fule File::Stat object 5 | # # for each test, which significantly impacts globbing with 6 | # # large search area. 7 | # def self.FileTest.is_type?(path, type) 8 | # result = nil 9 | # APR.with_pool do |pool| 10 | # err, native_finfo = APR.stat(path, APR::APR_FINFO_TYPE, pool) 11 | # if err == APR::APR_SUCCESS 12 | # result = native_finfo.filetype == type 13 | # end 14 | # end 15 | # result 16 | # end 17 | # end 18 | 19 | def blockdev?(path) 20 | path = File::Private.to_path_str(path) 21 | FileTest.is_type?(path, APR::Filetype::APR_BLK) 22 | end 23 | 24 | def chardev?(path) 25 | path = File::Private.to_path_str(path) 26 | FileTest.is_type?(path, APR::Filetype::APR_CHR) 27 | end 28 | 29 | def directory?(path) 30 | path = File::Private.to_path_str(path) 31 | FileTest.is_type?(path, APR::Filetype::APR_DIR) 32 | end 33 | 34 | # def executable?(path) 35 | # path = File::Private.to_path_str(path) 36 | # stat = File::Stat.new(path) rescue nil 37 | # stat.executable? 38 | # end 39 | # 40 | # def executable_real?(path) 41 | # path = File::Private.to_path_str(path) 42 | # stat = File::Stat.new(path) rescue nil 43 | # stat.executable_real? 44 | # end 45 | 46 | def exists?(path) 47 | path = File::Private.to_path_str(path) 48 | exists = true 49 | APR.with_stack_pool do |pool| 50 | err, f = APR.file_open(path, APR::APR_FOPEN_READ, 0, pool) 51 | exists = false if APR::APR_STATUS_IS_ENOENT(err) 52 | APR.file_close(f) if f 53 | end 54 | exists 55 | end 56 | alias exist? exists? 57 | 58 | def file?(path) 59 | path = File::Private.to_path_str(path) 60 | FileTest.is_type?(path, APR::Filetype::APR_REG) 61 | end 62 | 63 | # def grpowned?(path) 64 | # path = File::Private.to_path_str(path) 65 | # stat = File::Stat.new(path) rescue nil 66 | # stat.grpowned? 67 | # end 68 | 69 | # def identical?(path1, path2) 70 | # 71 | # end 72 | # 73 | # def owned?(path) 74 | # path = File::Private.to_path_str(path) 75 | # stat = File::Stat.new(path) rescue nil 76 | # stat.owned? 77 | # end 78 | 79 | def pipe?(path) 80 | path = File::Private.to_path_str(path) 81 | FileTest.is_type?(path, APR::Filetype::APR_PIPE) 82 | end 83 | 84 | # def readable?(path) 85 | # path = File::Private.to_path_str(path) 86 | # stat = File::Stat.new(path) rescue nil 87 | # stat.readable? 88 | # end 89 | # 90 | # def readable_real?(path) 91 | # path = File::Private.to_path_str(path) 92 | # stat = File::Stat.new(path) rescue nil 93 | # stat.readable_real? 94 | # end 95 | # 96 | # def setgid?(path) 97 | # path = File::Private.to_path_str(path) 98 | # stat = File::Stat.new(path) rescue nil 99 | # stat.setgid? 100 | # end 101 | # 102 | # def setuid?(path) 103 | # path = File::Private.to_path_str(path) 104 | # stat = File::Stat.new(path) rescue nil 105 | # stat.setuid? 106 | # end 107 | 108 | def size(path) 109 | stat = File::Stat.new(path) 110 | stat.size 111 | end 112 | alias size? size 113 | 114 | def socket?(path) 115 | path = File::Private.to_path_str(path) 116 | FileTest.is_type?(path, APR::Filetype::APR_SOCKET) 117 | end 118 | 119 | # def sticky?(path) 120 | # path = File::Private.to_path_str(path) 121 | # stat = File::Stat.new(path) rescue nil 122 | # stat.sticky? 123 | # end 124 | 125 | def symlink?(path) 126 | path = File::Private.to_path_str(path) 127 | FileTest.is_type?(path, APR::Filetype::APR_LNK) 128 | end 129 | 130 | # def world_readable?(path) 131 | # path = File::Private.to_path_str(path) 132 | # stat = File::Stat.new(path) rescue nil 133 | # stat.world_readable? 134 | # end 135 | # 136 | # def world_writable?(path) 137 | # path = File::Private.to_path_str(path) 138 | # stat = File::Stat.new(path) rescue nil 139 | # stat.world_writable? 140 | # end 141 | # 142 | # def writable?(path) 143 | # path = File::Private.to_path_str(path) 144 | # stat = File::Stat.new(path) rescue nil 145 | # stat.writable? 146 | # end 147 | # 148 | # def writable_real?(path) 149 | # path = File::Private.to_path_str(path) 150 | # stat = File::Stat.new(path) rescue nil 151 | # stat.writable_real? 152 | # end 153 | 154 | def zero?(path) 155 | path = File::Private.to_path_str(path) 156 | stat = File::Stat.new(path) rescue nil 157 | !stat.nil? && stat.zero? 158 | end 159 | 160 | instance_methods.each do |m| 161 | self.module_function m 162 | end 163 | end 164 | 165 | class File 166 | extend FileTest 167 | end 168 | -------------------------------------------------------------------------------- /mrblib/glob.rb: -------------------------------------------------------------------------------- 1 | class Dir 2 | class GlobAST 3 | class ParserError < StandardError 4 | end 5 | 6 | class Node 7 | attr_accessor :parent, :children 8 | 9 | def initialize(parent) 10 | @parent = parent 11 | @children = [] 12 | end 13 | end 14 | 15 | class Root < Node 16 | def initialize 17 | super(nil) 18 | end 19 | 20 | def accept(token) 21 | case token 22 | when :'{' 23 | child = Alternation.new(self) 24 | @children.push(child) 25 | child 26 | when :'}' 27 | raise ParserError.new("Unmatched closing brace") 28 | when :'/' 29 | @children.push(token) 30 | self 31 | when :'**' 32 | if @children[@children.length - 2] != :'**' 33 | @children.push(token) 34 | end 35 | self 36 | when :'$' 37 | # Do nothing 38 | self 39 | else 40 | # Everything else is a string at the root level 41 | if @children.last.kind_of?(String) 42 | @children.last.concat(token.to_s) 43 | else 44 | @children.push(token.to_s) 45 | end 46 | self 47 | end 48 | end 49 | 50 | def to_a 51 | parts = [['']] 52 | @children.each do |child| 53 | case child 54 | when :'/' 55 | parts.push(['']) 56 | when :'**' 57 | parts.last[0] = :'**' 58 | when String 59 | parts.last.each do |str| 60 | str.concat(child) 61 | end 62 | when Alternation 63 | replacement = [] 64 | last_part = parts.pop 65 | last_part.each do |str| 66 | child.to_a.each do |alt| 67 | replacement.push "#{str}#{alt}" 68 | end 69 | end 70 | parts.push(replacement) 71 | end 72 | end 73 | parts 74 | end 75 | 76 | end 77 | 78 | class Alternation < Node 79 | def initialize(*args) 80 | super 81 | @children.push('') 82 | end 83 | 84 | def accept(token) 85 | case token 86 | when :'{' 87 | child = Alternation.new(self) 88 | children.push(child) 89 | child 90 | when :'}' 91 | parent 92 | when :',' 93 | @children.push(:',') 94 | @children.push('') 95 | self 96 | when :'$' 97 | raise ParserError.new("Unmatched open brace") 98 | else 99 | # Everything else is considered a string in alternation, 100 | # so append it onto the most recent alternative 101 | @children.push(token.to_s) 102 | self 103 | end 104 | end 105 | 106 | def to_a 107 | alts = [['']] 108 | @children.each do |child| 109 | case child 110 | when String 111 | alts.last.each { |alt| alt.concat(child) } 112 | when :',' 113 | alts.push(['']) 114 | when Alternation 115 | replacement = [] 116 | last_alt = alts.pop 117 | last_alt.each do |alt| 118 | child.to_a.each do |child_alt| 119 | replacement.push "#{alt}#{child_alt}" 120 | end 121 | end 122 | alts.push(replacement) 123 | end 124 | end 125 | alts.flatten 126 | end 127 | end 128 | 129 | def initialize(str) 130 | @root = Root.new 131 | @rooted = str[0] == ?/ 132 | @table = nil 133 | parse(str) 134 | end 135 | 136 | def rooted? 137 | @rooted 138 | end 139 | 140 | def each_segment(&block) 141 | @table.each_with_index do |segment, i| 142 | if @rooted && i == 0 143 | next # Skip the leading [''] segment 144 | else 145 | block[segment, @table[i + 1]] 146 | end 147 | end 148 | end 149 | 150 | def segments 151 | result = [] 152 | each_segment do |seg| 153 | result.push(seg) 154 | end 155 | result 156 | end 157 | 158 | private 159 | 160 | def parse(str) 161 | current_node = @root 162 | lex(str) do |token| 163 | current_node = current_node.accept(token) 164 | end 165 | @table = @root.to_a 166 | end 167 | 168 | def lex(str) 169 | match = nil 170 | token = nil 171 | 172 | # # Special case: 173 | # # leading ** doens't need to be surrounded by /'s to be significant 174 | # if str[0..1] == '**' 175 | # yield :'**' 176 | # str = str[2..str.length] 177 | # end 178 | 179 | while str && !str.empty? && str != ?/ && str != ?\\ 180 | step = 1 181 | if str.start_with?(?\\) 182 | token = str[1] 183 | step = 2 184 | elsif "{},".include?(str[0]) 185 | token = str[0].to_sym 186 | step = 1 187 | elsif str[0..2] == '**/' 188 | # ** is only significant if it stands alone 189 | token = [:'**', :/] 190 | step = str[/^(\*\*\/)+/].length 191 | elsif str[0] == ?/ 192 | # Collapse consecutive /'s 193 | token = :/ 194 | step = str[/^\/*/].length 195 | elsif str[0] == ?[ 196 | # passthrough the character sets 197 | token = str[/^(\\.|[^\\])+\]/] 198 | step = token.length 199 | else 200 | i = 1 201 | i += 1 until "{},/\\".include?(str[i]) || str[i].nil? 202 | token = str[0...i] 203 | step = token.length 204 | end 205 | 206 | str = str[(step)...(str.length)] 207 | [token].flatten.each { |t| yield t } 208 | end 209 | yield :'$' 210 | end 211 | end 212 | 213 | class Globber 214 | def initialize 215 | @match_num = 0 216 | @exlicit_cwd = '.' 217 | end 218 | 219 | def glob(pattern, &block) 220 | @ast = GlobAST.new(pattern) rescue nil 221 | return nil unless @ast 222 | @segments = @ast.segments 223 | @block = block 224 | 225 | # Call into C implementation after setting up the instance variables 226 | self.glob_recurse(@ast.rooted? ? '/' : '', 0, &block) 227 | end 228 | 229 | def inspect 230 | " #{instance_variable_get(iv).inspect}" }.join(" ")}>" 231 | end 232 | end 233 | 234 | class << self 235 | def glob(*patterns) 236 | acc = [] 237 | patterns = patterns.flatten 238 | first = patterns.first 239 | 240 | if patterns.length == 1 && first.kind_of?(String) && first.include?("\0") 241 | patterns = first.split("\0") 242 | end 243 | 244 | patterns.each do |pattern| 245 | pattern = pattern.to_path if pattern.respond_to?(:to_path) 246 | results = [] 247 | globber = Globber.new 248 | globber.glob(pattern) do |match, match_num| 249 | results.push(match) 250 | end 251 | acc.concat(results) 252 | end 253 | 254 | if block_given? 255 | acc.each { |el| yield el } 256 | nil 257 | else 258 | acc 259 | end 260 | end 261 | alias [] glob 262 | end 263 | end 264 | -------------------------------------------------------------------------------- /mrblib/globals.rb: -------------------------------------------------------------------------------- 1 | # Features provided by mruby-apr that would normally need to be `require`d 2 | # (This allows us to run some CRuby code without pulling out `require` calls, 3 | # we can simply return false for these requires.) 4 | $BUILTIN_FEATURES = %w[ 5 | find 6 | fileutils 7 | forwardable 8 | observer 9 | ostruct 10 | pathname 11 | pp 12 | rbconfig 13 | shellwords 14 | socket 15 | tmpdir 16 | ] 17 | 18 | # Features that have been loaded by `require` 19 | $LOADED_FEATURES = [] 20 | 21 | # Load path 22 | $: = [] 23 | $LOAD_PATH = $: 24 | 25 | # Input record separator 26 | $/ = "\n" 27 | 28 | # Output record separator 29 | $\ 30 | 31 | # Output field separator 32 | $, = nil 33 | 34 | # This is a stub, just so that RubySpec doesn't throw up. 35 | module RbConfig 36 | CONFIG = Hash.new do |h, k| 37 | if k == 'bindir' 38 | # TODO: WINDOWS SUPPORT? 39 | h['bindir'] = File.dirname(`which mruby`.strip) 40 | else 41 | raise "RbConfig[#{k} : #{k.class}]" 42 | end 43 | end 44 | 45 | CONFIG['EXEEXT'] = APR::OS == 'Windows' ? '.exe' : '' 46 | CONFIG['RUBY_INSTALL_NAME'] = 'mruby' 47 | CONFIG['host_os'] = APR::OS == 'Windows' ? 'mswin' : 'unix' 48 | end 49 | 50 | # This is a stub, just so that RubySpec doesn't throw up. 51 | class SystemExit < StandardError 52 | end 53 | -------------------------------------------------------------------------------- /mrblib/io_error.rb: -------------------------------------------------------------------------------- 1 | class IOError < StandardError 2 | def initialize(*args) 3 | super(*args) 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /mrblib/ipsocket.rb: -------------------------------------------------------------------------------- 1 | class IPSocket < BasicSocket 2 | def recvfrom(maxlen) 3 | err, addr, msg = APR.socket_recvfrom(@apr_socket, 0, maxlen) 4 | APR.raise_apr_errno(err, ignore: APR::APR_EOF) 5 | err, ip = APR.sockaddr_ip_get(addr) 6 | APR.raise_apr_errno(err) 7 | err, hostname = APR.getnameinfo(addr) 8 | APR.raise_apr_errno(err) 9 | [msg, [BasicSocket::Util.address_family_to_s(addr.family), addr.port, hostname, ip]] 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /mrblib/kernel.rb: -------------------------------------------------------------------------------- 1 | $TOPLEVEL_OBJ = self 2 | 3 | module Kernel 4 | # Mostly for compatability with existing CRuby code. 5 | # This version of `pp` simply calls `puts obj.inspect` 6 | # for each object in `objs` 7 | def pp(*objs) 8 | objs.each { |o| puts o.inspect } 9 | end 10 | 11 | # Mostly for compatability with existing CRuby code. 12 | # This version of `pretty_inspect` simply calls `self.inspect` 13 | def pretty_inspect 14 | self.inspect 15 | end 16 | 17 | def spawn(*command) 18 | Process.spawn(*command) 19 | end 20 | 21 | def system(cmd) 22 | pid = spawn(cmd) 23 | Process.wait(pid) 24 | $?.exitstatus == 0 25 | end 26 | 27 | def `(command) 28 | r, w = IO.pipe 29 | pid = spawn(command, {out: w}) 30 | w.close 31 | result = r.read 32 | r.close 33 | Process.wait(pid) 34 | result 35 | end 36 | 37 | def load(path) 38 | unless path.kind_of?(String) 39 | path = path.to_str 40 | end 41 | 42 | if File.exist?(path) 43 | eval(File.read(path), nil, path, 0) 44 | else 45 | $LOAD_PATH.each do |dir| 46 | full_path = File.absolute_path("#{dir}#{File::SEPARATOR}#{path}") 47 | if File.exist?(full_path) 48 | eval(File.read(full_path), nil, full_path, 0) 49 | return true 50 | end 51 | end 52 | raise LoadError.new "Cannot load such file -- #{path}" 53 | end 54 | true 55 | end 56 | 57 | ALREADY_LOADED = 1 58 | LOADED = 2 59 | DNE = 3 60 | 61 | def try_require(full_path) 62 | # trace = false 63 | # trace = true if full_path.end_with?('classes.rb') 64 | # puts "try_require: full_path" if trace 65 | 66 | if $LOADED_FEATURES.include?(full_path) 67 | return ALREADY_LOADED 68 | end 69 | 70 | if File.exist?(full_path) 71 | $LOADED_FEATURES.push(full_path) 72 | begin 73 | eval(File.read(full_path), nil, full_path, 0) 74 | rescue SystemCallError => ex 75 | $LOADED_FEATURES.pop 76 | raise ex # Losing the backtrace... mruby limitation 77 | end 78 | return LOADED 79 | else 80 | return DNE 81 | end 82 | end 83 | 84 | def require(path) 85 | unless path.kind_of?(String) 86 | path = path.to_str 87 | end 88 | 89 | if $BUILTIN_FEATURES.include?(path) 90 | return false 91 | end 92 | 93 | empty = '' 94 | [empty].concat($LOAD_PATH).each do |dir| 95 | full_path = '' 96 | unless dir == empty 97 | full_path << dir 98 | full_path << File::SEPARATOR 99 | end 100 | full_path << path 101 | full_path << '.rb' unless path.end_with?('.rb') 102 | 103 | # puts "require '#{full_path}'" if trace 104 | result = try_require(full_path) 105 | case result 106 | when ALREADY_LOADED 107 | return false 108 | when LOADED 109 | return true 110 | else 111 | next 112 | end 113 | end 114 | 115 | raise LoadError.new "Cannot load such file -- #{path}" 116 | end 117 | 118 | end 119 | 120 | class LoadError < ScriptError 121 | def initialize(msg = nil) 122 | super 123 | end 124 | end 125 | -------------------------------------------------------------------------------- /mrblib/monkey_patches/module.rb: -------------------------------------------------------------------------------- 1 | class Module 2 | unless instance_methods.include? :name 3 | def name 4 | to_s 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /mrblib/monkey_patches/string.rb: -------------------------------------------------------------------------------- 1 | class String 2 | unless instance_methods.include? :frozen? 3 | def frozen? 4 | false 5 | end 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /mrblib/mrb_apr_gem_init.rb: -------------------------------------------------------------------------------- 1 | proc { # Creates a local scope (like IIFE in JavaScript) 2 | err, stdin_pool = APR.pool_create(nil) 3 | err, stdin = APR.file_open_flags_stdin(APR::APR_FOPEN_READ, stdin_pool) 4 | $stdin = File.new(stdin, "r", stdin_pool) if err == APR::APR_SUCCESS 5 | 6 | err, stdout_pool = APR.pool_create(nil) 7 | err, stdout = APR.file_open_flags_stdout(APR::APR_FOPEN_WRITE, stdout_pool) 8 | $stdout = File.new(stdout, "w", stdout_pool) if err == APR::APR_SUCCESS 9 | 10 | err, stderr_pool = APR.pool_create(nil) 11 | err, stderr = APR.file_open_flags_stderr(APR::APR_FOPEN_WRITE, stderr_pool) 12 | $stderr = File.new(stderr, "w", stderr_pool) if err == APR::APR_SUCCESS 13 | }[] 14 | 15 | STDIN = $stdin 16 | STDOUT = $stdout 17 | STDERR = $stderr 18 | 19 | module Kernel 20 | def puts(*a); $stdout.puts(*a); end 21 | def print(*a); $stdout.print(*a); end 22 | def gets(*a); $stdin.gets(*a); end 23 | end 24 | -------------------------------------------------------------------------------- /mrblib/mruby_backport_utils.rb: -------------------------------------------------------------------------------- 1 | # This file holds utilities for backporting code to mruby. 2 | # The main goal is to make the smallest modifications to the 3 | # source, and to keep as much code as possible. This should 4 | # make future modifications easier, as the changes should be 5 | # straightforward to follow, and mostly mechanical. 6 | # 7 | # For example, the `def_with_kwargs` class macro provides a 8 | # way to tranform a method definition using keyword arguments 9 | # to mruby-compatible syntax by modifying _only_ the method 10 | # signature line. 11 | # 12 | # The `on_mruby?` predicate allows `#ifdef` style design-time 13 | # (when classes are being loaded) mechanism for deciding how to 14 | # implement a feature. Leaving the existing code in place, rather 15 | # than modifying it for MRuby directly, eases the task of inspecting 16 | # the code to verify the port is correct. 17 | # 18 | # Once a module has been ported, and is functioning correctly 19 | # (ideally with good test coverage), these patches may be removed 20 | # in the process of optimizing an mruby-specific implementation of 21 | # the module. This should be done last in order to minimze the 22 | # introduction of new bugs before the mruby port is even running 23 | # and testable. From there, it's red-green-refactor. 24 | 25 | class Object 26 | def on_mruby? 27 | Object.const_defined?(:MRUBY_VERSION) 28 | end 29 | end 30 | 31 | class Module 32 | def def_with_kwargs(name, kwargs, &implementation) 33 | self.define_method(name) do |*args, &block| 34 | overrides = {} 35 | overrides = args.pop if args.last.kind_of?(Hash) 36 | 37 | kwargs.keys.each { |k| args.push(overrides[k] || kwargs[k]) } 38 | 39 | unless self.respond_to?("#{name}_implementation".to_sym) 40 | if self.class == Class 41 | self.class.define_method("#{name}_implementation", &implementation) 42 | else 43 | (class << self; self; end).define_method("#{name}_implementation", &implementation) 44 | end 45 | end 46 | 47 | self.send("#{name}_implementation", *args, &block) 48 | end 49 | end 50 | end 51 | -------------------------------------------------------------------------------- /mrblib/pathname.rb: -------------------------------------------------------------------------------- 1 | class Pathname 2 | ROOT = '/' 3 | DOT = '.' 4 | DOT_DOT = '..' 5 | 6 | def initialize(path_str) 7 | path_str = File::Private.to_path_str(path_str) 8 | @path = path_str.dup 9 | end 10 | 11 | def self.join(*parts) 12 | parts = parts.flatten 13 | 14 | rooted = false 15 | if parts[0] == ROOT 16 | rooted = true 17 | end 18 | 19 | parts = parts.select{ |p| 20 | !p.nil? && p != File::SEPARATOR 21 | }.map { |p| 22 | p.to_s 23 | } 24 | 25 | str = parts.join(File::SEPARATOR) 26 | if rooted 27 | str = "#{ROOT}#{str}" 28 | end 29 | 30 | str = str.each_char.inject('') do |acc, cur| 31 | acc.concat(cur) unless acc[acc.length - 1] == cur && cur == File::SEPARATOR 32 | acc 33 | end 34 | 35 | str 36 | end 37 | 38 | def +(other) 39 | Pathname.new(self.to_s + File::SEPARATOR + other.to_s) 40 | end 41 | 42 | # Non-standard 43 | def <<(other) 44 | @path.concat(File::SEPARATOR).concat(other.to_s) 45 | self 46 | end 47 | 48 | def absolute? 49 | @path.start_with?(ROOT) 50 | end 51 | 52 | def dup 53 | Pathname.new(@path.dup) 54 | end 55 | 56 | # Non-standard 57 | def cleanpath! 58 | parts = each_filename.to_a 59 | 60 | if absolute? 61 | parts.unshift ROOT 62 | end 63 | 64 | result = [] 65 | parts.each do |part| 66 | case part 67 | when DOT 68 | next 69 | when DOT_DOT 70 | case result.last 71 | when ROOT 72 | # No parent directory of the root 73 | next 74 | when DOT_DOT 75 | # If the last part was deemed a useful parent ref, 76 | # then we need this one too. 77 | result.push(DOT_DOT) 78 | when nil 79 | # This is the first part of the path, it must be useful. 80 | result.push(DOT_DOT) 81 | else 82 | # There is a path segment we can just pop to reduce the .. 83 | result.pop 84 | end 85 | else 86 | result.push(part) 87 | end 88 | end 89 | 90 | replace(result.empty? ? DOT : self.class.join(*result)) 91 | 92 | self 93 | end 94 | 95 | # Cleans the path by removing consecutive slashes, and useless dots. 96 | def cleanpath 97 | dup.cleanpath! 98 | end 99 | 100 | def hash 101 | @path.hash 102 | end 103 | 104 | def parent 105 | if root? 106 | self 107 | else 108 | names = each_filename.to_a[0...-1] 109 | if self.absolute? 110 | names.unshift(ROOT) 111 | end 112 | Pathname.new(Pathname.join(names)) 113 | end 114 | end 115 | 116 | # Non-standard 117 | def replace(new_path) 118 | @path = new_path.to_s.dup 119 | self 120 | end 121 | 122 | def relative? 123 | !@path.start_with?(ROOT) 124 | end 125 | 126 | def root? 127 | return false if @path.length == 0 128 | @path.each_char do |c| 129 | return false unless c == ROOT 130 | end 131 | true 132 | end 133 | 134 | def sub(pattern, replacement) 135 | Pathname.new(self.to_s.sub(pattern, replacement)) 136 | end 137 | 138 | def each_filename 139 | return self.enum_for(:each_filename) unless block_given? 140 | 141 | @path.split(File::SEPARATOR). 142 | select { |p| p && !p.empty? }. 143 | each { |f| yield f } 144 | end 145 | 146 | def to_s 147 | @path.dup 148 | end 149 | alias to_str to_s 150 | end 151 | -------------------------------------------------------------------------------- /mrblib/pipe.rb: -------------------------------------------------------------------------------- 1 | class IO 2 | # Pipe is essentially a File, the only difference is that 3 | # it exposed a constructor that takes an File to wrap. 4 | # This was required to allow results of apr_file_pipe_create 5 | # to be wrapped in a File object, without changing the standard 6 | # API of the File class. 7 | # 8 | # Note: 9 | # The mode & pool MUST be the same that the file was created with. 10 | class Pipe < File 11 | def initialize(apr_file, mode, pool) 12 | if apr_file.class != APR::File 13 | raise ArgumentError.new("File expected in first arg") 14 | end 15 | if pool.class != APR::Pool 16 | raise ArgumentError.new("Pool expected in third arg") 17 | end 18 | @native_file = apr_file 19 | @pool = pool 20 | 21 | if mode.class == Fixnum 22 | @flags = mode 23 | else 24 | @flags = IO::Util.mode_str_to_apr_flags(mode.to_s) 25 | end 26 | @closed = false 27 | end 28 | end 29 | 30 | # IO like object returned by IO.popen 31 | # This simply directs read methods to one pipe, 32 | # and write methods to another. 33 | # The `close` method closes both ends. 34 | # Use `close_read` and `close_write` to close one end only. 35 | class BidirectionalPipe 36 | # Expects a hash of the form { pid: Fixnum, read: Pipe, write: Pipe } 37 | # Either pipe may be nil, but not both 38 | def initialize(opt) 39 | @pid = opt[:pid] 40 | @read_pipe = opt[:read] 41 | @read_pipe.instance_variable_set(:@pid, opt[:pid]) unless @read_pipe.nil? 42 | @write_pipe = opt[:write] 43 | @write_pipe.instance_variable_set(:@pid, opt[:pid]) unless @write_pipe.nil? 44 | end 45 | 46 | def pid 47 | if closed? 48 | raise IOError.new("closed stream") 49 | end 50 | @pid 51 | end 52 | 53 | def close 54 | @write_pipe.close unless (@write_pipe.nil? || @write_pipe.closed?) 55 | @read_pipe.close unless (@read_pipe.nil? || @read_pipe.closed?) 56 | begin 57 | Process.wait(@pid) # Sets $? 58 | rescue SystemCallError 59 | # When simply closing the pipe, we don't care if somebody else 60 | # has already called `Process.wait` on our PID. 61 | end 62 | nil 63 | end 64 | 65 | def closed? 66 | (@read_pipe.nil? || @read_pipe.closed?) && (@write_pipe.nil? || @write_pipe.closed?) 67 | end 68 | 69 | def close_read 70 | raise IOError.new('closed stream') if @read_pipe.nil? || @read_pipe.closed? 71 | @read_pipe.close 72 | end 73 | 74 | def close_write 75 | raise IOError.new('closed stream') if @write_pipe.nil? || @write_pipe.closed? 76 | @write_pipe.close 77 | end 78 | 79 | def assert_can_write 80 | if @write_pipe.nil? || @write_pipe.closed? 81 | raise IOError.new('not open for writing') 82 | end 83 | end 84 | 85 | # IO Write Methods 86 | # (Some of these aren't actually implemented in the Pipe/File classes yet, 87 | # so they will raise an exception) 88 | 89 | def flush(*args) 90 | assert_can_write 91 | @write_pipe.flush(*args) 92 | end 93 | 94 | def <<(*args) 95 | assert_can_write 96 | @write_pipe.<<(*args) 97 | end 98 | 99 | def flush(*args) 100 | assert_can_write 101 | @write_pipe.flush(*args) 102 | end 103 | 104 | def print(*args) 105 | assert_can_write 106 | @write_pipe.print(*args) 107 | end 108 | 109 | def printf(*args) 110 | assert_can_write 111 | @write_pipe.printf(*args) 112 | end 113 | 114 | def putc(*args) 115 | assert_can_write 116 | @write_pipe.putc(*args) 117 | end 118 | 119 | def puts(*args) 120 | assert_can_write 121 | @write_pipe.puts(*args) 122 | end 123 | 124 | def syswrite(*args) 125 | assert_can_write 126 | @write_pipe.syswrite(*args) 127 | end 128 | 129 | def write(*args) 130 | assert_can_write 131 | @write_pipe.write(*args) 132 | end 133 | 134 | def write_nonblock(*args) 135 | assert_can_write 136 | @write_pipe.write_nonblock(*args) 137 | end 138 | 139 | 140 | # IO Read Methods 141 | # (Some of these aren't actually implemented in the Pipe/File classes yet, 142 | # so they will raise an exception) 143 | 144 | def assert_can_read 145 | if @read_pipe.nil? || @read_pipe.closed? 146 | raise IOError.new('not open for reading') 147 | end 148 | end 149 | 150 | def eof 151 | assert_can_read 152 | @read_pipe.eof 153 | end 154 | 155 | def eof? 156 | assert_can_read 157 | @read_pipe.eof? 158 | end 159 | 160 | def bytes(*args) 161 | assert_can_read 162 | @read_pipe.bytes(*args) 163 | end 164 | 165 | def chars(*args) 166 | assert_can_read 167 | @read_pipe.chars(*args) 168 | end 169 | 170 | def codepoints(*args) 171 | assert_can_read 172 | @read_pipe.codepoints(*args) 173 | end 174 | 175 | def each(*args) 176 | assert_can_read 177 | @read_pipe.each(*args) 178 | end 179 | 180 | def each_byte(*args) 181 | assert_can_read 182 | @read_pipe.each_byte(*args) 183 | end 184 | 185 | def each_char(*args) 186 | assert_can_read 187 | @read_pipe.each_char(*args) 188 | end 189 | 190 | def each_codepoint(*args) 191 | assert_can_read 192 | @read_pipe.each_codepoint(*args) 193 | end 194 | 195 | def each_line(*args) 196 | assert_can_read 197 | @read_pipe.each_line(*args) 198 | end 199 | 200 | def getbyte(*args) 201 | assert_can_read 202 | @read_pipe.getbyte(*args) 203 | end 204 | 205 | def getc(*args) 206 | assert_can_read 207 | @read_pipe.getc(*args) 208 | end 209 | 210 | def gets(*args) 211 | assert_can_read 212 | @read_pipe.gets(*args) 213 | end 214 | 215 | def read(*args) 216 | assert_can_read 217 | @read_pipe.read(*args) 218 | end 219 | 220 | def read_nonblock(*args) 221 | assert_can_read 222 | @read_pipe.read_nonblock(*args) 223 | end 224 | 225 | def readbyte(*args) 226 | assert_can_read 227 | @read_pipe.readbyte(*args) 228 | end 229 | 230 | def readchar(*args) 231 | assert_can_read 232 | @read_pipe.readchar(*args) 233 | end 234 | 235 | def readline(*args) 236 | assert_can_read 237 | @read_pipe.readline(*args) 238 | end 239 | 240 | def readlines(*args) 241 | assert_can_read 242 | @read_pipe.readlines(*args) 243 | end 244 | 245 | def readpartial(*args) 246 | assert_can_read 247 | @read_pipe.readpartial(*args) 248 | end 249 | 250 | def sysread(*args) 251 | assert_can_read 252 | @read_pipe.sysread(*args) 253 | end 254 | 255 | def ungetbyte(*args) 256 | assert_can_read 257 | @read_pipe.ungetbyte(*args) 258 | end 259 | 260 | def ungetc(*args) 261 | assert_can_read 262 | @read_pipe.ungetc(*args) 263 | end 264 | end 265 | end 266 | -------------------------------------------------------------------------------- /mrblib/process.rb: -------------------------------------------------------------------------------- 1 | module Process 2 | # No real privates in mruby, so use a sub module for some sort of hiding 3 | module Util 4 | 5 | # Some nasty details below involving proc creation on windows. 6 | # For more info, see: 7 | # - http://blogs.msdn.com/b/twistylittlepassagesallalike/archive/2011/04/23/everyone-quotes-arguments-the-wrong-way.aspx 8 | 9 | # Only for arguments that are (or will be, by apr) wrapped in double quotes 10 | def self.double_backslashes_preceding_quotes(arg) 11 | new_arg = "" 12 | preceding_quote = true # It's wrapped, so the trailing quotes are preceding a quote 13 | arg.reverse.each_char do |c| 14 | if preceding_quote 15 | if c == '\\' 16 | new_arg << '\\\\' 17 | else 18 | new_arg << c 19 | preceding_quote = false unless c == '"' 20 | end 21 | else 22 | new_arg << c 23 | preceding_quote = true if c == '"' 24 | end 25 | end 26 | new_arg.reverse 27 | end 28 | 29 | def self.quote_windows_argv(argv) 30 | new_argv = [argv[0]] 31 | if argv.length > 1 32 | argv[1..(argv.length - 1)].each do |arg| 33 | if arg.include? ' ' 34 | # APR does it's own quoting if there's a space in the arg 35 | # (But it's extremely naive, and doesn't escape contained quotes, so we have to) 36 | escaped = double_backslashes_preceding_quotes(arg).gsub('"', '\"') 37 | new_argv.push escaped 38 | elsif arg.include? '"' 39 | # To escape a double quote on windows, you have to be in a double quote, 40 | # so we escape and wrap 41 | escaped = double_backslashes_preceding_quotes(arg).gsub('"', '\"') 42 | new_argv.push "\"#{escaped}\"" 43 | else 44 | new_argv.push(arg) 45 | end 46 | end 47 | end 48 | new_argv 49 | end 50 | 51 | def self.parse_spawn_args(*command, pool) 52 | env = nil 53 | options = nil; 54 | 55 | if command.length == 0 56 | raise ArgumentError.new('Wrong number of arguments (0 for 1+)') 57 | end 58 | 59 | if command[0].class == Hash 60 | env = command.shift 61 | end 62 | 63 | if command.last.class == Hash 64 | options = command.pop 65 | end 66 | 67 | if command.length == 1 && command[0].class == String 68 | # WORKAROUND: 69 | # Encountering lots of problems when using APR_SHELLCMD directly. 70 | # It attempts to quote arguments in ways that appear unneeded. 71 | # Additionally, the quoting is often wrong. 72 | # So, using APR_PROGRAM_PATH, we can construct the shell command ourselves 73 | # to get around this limitation. 74 | argv = nil 75 | if APR::OS == 'Windows' 76 | # User is aware of shell processing, so they'll escape any quotes themselves. 77 | # Note that this goes directly through CreateProcess, so any cmd significant 78 | # metacharacters are not interpreted until the child proc (ie there is no outter 79 | # cmd shell to worry about) 80 | argv = ["cmd.exe", '/C', command[0]] 81 | else 82 | argv = ["sh", '-c', command[0]] 83 | end 84 | 85 | { env: env, argv: argv, options: options, cmd_type: APR::Cmdtype::APR_PROGRAM_PATH } 86 | elsif command[0].class == Array 87 | if command[0].length != 2 88 | raise ArgumentError.new('wrong first argument') 89 | end 90 | argv = [command[0][0], command[0][1]].concat(command[1..(command.length)]) 91 | if APR::OS == 'Windows' 92 | argv = quote_windows_argv(argv) 93 | end 94 | { env: env, argv: argv, options: options, cmd_type: APR::Cmdtype::APR_PROGRAM_PATH } 95 | else 96 | 97 | # Unix is simple... the args are passed in an actual vector, so just pass them along 98 | argv = command 99 | if APR::OS == 'Windows' 100 | # Windows is a horrible beast... only accepting a command line that is later processed 101 | # into an argv for the target program by CommandLineToArgvW (that is, if the program 102 | # doesn't use the command line directly). So we have to quote the args correctly 103 | # to allow the constructed command line string to be deconstructed back into the 104 | # original argument vector. 105 | # (Note that the construction of the commandline string is done with APR itself) 106 | argv = quote_windows_argv(command) 107 | end 108 | { env: env, argv: argv, options: options, cmd_type: APR::Cmdtype::APR_PROGRAM_PATH } 109 | end 110 | end 111 | end 112 | 113 | def self.spawn(*command) 114 | # Going to mutate this, don't want to mess with client's copy 115 | command = command.dup 116 | 117 | APR.with_stack_pool do |pool| 118 | err, proc_attr = APR.procattr_create pool 119 | args = Util.parse_spawn_args(*command, pool) 120 | env = args[:env] 121 | argv = args[:argv] 122 | options = args[:options] 123 | cmd_type = args[:cmd_type] 124 | 125 | APR.procattr_cmdtype_set proc_attr, cmd_type 126 | 127 | # TODO: Configure environment variables from env hash 128 | 129 | if options 130 | if options[:in] 131 | # Pass nil as the parent file, or else APR tries to create a new pipe 132 | # between the two files. If a pipe is required for the child process, 133 | # it will have been created by IO.pipe already by the client. 134 | err = APR.procattr_child_in_set proc_attr, options[:in].native_file, nil 135 | APR.raise_apr_errno(err) 136 | end 137 | if options[:out] 138 | err = APR.procattr_child_out_set proc_attr, options[:out].native_file, nil 139 | APR.raise_apr_errno(err) 140 | end 141 | if options[:err] 142 | err = APR.procattr_child_err_set proc_attr, options[:err].native_file, nil 143 | APR.raise_apr_errno(err) 144 | end 145 | else 146 | APR.procattr_io_set(proc_attr, APR::APR_NO_PIPE, APR::APR_NO_PIPE, APR::APR_NO_PIPE) 147 | end 148 | 149 | err, process = APR.proc_create argv[0], argv, nil, proc_attr, pool 150 | APR.raise_apr_errno(err) 151 | 152 | process.pid 153 | end 154 | end 155 | 156 | def self.wait(pid) 157 | proc = APR.proc_from_pid(pid) 158 | err, exit_code, exit_why = APR.proc_wait(proc, APR::WaitHow::APR_WAIT) 159 | APR.raise_apr_errno(err, ignore: [APR::APR_CHILD_NOTDONE, APR::APR_CHILD_DONE]) 160 | $? = Process::Status.new(pid, exit_code, exit_why) 161 | return pid 162 | end 163 | end 164 | -------------------------------------------------------------------------------- /mrblib/process_status.rb: -------------------------------------------------------------------------------- 1 | module Process 2 | class Status 3 | def initialize(pid, exit_status, apr_exit_why) 4 | @pid = pid 5 | @exitstatus = exit_status 6 | if apr_exit_why == APR::ExitWhy::APR_PROC_EXIT 7 | @exited = true 8 | @signaled = false 9 | @coredump = false 10 | elsif apr_exit_why == APR::ExitWhy::APR_PROC_SIGNAL 11 | @exited = false 12 | @signaled = true 13 | @coredump = false 14 | elsif apr_exit_why == APR::ExitWhy::APR_PROC_SIGNAL_CORE 15 | @exited = false 16 | @signaled = true 17 | @coredump = true 18 | else 19 | raise ArgumentError.new('Invalid apr_exit_why in param #3') 20 | end 21 | end 22 | 23 | def coredump? 24 | @coredump 25 | end 26 | 27 | def exitstatus 28 | @exitstatus 29 | end 30 | 31 | def exited? 32 | @exited 33 | end 34 | 35 | def pid 36 | @pid 37 | end 38 | 39 | def signaled? 40 | @signaled 41 | end 42 | 43 | def success? 44 | if @exited 45 | @exitstatus == 0 46 | else 47 | nil 48 | end 49 | end 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /mrblib/signal.rb: -------------------------------------------------------------------------------- 1 | # Only here to allow RubySpec to run (for now). 2 | module Signal 3 | def self.trap(*args) 4 | $stderr.puts "WARNING: Signal handling is not supported. Registered callbacks will not be called." 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /mrblib/socket_constants.rb: -------------------------------------------------------------------------------- 1 | class Socket 2 | AF_APPLETALK = 16 3 | AF_CCITT = 10 4 | AF_CHAOS = 5 5 | AF_CNT = 21 6 | AF_COIP = 20 7 | AF_DATAKIT = 9 8 | AF_DLI = 13 9 | AF_E164 = 28 10 | AF_ECMA = 8 11 | AF_HYLINK = 15 12 | AF_IMPLINK = 3 13 | AF_INET = 2 14 | AF_INET6 = 30 15 | AF_IPX = 23 16 | AF_ISDN = 28 17 | AF_ISO = 7 18 | AF_LAT = 14 19 | AF_LINK = 18 20 | AF_LOCAL = 1 21 | AF_MAX = 40 22 | AF_NATM = 31 23 | AF_NDRV = 27 24 | AF_NETBIOS = 33 25 | AF_NS = 6 26 | AF_OSI = 7 27 | AF_PPP = 34 28 | AF_PUP = 4 29 | AF_ROUTE = 17 30 | AF_SIP = 24 31 | AF_SNA = 11 32 | AF_SYSTEM = 32 33 | AF_UNIX = 1 34 | AF_UNSPEC = 0 35 | AI_ADDRCONFIG = 1024 36 | AI_ALL = 256 37 | AI_CANONNAME = 2 38 | AI_DEFAULT = 1536 39 | AI_MASK = 5127 40 | AI_NUMERICHOST = 4 41 | AI_NUMERICSERV = 4096 42 | AI_PASSIVE = 1 43 | AI_V4MAPPED = 2048 44 | AI_V4MAPPED_CFG = 512 45 | EAI_ADDRFAMILY = 1 46 | EAI_AGAIN = 2 47 | EAI_BADFLAGS = 3 48 | EAI_BADHINTS = 12 49 | EAI_FAIL = 4 50 | EAI_FAMILY = 5 51 | EAI_MAX = 15 52 | EAI_MEMORY = 6 53 | EAI_NODATA = 7 54 | EAI_NONAME = 8 55 | EAI_OVERFLOW = 14 56 | EAI_PROTOCOL = 13 57 | EAI_SERVICE = 9 58 | EAI_SOCKTYPE = 10 59 | EAI_SYSTEM = 11 60 | IFNAMSIZ = 16 61 | IF_NAMESIZE = 16 62 | INADDR_ALLHOSTS_GROUP = 3758096385 63 | INADDR_ANY = 0 64 | INADDR_BROADCAST = 4294967295 65 | INADDR_LOOPBACK = 2130706433 66 | INADDR_MAX_LOCAL_GROUP = 3758096639 67 | INADDR_NONE = 4294967295 68 | INADDR_UNSPEC_GROUP = 3758096384 69 | INET6_ADDRSTRLEN = 46 70 | INET_ADDRSTRLEN = 16 71 | IPPORT_RESERVED = 1024 72 | IPPORT_USERRESERVED = 5000 73 | IPPROTO_AH = 51 74 | IPPROTO_DSTOPTS = 60 75 | IPPROTO_EGP = 8 76 | IPPROTO_EON = 80 77 | IPPROTO_ESP = 50 78 | IPPROTO_FRAGMENT = 44 79 | IPPROTO_GGP = 3 80 | IPPROTO_HELLO = 63 81 | IPPROTO_HOPOPTS = 0 82 | IPPROTO_ICMP = 1 83 | IPPROTO_ICMPV6 = 58 84 | IPPROTO_IDP = 22 85 | IPPROTO_IGMP = 2 86 | IPPROTO_IP = 0 87 | IPPROTO_IPV6 = 41 88 | IPPROTO_MAX = 256 89 | IPPROTO_ND = 77 90 | IPPROTO_NONE = 59 91 | IPPROTO_PUP = 12 92 | IPPROTO_RAW = 255 93 | IPPROTO_ROUTING = 43 94 | IPPROTO_TCP = 6 95 | IPPROTO_TP = 29 96 | IPPROTO_UDP = 17 97 | IPPROTO_XTP = 36 98 | IPV6_CHECKSUM = 26 99 | IPV6_DONTFRAG = 62 100 | IPV6_DSTOPTS = 50 101 | IPV6_HOPLIMIT = 47 102 | IPV6_HOPOPTS = 49 103 | IPV6_JOIN_GROUP = 12 104 | IPV6_LEAVE_GROUP = 13 105 | IPV6_MULTICAST_HOPS = 10 106 | IPV6_MULTICAST_IF = 9 107 | IPV6_MULTICAST_LOOP = 11 108 | IPV6_NEXTHOP = 48 109 | IPV6_PATHMTU = 44 110 | IPV6_PKTINFO = 46 111 | IPV6_RECVDSTOPTS = 40 112 | IPV6_RECVHOPLIMIT = 37 113 | IPV6_RECVHOPOPTS = 39 114 | IPV6_RECVPATHMTU = 43 115 | IPV6_RECVPKTINFO = 61 116 | IPV6_RECVRTHDR = 38 117 | IPV6_RECVTCLASS = 35 118 | IPV6_RTHDR = 51 119 | IPV6_RTHDRDSTOPTS = 57 120 | IPV6_RTHDR_TYPE_0 = 0 121 | IPV6_TCLASS = 36 122 | IPV6_UNICAST_HOPS = 4 123 | IPV6_USE_MIN_MTU = 42 124 | IPV6_V6ONLY = 27 125 | IP_ADD_MEMBERSHIP = 12 126 | IP_ADD_SOURCE_MEMBERSHIP = 70 127 | IP_BLOCK_SOURCE = 72 128 | IP_DEFAULT_MULTICAST_LOOP = 1 129 | IP_DEFAULT_MULTICAST_TTL = 1 130 | IP_DROP_MEMBERSHIP = 13 131 | IP_DROP_SOURCE_MEMBERSHIP = 71 132 | IP_HDRINCL = 2 133 | IP_IPSEC_POLICY = 21 134 | IP_MAX_MEMBERSHIPS = 4095 135 | IP_MSFILTER = 74 136 | IP_MULTICAST_IF = 9 137 | IP_MULTICAST_LOOP = 11 138 | IP_MULTICAST_TTL = 10 139 | IP_OPTIONS = 1 140 | IP_PKTINFO = 26 141 | IP_PORTRANGE = 19 142 | IP_RECVDSTADDR = 7 143 | IP_RECVIF = 20 144 | IP_RECVOPTS = 5 145 | IP_RECVRETOPTS = 6 146 | IP_RECVTTL = 24 147 | IP_RETOPTS = 8 148 | IP_TOS = 3 149 | IP_TTL = 4 150 | IP_UNBLOCK_SOURCE = 73 151 | LOCAL_PEERCRED = 1 152 | MCAST_BLOCK_SOURCE = 84 153 | MCAST_EXCLUDE = 2 154 | MCAST_INCLUDE = 1 155 | MCAST_JOIN_GROUP = 80 156 | MCAST_JOIN_SOURCE_GROUP = 82 157 | MCAST_LEAVE_GROUP = 81 158 | MCAST_LEAVE_SOURCE_GROUP = 83 159 | MCAST_UNBLOCK_SOURCE = 85 160 | MSG_CTRUNC = 32 161 | MSG_DONTROUTE = 4 162 | MSG_DONTWAIT = 128 163 | MSG_EOF = 256 164 | MSG_EOR = 8 165 | MSG_FLUSH = 1024 166 | MSG_HAVEMORE = 8192 167 | MSG_HOLD = 2048 168 | MSG_OOB = 1 169 | MSG_PEEK = 2 170 | MSG_RCVMORE = 16384 171 | MSG_SEND = 4096 172 | MSG_TRUNC = 16 173 | MSG_WAITALL = 64 174 | NI_DGRAM = 16 175 | NI_MAXHOST = 1025 176 | NI_MAXSERV = 32 177 | NI_NAMEREQD = 4 178 | NI_NOFQDN = 1 179 | NI_NUMERICHOST = 2 180 | NI_NUMERICSERV = 8 181 | PF_APPLETALK = 16 182 | PF_CCITT = 10 183 | PF_CHAOS = 5 184 | PF_CNT = 21 185 | PF_COIP = 20 186 | PF_DATAKIT = 9 187 | PF_DLI = 13 188 | PF_ECMA = 8 189 | PF_HYLINK = 15 190 | PF_IMPLINK = 3 191 | PF_INET = 2 192 | PF_INET6 = 30 193 | PF_IPX = 23 194 | PF_ISDN = 28 195 | PF_ISO = 7 196 | PF_KEY = 29 197 | PF_LAT = 14 198 | PF_LINK = 18 199 | PF_LOCAL = 1 200 | PF_MAX = 40 201 | PF_NATM = 31 202 | PF_NDRV = 27 203 | PF_NETBIOS = 33 204 | PF_NS = 6 205 | PF_OSI = 7 206 | PF_PIP = 25 207 | PF_PPP = 34 208 | PF_PUP = 4 209 | PF_ROUTE = 17 210 | PF_RTIP = 22 211 | PF_SIP = 24 212 | PF_SNA = 11 213 | PF_SYSTEM = 32 214 | PF_UNIX = 1 215 | PF_UNSPEC = 0 216 | PF_XTP = 19 217 | SCM_CREDS = 3 218 | SCM_RIGHTS = 1 219 | SCM_TIMESTAMP = 2 220 | SHUT_RD = 0 221 | SHUT_RDWR = 2 222 | SHUT_WR = 1 223 | SOCK_DGRAM = 2 224 | SOCK_RAW = 3 225 | SOCK_RDM = 4 226 | SOCK_SEQPACKET = 5 227 | SOCK_STREAM = 1 228 | SOL_SOCKET = 65535 229 | SOMAXCONN = 128 230 | SO_ACCEPTCONN = 2 231 | SO_BROADCAST = 32 232 | SO_DEBUG = 1 233 | SO_DONTROUTE = 16 234 | SO_DONTTRUNC = 8192 235 | SO_ERROR = 4103 236 | SO_KEEPALIVE = 8 237 | SO_LINGER = 128 238 | SO_NKE = 4129 239 | SO_NOSIGPIPE = 4130 240 | SO_NREAD = 4128 241 | SO_OOBINLINE = 256 242 | SO_RCVBUF = 4098 243 | SO_RCVLOWAT = 4100 244 | SO_RCVTIMEO = 4102 245 | SO_REUSEADDR = 4 246 | SO_REUSEPORT = 512 247 | SO_SNDBUF = 4097 248 | SO_SNDLOWAT = 4099 249 | SO_SNDTIMEO = 4101 250 | SO_TIMESTAMP = 1024 251 | SO_TYPE = 4104 252 | SO_USELOOPBACK = 64 253 | SO_WANTMORE = 16384 254 | SO_WANTOOBFLAG = 32768 255 | TCP_KEEPCNT = 258 256 | TCP_KEEPINTVL = 257 257 | TCP_MAXSEG = 2 258 | TCP_NODELAY = 1 259 | TCP_NOOPT = 8 260 | TCP_NOPUSH = 4 261 | end 262 | -------------------------------------------------------------------------------- /mrblib/socket_error.rb: -------------------------------------------------------------------------------- 1 | class SocketError < StandardError 2 | end 3 | -------------------------------------------------------------------------------- /mrblib/system_call_error.rb: -------------------------------------------------------------------------------- 1 | class SystemCallError < StandardError 2 | class << self 3 | alias _new new 4 | end 5 | 6 | def self.new(msg, errno) 7 | if (subclass = Errno.lookup(errno)) 8 | subclass.new(msg) 9 | else 10 | self._new(msg, errno) 11 | end 12 | end 13 | 14 | def initialize(msg, errno) 15 | if self.class == ::SystemCallError 16 | super("Unkown Error (#{errno}) - #{msg}") 17 | else 18 | super("#{self.class.name} (#{errno}) - #{msg}") 19 | end 20 | @errno = errno 21 | end 22 | 23 | def inspect 24 | "#<#{self.class.name}>: #{message}" 25 | end 26 | 27 | def errno 28 | @errno 29 | end 30 | end 31 | 32 | module Errno 33 | @lookup = {} 34 | 35 | def self.define(name, errno) 36 | errClass = Class.new(SystemCallError) 37 | 38 | errClass.define_singleton_method(:new) do |*args| 39 | self._new(*args) 40 | end 41 | 42 | errClass.define_singleton_method(:name) do 43 | @name ||= name.to_s 44 | end 45 | 46 | errClass.define_method(:initialize) do |msg| 47 | super(msg, errno) 48 | end 49 | 50 | errClass.define_method(:inspect) do |msg| 51 | "#<#{self.class.name}>: #{self.message}" 52 | end 53 | 54 | Errno.const_set(name, errClass) 55 | @lookup[errno] = errClass 56 | errClass 57 | end 58 | 59 | def self.lookup(errno) 60 | @lookup[errno] 61 | end 62 | 63 | APR::Errno.constants(false).each do |const| 64 | ::Errno.define(const, APR::Errno.const_get(const)) 65 | end 66 | end 67 | -------------------------------------------------------------------------------- /mrblib/tcpserver.rb: -------------------------------------------------------------------------------- 1 | class TCPServer < TCPSocket 2 | def initialize(hostname, port = nil) 3 | if port == nil 4 | port = hostname 5 | hostname = nil 6 | end 7 | 8 | err, @pool = APR.pool_create(nil) 9 | APR.raise_apr_errno(err) 10 | 11 | @local_host = hostname 12 | @local_port = port 13 | 14 | err, @apr_local_addrinfo = APR.sockaddr_info_get(hostname, APR::APR_INET, port, 0, @pool) 15 | APR.raise_apr_errno(err) 16 | err, @apr_socket = APR.socket_create(APR::APR_INET, APR::SOCK_STREAM, APR::APR_PROTO_TCP, @pool) 17 | APR.raise_apr_errno(err) 18 | 19 | err = APR.socket_bind(@apr_socket, @apr_local_addrinfo) 20 | APR.raise_apr_errno(err) 21 | end 22 | 23 | def accept 24 | err, client = APR.socket_accept(@apr_socket, @pool) 25 | APR::raise_apr_errno(err) 26 | TCPSocket.new(client, @pool) 27 | end 28 | 29 | # def accept_nonblock 30 | # end 31 | 32 | def listen(backlog) 33 | err = APR.socket_listen(@apr_socket, backlog) 34 | APR::raise_apr_errno(err) 35 | end 36 | 37 | # def sysaccept 38 | # end 39 | end 40 | -------------------------------------------------------------------------------- /mrblib/tcpsocket.rb: -------------------------------------------------------------------------------- 1 | class TCPSocket < IPSocket 2 | def initialize(remote_host, remote_port, local_host=nil, local_port=nil) 3 | super() 4 | 5 | # Wrapper semantics, for internal use only 6 | if (remote_host.class == APR::Socket) 7 | @apr_socket = remote_host 8 | @pool = remote_port 9 | err, @apr_remote_addrinfo = APR.socket_addr_get(APR::Interface::APR_REMOTE, @apr_socket) 10 | APR::raise_apr_errno(err) 11 | err, @remote_host = APR.sockaddr_ip_get(@apr_remote_addrinfo) 12 | APR::raise_apr_errno(err) 13 | return 14 | end 15 | 16 | err, @pool = APR.pool_create(nil) 17 | APR.raise_apr_errno(err) 18 | 19 | @remote_host = remote_host 20 | @remote_port = remote_port 21 | @local_host = local_host 22 | @local_port = local_port 23 | 24 | err, @apr_remote_addrinfo = APR.sockaddr_info_get(remote_host, APR::APR_INET, remote_port, 0, @pool) 25 | APR.raise_apr_errno(err) 26 | 27 | if local_host && local_port 28 | err, @apr_local_addrinfo = APR.sockaddr_info_get(local_host, APR::APR_INET, local_port, 0, @pool) 29 | end 30 | 31 | err, @apr_socket = APR.socket_create(APR::APR_INET, APR::SOCK_STREAM, APR::APR_PROTO_TCP, @pool) 32 | APR.raise_apr_errno(err) 33 | 34 | err = APR.socket_connect(@apr_socket, @apr_remote_addrinfo) 35 | APR.raise_apr_errno(err) 36 | 37 | if @apr_local_addrinfo 38 | err = APR.socket_bind(@apr_socket, @apr_local_addrinfo) 39 | APR.raise_apr_errno(err) 40 | end 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /mrblib/udpsocket.rb: -------------------------------------------------------------------------------- 1 | class UDPSocket < IPSocket 2 | def initialize(address_family = Socket::AF_INET, pool = nil) 3 | super() 4 | 5 | # Wrapper semantics, for internal use only 6 | if (address_family.class == APR::Socket) 7 | @apr_socket = address_family 8 | @pool = pool 9 | return 10 | end 11 | 12 | address_family = BasicSocket::Util.to_apr_address_family(address_family) 13 | 14 | err, @pool = APR.pool_create(nil) 15 | APR.raise_apr_errno(err) 16 | 17 | err, @apr_socket = APR.socket_create(address_family, APR::SOCK_DGRAM, APR::APR_PROTO_UDP, @pool) 18 | APR.raise_apr_errno(err) 19 | end 20 | 21 | # Base Class Overrides 22 | # -------------------- 23 | 24 | def read(limit=nil) 25 | assert_can_read 26 | 27 | # Handle limit == 0 case up front. Now all calls 28 | # delegated to super `read` will return nil at EOF 29 | return "" if limit == 0 30 | 31 | # The default read for basic socket delegates to apr_socket_read, 32 | # which returns after a UDP packet is finished. In Ruby style, we should 33 | # instead treat consecutive UDP packets as a stream when `read` is called. 34 | result = nil 35 | bytes_read = 0 36 | loop { 37 | part = super(limit && limit - bytes_read) 38 | break if part.nil? 39 | result = result.to_s + part 40 | bytes_read += part.length 41 | break if bytes_read >= limit 42 | } 43 | 44 | result 45 | end 46 | 47 | # Instance Methods 48 | # ---------------- 49 | 50 | def bind(host, port) 51 | err, @apr_local_addrinfo = APR.sockaddr_info_get(host, APR::APR_INET, port, 0, @pool) 52 | APR.raise_apr_errno(err) 53 | 54 | err = APR.socket_bind(@apr_socket, @apr_local_addrinfo) 55 | APR.raise_apr_errno(err) 56 | end 57 | 58 | def connect(host, port) 59 | err, @apr_remote_addrinfo = APR.sockaddr_info_get(host, APR::APR_INET, port, 0, @pool) 60 | APR.raise_apr_errno(err) 61 | 62 | err = APR.socket_connect(@apr_socket, @apr_remote_addrinfo) 63 | APR.raise_apr_errno(err) 64 | end 65 | end 66 | -------------------------------------------------------------------------------- /mruby-bindings.in/ctypes.rb: -------------------------------------------------------------------------------- 1 | # CTypes.define('Example') do 2 | # self.needs_unboxing = true 3 | # self.needs_boxing_cleanup = false 4 | # self.needs_unboxing_cleanup = false 5 | # self.needs_type_check = true 6 | # 7 | # self.recv_template = 'mrb_value %{value};' 8 | # self.format_specifier = 'o' 9 | # self.get_args_template = '&%{value}' 10 | # self.type_check_template = nil 11 | # self.invocation_arg_template = '%{value}' 12 | # self.field_swap_template = %{old} = %{new}; 13 | # 14 | # self.unboxing_fn.invocation_template = '%{as} = TODO_mruby_unbox_Example(%{unbox});' 15 | # self.unboxing_fn.cleanup_template = 'free(%{value});' 16 | # 17 | # self.boxing_fn.invocation_template = '%{as} = TODO_mruby_box_Example(%{box});' 18 | # self.boxing_fn.cleanup_template = 'free(%{value});' 19 | # end 20 | 21 | # This block is called to determine the Ruby class name to use for a C type. 22 | CTypes.translate_type_names do |name| 23 | MRubyBindings.type_name_to_rb_class(name).sub(/^Apr(.*)(T|E)/, "\\1") 24 | end 25 | 26 | # This block is called to determine the Ruby method name to use for a C function. 27 | CTypes.translate_fn_names do |name| 28 | name.sub(/^apr_/, '') 29 | end 30 | 31 | ## This block is called to determine the Ruby constant name to use for a C enum value. 32 | # CTypes.translate_enum_names do |name| 33 | # name 34 | # end 35 | 36 | CTypes.typedef('int', 'apr_time_t') 37 | -------------------------------------------------------------------------------- /mruby-bindings.in/dummy_decls.h: -------------------------------------------------------------------------------- 1 | int apr_time_sec(apr_time_t time); 2 | -------------------------------------------------------------------------------- /mruby-bindings.in/includes.h: -------------------------------------------------------------------------------- 1 | #include "apr.h" 2 | #include "apr_env.h" 3 | #include "apr_errno.h" 4 | #include "apr_file_info.h" 5 | #include "apr_file_io.h" 6 | #include "apr_fnmatch.h" 7 | #include "apr_general.h" 8 | #include "apr_global_mutex.h" 9 | #include "apr_network_io.h" 10 | #include "apr_pools.h" 11 | #include "apr_proc_mutex.h" 12 | #include "apr_signal.h" 13 | #include "apr_strings.h" 14 | #include "apr_thread_proc.h" 15 | #include "apr_time.h" 16 | -------------------------------------------------------------------------------- /rakelib/mruby-bindings.rake: -------------------------------------------------------------------------------- 1 | namespace :bindings do 2 | desc 'Extract type information from C files' 3 | task :scrape do 4 | File.delete('declarations.json') if File.exists?('declarations.json') 5 | 6 | inc = `apr-1-config --includedir`.strip 7 | headers = %W[ 8 | #{inc}/apr.h 9 | #{inc}/apr_env.h 10 | #{inc}/apr_errno.h 11 | #{inc}/apr_file_info.h 12 | #{inc}/apr_file_io.h 13 | #{inc}/apr_fnmatch.h 14 | #{inc}/apr_general.h 15 | #{inc}/apr_global_mutex.h 16 | #{inc}/apr_network_io.h 17 | #{inc}/apr_pools.h 18 | #{inc}/apr_proc_mutex.h 19 | #{inc}/apr_signal.h 20 | #{inc}/apr_strings.h 21 | #{inc}/apr_time.h 22 | #{inc}/apr_thread_proc.h 23 | #{inc}/apr_want.h 24 | mruby-bindings.in/dummy_decls.h 25 | ] 26 | 27 | if headers.length == 0 28 | $stderr.puts 'No headers defined. Please update rakelib/mruby-bindings.rake' 29 | exit 1 30 | end 31 | 32 | headers.each do |header| 33 | sh "clang2json #{header} >> declarations.json" 34 | end 35 | end 36 | 37 | desc 'Inspect all declarations in an interactive Pry shell (require pry gem)' 38 | task :pry do 39 | require 'pry' 40 | require 'mruby_bindings' 41 | MRubyBindings.read_declarations("declarations.json") do |lib| 42 | binding.pry 43 | end 44 | end 45 | 46 | desc 'Generate bindings' 47 | task :generate do 48 | cmd = ['mrbind generate'] 49 | cmd << '-input declarations.json' 50 | cmd << '-module APR' 51 | cmd << '-gem mruby-apr' 52 | cmd << '-load mruby-bindings.in/ctypes.rb' if File.exists?('mruby-bindings.in/ctypes.rb') 53 | cmd << '-load mruby-bindings.in/fn_types.rb' if File.exists?('mruby-bindings.in/fn_types.rb') 54 | cmd << '-load mruby-bindings.in/macro_types.rb' if File.exists?('mruby-bindings.in/macro_types.rb') 55 | cmd << '-includes mruby-bindings.in/includes.h' if File.exists?('mruby-bindings.in/includes.h') 56 | cmd << '-output bindings' 57 | cmd << '-force' 58 | sh cmd.join(' ') 59 | end 60 | 61 | desc "Merge generated code into mrbgem" 62 | task :merge do 63 | sh "mrbind merge -from bindings -to ." 64 | end 65 | 66 | namespace :merge do 67 | desc "Merge generated code from src folder" 68 | task :src do 69 | sh "mrbind merge -from bindings -to . src" 70 | end 71 | 72 | desc "Merge generated code from include folder" 73 | task :include do 74 | sh "mrbind merge -from bindings -to . include" 75 | end 76 | 77 | desc "Merge generated code from mrblib folder" 78 | task :mrblib do 79 | sh "mrbind merge -from bindings -to . mrblib" 80 | end 81 | end 82 | 83 | desc 'Regenerate functions & classes headers' 84 | task :'enable-functions' do 85 | sh 'mrbind enable-functions -m APR -g mruby-apr -o .' 86 | end 87 | 88 | task :fn_count do 89 | sh "cat include/mruby_APR_functions.h | egrep 'TRUE|FALSE' | wc -l" 90 | end 91 | 92 | task :bound_fns do 93 | sh "cat include/mruby_APR_functions.h | egrep 'TRUE'" 94 | end 95 | 96 | task :bound_fn_count do 97 | sh "cat include/mruby_APR_functions.h | egrep 'TRUE' | wc -l" 98 | end 99 | 100 | task :unbound_fns do 101 | sh "cat include/mruby_APR_functions.h | egrep 'FALSE'" 102 | end 103 | 104 | task :unbound_fn_count do 105 | sh "cat include/mruby_APR_functions.h | egrep 'FALSE' | wc -l" 106 | end 107 | end 108 | -------------------------------------------------------------------------------- /refactor.rb: -------------------------------------------------------------------------------- 1 | # cat src/mruby_APR.c | ruby -e 'puts $stdin.read.gsub(/\n{3,}/m, "\n\n")' > temp; mv temp src/mruby_APR.c 2 | 3 | ## 4 | ## Use format specifier for ints 5 | ## 6 | # File.open('src/mruby_APR.c', 'r') do |f| 7 | # while l = f.gets 8 | # if (l =~ /mrb_mruby_curses_gem_init/) 9 | # puts l 10 | # break 11 | # elsif (l =~ /#if BIND/) 12 | # puts l 13 | # 14 | # ints = [] 15 | # func = '' 16 | # loop { 17 | # l = f.gets 18 | # func << l 19 | # if int = l[/mrb_obj_is_kind_of\(mrb, ([^,]+), mrb->fixnum_class\)/, 1] 20 | # ints << int 21 | # end 22 | # break if l =~ /^#endif/ 23 | # } 24 | # 25 | # # puts ints.inspect 26 | # match = func.match(/mrb_get_args\(mrb, "[^"]+"(.*)\);$/) 27 | # unless match 28 | # puts func 29 | # next 30 | # end 31 | # 32 | # params = match[1].gsub(',', '').gsub('&', '').strip.split(/\s/) 33 | # 34 | # ints.each do |int| 35 | # index = params.index(int) 36 | # func.gsub!(/mrb_value #{int};/, "mrb_int native_#{int};") 37 | # func.gsub!(/^\s+if \(!mrb_obj_is_kind_of\(mrb, #{int}, mrb->fixnum_class(.*?)^\s*}\n/m, "") 38 | # func.gsub!(/^.*mrb_fixnum\(#{int}\).*$/, '') 39 | # func.sub!(/mrb_get_args\(mrb, "(.{#{index}})o/, "mrb_get_args(mrb, \"\\1i") 40 | # func.sub!(/mrb_get_args(.*)&#{int}(,|\))/, "mrb_get_args\\1&native_#{int}\\2") 41 | # end 42 | # puts func 43 | # else 44 | # puts l 45 | # end 46 | # end 47 | # 48 | # # Pump out the remainder of the file, if any 49 | # while l = f.gets 50 | # puts l 51 | # end 52 | # end 53 | 54 | ## 55 | ## Use format specifier for strings 56 | ## 57 | # File.open('src/mruby_APR.c', 'r') do |f| 58 | # while l = f.gets 59 | # if (l =~ /mrb_mruby_curses_gem_init/) 60 | # puts l 61 | # break 62 | # elsif (l =~ /#if BIND/) 63 | # puts l 64 | # 65 | # strings = [] 66 | # func = '' 67 | # loop { 68 | # l = f.gets 69 | # func << l 70 | # if str = l[/ = mrb_string_value_cstr\(mrb, &(\S*)\);/, 1] 71 | # strings << str 72 | # end 73 | # break if l =~ /^#endif/ 74 | # } 75 | # 76 | # # puts strings.inspect 77 | # match = func.match(/mrb_get_args\(mrb, "[^"]+"(.*)\);$/) 78 | # unless match 79 | # puts func 80 | # next 81 | # end 82 | # 83 | # params = match[1].gsub(',', '').gsub('&', '').strip.split(/\s/) 84 | # 85 | # strings.each do |str| 86 | # index = params.index(str) 87 | # func.gsub!(/mrb_value #{str};/, "char * native_#{str};") 88 | # func.gsub!(/^\s+if \(!mrb_obj_is_kind_of\(mrb, #{str}, mrb->string_class(.*?)^\s*}\n/m, "") 89 | # func.gsub!(/^.*mrb_string_value_cstr\(mrb, &#{str}\).*$/, '') 90 | # func.sub!(/mrb_get_args\(mrb, "(.{#{index}})o/, "mrb_get_args(mrb, \"\\1z") 91 | # func.sub!(/mrb_get_args(.*)&#{str}(,|\))/, "mrb_get_args\\1&native_#{str}\\2") 92 | # end 93 | # puts func 94 | # else 95 | # puts l 96 | # end 97 | # end 98 | # 99 | # # Pump out the remainder of the file, if any 100 | # while l = f.gets 101 | # puts l 102 | # end 103 | # end 104 | 105 | # def tag_fns 106 | # File.open('src/mruby_APR.c') do |f| 107 | # stop = false 108 | # f.each_line do |l| 109 | # if !stop && fn = l[/#if BIND_(.*)_FUNCTION/, 1] 110 | # puts "/* MRUBY_BINDING: #{fn} */" 111 | # puts l 112 | # elsif !stop && l =~ /^\#endif$/ 113 | # puts l 114 | # puts "/* MRUBY_BINDING_END */" 115 | # elsif !stop && l =~ /gem_init/ 116 | # puts l 117 | # stop = true 118 | # else 119 | # puts l 120 | # end 121 | # end 122 | # end 123 | # end 124 | # tag_fns 125 | 126 | def add_shas 127 | File.open('src/mruby_APR.c') do |f| 128 | f.each_line do |l| 129 | if l[/MRUBY_BINDING:/] 130 | puts l 131 | puts "/* sha: user_edited */" 132 | else 133 | puts l 134 | end 135 | end 136 | end 137 | end 138 | add_shas 139 | 140 | # def trim_disabled_fns 141 | # disabled = Hash.new { |h, k| h[k] = false } 142 | # File.open('include/mruby_APR.h', 'r') do |f| 143 | # f.each_line do |line| 144 | # if (match = line[/#define\s*BIND_(.*)_FUNCTION\s*FALSE/, 1]) 145 | # disabled[match] = true 146 | # end 147 | # end 148 | # end 149 | # 150 | # File.open('src/mruby_APR.c', 'r') do |f| 151 | # File.open('src/mruby_APR.c.trimmed', 'w') do |out| 152 | # line = f.gets 153 | # loop { 154 | # break if line.nil? 155 | # 156 | # if match = line[/MRUBY_BINDING: (\S+)/, 1] 157 | # if disabled[match] 158 | # line = f.gets until line =~ /MRUBY_BINDING_END/ 159 | # line = f.gets 160 | # line = f.gets until line =~ /\S/ 161 | # next 162 | # end 163 | # end 164 | # 165 | # # Important to keep #if's indented for this guy 166 | # if match = line[/^#if BIND_(\S+)_FUNCTION/, 1] 167 | # if disabled[match] 168 | # line = f.gets until line =~ /^#endif/ 169 | # line = f.gets 170 | # line = f.gets until line =~ /\S/ 171 | # next 172 | # end 173 | # end 174 | # 175 | # out.puts line 176 | # line = f.gets 177 | # } 178 | # end 179 | # end 180 | # 181 | # File.rename('src/mruby_APR.c.trimmed', 'src/mruby_APR.c') 182 | # end 183 | # trim_disabled_fns() 184 | -------------------------------------------------------------------------------- /sandbox/bin_write_text_read.txt: -------------------------------------------------------------------------------- 1 | one two -------------------------------------------------------------------------------- /sandbox/echo_out.txt: -------------------------------------------------------------------------------- 1 | some string 2 | -------------------------------------------------------------------------------- /sandbox/empty_file.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbreeden/mruby-apr/98d47bbd40bba9be13224c190caf6228dc08ec8b/sandbox/empty_file.txt -------------------------------------------------------------------------------- /sandbox/file_for_writing.txt: -------------------------------------------------------------------------------- 1 | my message 2 | -------------------------------------------------------------------------------- /sandbox/shell.rb: -------------------------------------------------------------------------------- 1 | system %q[ruby -e "puts '$HOME'"] 2 | -------------------------------------------------------------------------------- /sandbox/test.txt: -------------------------------------------------------------------------------- 1 | BeforeNullAfterNull -------------------------------------------------------------------------------- /sandbox/two_line_file.txt: -------------------------------------------------------------------------------- 1 | This file has two lines. 2 | This is the second line. 3 | -------------------------------------------------------------------------------- /sandbox/windows print three args.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | int main(int argc, char** argv) { 4 | printf("%s, %s, %s\n", argv[1], argv[2], argv[3]); 5 | } 6 | -------------------------------------------------------------------------------- /sandbox/windows print three args.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jbreeden/mruby-apr/98d47bbd40bba9be13224c190caf6228dc08ec8b/sandbox/windows print three args.exe -------------------------------------------------------------------------------- /specs/apr_dir.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('APR API: Directories') do 4 | err, @pool = APR.pool_create(nil) 5 | @a_rwx = 0x070707 6 | 7 | def check_errno(errno) 8 | unless assert(errno == 0) 9 | raise "ERRNO(#{errno}) #{APR.strerror(errno)}" 10 | end 11 | end 12 | 13 | describe 'APR.dir_open(path: String, pool: Pool): [errno: Fixnum, dir: Dir]' do 14 | it 'Gets file information for each entry in the directory' do 15 | err, dir = APR.dir_open '.', @pool 16 | check_errno(err) 17 | APR.dir_close dir 18 | end 19 | end 20 | 21 | describe 'APR.dir_read(finfo: Finfo, wanted: Fixnum, dir: Dir): errno: Fixnum' do 22 | it 'Gets file information for each entry in the directory' do 23 | err, dir = APR.dir_open '.', @pool 24 | check_errno(err) 25 | 26 | time_pattern = "*[0-9][0-9]:[0-9][0-9]:[0-9][0-9]*" 27 | 28 | err, finfo = APR.dir_read 0, dir 29 | 30 | found_cwd = false 31 | found_parnet = false 32 | while err == 0 || err == APR::APR_INCOMPLETE 33 | # Just checking the access, modification, and creation times, since these should be available 34 | assert(0 == APR.fnmatch(time_pattern, APR.ctime(finfo.atime)[1], 0)) 35 | assert(0 == APR.fnmatch(time_pattern, APR.ctime(finfo.mtime)[1], 0)) 36 | assert(0 == APR.fnmatch(time_pattern, APR.ctime(finfo.ctime)[1], 0)) 37 | found_cwd ||= (finfo.name == '.') 38 | found_parent ||= (finfo.name == '..') 39 | 40 | err, finfo = APR.dir_read 0, dir 41 | end 42 | assert (found_parent && found_cwd) 43 | APR.dir_close dir 44 | end 45 | end 46 | 47 | describe 'APR.dir_make(path: String, permissions: Fixnum, pool: Pool): errno: Fixnum' do 48 | it 'Creates a directory' do 49 | err = APR.dir_make "#{$sandbox}/test_create_dir", @a_rwx, @pool 50 | check_errno(err) 51 | err, dir = APR.dir_open("#{$sandbox}/test_create_dir", @pool) 52 | check_errno(err) 53 | end 54 | end 55 | 56 | describe 'APR.dir_make_recursive(path: String, permissions: Fixnum, pool: Poolype): errno: Fixnum' do 57 | it 'Creates a directory and any required parent directories' do 58 | err = APR.dir_make_recursive "#{$sandbox}/test_create_dir/some/nested/dir", @a_rwx, @pool 59 | check_errno(err) 60 | err, dir = APR.dir_open("#{$sandbox}/test_create_dir/some/nested/dir", @pool) 61 | check_errno(err) 62 | APR.dir_close(dir) 63 | end 64 | end 65 | 66 | describe 'APR.dir_remove(path: String, pool: Poolype): errno: Fixnum' do 67 | it 'Deletes a directory' do 68 | err = APR.dir_remove "#{$sandbox}/test_create_dir/some/nested/dir", @pool 69 | check_errno(err) 70 | err = APR.dir_remove "#{$sandbox}/test_create_dir/some/nested", @pool 71 | check_errno(err) 72 | err = APR.dir_remove "#{$sandbox}/test_create_dir/some/", @pool 73 | check_errno(err) 74 | err = APR.dir_remove "#{$sandbox}/test_create_dir", @pool 75 | end 76 | end 77 | 78 | end 79 | -------------------------------------------------------------------------------- /specs/apr_proc.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('APR API: Processes') do 4 | err, @pool = APR.pool_create(nil) 5 | 6 | describe 'APR.proc_create(command: String, argv: Array, env: Array, proc_attr: Procattr, pool: Pool): [errno: Fixnum, proc: Proc]' do 7 | it 'Can run a shell command and redirect output to a file' do 8 | err, proc_attr = APR.procattr_create @pool 9 | assert(err == 0) 10 | 11 | # WORKAROUND: 12 | # Encountering lots of problems when using APR_SHELLCMD directly. 13 | # It attempts to quote arguments in ways that appear unneeded. 14 | # Additionally, the quoting is often wrong. 15 | # So, using APR_PROGRAM_PATH, we can construct the shell command ourselves 16 | # to get around this limitation. 17 | err = APR.procattr_cmdtype_set proc_attr, APR::Cmdtype::APR_PROGRAM_PATH 18 | assert(err == 0) 19 | 20 | err, file = APR.file_open "#{$sandbox}/echo_out.txt", 21 | APR::APR_FOPEN_CREATE | APR::APR_FOPEN_WRITE | APR::APR_FOPEN_TRUNCATE, 22 | APR::APR_FPROT_OS_DEFAULT, 23 | @pool 24 | assert(err == 0) 25 | 26 | err = APR.procattr_child_out_set proc_attr, file, nil 27 | assert(err == 0) 28 | 29 | argv = nil 30 | if APR::OS == 'Windows' 31 | argv = ["cmd.exe", '/C', "ruby -e \"puts 'some string'\""] 32 | else 33 | argv = ["sh", '-c', "ruby -e \"puts 'some string'\""] 34 | end 35 | 36 | err, process = APR.proc_create argv[0], argv, nil, proc_attr, @pool 37 | assert(err == 0) 38 | 39 | err, exitcode, exitwhy = APR.proc_wait process, APR::WaitHow::APR_WAIT 40 | 41 | APR.file_close(file) 42 | 43 | err, file = APR.file_open "#{$sandbox}/echo_out.txt", APR::APR_FOPEN_READ, 0, @pool 44 | assert(err == 0) 45 | 46 | err, str = APR.file_read file, 100 47 | assert(err == 0) 48 | # strip newline from echo before compare 49 | assert (str.strip == "some string") 50 | APR.file_close(file) 51 | end 52 | 53 | it 'Can run a shell command and pipe output to parent via APR.file_pipe_create' do 54 | err, proc_attr = APR.procattr_create @pool 55 | assert(err == 0) 56 | 57 | err = APR.procattr_cmdtype_set proc_attr, APR::Cmdtype::APR_SHELLCMD_ENV 58 | assert(err == 0) 59 | 60 | err, readEnd, writeEnd = APR.file_pipe_create @pool 61 | 62 | # Passing pipe ends: child, parent 63 | err = APR.procattr_child_out_set proc_attr, writeEnd, readEnd 64 | assert(err == 0) 65 | 66 | err, argv = APR.tokenize_to_argv "echo this string of args", @pool 67 | assert(argv.length == 5) 68 | assert(err == 0) 69 | 70 | err, process = APR.proc_create "echo", argv, nil, proc_attr, @pool 71 | assert(err == 0) 72 | 73 | rr, str = APR.file_read readEnd, 100 74 | assert(err == 0) 75 | # strip newline from echo before compare 76 | assert (str.strip == "this string of args") 77 | 78 | APR.file_close(readEnd) 79 | 80 | err, exitcode, exitwhy = APR.proc_wait process, APR::WaitHow::APR_WAIT 81 | end 82 | end 83 | 84 | describe "APR.procattr_io_set(procattr: Procattr, in: Fixnum, out: Fixnum, err: Fixnum): errno: Fixnum" do 85 | it 'Can automatically create pipes between the parent and child processes (for std in, out, & err)' do 86 | err, proc_attr = APR.procattr_create @pool 87 | assert(err == 0) 88 | 89 | err = APR.procattr_cmdtype_set proc_attr, APR::Cmdtype::APR_SHELLCMD_ENV 90 | assert(err == 0) 91 | 92 | # in out err 93 | APR.procattr_io_set proc_attr, APR::APR_NO_PIPE, APR::APR_FULL_BLOCK, APR::APR_NO_PIPE 94 | 95 | err, argv = APR.tokenize_to_argv "echo this string of args", @pool 96 | assert(argv.length == 5) 97 | assert(err == 0) 98 | 99 | err, process = APR.proc_create "echo", argv, nil, proc_attr, @pool 100 | assert(err == 0) 101 | 102 | err, str = APR.file_read process.out, 100 103 | assert(err == 0) 104 | # strip newline from echo before compare 105 | assert (str.strip == "this string of args") 106 | 107 | APR.file_close(process.out) 108 | 109 | err, exitcode, exitwhy = APR.proc_wait process, APR::WaitHow::APR_WAIT 110 | end 111 | end 112 | 113 | end 114 | -------------------------------------------------------------------------------- /specs/apr_socket.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('APR API: Sockets') do 4 | err, @pool = APR.pool_create(nil) 5 | 6 | def run_server 7 | @server_pid = spawn "ruby ./helpers/tcp_server.rb" 8 | `sleep 1` 9 | end 10 | 11 | def wait_for_server 12 | Process.wait(@server_pid) 13 | end 14 | 15 | def run_client 16 | @client_pid = spawn "sleep 1 && ruby ./helpers/tcp_client.rb" 17 | end 18 | 19 | def wait_for_client 20 | Process.wait(@client_pid) 21 | end 22 | 23 | describe 'APR.socket_connect(socket: Socket, addr: Sockaddr)' do 24 | it 'Connects a client socket to a server' do 25 | run_server 26 | 27 | # Host Family Port Flags 28 | err, server_addr = APR.sockaddr_info_get "localhost", APR::APR_INET, 8888, 0, @pool 29 | APR.raise_apr_errno(err) 30 | 31 | err, client = APR.socket_create(APR::APR_INET, APR::SOCK_STREAM, APR::APR_PROTO_TCP, @pool) 32 | APR.raise_apr_errno(err) 33 | 34 | err = APR.socket_connect(client, server_addr) 35 | APR.raise_apr_errno(err) 36 | 37 | err, buf = APR.socket_recv(client, 100) 38 | APR.raise_apr_errno(err) 39 | 40 | assert (buf == 'socket data') 41 | end 42 | end 43 | 44 | describe 'APR.socket_atreadeof(socket: Socket)' do 45 | it 'Returns [APR::APR_SUCCESS, true] when the read buffer is empty and the socket has been closed by the peer' do 46 | run_server 47 | 48 | # Host Family Port Flags 49 | err, server_addr = APR.sockaddr_info_get "localhost", APR::APR_INET, 8888, 0, @pool 50 | APR.raise_apr_errno(err) 51 | 52 | err, client = APR.socket_create(APR::APR_INET, APR::SOCK_STREAM, APR::APR_PROTO_TCP, @pool) 53 | APR.raise_apr_errno(err) 54 | 55 | err = APR.socket_connect(client, server_addr) 56 | APR.raise_apr_errno(err) 57 | 58 | eof_check = APR.socket_atreadeof(client) 59 | assert (eof_check[0] == APR::APR_SUCCESS && eof_check[1] == false) 60 | err, buf = APR.socket_recv(client, 100) 61 | APR.raise_apr_errno(err) 62 | 63 | wait_for_server 64 | eof_check = APR.socket_atreadeof(client) 65 | assert (eof_check[0] == APR::APR_SUCCESS && eof_check[1] == true) 66 | end 67 | end 68 | 69 | describe 'APR.socket_send(socket, message, length)' do 70 | it 'Returns a APR::APR_EOF when the connection is closed' do 71 | err, server_addr = APR.sockaddr_info_get "www.google.com", APR::APR_INET, 80, 0, @pool 72 | APR.raise_apr_errno(err) 73 | 74 | err, client = APR.socket_create(APR::APR_INET, APR::SOCK_STREAM, APR::APR_PROTO_TCP, @pool) 75 | APR.raise_apr_errno(err) 76 | 77 | err = APR.socket_connect(client, server_addr) 78 | APR.raise_apr_errno(err) 79 | 80 | msg = "GET http://www.google.com/ HTTP/1.1\nConnection: close\n\n" 81 | APR.socket_send(client, msg, msg.length) 82 | 83 | err = 0 84 | while err == 0 85 | err, buf = APR.socket_recv(client, 1000) 86 | APR.raise_apr_errno(err, ignore: APR::APR_EOF) 87 | end 88 | 89 | assert (err == APR::APR_EOF) 90 | end 91 | end 92 | 93 | describe 'APR.socket_bind(socket, addr)' do 94 | it 'Binds a server socket to an address' do 95 | # Host Family Port Flags 96 | err, server_addr = APR.sockaddr_info_get "localhost", APR::APR_INET, 8889, 0, @pool 97 | APR.raise_apr_errno(err) 98 | 99 | err, server = APR.socket_create(APR::APR_INET, APR::SOCK_STREAM, APR::APR_PROTO_TCP, @pool) 100 | APR.raise_apr_errno(err) 101 | 102 | err = APR.socket_bind(server, server_addr) 103 | APR.raise_apr_errno(err) 104 | 105 | run_client 106 | 107 | APR.socket_listen(server, 100) 108 | err, client = APR.socket_accept(server, @pool) 109 | APR.raise_apr_errno(err) 110 | 111 | err, msg = APR.socket_recv(client, 1000) 112 | APR.raise_apr_errno(err, ignore: APR::APR_EOF) 113 | 114 | assert (msg == 'socket data') 115 | end 116 | end 117 | end 118 | -------------------------------------------------------------------------------- /specs/apr_time.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('APR API: Time') do 4 | err, @pool = APR.pool_create(nil) 5 | 6 | def check_errno(errno) 7 | unless assert(errno == 0) 8 | raise APR.strerror(errno) 9 | end 10 | end 11 | 12 | describe 'APR.time_now(pool: Pool): time: Time' do 13 | it 'Gets the current time' do 14 | time = APR.time_now 0 15 | err, time_s = APR.ctime(time) 16 | 17 | check_errno(err) 18 | assert(0 == APR.fnmatch("*[0-9][0-9]:[0-9][0-9]:[0-9][0-9]*", time_s, 0)) 19 | end 20 | end 21 | 22 | end 23 | -------------------------------------------------------------------------------- /specs/fixture.rb: -------------------------------------------------------------------------------- 1 | $GEM_DIR = '..' 2 | $sandbox = "#{$GEM_DIR}/sandbox" 3 | 4 | class APR::Spec 5 | class SkipTest < StandardError 6 | end 7 | 8 | def initialize(label, &block) 9 | @fixture_label = label 10 | @test_count = 0 11 | @fail_count = 0 12 | @pending_count = 0 13 | @current_test_passed = true 14 | @current_test_pending = false 15 | @indentation = 0 16 | write 17 | write label 18 | write '-' * label.size 19 | write 20 | self.instance_eval(&block) 21 | summarize 22 | end 23 | 24 | def write(*lines) 25 | if lines.empty? 26 | puts 27 | else 28 | lines.each { |l| l.gsub!("\n", "\n#{ ' ' * (@indentation * 2)}") } 29 | lines.each do |l| 30 | print (' ' * (@indentation * 2)) unless l.empty? 31 | puts l 32 | end 33 | end 34 | end 35 | 36 | def blurb(text) 37 | write text 38 | puts 39 | end 40 | 41 | def indent(&block) 42 | @indentation += 1 43 | if block_given? 44 | begin 45 | block[] 46 | ensure 47 | unindent 48 | end 49 | end 50 | end 51 | 52 | def unindent 53 | if @indentation >= 1 54 | @indentation = @indentation - 1 55 | else 56 | @indentation = 0 57 | end 58 | end 59 | 60 | def bullet 61 | if @indentation % 3 == 0 62 | '-' 63 | elsif @indentation % 3 == 1 64 | '+' 65 | else 66 | '*' 67 | end 68 | end 69 | 70 | def describe(label, &block) 71 | write "#{bullet} #{label}" 72 | indent do 73 | self.instance_eval(&block) 74 | write '' 75 | end 76 | end 77 | alias desc describe 78 | alias context describe 79 | 80 | def it(label, &block) 81 | if ENV['SPEC'] && ! (Regexp.new(ENV['SPEC']) =~ label) 82 | return nil 83 | end 84 | 85 | @current_test_passed = true 86 | @current_test_pending = false 87 | exc = nil 88 | 89 | begin 90 | if block 91 | self.instance_eval(&block) 92 | else 93 | skip 94 | end 95 | rescue SkipTest => ex 96 | @current_test_pending = true 97 | rescue StandardError => ex 98 | exc = ex 99 | @current_test_passed = false 100 | end 101 | 102 | tag = "" 103 | if @current_test_pending 104 | tag = "[SKIPPED] " 105 | elsif !@current_test_passed 106 | tag = "[FAILED] " 107 | end 108 | write "#{bullet} #{tag}#{label}" 109 | 110 | @test_count += 1 111 | @fail_count += 1 unless @current_test_passed || @current_test_pending 112 | @pending_count += 1 if @current_test_pending 113 | 114 | if exc && !@current_test_pending 115 | write "\nUncaught #{exc.class.to_s}: #{exc}\n#{exc.backtrace.join("\n")}\n\n" 116 | end 117 | end 118 | alias test it 119 | 120 | def assert(condition) 121 | @current_test_passed &&= condition 122 | condition # So client can react to result 123 | end 124 | 125 | def assert_raises(excClass, &block) 126 | begin 127 | block[] 128 | write "!!! Expected #{excClass} to be thrown but nothing was." 129 | rescue excClass 130 | return 131 | rescue Exception => ex 132 | # fall through 133 | write "!!! Expected #{excClass} to be thrown but caught #{ex.class}." 134 | end 135 | @current_test_passed = false 136 | end 137 | 138 | def fail 139 | @current_test_passed = false 140 | end 141 | 142 | def skip 143 | raise SkipTest.new 144 | end 145 | alias pending skip 146 | 147 | def summarize 148 | write 149 | write "#{@fail_count == 0 ? 'SUCCESS' : 'FAILURE' } [#{@fail_count} failed, #{@pending_count} skipped, #{@test_count} total]" 150 | end 151 | end 152 | -------------------------------------------------------------------------------- /specs/helpers/tcp_client.rb: -------------------------------------------------------------------------------- 1 | # This should be run with CRuby for testing TCP server sockets 2 | 3 | require 'socket' 4 | 5 | client = TCPSocket.new 'localhost', 8889 6 | client.print "socket data" 7 | client.close 8 | -------------------------------------------------------------------------------- /specs/helpers/tcp_server.rb: -------------------------------------------------------------------------------- 1 | # This should be run with CRuby for testing TCP client sockets 2 | 3 | require 'socket' 4 | 5 | server = TCPServer.new 8888 6 | 7 | client = server.accept 8 | client.write "socket data" 9 | client.close 10 | -------------------------------------------------------------------------------- /specs/ruby_dir.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('Ruby API: Dir') do 4 | sandbox_dir = "#{$GEM_DIR}/sandbox" 5 | 6 | describe 'Dir' do 7 | it 'Is implemented, but needs tests' do 8 | pending 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /specs/ruby_file_stat.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('Ruby API: File::Stat') do 4 | empty_file = "#{$sandbox}/empty_file.txt" 5 | two_line_file = "#{$sandbox}/two_line_file.txt" 6 | file_for_writing = "#{$sandbox}/file_for_writing.txt" 7 | 8 | describe 'Stat#atime' do 9 | it 'Gives the access time of the file as a Time' do 10 | # Unfortunately have to sleep for a second to guarantee atime > "now" 11 | APR.sleep 2000000 # micro seconds 12 | stat = File::Stat.new(empty_file) 13 | assert(stat.atime.class == Time) 14 | end 15 | end 16 | 17 | describe 'Stat#ctime' do 18 | it 'Gives the creation time of the file as a Time' do 19 | created_file = "#{$sandbox}/random_created_file_#{rand(1000000)}.txt" 20 | File.delete(created_file) if File.exists?(created_file) 21 | now = Time.now 22 | sleep 2 23 | File.open(created_file, 'w') do |f| 24 | f.puts "Created after #{now}" 25 | end 26 | stat = File::Stat.new(created_file) 27 | assert(stat.ctime > now) 28 | File.delete(created_file) 29 | end 30 | end 31 | 32 | describe 'Stat#mtime' do 33 | it 'Gives the last modified time of the file as a Time' do 34 | stat1 = File::Stat.new(file_for_writing) 35 | File.open(file_for_writing, 'w') do |f| 36 | f.puts "Modification" 37 | end 38 | stat2 = File::Stat.new(file_for_writing) 39 | assert(stat2.mtime > stat1.mtime) 40 | end 41 | end 42 | 43 | describe 'Stat#size' do 44 | it 'Gives the size of the file in bytes' do 45 | stat = File::Stat.new(two_line_file) 46 | # File hase 2 24-char lines, size depends on line endings 47 | assert(50 <= stat.size && stat.size <= 52) 48 | end 49 | end 50 | 51 | describe 'Stat#directory?' do 52 | it 'Returns true if the file is a directory' do 53 | stat = File::Stat.new($sandbox) 54 | assert(stat.directory?) 55 | end 56 | 57 | it 'Returns false for non-directory files' do 58 | stat = File::Stat.new(empty_file) 59 | assert(!stat.directory?) 60 | end 61 | end 62 | 63 | describe 'Stat#file?' do 64 | it 'Returns true if the file is a regular file' do 65 | stat = File::Stat.new(empty_file) 66 | assert(stat.file?) 67 | end 68 | 69 | it 'Returns false for non-regular files' do 70 | stat = File::Stat.new($sandbox) 71 | assert(!stat.file?) 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /specs/ruby_forwardable.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | class TestForwardee 4 | def return_one 5 | 1 6 | end 7 | 8 | def return_arg(arg) 9 | arg 10 | end 11 | 12 | def run_block(&block) 13 | block[] 14 | end 15 | end 16 | 17 | class TestForwarder 18 | extend ::Forwardable 19 | delegate [:return_one, :return_arg, :run_block] => :@forwardee 20 | 21 | def initialize 22 | @forwardee = TestForwardee.new 23 | end 24 | end 25 | 26 | APR::Spec.new('Ruby API: Forwardable') do 27 | describe 'Forwardable#delegate' do 28 | it 'Creates delegate methods on classes' do 29 | f = TestForwarder.new 30 | assert f.return_one == 1 31 | end 32 | 33 | it 'Creates delegate methods on instances' do 34 | forwardee = Object.new 35 | class << forwardee 36 | def return_two 37 | 2 38 | end 39 | end 40 | forwarder = Object.new 41 | forwarder.instance_variable_set(:@forwardee, forwardee) 42 | forwarder.extend Forwardable 43 | forwarder.delegate :return_two => :@forwardee 44 | assert forwarder.return_two == 2 45 | end 46 | 47 | it 'Passes arguments along' do 48 | f = TestForwarder.new 49 | assert f.return_arg('test') == 'test' 50 | end 51 | 52 | it 'Passes blocks along' do 53 | f = TestForwarder.new 54 | success = false 55 | f.run_block do 56 | success = true 57 | end 58 | assert success 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /specs/ruby_io.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('Ruby API: IO') do 4 | describe 'IO.pipe' do 5 | it 'Creates a pair of File objects to be used as the read & write ends of the pipe' do 6 | r, w = IO.pipe 7 | w.write('my message') 8 | w.close 9 | msg = r.read(10) 10 | r.close 11 | assert(msg == 'my message') 12 | end 13 | end 14 | 15 | describe 'IO.popen([env,] cmd, mode="r" [, opt])' do 16 | it 'Runs the specified command as a subprocess, returning an IO like object with a pid member' do 17 | pipe = IO.popen('exit 4') 18 | pipe.close 19 | assert($?.exitstatus == 4) 20 | end 21 | 22 | it 'Connects the returned IO-like object to child\'s stdin for mode "r"' do 23 | pipe = IO.popen('ruby -e "puts 123"', "r") 24 | msg = pipe.read(3) 25 | assert(msg == '123') 26 | pipe.close 27 | end 28 | 29 | it 'Connects the returned IO-like object to child\'s stdout for mode "w"' do 30 | pipe = IO.popen('ruby -e "gets; exit 2"', "w") 31 | pipe.puts('123') 32 | pipe.close 33 | assert($?.exitstatus == 2) 34 | end 35 | 36 | it 'Connects the returned IO-like object to child\'s stdin & stdout for mode "r+"' do 37 | pipe = IO.popen('ruby -e "l = gets; puts l"', "r+") 38 | pipe.puts('123') 39 | read = pipe.gets 40 | assert(read.strip == "123") 41 | pipe.close 42 | end 43 | 44 | it 'Sends EOF when the output pipe is closed' do 45 | pipe = IO.popen('ruby -e "data = STDIN.read; puts data"', "r+") 46 | pipe.write('123') 47 | pipe.close_write 48 | read = pipe.read 49 | assert(read.strip == "123") 50 | pipe.close 51 | end 52 | 53 | it 'Yeilds the IO like object instead of returning it if a block is provided' do 54 | data = 'failed' 55 | IO.popen('ruby -e "data = STDIN.read; puts data"', "r+") do |io| 56 | io.puts('success') 57 | io.close_write 58 | data = io.gets.strip 59 | end 60 | assert(data == 'success') 61 | end 62 | 63 | it 'Closes the IO object after yielding to a block' do 64 | io_ref = nil 65 | IO.popen('ruby -e "data = STDIN.read; puts data"', "r+") do |io| 66 | io_ref = io 67 | def io.close 68 | @i_closed = true 69 | end 70 | def io.did_you_close? 71 | @i_closed ||= false 72 | end 73 | end 74 | assert(io_ref.did_you_close?) 75 | end 76 | 77 | it 'Handles \\r\\n & \\n line endings in text mode' do 78 | pending 79 | end 80 | end 81 | 82 | describe 'IO.pipe' do 83 | it 'Both pipes are closed & freed after each is garbage collected' do 84 | # Right now you have to close them manually. 85 | # Going to have to track, on the C side, when each is GC'ed 86 | # Need to do the same for ordinary files 87 | # TODO: Verify, but I'm pretty sure APR pool GC has been implemented, 88 | # and covers this case. 89 | pending 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /specs/ruby_kernel.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new("Ruby API: Kernel") do 4 | describe 'Kernel::` (backquote)' do 5 | it 'Runs a command and returns it\'s standard output' do 6 | assert(`echo 1234`.strip == '1234') 7 | end 8 | 9 | it 'Sets $? based on the exit status of the child process' do 10 | `exit 1` 11 | assert($?.exitstatus == 1) 12 | `exit 2` 13 | assert($?.exitstatus == 2) 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /specs/ruby_process.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | APR::Spec.new('Ruby API: Process') do 4 | file_for_writing = "#{$GEM_DIR}/sandbox/file_for_writing.txt" 5 | 6 | describe 'Process::spawn' do 7 | it 'Spawns a shell command if given a string' do 8 | # If there is a shell involved, the command executed below should be 9 | # interpretted, and the environment variable expanded. So, if we 10 | # correctly utilize the shall, the variable's value should be printed 11 | # instead of the variable's name. 12 | ENV["I_SHOULD_NOT_BE_PRINTED"] = "I should be printed" 13 | 14 | cmd = nil 15 | unless /windows/i =~ ENV['OS'] 16 | cmd = 'ruby -e "puts \"$I_SHOULD_NOT_BE_PRINTED\""' 17 | else 18 | cmd = 'ruby -e "puts \"%I_SHOULD_NOT_BE_PRINTED%\""' 19 | end 20 | 21 | r, w = IO.pipe 22 | pid = Process.spawn(cmd, out: w) 23 | w.close 24 | 25 | assert(r.read.strip == 'I should be printed') 26 | r.close 27 | end 28 | 29 | it 'Interprets shell command arguments correctly' do 30 | capture_out = proc do |cmd| 31 | r, w = IO.pipe 32 | pid = Process.spawn(*cmd, out: w) 33 | w.close 34 | result = r.read 35 | r.close 36 | result.strip 37 | end 38 | 39 | # Command with double quotes 40 | assert '1' == capture_out[%q[ruby -e "puts(1)"]] 41 | # Single quote in double quotes 42 | assert 'String' == capture_out[%q[ruby -e "puts '2'.class"]] 43 | # Double quotes in single quotes 44 | assert 'String' == capture_out[%q[ruby -e 'puts "3".class']] 45 | # Nesting quotes, escaped from the shell (%q does not require escaping \) 46 | assert 'String' == capture_out[%q[ruby -e "puts \"4\".class"]] 47 | # Command combinations 48 | assert 'FAILED' != capture_out[ %q[ ruby -e "exit 0" || ruby -e "puts 'FAILED'" ]] 49 | assert 'SUCCESS' == capture_out[ %q[ ruby -e "exit 0" && ruby -e "puts 'SUCCESS'" ]] 50 | assert 'SUCCESS' == capture_out[ %q[ ruby -e "exit 1" || ruby -e "puts 'SUCCESS'" ]] 51 | assert 'FAILED' != capture_out[ %q[ ruby -e "exit 1" && ruby -e "puts 'FAILED'" ]] 52 | end 53 | 54 | it 'Spawns a program from the path, with no shell, if given argv as multiple args' do 55 | # If there was a shell involved, the command executed below would be 56 | # interpretted, and the environment variable expanded. So, if we 57 | # correctly bypass the shall, the variable name should be printed 58 | # instead of the variable's value. 59 | ENV["I_SHOULD_BE_PRINTED"] = "I should not" 60 | 61 | cmd = nil 62 | unless /windows/i =~ ENV['OS'] 63 | cmd = ['ruby', '-e', 'puts "$I_SHOULD_BE_PRINTED"'] 64 | else 65 | cmd = ['ruby', '-e', 'puts "%I_SHOULD_BE_PRINTED%"'] 66 | end 67 | 68 | r, w = IO.pipe 69 | pid = Process.spawn(*cmd, out: w) 70 | w.close 71 | 72 | result = r.read 73 | assert(result.include? 'I_SHOULD_BE_PRINTED') 74 | 75 | # TODO Test commands with slashes not preceding quote, slashes preceding quote, and even/odd number of trailing slashes (because windows sucks) 76 | end 77 | 78 | it 'Quotes arguments to non-shell commands correctly' do 79 | break unless /windows/i =~ ENV['OS'] 80 | ENV["I_SHOULD_BE_PRINTED"] = "I should not" 81 | 82 | # This command is going to be processed by Process.spawn, 83 | # subbing '\"' for every '"'. This tests makes sure the argument 84 | # still reaches the child command correctly. (CommandLineToArgvW 85 | # should be constructing argv for the command, and converting 86 | # the escaped quotes into regular quotes) 87 | cmd = ['ruby', '-e', 'puts("%I_SHOULD_BE_PRINTED%")'] 88 | 89 | r, w = IO.pipe 90 | pid = Process.spawn(*cmd, out: w) 91 | w.close 92 | 93 | result = r.read 94 | assert(result.include? 'I_SHOULD_BE_PRINTED') 95 | 96 | # TODO Test commands with slashes not preceding quote, slashes preceding quote, and even/odd number of trailing slashes (because windows sucks) 97 | end 98 | 99 | it 'Can spawn a non shell command on windows with spaces in the name' do 100 | break unless /windows/i =~ ENV['OS'] 101 | cmd = ["#{$GEM_DIR}/sandbox/windows print three args.exe", 'simple commands don\'t have spaces', '"\'"s', 'or \'"\'s'] 102 | 103 | r, w = IO.pipe 104 | pid = Process.spawn(*cmd, out: w) 105 | w.close 106 | 107 | result = r.read 108 | assert(result.strip == %q[simple commands don't have spaces, "'"s, or '"'s]) 109 | 110 | # TODO Test commands with slashes not preceding quote, slashes preceding quote, and even/odd number of trailing slashes (because windows sucks) 111 | end 112 | 113 | it 'Handles quoted arguments with spaces & an even number of trailing backslashes on windows' do 114 | break unless /windows/i =~ ENV['OS'] 115 | cmd = ["#{$GEM_DIR}/sandbox/windows print three args.exe", '1', '2', '3 \\\\'] 116 | 117 | r, w = IO.pipe 118 | pid = Process.spawn(*cmd, out: w) 119 | w.close 120 | 121 | result = r.read 122 | assert(result.strip == %q[1, 2, 3 \\\\]) 123 | end 124 | 125 | it 'Handles quoted arguments with spaces & an odd number of trailing backslashes on windows' do 126 | break unless /windows/i =~ ENV['OS'] 127 | cmd = ["#{$GEM_DIR}/sandbox/windows print three args.exe", '1', '2', '3 \\\\\\'] 128 | 129 | r, w = IO.pipe 130 | pid = Process.spawn(*cmd, out: w) 131 | w.close 132 | 133 | result = r.read 134 | assert(result.strip == %q[1, 2, 3 \\\\\\]) 135 | end 136 | 137 | it 'Handles arguments with an even number slashes preceding quotes on Windows' do 138 | break unless /windows/i =~ ENV['OS'] 139 | cmd = ["#{$GEM_DIR}/sandbox/windows print three args.exe", '1', '2', '"\\ \\\\"'] 140 | 141 | r, w = IO.pipe 142 | pid = Process.spawn(*cmd, out: w) 143 | w.close 144 | 145 | result = r.read 146 | assert(result.strip == %q[1, 2, "\\ \\\\"]) 147 | end 148 | 149 | it 'Handles arguments with an odd number slashes preceding quotes on Windows' do 150 | break unless /windows/i =~ ENV['OS'] 151 | cmd = ["#{$GEM_DIR}/sandbox/windows print three args.exe", '1', '2', '"\\"'] 152 | 153 | r, w = IO.pipe 154 | pid = Process.spawn(*cmd, out: w) 155 | w.close 156 | 157 | result = r.read 158 | assert(result.strip == %q[1, 2, "\\"]) 159 | end 160 | 161 | it 'Handles arguments with slashes not preceding quotes on windows' do 162 | break unless /windows/i =~ ENV['OS'] 163 | cmd = ["#{$GEM_DIR}/sandbox/windows print three args.exe", '1', '2', '\\'] 164 | 165 | r, w = IO.pipe 166 | pid = Process.spawn(*cmd, out: w) 167 | w.close 168 | 169 | result = r.read 170 | assert(result.strip == %q[1, 2, \\]) 171 | end 172 | 173 | it 'Supports redirecting in, out, & err streams to/from a Pipe\'s created by IO.pipe' do 174 | r, w = IO.pipe 175 | Process.spawn('ruby -e "puts \'my message\'"', out: w) 176 | w.close # Close in parent so we can get EOF 177 | msg = r.read 178 | r.close # Close read when finished so resources are cleaned up 179 | # Stripping because windows might end with \r\n, and unix with \n. 180 | assert (msg.strip == "my message") 181 | end 182 | 183 | it 'Supports redirecting to ordinary file objects' do 184 | out_file = File.open(file_for_writing, 'w') 185 | pid = Process.spawn("echo my message", out: out_file) 186 | out_file.close 187 | Process.wait(pid) 188 | read = nil 189 | File.open(file_for_writing) do |f| 190 | read = f.read 191 | end 192 | assert(read.strip == "my message") 193 | end 194 | end 195 | 196 | describe 'Process::wait' do 197 | it 'Sets $? based on the exit status of the indicated process' do 198 | pid = Process.spawn('ruby -e "exit 1"') 199 | Process.wait pid 200 | assert($?.exitstatus == 1) 201 | end 202 | 203 | it 'If called twice on the same PID, does the right thing... which is...?' do 204 | pending 205 | end 206 | end 207 | end 208 | -------------------------------------------------------------------------------- /specs/ruby_tcpsocket.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | begin 4 | Object.const_get(:MRUBY_VERSION) 5 | rescue 6 | # Running on MRI 7 | require 'socket' 8 | end 9 | 10 | APR::Spec.new('Ruby API: TCPSocket, & TCPServer') do 11 | describe "TCPSocket::new(remote_host, remote_port, local_host=nil, local_port=nil)" do 12 | it "Creates a connected TCP socket when given remote host & port" do 13 | s = TCPSocket.new("www.google.com", 80) 14 | s.write("GET http://www.google.com/ HTTP/1.1\nConnection: close\n\n") 15 | msg = s.read 16 | assert (msg =~ /200 OK/) 17 | end 18 | end 19 | 20 | describe "TCPSocket#write(str)" do 21 | # Tested by TCPSocket::new 22 | it "Writes the given str to the socket" 23 | end 24 | 25 | describe "TCPSocket#read(len=nil)" do 26 | # Tested by TCPSocket::new 27 | it "Reads from the socket until EOF (when the socket is closed)" 28 | 29 | it "Reads at most len bytes if len is provided" do 30 | s = TCPSocket.new("www.google.com", 80) 31 | s.write("GET http://www.google.com/ HTTP/1.1\n\n") 32 | msg = s.read(100) 33 | assert (msg =~ /200 OK/ && msg.length == 100) 34 | end 35 | 36 | it "Returns the empty string after EOF has been encountered, if length is not provided" do 37 | s = TCPSocket.new("www.google.com", 80) 38 | s.write("GET http://www.google.com/ HTTP/1.1\nConnection: close\n\n") 39 | s.read # Read all input 40 | second_response = s.read # Should be nothing left 41 | assert (second_response == '') 42 | end 43 | 44 | it "Returns nil after EOF has been encountered, if length is provided" do 45 | s = TCPSocket.new("www.google.com", 80) 46 | s.write("GET http://www.google.com/ HTTP/1.1\nConnection: close\n\n") 47 | s.read # Read all input 48 | second_response = s.read(10) # Should be nothing left 49 | assert (second_response == nil) 50 | end 51 | end 52 | 53 | describe "TCPSocket#recv(maxlen)" do 54 | it "Reads at most maxlen bytes" do 55 | s = TCPSocket.new("www.google.com", 80) 56 | s.write("GET http://www.google.com/ HTTP/1.1\n\n") 57 | msg = s.recv(100) 58 | assert (msg =~ /200 OK/ && msg.length == 100) 59 | end 60 | end 61 | 62 | describe "TCPSocket#close_read" do 63 | it "Closes a socket for reading" do 64 | exc = nil 65 | begin 66 | s = TCPSocket.new("www.google.com", 80) 67 | s.write("GET http://www.google.com/ HTTP/1.1\n\n") 68 | s.close_read 69 | puts s.read(100) 70 | rescue Exception => e 71 | exc = e 72 | end 73 | 74 | assert (exc.class == IOError) 75 | end 76 | end 77 | 78 | describe "TCPSocket#close_write" do 79 | it "Closes a socket for writing" do 80 | exc = nil 81 | begin 82 | s = TCPSocket.new("www.google.com", 80) 83 | s.close_write 84 | s.write("GET http://www.google.com/ HTTP/1.1\n\n") 85 | rescue Exception => e 86 | exc = e 87 | end 88 | 89 | assert (exc.class == IOError) 90 | end 91 | end 92 | 93 | describe "TCPSocket#close" do 94 | it "Closes a socket for reading & writing" do 95 | exc = nil 96 | s = TCPSocket.new("www.google.com", 80) 97 | s.close 98 | 99 | begin 100 | s.write("GET http://www.google.com/ HTTP/1.1\n\n") 101 | rescue Exception => e 102 | exc = e 103 | end 104 | assert (exc.class == IOError) 105 | 106 | begin 107 | s.read 108 | rescue Exception => e 109 | exc = e 110 | end 111 | assert (exc.class == IOError) 112 | end 113 | end 114 | 115 | describe "TCPSocket#eof?" do 116 | it "Returns true if the socket has been closed by the peer" do 117 | s = TCPSocket.new("www.google.com", 80) 118 | s.write("GET http://www.google.com/ HTTP/1.1\nConnection: close\n\n") 119 | assert(!s.eof?) 120 | s.read 121 | assert(s.eof?) 122 | end 123 | end 124 | 125 | describe "TCPSocket#gets" do 126 | it "Read from the socket one line at a time" do 127 | s = TCPSocket.new("www.google.com", 80) 128 | s.write("GET http://www.google.com/ HTTP/1.1\nConnection: close\n\n") 129 | assert (s.gets =~ /200 OK\s+$/) 130 | hit_content_type = false 131 | while line = s.gets 132 | hit_content_type = true if line =~ /^Content-Type:/ 133 | end 134 | assert(hit_content_type) 135 | end 136 | end 137 | 138 | describe "TCPServer::new([hostname], port)" do 139 | it "Creates a new TCPServer on the given port" do 140 | server = TCPServer.new('localhost', 9999) 141 | server.listen(1) 142 | 143 | client = TCPSocket.new('localhost', 9999) 144 | client.write('client to server') 145 | client.close 146 | 147 | server_client_handle = server.accept 148 | result = server_client_handle.read 149 | assert (result == 'client to server') 150 | end 151 | end 152 | end 153 | -------------------------------------------------------------------------------- /specs/ruby_udpsocket.rb: -------------------------------------------------------------------------------- 1 | load 'fixture.rb' 2 | 3 | begin 4 | Object.const_get(:MRUBY_VERSION) 5 | rescue 6 | # Running on MRI 7 | require 'socket' 8 | end 9 | 10 | APR::Spec.new('Ruby API: UDPSocket') do 11 | describe "UDPSocket::read(length=nil)" do 12 | it "Reads at most length bytes from a bound UDPSocket" do 13 | server = UDPSocket.new() 14 | server.bind('localhost', 9999) 15 | 16 | msg = 'client to server' 17 | io = IO.popen("ruby", 'w') 18 | io.write(<<-EOS) 19 | require 'socket' 20 | client = UDPSocket.new() 21 | client.connect('localhost', 9999) 22 | client.write('#{msg}') 23 | client.close 24 | EOS 25 | io.close 26 | 27 | result = server.read(msg.length) 28 | assert (result == msg) 29 | server.close 30 | end 31 | 32 | it "Reads consecutive packets as a stream" do 33 | server = UDPSocket.new() 34 | server.bind('localhost', 9999) 35 | 36 | io = IO.popen("ruby", 'w') 37 | io.write(<<-EOS) 38 | require 'socket' 39 | 40 | client = UDPSocket.new() 41 | client.connect('localhost', 9999) 42 | client.write('one') 43 | client.close 44 | 45 | client2 = UDPSocket.new() 46 | client2.connect('localhost', 9999) 47 | client2.write('two') 48 | client2.close 49 | EOS 50 | io.close 51 | 52 | result = server.read(6) 53 | assert (result == 'onetwo') 54 | server.close 55 | end 56 | end 57 | 58 | describe "UDPSocket::recv(maxlen)" do 59 | it "Reads at most maxlen bytes from a bound UDPSocket" do 60 | server = UDPSocket.new() 61 | server.bind('localhost', 9999) 62 | 63 | msg = 'client to server' 64 | io = IO.popen("ruby", 'w') 65 | io.write(<<-EOS) 66 | require 'socket' 67 | client = UDPSocket.new() 68 | client.connect('localhost', 9999) 69 | client.write('#{msg}') 70 | client.close 71 | EOS 72 | io.close 73 | 74 | result = server.recv(msg.length) 75 | assert (result == msg) 76 | server.close 77 | end 78 | end 79 | 80 | describe "UDPSocket::recvfrom(maxlen)" do 81 | it "Reads from a bound UDPSocket, returning the sender's address" do 82 | server = UDPSocket.new() 83 | server.bind('localhost', 9999) 84 | 85 | msg = 'client to server' 86 | io = IO.popen("ruby", 'w') 87 | io.write(<<-EOS) 88 | require 'socket' 89 | client = UDPSocket.new() 90 | client.connect('localhost', 9999) 91 | client.write('#{msg}') 92 | client.close 93 | EOS 94 | io.close 95 | 96 | received, addrinfo = server.recvfrom(msg.length) 97 | assert (received == msg) 98 | assert (addrinfo[0] == 'AF_INET') 99 | assert (addrinfo[2] == 'localhost') 100 | server.close 101 | end 102 | end 103 | 104 | describe "UDPSocket::write(str)" do 105 | it "Writes the given string to a connected UDPSocket" do 106 | msg = 'client to server' 107 | io = IO.popen("ruby", 'w') 108 | io.write(<<-EOS) 109 | require 'socket' 110 | client = UDPSocket.new() 111 | client.bind('localhost', 9999) 112 | client.connect('localhost', 9998) 113 | client.write client.read(#{msg.length}).reverse 114 | client.close 115 | EOS 116 | io.close_write 117 | 118 | `sleep 1` 119 | 120 | server = UDPSocket.new() 121 | server.bind('localhost', 9998) 122 | server.connect('localhost', 9999) 123 | server.write(msg) 124 | assert (server.read(msg.length).reverse == msg) 125 | end 126 | end 127 | end 128 | -------------------------------------------------------------------------------- /src/mruby_apr_dir_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_dir_t 3 | * Defined in file apr_file_info.h @ line 121 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Dir_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Dir::initialize */ 16 | /* sha: 59df0c9500b378b8231133135551efbccfb6326b700b95aefec564d7c90cd8e1 */ 17 | #if BIND_Dir_INITIALIZE 18 | mrb_value 19 | mrb_APR_Dir_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_dir_t* native_object = (apr_dir_t*)calloc(1, sizeof(apr_dir_t)); 23 | mruby_gift_apr_dir_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Dir_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Dir::class_definition */ 42 | /* sha: 2ce0af74e22b9cbf59cec741314680d7278d632acceb66e94d0a6fd9d9081b7a */ 43 | struct RClass* Dir_class = mrb_define_class_under(mrb, APR_module(mrb), "Dir", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Dir_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Dir::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Dir::class_method_definitions */ 53 | /* sha: 0a23c41cfaa5de27a056220d5e833aa3f60fc8f348ae929caa46a728bcbe4ea9 */ 54 | #if BIND_Dir_INITIALIZE 55 | mrb_define_method(mrb, Dir_class, "initialize", mrb_APR_Dir_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Dir::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_file_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_file_t 3 | * Defined in file apr_file_info.h @ line 212 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_File_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: File::initialize */ 16 | /* sha: 7fb1148a0e01622586ac548c8cfae4578c8004d50526f93ebac9ed34d3a3af0e */ 17 | #if BIND_File_INITIALIZE 18 | mrb_value 19 | mrb_APR_File_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_file_t* native_object = (apr_file_t*)calloc(1, sizeof(apr_file_t)); 23 | mruby_gift_apr_file_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_File_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: File::class_definition */ 42 | /* sha: b69fb80aeec311c3f2dd37f1a8fad37541260b56ae6d8b996fda2021d56df681 */ 43 | struct RClass* File_class = mrb_define_class_under(mrb, APR_module(mrb), "File", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(File_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: File::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: File::class_method_definitions */ 53 | /* sha: f45ddcd7e71c27adc3f1cf68b46c63e1c3333580d941e69087c0f33dce7b071c */ 54 | #if BIND_File_INITIALIZE 55 | mrb_define_method(mrb, File_class, "initialize", mrb_APR_File_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: File::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_finfo_t.c: -------------------------------------------------------------------------------- 1 | /* - MRUBY_BINDINGS_NO_CLOBBER - 2 | * apr_finfo_t 3 | * Defined in file apr_file_info.h @ line 143 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Finfo_TYPE 9 | 10 | mrb_value 11 | mrb_APR_Finfo_initialize(mrb_state* mrb, mrb_value self) { 12 | apr_finfo_t* native_object = (apr_finfo_t*)malloc(sizeof(apr_finfo_t)); 13 | mruby_gift_apr_finfo_t_data_ptr(self, native_object); 14 | return self; 15 | } 16 | 17 | mrb_value 18 | mrb_APR_Finfo_get_pool(mrb_state* mrb, mrb_value self) { 19 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 20 | 21 | apr_pool_t * native_field = native_self->pool; 22 | 23 | mrb_value ruby_field = (native_field == NULL ? mrb_nil_value() : mruby_box_apr_pool_t(mrb, native_field)); 24 | /* Store the ruby object to prevent garage collection of the underlying native object */ 25 | mrb_iv_set(mrb, self, mrb_intern_cstr(mrb, "@pool_box"), ruby_field); 26 | 27 | return ruby_field; 28 | } 29 | 30 | mrb_value 31 | mrb_APR_Finfo_get_valid(mrb_state* mrb, mrb_value self) { 32 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 33 | apr_int32_t native_field = native_self->valid; 34 | mrb_value ruby_field = mrb_fixnum_value(native_field); 35 | return ruby_field; 36 | } 37 | 38 | 39 | mrb_value 40 | mrb_APR_Finfo_get_protection(mrb_state* mrb, mrb_value self) { 41 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 42 | apr_fileperms_t native_field = native_self->protection; 43 | mrb_value ruby_field = mrb_fixnum_value(native_field); 44 | return ruby_field; 45 | } 46 | 47 | 48 | mrb_value 49 | mrb_APR_Finfo_get_filetype(mrb_state* mrb, mrb_value self) { 50 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 51 | apr_filetype_e native_field = native_self->filetype; 52 | mrb_value ruby_field = mrb_fixnum_value(native_field); 53 | return ruby_field; 54 | } 55 | 56 | 57 | mrb_value 58 | mrb_APR_Finfo_get_device(mrb_state* mrb, mrb_value self) { 59 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 60 | apr_dev_t native_field = native_self->device; 61 | mrb_value ruby_field = mrb_fixnum_value(native_field); 62 | return ruby_field; 63 | } 64 | 65 | mrb_value 66 | mrb_APR_Finfo_get_nlink(mrb_state* mrb, mrb_value self) { 67 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 68 | apr_int32_t native_field = native_self->nlink; 69 | if (native_field > MRB_INT_MAX) { 70 | mrb_raise(mrb, mrb->eStandardError_class, "MRuby cannot represent integers greater than MRB_INT_MAX"); 71 | return mrb_nil_value(); 72 | } 73 | mrb_value ruby_field = mrb_fixnum_value(native_field); 74 | return ruby_field; 75 | } 76 | 77 | mrb_value 78 | mrb_APR_Finfo_get_size(mrb_state* mrb, mrb_value self) { 79 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 80 | apr_off_t native_field = native_self->size; 81 | if (native_field > MRB_INT_MAX) { 82 | mrb_raise(mrb, mrb->eStandardError_class, "MRuby cannot represent integers greater than MRB_INT_MAX"); 83 | return mrb_nil_value(); 84 | } 85 | mrb_value ruby_field = mrb_fixnum_value(native_field); 86 | return ruby_field; 87 | } 88 | 89 | mrb_value 90 | mrb_APR_Finfo_get_csize(mrb_state* mrb, mrb_value self) { 91 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 92 | apr_off_t native_field = native_self->csize; 93 | if (native_field > MRB_INT_MAX) { 94 | mrb_raise(mrb, mrb->eStandardError_class, "MRuby cannot represent integers greater than MRB_INT_MAX"); 95 | return mrb_nil_value(); 96 | } 97 | mrb_value ruby_field = mrb_fixnum_value(native_field); 98 | return ruby_field; 99 | } 100 | 101 | mrb_value 102 | mrb_APR_Finfo_get_atime(mrb_state* mrb, mrb_value self) { 103 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 104 | return mrb_fixnum_value(native_self->atime); 105 | } 106 | 107 | mrb_value 108 | mrb_APR_Finfo_get_mtime(mrb_state* mrb, mrb_value self) { 109 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 110 | return mrb_fixnum_value(native_self->mtime); 111 | } 112 | 113 | mrb_value 114 | mrb_APR_Finfo_get_ctime(mrb_state* mrb, mrb_value self) { 115 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 116 | return mrb_fixnum_value(native_self->ctime); 117 | } 118 | 119 | mrb_value 120 | mrb_APR_Finfo_get_fname(mrb_state* mrb, mrb_value self) { 121 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 122 | const char * native_field = native_self->fname; 123 | mrb_value ruby_field = mrb_str_new_cstr(mrb, native_field); 124 | return ruby_field; 125 | } 126 | 127 | mrb_value 128 | mrb_APR_Finfo_get_name(mrb_state* mrb, mrb_value self) { 129 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 130 | const char * native_field = native_self->name; 131 | mrb_value ruby_field = mrb_str_new_cstr(mrb, native_field); 132 | return ruby_field; 133 | } 134 | 135 | mrb_value 136 | mrb_APR_Finfo_get_filehand(mrb_state* mrb, mrb_value self) { 137 | apr_finfo_t * native_self = mruby_unbox_apr_finfo_t(self); 138 | struct apr_file_t * native_field = native_self->filehand; 139 | mrb_value ruby_field = (native_field == NULL ? mrb_nil_value() : mruby_box_apr_file_t(mrb, native_field)); 140 | return ruby_field; 141 | } 142 | 143 | 144 | void mrb_APR_Finfo_init(mrb_state* mrb) { 145 | struct RClass* Finfo_class = mrb_define_class_under(mrb, APR_module(mrb), "Finfo", mrb->object_class); 146 | MRB_SET_INSTANCE_TT(Finfo_class, MRB_TT_DATA); 147 | 148 | mrb_define_method(mrb, Finfo_class, "initialize", mrb_APR_Finfo_initialize, MRB_ARGS_NONE()); 149 | 150 | mrb_define_method(mrb, Finfo_class, "pool", mrb_APR_Finfo_get_pool, MRB_ARGS_ARG(0, 0)); 151 | mrb_define_method(mrb, Finfo_class, "valid", mrb_APR_Finfo_get_valid, MRB_ARGS_ARG(0, 0)); 152 | mrb_define_method(mrb, Finfo_class, "protection", mrb_APR_Finfo_get_protection, MRB_ARGS_ARG(0, 0)); 153 | mrb_define_method(mrb, Finfo_class, "filetype", mrb_APR_Finfo_get_filetype, MRB_ARGS_ARG(0, 0)); 154 | mrb_define_method(mrb, Finfo_class, "device", mrb_APR_Finfo_get_device, MRB_ARGS_ARG(0, 0)); 155 | mrb_define_method(mrb, Finfo_class, "nlink", mrb_APR_Finfo_get_nlink, MRB_ARGS_ARG(0, 0)); 156 | mrb_define_method(mrb, Finfo_class, "size", mrb_APR_Finfo_get_size, MRB_ARGS_ARG(0, 0)); 157 | mrb_define_method(mrb, Finfo_class, "csize", mrb_APR_Finfo_get_csize, MRB_ARGS_ARG(0, 0)); 158 | mrb_define_method(mrb, Finfo_class, "atime", mrb_APR_Finfo_get_atime, MRB_ARGS_ARG(0, 0)); 159 | mrb_define_method(mrb, Finfo_class, "mtime", mrb_APR_Finfo_get_mtime, MRB_ARGS_ARG(0, 0)); 160 | mrb_define_method(mrb, Finfo_class, "ctime", mrb_APR_Finfo_get_ctime, MRB_ARGS_ARG(0, 0)); 161 | mrb_define_method(mrb, Finfo_class, "fname", mrb_APR_Finfo_get_fname, MRB_ARGS_ARG(0, 0)); 162 | mrb_define_method(mrb, Finfo_class, "name", mrb_APR_Finfo_get_name, MRB_ARGS_ARG(0, 0)); 163 | mrb_define_method(mrb, Finfo_class, "filehand", mrb_APR_Finfo_get_filehand, MRB_ARGS_ARG(0, 0)); 164 | 165 | } 166 | 167 | #endif 168 | -------------------------------------------------------------------------------- /src/mruby_apr_global_mutex_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_global_mutex_t 3 | * Defined in file apr_global_mutex.h @ line 46 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_GlobalMutex_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: GlobalMutex::initialize */ 16 | /* sha: 0c460c6e17cae2ee552a536ea5349a51e70b3104734125f4b7c78caa084b28ca */ 17 | #if BIND_GlobalMutex_INITIALIZE 18 | mrb_value 19 | mrb_APR_GlobalMutex_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_global_mutex_t* native_object = (apr_global_mutex_t*)calloc(1, sizeof(apr_global_mutex_t)); 23 | mruby_gift_apr_global_mutex_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_GlobalMutex_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: GlobalMutex::class_definition */ 42 | /* sha: 5b51c28a094b11c57462017e43966700fae02510dfbccc90fc2d9166d17dcd0f */ 43 | struct RClass* GlobalMutex_class = mrb_define_class_under(mrb, APR_module(mrb), "GlobalMutex", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(GlobalMutex_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: GlobalMutex::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: GlobalMutex::class_method_definitions */ 53 | /* sha: f2da77931083ab470cf0d4841a37642e4bae414b5c1253488bcddc976a38f983 */ 54 | #if BIND_GlobalMutex_INITIALIZE 55 | mrb_define_method(mrb, GlobalMutex_class, "initialize", mrb_APR_GlobalMutex_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: GlobalMutex::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_ipsubnet_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_ipsubnet_t 3 | * Defined in file apr_network_io.h @ line 199 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Ipsubnet_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Ipsubnet::initialize */ 16 | /* sha: bd5c30444357cfb44faa078fcd8447e65073975928bc1390f58ec5f281e1f6d8 */ 17 | #if BIND_Ipsubnet_INITIALIZE 18 | mrb_value 19 | mrb_APR_Ipsubnet_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_ipsubnet_t* native_object = (apr_ipsubnet_t*)calloc(1, sizeof(apr_ipsubnet_t)); 23 | mruby_gift_apr_ipsubnet_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Ipsubnet_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Ipsubnet::class_definition */ 42 | /* sha: 4e353fcd1b406b70ff682e8cee199feb256a46b49b19ee448af68574451b081d */ 43 | struct RClass* Ipsubnet_class = mrb_define_class_under(mrb, APR_module(mrb), "Ipsubnet", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Ipsubnet_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Ipsubnet::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Ipsubnet::class_method_definitions */ 53 | /* sha: 38a193ee422f8cdf7947ca85cb684ae2095e174061759ae45816113ec17d90e7 */ 54 | #if BIND_Ipsubnet_INITIALIZE 55 | mrb_define_method(mrb, Ipsubnet_class, "initialize", mrb_APR_Ipsubnet_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Ipsubnet::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_other_child_rec_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_other_child_rec_t 3 | * Defined in file apr_thread_proc.h @ line 192 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_OtherChildRec_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: OtherChildRec::initialize */ 16 | /* sha: 81afc0525883aaca96c40db02853ebac43af9d9fec62ff3376f6fc54e4d4bfb1 */ 17 | #if BIND_OtherChildRec_INITIALIZE 18 | mrb_value 19 | mrb_APR_OtherChildRec_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_other_child_rec_t* native_object = (apr_other_child_rec_t*)calloc(1, sizeof(apr_other_child_rec_t)); 23 | mruby_gift_apr_other_child_rec_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_OtherChildRec_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: OtherChildRec::class_definition */ 42 | /* sha: 60246a90d5a6be009fdeed81404951eef297f402e9baa72ab50c335065aa647c */ 43 | struct RClass* OtherChildRec_class = mrb_define_class_under(mrb, APR_module(mrb), "OtherChildRec", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(OtherChildRec_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: OtherChildRec::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: OtherChildRec::class_method_definitions */ 53 | /* sha: 262e9bb11f26b26bf2d13043b2d4e88800d55b850c7e4c54928b49c04a0798e3 */ 54 | #if BIND_OtherChildRec_INITIALIZE 55 | mrb_define_method(mrb, OtherChildRec_class, "initialize", mrb_APR_OtherChildRec_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: OtherChildRec::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_pool_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_pool_t 3 | * Defined in file apr_pools.h @ line 60 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Pool_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Pool::initialize */ 16 | /* sha: 188a895df6ae319edaabc00533d3faa5487c060ec49b9bb6b04765fa8ad39340 */ 17 | #if BIND_Pool_INITIALIZE 18 | mrb_value 19 | mrb_APR_Pool_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_pool_t* native_object = (apr_pool_t*)calloc(1, sizeof(apr_pool_t)); 23 | mruby_gift_apr_pool_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Pool_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Pool::class_definition */ 42 | /* sha: 5075c7cb95f4205b6c43e98ba02e2898126a85beb5ff1dbd026782ffaa3ed48d */ 43 | struct RClass* Pool_class = mrb_define_class_under(mrb, APR_module(mrb), "Pool", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Pool_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Pool::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Pool::class_method_definitions */ 53 | /* sha: ad3762668a91ddc8a364ac98ed88530023c05663bb065f37533eccddf609e1f1 */ 54 | #if BIND_Pool_INITIALIZE 55 | mrb_define_method(mrb, Pool_class, "initialize", mrb_APR_Pool_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Pool::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_proc_mutex_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_proc_mutex_t 3 | * Defined in file apr_proc_mutex.h @ line 54 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_ProcMutex_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: ProcMutex::initialize */ 16 | /* sha: 2619695d73b69bccc0a6d3bf25cde2450ce683b21a04ba47f37ba416663cc8f6 */ 17 | #if BIND_ProcMutex_INITIALIZE 18 | mrb_value 19 | mrb_APR_ProcMutex_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_proc_mutex_t* native_object = (apr_proc_mutex_t*)calloc(1, sizeof(apr_proc_mutex_t)); 23 | mruby_gift_apr_proc_mutex_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_ProcMutex_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: ProcMutex::class_definition */ 42 | /* sha: b36705547566f5c49979781af8737d3646e1ed9fcd8b6cbe043c41bf306eb9f9 */ 43 | struct RClass* ProcMutex_class = mrb_define_class_under(mrb, APR_module(mrb), "ProcMutex", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(ProcMutex_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: ProcMutex::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: ProcMutex::class_method_definitions */ 53 | /* sha: b3319f3ac53a91046d80f0e2e80c8cf2636ace82242957605bd0c0ce62eb8717 */ 54 | #if BIND_ProcMutex_INITIALIZE 55 | mrb_define_method(mrb, ProcMutex_class, "initialize", mrb_APR_ProcMutex_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: ProcMutex::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_proc_t.c: -------------------------------------------------------------------------------- 1 | /* - MRUBY_BINDINGS_NO_CLOBBER - 2 | * apr_proc_t 3 | * Defined in file apr_thread_proc.h @ line 133 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Proc_TYPE 9 | 10 | mrb_value 11 | mrb_APR_Proc_initialize(mrb_state* mrb, mrb_value self) { 12 | apr_proc_t* native_object = (apr_proc_t*)malloc(sizeof(apr_proc_t)); 13 | mruby_gift_apr_proc_t_data_ptr(self, native_object); 14 | return self; 15 | } 16 | 17 | mrb_value 18 | mrb_APR_Proc_get_pid(mrb_state* mrb, mrb_value self) { 19 | apr_proc_t * native_self = mruby_unbox_apr_proc_t(self); 20 | pid_t native_field = native_self->pid; 21 | mrb_value ruby_field = mrb_fixnum_value(native_field); 22 | return ruby_field; 23 | } 24 | 25 | mrb_value 26 | mrb_APR_Proc_get_in(mrb_state* mrb, mrb_value self) { 27 | apr_proc_t * native_self = mruby_unbox_apr_proc_t(self); 28 | apr_file_t * native_field = native_self->in; 29 | mrb_value ruby_field = (native_field == NULL ? mrb_nil_value() : mruby_box_apr_file_t(mrb, native_field)); 30 | return ruby_field; 31 | } 32 | 33 | mrb_value 34 | mrb_APR_Proc_get_out(mrb_state* mrb, mrb_value self) { 35 | apr_proc_t * native_self = mruby_unbox_apr_proc_t(self); 36 | apr_file_t * native_field = native_self->out; 37 | mrb_value ruby_field = (native_field == NULL ? mrb_nil_value() : mruby_box_apr_file_t(mrb, native_field)); 38 | return ruby_field; 39 | } 40 | 41 | mrb_value 42 | mrb_APR_Proc_get_err(mrb_state* mrb, mrb_value self) { 43 | apr_proc_t * native_self = mruby_unbox_apr_proc_t(self); 44 | apr_file_t * native_field = native_self->err; 45 | mrb_value ruby_field = (native_field == NULL ? mrb_nil_value() : mruby_box_apr_file_t(mrb, native_field)); 46 | return ruby_field; 47 | } 48 | 49 | void mrb_APR_Proc_init(mrb_state* mrb) { 50 | struct RClass* Proc_class = mrb_define_class_under(mrb, APR_module(mrb), "Proc", mrb->object_class); 51 | MRB_SET_INSTANCE_TT(Proc_class, MRB_TT_DATA); 52 | 53 | mrb_define_method(mrb, Proc_class, "initialize", mrb_APR_Proc_initialize, MRB_ARGS_NONE()); 54 | 55 | mrb_define_method(mrb, Proc_class, "pid", mrb_APR_Proc_get_pid, MRB_ARGS_ARG(0, 0)); 56 | mrb_define_method(mrb, Proc_class, "in", mrb_APR_Proc_get_in, MRB_ARGS_ARG(0, 0)); 57 | mrb_define_method(mrb, Proc_class, "out", mrb_APR_Proc_get_out, MRB_ARGS_ARG(0, 0)); 58 | mrb_define_method(mrb, Proc_class, "err", mrb_APR_Proc_get_err, MRB_ARGS_ARG(0, 0)); 59 | } 60 | 61 | #endif 62 | -------------------------------------------------------------------------------- /src/mruby_apr_procattr_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_procattr_t 3 | * Defined in file apr_thread_proc.h @ line 183 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Procattr_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Procattr::initialize */ 16 | /* sha: f28c9d473065ee206f7b5eb54e026bf8d370af4a321fca9c8b00d74646f3059a */ 17 | #if BIND_Procattr_INITIALIZE 18 | mrb_value 19 | mrb_APR_Procattr_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_procattr_t* native_object = (apr_procattr_t*)calloc(1, sizeof(apr_procattr_t)); 23 | mruby_gift_apr_procattr_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Procattr_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Procattr::class_definition */ 42 | /* sha: e01959b617640fc05b2f45ce32f4a8c353d7ad541881291738ce242811e08108 */ 43 | struct RClass* Procattr_class = mrb_define_class_under(mrb, APR_module(mrb), "Procattr", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Procattr_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Procattr::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Procattr::class_method_definitions */ 53 | /* sha: f77f51ee019e9cf8085c28fe0c7cbeb94451a7d83bc13254d3a687cb64b502d2 */ 54 | #if BIND_Procattr_INITIALIZE 55 | mrb_define_method(mrb, Procattr_class, "initialize", mrb_APR_Procattr_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Procattr::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_socket_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_socket_t 3 | * Defined in file apr_network_io.h @ line 191 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Socket_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Socket::initialize */ 16 | /* sha: 3f2356ce4f35e709b57222af064b4bb8777eb4ff4242684d9251ae1ae6fb2256 */ 17 | #if BIND_Socket_INITIALIZE 18 | mrb_value 19 | mrb_APR_Socket_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_socket_t* native_object = (apr_socket_t*)calloc(1, sizeof(apr_socket_t)); 23 | mruby_gift_apr_socket_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Socket_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Socket::class_definition */ 42 | /* sha: e20a33894c1f1d6c986b1cf41b73485df726f94faba4c31b301367241f68ea14 */ 43 | struct RClass* Socket_class = mrb_define_class_under(mrb, APR_module(mrb), "Socket", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Socket_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Socket::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Socket::class_method_definitions */ 53 | /* sha: 17dc079606987449ed036a7604e89d7807d71d02e8711d018a006bcba1bc9533 */ 54 | #if BIND_Socket_INITIALIZE 55 | mrb_define_method(mrb, Socket_class, "initialize", mrb_APR_Socket_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Socket::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_thread_once_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_thread_once_t 3 | * Defined in file apr_thread_proc.h @ line 186 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_ThreadOnce_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: ThreadOnce::initialize */ 16 | /* sha: 9bd6cb728e920ece2e9da7fb41930099fbb4fa662ba46ea5e046fa90290fd348 */ 17 | #if BIND_ThreadOnce_INITIALIZE 18 | mrb_value 19 | mrb_APR_ThreadOnce_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_thread_once_t* native_object = (apr_thread_once_t*)calloc(1, sizeof(apr_thread_once_t)); 23 | mruby_gift_apr_thread_once_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_ThreadOnce_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: ThreadOnce::class_definition */ 42 | /* sha: 67e4c7428206bc2128c80b564b9bb377c9be9567e64b8330eab8997aa87dd302 */ 43 | struct RClass* ThreadOnce_class = mrb_define_class_under(mrb, APR_module(mrb), "ThreadOnce", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(ThreadOnce_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: ThreadOnce::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: ThreadOnce::class_method_definitions */ 53 | /* sha: 6d454b3a48a061141bf745aebf4f4cbab59d11e5e6f0160e65677bad44e0c144 */ 54 | #if BIND_ThreadOnce_INITIALIZE 55 | mrb_define_method(mrb, ThreadOnce_class, "initialize", mrb_APR_ThreadOnce_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: ThreadOnce::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_thread_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_thread_t 3 | * Defined in file apr_thread_proc.h @ line 177 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Thread_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Thread::initialize */ 16 | /* sha: eca0695fb0dc749d2c76e2f42e43a25d03d8c0d881b640a4695b4f67ea6ce432 */ 17 | #if BIND_Thread_INITIALIZE 18 | mrb_value 19 | mrb_APR_Thread_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_thread_t* native_object = (apr_thread_t*)calloc(1, sizeof(apr_thread_t)); 23 | mruby_gift_apr_thread_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Thread_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Thread::class_definition */ 42 | /* sha: b1f41192ab79473ff0b5482cddfcd4fb5cdccd7a58afcabbfd158d0611535d47 */ 43 | struct RClass* Thread_class = mrb_define_class_under(mrb, APR_module(mrb), "Thread", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Thread_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Thread::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Thread::class_method_definitions */ 53 | /* sha: 1d30cd1cd6706e0963a9cec615deb6793aa4ca9ae4bac6567b0e640e658b7d96 */ 54 | #if BIND_Thread_INITIALIZE 55 | mrb_define_method(mrb, Thread_class, "initialize", mrb_APR_Thread_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Thread::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_threadattr_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_threadattr_t 3 | * Defined in file apr_thread_proc.h @ line 180 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Threadattr_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Threadattr::initialize */ 16 | /* sha: f852ef8b9a7f5566517f3f1014bb1adbdcb9cf0837cc37a232ebb7de1bce27a7 */ 17 | #if BIND_Threadattr_INITIALIZE 18 | mrb_value 19 | mrb_APR_Threadattr_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_threadattr_t* native_object = (apr_threadattr_t*)calloc(1, sizeof(apr_threadattr_t)); 23 | mruby_gift_apr_threadattr_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Threadattr_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Threadattr::class_definition */ 42 | /* sha: a1a8eb328af4819a0881fe198ce299b4471a05e0f2ac6cb7843d6c6a5cad03f1 */ 43 | struct RClass* Threadattr_class = mrb_define_class_under(mrb, APR_module(mrb), "Threadattr", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Threadattr_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Threadattr::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Threadattr::class_method_definitions */ 53 | /* sha: e12802d75f2843858a1e908e2b1c448e35d36045cab15e1acac66c2740a7a3f8 */ 54 | #if BIND_Threadattr_INITIALIZE 55 | mrb_define_method(mrb, Threadattr_class, "initialize", mrb_APR_Threadattr_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Threadattr::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | -------------------------------------------------------------------------------- /src/mruby_apr_threadkey_t.c: -------------------------------------------------------------------------------- 1 | /* 2 | * apr_threadkey_t 3 | * Defined in file apr_thread_proc.h @ line 189 4 | */ 5 | 6 | #include "mruby_APR.h" 7 | 8 | #if BIND_Threadkey_TYPE 9 | 10 | /* MRUBY_BINDING: header */ 11 | /* sha: user_defined */ 12 | 13 | /* MRUBY_BINDING_END */ 14 | 15 | /* MRUBY_BINDING: Threadkey::initialize */ 16 | /* sha: 928a124f348d17a298ae63aa55fcafb957a6b559b71b0a8c035bbf18ecdc5bd7 */ 17 | #if BIND_Threadkey_INITIALIZE 18 | mrb_value 19 | mrb_APR_Threadkey_initialize(mrb_state* mrb, mrb_value self) { 20 | mrb_raise(mrb, E_NOMETHOD_ERROR, "No initializer defined"); 21 | /* 22 | apr_threadkey_t* native_object = (apr_threadkey_t*)calloc(1, sizeof(apr_threadkey_t)); 23 | mruby_gift_apr_threadkey_t_data_ptr(self, native_object); 24 | return self; 25 | */ 26 | } 27 | #endif 28 | /* MRUBY_BINDING_END */ 29 | 30 | 31 | void mrb_APR_Threadkey_init(mrb_state* mrb) { 32 | static int initialized = 0; 33 | if (initialized) return; 34 | else initialized = 1; 35 | 36 | /* MRUBY_BINDING: pre_class_definition */ 37 | /* sha: user_defined */ 38 | 39 | /* MRUBY_BINDING_END */ 40 | 41 | /* MRUBY_BINDING: Threadkey::class_definition */ 42 | /* sha: e8f2bb5b7961e1c21644014229bc34723587f0733c281d479217b0bd74d05568 */ 43 | struct RClass* Threadkey_class = mrb_define_class_under(mrb, APR_module(mrb), "Threadkey", mrb->object_class); 44 | MRB_SET_INSTANCE_TT(Threadkey_class, MRB_TT_DATA); 45 | /* MRUBY_BINDING_END */ 46 | 47 | /* MRUBY_BINDING: Threadkey::pre_class_method_definitions */ 48 | /* sha: user_defined */ 49 | 50 | /* MRUBY_BINDING_END */ 51 | 52 | /* MRUBY_BINDING: Threadkey::class_method_definitions */ 53 | /* sha: c4f591693005182f404b1f8dbdf4d7bc7e77fd23c21b98c2815667a53a124a24 */ 54 | #if BIND_Threadkey_INITIALIZE 55 | mrb_define_method(mrb, Threadkey_class, "initialize", mrb_APR_Threadkey_initialize, MRB_ARGS_NONE()); 56 | #endif 57 | /* MRUBY_BINDING_END */ 58 | 59 | 60 | 61 | /* MRUBY_BINDING: Threadkey::post_class_definition */ 62 | /* sha: user_defined */ 63 | 64 | /* MRUBY_BINDING_END */ 65 | } 66 | 67 | /* MRUBY_BINDING: footer */ 68 | /* sha: user_defined */ 69 | 70 | /* MRUBY_BINDING_END */ 71 | #endif 72 | --------------------------------------------------------------------------------