ffi-libc 0.0.3 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 0102b721ed989c2427b5531a522da0001f4dfda43cf1c295e8eda3071891e02d
4
+ data.tar.gz: 4e06ead22308e1fdb667d24defc2ea3a069d4737732b1ab046777b663a4d5e00
5
+ SHA512:
6
+ metadata.gz: 9c4a840ac2740ba51db453edc891b17db0fae22dfe5cebdf5598107b175377ba2436d1dfebbead02fec119bc10a39703b64fa74595467100c0ee35952871a303
7
+ data.tar.gz: beca1246d6d97ce653c508025f636c70c0dd19ffbd11ff4ffea569495b230f5d401819c89949607c5caa3b94baacc3be4b0c092933f1a2126ac13bfca8fd8fe5
@@ -0,0 +1,29 @@
1
+ name: CI
2
+
3
+ on: [ push, pull_request ]
4
+
5
+ jobs:
6
+ tests:
7
+ runs-on: ubuntu-latest
8
+ strategy:
9
+ fail-fast: false
10
+ matrix:
11
+ ruby:
12
+ - 2.4
13
+ - 2.5
14
+ - 2.6
15
+ - 2.7
16
+ - 3.0
17
+ - jruby
18
+ - truffleruby
19
+ name: Ruby ${{ matrix.ruby }}
20
+ steps:
21
+ - uses: actions/checkout@v2
22
+ - name: Set up Ruby
23
+ uses: ruby/setup-ruby@v1
24
+ with:
25
+ ruby-version: ${{ matrix.ruby }}
26
+ - name: Install dependencies
27
+ run: bundle install --jobs 4 --retry 3
28
+ - name: Run tests
29
+ run: bundle exec rake test
data/.gitignore CHANGED
@@ -1,4 +1,6 @@
1
- doc
2
- pkg
3
- .bundle
4
- .yardoc
1
+ /Gemfile.lock
2
+ /doc/
3
+ /pkg/
4
+ /.bundle
5
+ /.yardoc
6
+ /vendor/bundle
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --colour --format documentation
data/ChangeLog.md CHANGED
@@ -1,3 +1,47 @@
1
+ ### 0.1.1 / 2021-09-22
2
+
3
+ * Removed `sys_errlist` and `sys_nerr` variables, as they have been removed
4
+ from glibc (see:
5
+ https://sourceware.org/pipermail/libc-announce/2020/000029.html).
6
+ * Load `libc` via `FFI::Library::LIBC`.
7
+
8
+ ### 0.1.0 / 2013-08-15
9
+
10
+ * Require ffi ~> 1.0.
11
+ * Added `alarm`.
12
+ * Added `clock`.
13
+ * Added `getc`.
14
+ * Added `getchar`.
15
+ * Added `gets`.
16
+ * Added `ungetc`.
17
+ * Added `getifaddrs`.
18
+ * Added `puts`.
19
+ * Added `putchar`.
20
+ * Added `putc`.
21
+ * Added `strcmp`.
22
+ * Added `strncmp`.
23
+ * Added {FFI::LibC::NULL}.
24
+ * Added {FFI::LibC::Ifaddrs}.
25
+ * Added {FFI::LibC.raise_error}.
26
+ * Added {FFI::LibC.each_ifaddr}.
27
+ * Added {FFI::LibC.rusage}.
28
+
29
+ ### 0.0.5 / 2011-05-11
30
+
31
+ * Skip `clearenv`, `memrchr`, `stdin`, `stdout` and `stderr` if they cannot
32
+ be loaded (thanks FreneticEntropy and mephux).
33
+ * The `libc` installed on OSX lacks these functions/global-variables.
34
+ * Opt into `test.rubygems.org`.
35
+
36
+ ### 0.0.4 / 2011-02-03
37
+
38
+ * Require ffi >= 0.6.0, <= 1.1.0:
39
+ * JRuby requires ffi >= 1.0.0.
40
+ * A lot of projects still require ffi ~> 0.6.0.
41
+ * Added `stdin`.
42
+ * Added `stdout`.
43
+ * Added `stderr`.
44
+
1
45
  ### 0.0.3 / 2010-08-03
2
46
 
3
47
  * Load libc from the current process.
@@ -11,10 +55,10 @@
11
55
  * Added the Structs:
12
56
  * {FFI::LibC::InAddr}.
13
57
  * {FFI::LibC::In6Addr}.
14
- * {FFI::LibC::SockAddr}.
15
- * {FFI::LibC::SockAddrDL}.
16
- * {FFI::LibC::SockAddrIn}.
17
- * {FFI::LibC::SockAddrIn6}.
58
+ * {FFI::LibC::Sockaddr}.
59
+ * {FFI::LibC::SockaddrDL}.
60
+ * {FFI::LibC::SockaddrIn}.
61
+ * {FFI::LibC::SockaddrIn6}.
18
62
 
19
63
  ### 0.0.1 / 2010-05-19
20
64
 
data/Gemfile CHANGED
@@ -1,24 +1,11 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- group(:runtime) do
4
- gem 'ffi', '~> 0.6.0'
3
+ gemspec
4
+
5
+ group :development do
6
+ gem 'rake'
7
+ gem 'rubygems-tasks', '~> 0.2'
8
+ gem 'rspec', '~> 3.0'
9
+ gem 'kramdown'
10
+ gem 'yard', '~> 0.9'
5
11
  end
6
-
7
- group(:development) do
8
- gem 'bundler', '~> 0.9.25'
9
- gem 'rake', '~> 0.8.7'
10
- gem 'jeweler', '~> 1.4.0', :git => 'git://github.com/technicalpickles/jeweler.git'
11
- end
12
-
13
- group(:doc) do
14
- case RUBY_PLATFORM
15
- when 'java'
16
- gem 'maruku', '~> 0.6.0'
17
- else
18
- gem 'rdiscount', '~> 1.6.3'
19
- end
20
-
21
- gem 'yard', '~> 0.5.3'
22
- end
23
-
24
- gem 'rspec', '~> 1.3.0', :group => [:development, :test]
data/LICENSE.txt CHANGED
@@ -1,7 +1,4 @@
1
-
2
- The MIT License
3
-
4
- Copyright (c) 2010 Hal Brodigan
1
+ Copyright (c) 2010-2021 Hal Brodigan
5
2
 
6
3
  Permission is hereby granted, free of charge, to any person obtaining
7
4
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,8 +1,11 @@
1
1
  # ffi-libc
2
2
 
3
- * [github.com/postmodern/ffi-libc](http://github.com/postmodern/ffi-libc/)
4
- * [github.com/postmodern/ffi-libc/issues](http://github.com/postmodern/ffi-libc/issues)
5
- * Postmodern (postmodern.mod3 at gmail.com)
3
+ [![CI](https://github.com/postmodern/ffi-libc/actions/workflows/ruby.yml/badge.svg)](https://github.com/postmodern/ffi-libc/actions/workflows/ruby.yml)
4
+ [![Code Climate](https://codeclimate.com/github/postmodern/ffi-libc.svg)](https://codeclimate.com/github/postmodern/ffi-libc)
5
+
6
+ * [Source](https://github.com/postmodern/ffi-libc/)
7
+ * [Issues](https://github.com/postmodern/ffi-libc/issues)
8
+ * [Documentation](https://rubydoc.info/gems/ffi-libc)
6
9
 
7
10
  ## Description
8
11
 
@@ -10,18 +13,122 @@ Useful Ruby FFI bindings for `libc`.
10
13
 
11
14
  ## Features
12
15
 
13
- * Provides common Structs used in `libc`.
14
- * Binds to common functions and global variables in `libc`.
16
+ * Provides common Structs used in `libc`:
17
+ * {FFI::LibC::Ifaddrs}
18
+ * {FFI::LibC::In6Addr}
19
+ * {FFI::LibC::InAddr}
20
+ * {FFI::LibC::SockaddrDL}
21
+ * {FFI::LibC::SockaddrFamily}
22
+ * {FFI::LibC::SockaddrIn6}
23
+ * {FFI::LibC::SockaddrIn}
24
+ * {FFI::LibC::Sockaddr}
25
+ * {FFI::LibC::Timeval}
26
+ * {FFI::LibC::Timezone}
27
+ * {FFI::LibC::RUsage}
28
+ * Binds to common functions and global variables in `libc`:
29
+ * `errno.h`:
30
+ * `sys_errlist` (BSD)
31
+ * `sys_nerr` (BSD)
32
+ * `errno`
33
+ * `unistd.h`:
34
+ * `brk`
35
+ * `sbrk`
36
+ * `getpid`
37
+ * `getppid`
38
+ * `getuid`
39
+ * `geteuid`
40
+ * `getgid`
41
+ * `getegid`
42
+ * `stdlib.h`:
43
+ * `calloc`
44
+ * `malloc`
45
+ * `free`
46
+ * `realloc`
47
+ * `getenv`
48
+ * `putenv`
49
+ * `unsetenv`
50
+ * `clearenv`
51
+ * `time.h`:
52
+ * `time`
53
+ * `sys/time.h`:
54
+ * `gettimeofday`
55
+ * `settimeofday`
56
+ * `sys/resource.h` / `bits/resource.h`:
57
+ * `getrusage`
58
+ * `sys/mman.h`:
59
+ * `mmap`
60
+ * `munmap`
61
+ * `string.h`:
62
+ * `bzero`
63
+ * `memset`
64
+ * `memcpy`
65
+ * `memcmp`
66
+ * `memchr`
67
+ * `memrchr`
68
+ * `strcpy`
69
+ * `strncpy`
70
+ * `strlen`
71
+ * `index`
72
+ * `rindex`
73
+ * `strchr`
74
+ * `strrchr`
75
+ * `strstr`
76
+ * `strerror`
77
+ * `stdio.h`:
78
+ * `stdin`
79
+ * `stdout`
80
+ * `stderr`
81
+ * `fopen`
82
+ * `fdopen`
83
+ * `freopen`
84
+ * `fseek`
85
+ * `ftell`
86
+ * `rewind`
87
+ * `fread`
88
+ * `fwrite`
89
+ * `fgetc`
90
+ * `fgets`
91
+ * `fputc`
92
+ * `fputs`
93
+ * `fflush`
94
+ * `fclose`
95
+ * `clearerr`
96
+ * `feof`
97
+ * `ferror`
98
+ * `fileno`
99
+ * `perror`
100
+ * `netdb.h`:
101
+ * `getnameinfo`
102
+ * `ifaddrs.h`:
103
+ * `getifaddrs`
104
+ * `freeifaddrs`
15
105
 
16
106
  ## Requirements
17
107
 
18
- * [ffi](http://github.com/ffi/ffi) ~> 0.6.0
108
+ * [ffi] ~> 1.0
19
109
 
20
110
  ## Install
21
111
 
22
- $ sudo gem install ffi-libc
112
+ ```shell
113
+ $ gem install ffi-libc
114
+ ```
115
+
116
+ ### gemspec
117
+
118
+ ```ruby
119
+ gem.add_dependency 'ffi-libc', '~> 0.1'
120
+ ```
121
+
122
+ ### Gemfile
123
+
124
+ ```ruby
125
+ gem 'ffi-libc', '~> 0.1'
126
+ ```
23
127
 
24
128
  ## License
25
129
 
130
+ Copyright (c) 2010-2021 Hal Brodigan
131
+
26
132
  See {file:LICENSE.txt} for license information.
27
133
 
134
+ [ffi]: https://github.com/ffi/ffi#readme
data/Rakefile CHANGED
@@ -1,38 +1,13 @@
1
1
  require 'rubygems'
2
- require 'bundler'
3
2
 
4
- begin
5
- Bundler.setup(:development, :doc)
6
- rescue Bundler::BundlerError => e
7
- STDERR.puts e.message
8
- STDERR.puts "Run `bundle install` to install missing gems"
9
- exit e.status_code
10
- end
3
+ require 'rubygems/tasks'
4
+ Gem::Tasks.new
11
5
 
12
- require 'rake'
13
- require 'rake/clean'
14
- require 'jeweler'
15
-
16
- Jeweler::Tasks.new do |gem|
17
- gem.name = 'ffi-libc'
18
- gem.licenses = ['MIT']
19
- gem.summary = %Q{Useful FFI bindings for libc}
20
- gem.email = 'postmodern.mod3@gmail.com'
21
- gem.homepage = %Q{http://github.com/postmodern/ffi-libc}
22
- gem.description = %Q{Useful Ruby FFI bindings for libc.}
23
- gem.authors = ['Postmodern']
24
- gem.has_rdoc = 'yard'
25
- end
26
-
27
- require 'spec/rake/spectask'
28
-
29
- desc "Run all specifications"
30
- Spec::Rake::SpecTask.new(:spec) do |spec|
31
- spec.libs += ['lib', 'spec']
32
- spec.spec_files = FileList['spec/**/*_spec.rb']
33
- spec.spec_opts = ['--options', '.specopts']
34
- end
6
+ require 'rspec/core/rake_task'
7
+ RSpec::Core::RakeTask.new
8
+ task :test => :spec
35
9
  task :default => :spec
36
10
 
37
11
  require 'yard'
38
12
  YARD::Rake::YardocTask.new
13
+ task :doc => :yard
data/ffi-libc.gemspec CHANGED
@@ -1,77 +1,61 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE DIRECTLY
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
- # -*- encoding: utf-8 -*-
1
+ # encoding: utf-8
5
2
 
6
- Gem::Specification.new do |s|
7
- s.name = %q{ffi-libc}
8
- s.version = "0.0.3"
3
+ require 'yaml'
9
4
 
10
- s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
- s.authors = ["Postmodern"]
12
- s.date = %q{2010-08-03}
13
- s.description = %q{Useful Ruby FFI bindings for libc.}
14
- s.email = %q{postmodern.mod3@gmail.com}
15
- s.extra_rdoc_files = [
16
- "ChangeLog.md",
17
- "LICENSE.txt",
18
- "README.md"
19
- ]
20
- s.files = [
21
- ".gitignore",
22
- ".specopts",
23
- ".yardopts",
24
- "ChangeLog.md",
25
- "Gemfile",
26
- "LICENSE.txt",
27
- "README.md",
28
- "Rakefile",
29
- "VERSION",
30
- "ffi-libc.gemspec",
31
- "lib/ffi/libc.rb",
32
- "lib/ffi/libc/af.rb",
33
- "lib/ffi/libc/in6_addr.rb",
34
- "lib/ffi/libc/in_addr.rb",
35
- "lib/ffi/libc/libc.rb",
36
- "lib/ffi/libc/sock_addr.rb",
37
- "lib/ffi/libc/sock_addr_dl.rb",
38
- "lib/ffi/libc/sock_addr_family.rb",
39
- "lib/ffi/libc/sock_addr_in.rb",
40
- "lib/ffi/libc/sock_addr_in6.rb",
41
- "lib/ffi/libc/timeval.rb",
42
- "lib/ffi/libc/timezone.rb",
43
- "lib/ffi/libc/types.rb"
44
- ]
45
- s.has_rdoc = %q{yard}
46
- s.homepage = %q{http://github.com/postmodern/ffi-libc}
47
- s.licenses = ["MIT"]
48
- s.require_paths = ["lib"]
49
- s.rubygems_version = %q{1.3.7}
50
- s.summary = %q{Useful FFI bindings for libc}
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
51
7
 
52
- if s.respond_to? :specification_version then
53
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
54
- s.specification_version = 3
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
55
12
 
56
- if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
57
- s.add_runtime_dependency(%q<ffi>, ["~> 0.6.0"])
58
- s.add_development_dependency(%q<bundler>, ["~> 0.9.25"])
59
- s.add_development_dependency(%q<rake>, ["~> 0.8.7"])
60
- s.add_development_dependency(%q<jeweler>, ["~> 1.4.0"])
61
- s.add_development_dependency(%q<rspec>, ["~> 1.3.0"])
62
- else
63
- s.add_dependency(%q<ffi>, ["~> 0.6.0"])
64
- s.add_dependency(%q<bundler>, ["~> 0.9.25"])
65
- s.add_dependency(%q<rake>, ["~> 0.8.7"])
66
- s.add_dependency(%q<jeweler>, ["~> 1.4.0"])
67
- s.add_dependency(%q<rspec>, ["~> 1.3.0"])
13
+ require 'ffi/libc/version'
14
+ FFI::LibC::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+
30
+ gem.executables = gemspec.fetch('executables') do
31
+ glob['bin/*'].map { |path| File.basename(path) }
32
+ end
33
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
34
+
35
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
36
+ gem.test_files = glob[gemspec['test_files'] || '{test/{**/}*_test.rb']
37
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
38
+
39
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
40
+ %w[ext lib].select { |dir| File.directory?(dir) }
41
+ })
42
+
43
+ gem.requirements = gemspec['requirements']
44
+ gem.required_ruby_version = gemspec['required_ruby_version']
45
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
46
+ gem.post_install_message = gemspec['post_install_message']
47
+
48
+ split = lambda { |string| string.split(/,\s*/) }
49
+
50
+ if gemspec['dependencies']
51
+ gemspec['dependencies'].each do |name,versions|
52
+ gem.add_dependency(name,split[versions])
68
53
  end
69
- else
70
- s.add_dependency(%q<ffi>, ["~> 0.6.0"])
71
- s.add_dependency(%q<bundler>, ["~> 0.9.25"])
72
- s.add_dependency(%q<rake>, ["~> 0.8.7"])
73
- s.add_dependency(%q<jeweler>, ["~> 1.4.0"])
74
- s.add_dependency(%q<rspec>, ["~> 1.3.0"])
75
54
  end
76
- end
77
55
 
56
+ if gemspec['development_dependencies']
57
+ gemspec['development_dependencies'].each do |name,versions|
58
+ gem.add_development_dependency(name,split[versions])
59
+ end
60
+ end
61
+ end
data/gemspec.yml ADDED
@@ -0,0 +1,21 @@
1
+ name: ffi-libc
2
+ version: 0.1.1
3
+ summary: Useful FFI bindings for libc
4
+ description: Useful Ruby FFI bindings for libc.
5
+ license: MIT
6
+ authors: Postmodern
7
+ email: postmodern.mod3@gmail.com
8
+ homepage: https://github.com/postmodern/ffi-libc#redme
9
+ has_yard: true
10
+
11
+ metadata:
12
+ documentation_uri: https://rubydoc.info/gems/ffi-libc
13
+ source_code_uri: https://github.com/postmodern/ffi-libc
14
+ bug_tracker_uri: https://github.com/postmodern/ffi-libc/issues
15
+ changelog_uri: https://github.com/postmodern/ffi-libc/blob/master/ChangeLog.md
16
+
17
+ dependencies:
18
+ ffi: ~> 1.0
19
+
20
+ development_dependencies:
21
+ bundler: ~> 2.0
@@ -0,0 +1,93 @@
1
+ require 'ffi/libc/ifaddrs_union'
2
+ require 'ffi/libc/sockaddr'
3
+
4
+ module FFI
5
+ module LibC
6
+ #
7
+ # @since 0.1.0
8
+ #
9
+ class Ifaddrs < FFI::Struct
10
+
11
+ layout :ifa_next, :pointer,
12
+ :ifa_name, :string,
13
+ :ifa_flags, :uint,
14
+ :ifa_addr, :pointer,
15
+ :ifa_netmask, :pointer,
16
+ :ifa_ifu, IfaddrsUnion,
17
+ :ifa_data, :pointer
18
+
19
+ #
20
+ # Gets the next Interface Address in the list.
21
+ #
22
+ # @return [Ifaddrs, nil]
23
+ # The next Interface Address in the list.
24
+ #
25
+ def next
26
+ unless self[:ifa_next].null?
27
+ Ifaddrs.new(self[:ifa_next])
28
+ end
29
+ end
30
+
31
+ #
32
+ # The name of the Interface.
33
+ #
34
+ # @return [String]
35
+ # The name.
36
+ #
37
+ def name
38
+ self[:ifa_name]
39
+ end
40
+
41
+ #
42
+ # The flags of the Interface.
43
+ #
44
+ # @return [Integer]
45
+ # The flags.
46
+ #
47
+ def flags
48
+ self[:ifa_flags]
49
+ end
50
+
51
+ #
52
+ # The address of the Interface.
53
+ #
54
+ # @return [Sockaddr]
55
+ # The basic socket address.
56
+ #
57
+ def addr
58
+ Sockaddr.new(self[:ifa_addr])
59
+ end
60
+
61
+ #
62
+ # The netmask of the Interface.
63
+ #
64
+ # @return [Sockaddr]
65
+ # The socket address containing the netmask.
66
+ #
67
+ def netmask
68
+ Sockaddr.new(self[:ifa_netmask])
69
+ end
70
+
71
+ #
72
+ # The broadcast address of the Interface.
73
+ #
74
+ # @return [Sockaddr]
75
+ # The broadcast address.
76
+ #
77
+ def broadaddr
78
+ Sockaddr.new(self[:ifa_ifu][:ifu_broadaddr])
79
+ end
80
+
81
+ #
82
+ # The destination address of the Interface.
83
+ #
84
+ # @return [Sockaddr]
85
+ # The destination address.
86
+ #
87
+ def dstaddr
88
+ Sockaddr.new(self[:ifa_ifu][:ifu_dstaddr])
89
+ end
90
+
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,15 @@
1
+ require 'ffi'
2
+
3
+ module FFI
4
+ module LibC
5
+ #
6
+ # @since 0.1.0
7
+ #
8
+ class IfaddrsUnion < FFI::Union
9
+
10
+ layout :ifu_broadaddr, :pointer,
11
+ :ifu_dstaddr, :pointer
12
+
13
+ end
14
+ end
15
+ end
data/lib/ffi/libc/libc.rb CHANGED
@@ -1,6 +1,8 @@
1
1
  require 'ffi/libc/types'
2
2
  require 'ffi/libc/timeval'
3
3
  require 'ffi/libc/timezone'
4
+ require 'ffi/libc/ifaddrs'
5
+ require 'ffi/libc/rusage'
4
6
 
5
7
  require 'ffi'
6
8
 
@@ -8,13 +10,23 @@ module FFI
8
10
  module LibC
9
11
  extend FFI::Library
10
12
 
11
- ffi_lib [FFI::CURRENT_PROCESS, 'c']
13
+ ffi_lib FFI::Library::LIBC
14
+
15
+ # The NULL constant
16
+ NULL = nil
12
17
 
13
18
  # errno.h
14
- attach_variable :sys_errlist, :pointer
15
- attach_variable :sys_nerr, :int
19
+ begin
20
+ attach_variable :sys_errlist, :pointer
21
+ attach_variable :sys_nerr, :int
22
+ rescue FFI::NotFoundError
23
+ end
16
24
  attach_variable :errno, :int
17
25
 
26
+ def self.raise_error(error=self.errno)
27
+ raise(strerror(error))
28
+ end
29
+
18
30
  # unistd.h
19
31
  attach_function :brk, [:pointer], :int
20
32
  attach_function :sbrk, [:pointer], :pointer
@@ -24,6 +36,7 @@ module FFI
24
36
  attach_function :geteuid, [], :uid_t
25
37
  attach_function :getgid, [], :gid_t
26
38
  attach_function :getegid, [], :gid_t
39
+ attach_function :alarm, [:uint], :uint
27
40
 
28
41
  # stdlib.h
29
42
  attach_function :calloc, [:size_t, :size_t], :pointer
@@ -33,9 +46,15 @@ module FFI
33
46
  attach_function :getenv, [:string], :string
34
47
  attach_function :putenv, [:string], :int
35
48
  attach_function :unsetenv, [:string], :int
36
- attach_function :clearenv, [], :int
49
+
50
+ begin
51
+ attach_function :clearenv, [], :int
52
+ rescue FFI::NotFoundError
53
+ # clearenv is not available on OSX
54
+ end
37
55
 
38
56
  # time.h
57
+ attach_function :clock, [], :clock_t
39
58
  attach_function :time, [:pointer], :time_t
40
59
 
41
60
  # sys/time.h
@@ -49,33 +68,48 @@ module FFI
49
68
  # string.h
50
69
  attach_function :bzero, [:pointer, :size_t], :void
51
70
  attach_function :memset, [:pointer, :int, :size_t], :pointer
52
- attach_function :memcpy, [:pointer, :pointer, :size_t], :pointer
53
- attach_function :memcmp, [:pointer, :pointer, :size_t], :int
54
- attach_function :memchr, [:pointer, :int, :size_t], :pointer
55
- attach_function :memrchr, [:pointer, :int, :size_t], :pointer
56
- attach_function :strcpy, [:string, :string], :pointer
57
- attach_function :strncpy, [:string, :string, :size_t], :pointer
58
- attach_function :strlen, [:string], :size_t
59
- attach_function :index, [:string, :int], :string
60
- attach_function :rindex, [:string, :int], :string
61
- attach_function :strchr, [:string, :int], :string
62
- attach_function :strrchr, [:string, :int], :string
63
- attach_function :strstr, [:string, :string], :string
71
+ attach_function :memcpy, [:buffer_out, :buffer_in, :size_t], :pointer
72
+ attach_function :memcmp, [:buffer_in, :buffer_in, :size_t], :int
73
+ attach_function :memchr, [:buffer_in, :int, :size_t], :pointer
74
+
75
+ begin
76
+ attach_function :memrchr, [:buffer_in, :int, :size_t], :pointer
77
+ rescue FFI::NotFoundError
78
+ # memrchr is not available on OSX
79
+ end
80
+
81
+ attach_function :strcpy, [:buffer_out, :string], :pointer
82
+ attach_function :strncpy, [:buffer_out, :string, :size_t], :pointer
83
+ attach_function :strcmp, [:buffer_in, :buffer_in], :int
84
+ attach_function :strncmp, [:buffer_in, :buffer_in, :size_t], :int
85
+ attach_function :strlen, [:buffer_in], :size_t
86
+ attach_function :index, [:buffer_in, :int], :pointer
87
+ attach_function :rindex, [:buffer_in, :int], :pointer
88
+ attach_function :strchr, [:buffer_in, :int], :pointer
89
+ attach_function :strrchr, [:buffer_in, :int], :pointer
90
+ attach_function :strstr, [:buffer_in, :string], :pointer
64
91
  attach_function :strerror, [:int], :string
65
92
 
66
- # stdio.h
93
+ begin
94
+ attach_variable :stdin, :pointer
95
+ attach_variable :stdout, :pointer
96
+ attach_variable :stderr, :pointer
97
+ rescue FFI::NotFoundError
98
+ # stdin, stdout, stderr are not available on OSX
99
+ end
100
+
67
101
  attach_function :fopen, [:string, :string], :FILE
68
102
  attach_function :fdopen, [:int, :string], :FILE
69
103
  attach_function :freopen, [:string, :string, :FILE], :FILE
70
104
  attach_function :fseek, [:FILE, :long, :int], :int
71
105
  attach_function :ftell, [:FILE], :long
72
106
  attach_function :rewind, [:FILE], :void
73
- attach_function :fread, [:pointer, :size_t, :size_t, :FILE], :size_t
74
- attach_function :fwrite, [:pointer, :size_t, :size_t, :FILE], :size_t
107
+ attach_function :fread, [:buffer_out, :size_t, :size_t, :FILE], :size_t
108
+ attach_function :fwrite, [:buffer_in, :size_t, :size_t, :FILE], :size_t
75
109
  attach_function :fgetc, [:FILE], :int
76
- attach_function :fgets, [:pointer, :int, :FILE], :pointer
110
+ attach_function :fgets, [:buffer_out, :int, :FILE], :pointer
77
111
  attach_function :fputc, [:int, :FILE], :int
78
- attach_function :fputs, [:string, :FILE], :int
112
+ attach_function :fputs, [:buffer_in, :FILE], :int
79
113
  attach_function :fflush, [:FILE], :int
80
114
  attach_function :fclose, [:FILE], :int
81
115
  attach_function :clearerr, [:FILE], :void
@@ -83,5 +117,104 @@ module FFI
83
117
  attach_function :ferror, [:FILE], :int
84
118
  attach_function :fileno, [:FILE], :int
85
119
  attach_function :perror, [:string], :void
120
+
121
+ attach_function :getc, [:FILE], :int
122
+ attach_function :getchar, [], :int
123
+ attach_function :gets, [:buffer_out], :int
124
+ attach_function :ungetc, [:int, :pointer], :int
125
+
126
+ attach_function :putc, [:int, :FILE], :int
127
+ attach_function :putchar, [:int], :int
128
+ attach_function :puts, [:string], :int
129
+
130
+ # netdb.h
131
+ attach_function :getnameinfo, [
132
+ :pointer,
133
+ :socklen_t, :pointer,
134
+ :socklen_t, :pointer,
135
+ :socklen_t, :int
136
+ ], :int
137
+
138
+ NI_MAXHOST = 1024
139
+ NI_MAXSERV = 32
140
+
141
+ NI_NUMERICHOST = 1 # Don't try to look up hostname.
142
+ NI_NUMERICSERV = 2 # Don't convert port number to name.
143
+ NI_NOFQDN = 4 # Only return nodename portion.
144
+ NI_NAMEREQD = 8 # Don't return numeric addresses.
145
+ NI_DGRAM = 16 # Look up UDP service rather than TCP.
146
+
147
+ # ifaddrs.h
148
+ attach_function :getifaddrs, [:pointer], :int
149
+ attach_function :freeifaddrs, [:pointer], :void
150
+
151
+ #
152
+ # Enumerates over the Interface Addresses.
153
+ #
154
+ # @yield [ifaddr]
155
+ # The given block will be passed each Interface Address.
156
+ #
157
+ # @yieldparam [Ifaddrs] ifaddr
158
+ # An Interface Address.
159
+ #
160
+ # @return [Enumerator]
161
+ # If no block is given, an enumerator will be returned.
162
+ #
163
+ # @since 0.1.0
164
+ #
165
+ def self.each_ifaddr
166
+ return enum_for(__method__) unless block_given?
167
+
168
+ ptr = MemoryPointer.new(:pointer)
169
+
170
+ if getifaddrs(ptr) == -1
171
+ raise_error
172
+ end
173
+
174
+ if (ifaddrs = ptr.get_pointer(0)).null?
175
+ return
176
+ end
177
+
178
+ ifaddr = Ifaddrs.new(ifaddrs)
179
+
180
+ while ifaddr
181
+ yield ifaddr
182
+
183
+ ifaddr = ifaddr.next
184
+ end
185
+
186
+ freeifaddrs(ifaddrs)
187
+ end
188
+
189
+ # bits/resource.h (Linux) / sys/resource.h (Darwin)
190
+ RUSAGE_SELF = 0
191
+ RUSAGE_CHILDREN = -1
192
+ RUSAGE_THREAD = 1 # Linux/glibc only
193
+
194
+ attach_function :getrusage, [:int, :pointer], :int
195
+
196
+ #
197
+ # Gets the RUsage for the user.
198
+ #
199
+ # @param [RUSAGE_SELF, RUSAGE_CHILDREN, RUSAGE_THREAD] who
200
+ # Whome to get RUsage statistics for.
201
+ #
202
+ # @return [RUsage]
203
+ # The RUsage statistics.
204
+ #
205
+ # @raise [RuntimeError]
206
+ # An error has occurred.
207
+ #
208
+ # @since 0.1.0
209
+ #
210
+ def self.rusage(who=RUSAGE_SELF)
211
+ rusage = RUsage.new
212
+
213
+ unless (ret = getrusage(who,rusage)) == 0
214
+ raise_error(ret)
215
+ end
216
+
217
+ return rusage
218
+ end
86
219
  end
87
220
  end
@@ -0,0 +1,30 @@
1
+ require 'ffi/libc/types'
2
+ require 'ffi/libc/timeval'
3
+
4
+ module FFI
5
+ module LibC
6
+ #
7
+ # @since 0.1.0
8
+ #
9
+ class RUsage < FFI::Struct
10
+
11
+ layout :ru_utime, Timeval,
12
+ :ru_stime, Timeval,
13
+ :ru_maxrss, :long,
14
+ :ru_ixrss, :long,
15
+ :ru_idrss, :long,
16
+ :ru_isrss, :long,
17
+ :ru_minflt, :long,
18
+ :ru_majflt, :long,
19
+ :ru_nswap, :long,
20
+ :ru_inblock, :long,
21
+ :ru_oublock, :long,
22
+ :ru_msgsnd, :long,
23
+ :ru_msgrcv, :long,
24
+ :ru_nsignals, :long,
25
+ :ru_nvcsw, :long,
26
+ :ru_nivcsw, :long
27
+
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,16 @@
1
+ require 'ffi/libc/types'
2
+ require 'ffi/libc/sockaddr_family'
3
+
4
+ module FFI
5
+ module LibC
6
+ #
7
+ # The generic `sockaddr` structure.
8
+ #
9
+ class Sockaddr < SockaddrFamily
10
+
11
+ layout :family, :sa_family_t,
12
+ :data, [:char, 14]
13
+
14
+ end
15
+ end
16
+ end
@@ -1,12 +1,12 @@
1
1
  require 'ffi/libc/types'
2
- require 'ffi/libc/sock_addr_family'
2
+ require 'ffi/libc/sockaddr_family'
3
3
 
4
4
  module FFI
5
5
  module LibC
6
6
  #
7
7
  # The data-link socket address
8
8
  #
9
- class SockAddrDL < SockAddrFamily
9
+ class SockaddrDL < SockaddrFamily
10
10
 
11
11
  layout :len, :uint8,
12
12
  :family, :sa_family_t,
@@ -5,7 +5,7 @@ module FFI
5
5
  #
6
6
  # Common abstract superclass for all sockaddr struct classes
7
7
  #
8
- class SockAddrFamily < ::FFI::Struct
8
+ class SockaddrFamily < ::FFI::Struct
9
9
 
10
10
  end
11
11
  end
@@ -0,0 +1,19 @@
1
+ require 'ffi/libc/types'
2
+ require 'ffi/libc/sockaddr_family'
3
+
4
+ module FFI
5
+ module LibC
6
+ #
7
+ # sockaddr inet, always good to have around
8
+ #
9
+ class SockaddrIn < SockaddrFamily
10
+
11
+ layout :len, :uint8,
12
+ :family, :sa_family_t,
13
+ :port, :in_port_t,
14
+ :addr, :in_addr_t,
15
+ :_sa_zero, [:uint8, 8]
16
+
17
+ end
18
+ end
19
+ end
@@ -1,4 +1,5 @@
1
1
  require 'ffi/libc/types'
2
+ require 'ffi/libc/sockaddr_family'
2
3
  require 'ffi/libc/in6_addr'
3
4
 
4
5
  module FFI
@@ -6,7 +7,7 @@ module FFI
6
7
  #
7
8
  # IPv6 socket address
8
9
  #
9
- class SockAddrIn6 < SockAddrFamily
10
+ class SockaddrIn6 < SockaddrFamily
10
11
 
11
12
  layout :len, :uint8,
12
13
  :family, :sa_family_t,
@@ -7,5 +7,8 @@ module FFI
7
7
  typedef :pointer, :FILE
8
8
  typedef :uint32, :in_addr_t
9
9
  typedef :uint16, :in_port_t
10
+
11
+ # time.h
12
+ typedef :long, :clock_t
10
13
  end
11
14
  end
data/lib/ffi/libc.rb CHANGED
@@ -1,2 +1,13 @@
1
1
  require 'ffi/libc/types'
2
+ require 'ffi/libc/af'
3
+ require 'ffi/libc/ifaddrs'
4
+ require 'ffi/libc/in_addr'
5
+ require 'ffi/libc/in6_addr'
6
+ require 'ffi/libc/sockaddr'
7
+ require 'ffi/libc/sockaddr_dl'
8
+ require 'ffi/libc/sockaddr_in'
9
+ require 'ffi/libc/sockaddr_in6'
10
+ require 'ffi/libc/timeval'
11
+ require 'ffi/libc/timezone'
12
+ require 'ffi/libc/rusage'
2
13
  require 'ffi/libc/libc'
@@ -0,0 +1,30 @@
1
+ require 'spec_helper'
2
+ require 'ffi/libc/ifaddrs'
3
+
4
+ describe Ifaddrs do
5
+ subject { LibC.each_ifaddr.first }
6
+
7
+ it "should have a name" do
8
+ expect(subject.name).to_not be_empty
9
+ end
10
+
11
+ it "should have flags" do
12
+ expect(subject.flags).to be_kind_of(Integer)
13
+ end
14
+
15
+ it "should have an addr" do
16
+ expect(subject.addr).to be_kind_of(Sockaddr)
17
+ end
18
+
19
+ it "should have an netmask" do
20
+ expect(subject.netmask).to be_kind_of(Sockaddr)
21
+ end
22
+
23
+ it "should have a broadcast addr" do
24
+ expect(subject.broadaddr).to be_kind_of(Sockaddr)
25
+ end
26
+
27
+ it "should have a destination addr" do
28
+ expect(subject.dstaddr).to be_kind_of(Sockaddr)
29
+ end
30
+ end
data/spec/libc_spec.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+ require 'ffi/libc'
3
+
4
+ describe FFI::LibC do
5
+ describe "NULL" do
6
+ subject { described_class::NULL }
7
+
8
+ it { expect(subject).to be == nil }
9
+ end
10
+
11
+ describe "each_ifaddr" do
12
+ it "should yield Ifaddrs" do
13
+ addrs = []
14
+
15
+ described_class.each_ifaddr do |ifaddr|
16
+ addrs << ifaddr
17
+ end
18
+
19
+ expect(addrs).to all(be_kind_of(Ifaddrs))
20
+ end
21
+
22
+ context "when not given a block" do
23
+ subject { described_class.each_ifaddr }
24
+
25
+ it { expect(subject).to be_kind_of(Enumerable) }
26
+ end
27
+ end
28
+
29
+ describe "rusage" do
30
+ subject { described_class.rusage }
31
+
32
+ it "should be able to fetch its own memory usage" do
33
+ expect(subject[:ru_maxrss]).to be > 4000
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,5 @@
1
+ require 'rspec'
2
+ require 'ffi/libc'
3
+
4
+ include FFI
5
+ include FFI::LibC
metadata CHANGED
@@ -1,163 +1,107 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: ffi-libc
3
- version: !ruby/object:Gem::Version
4
- prerelease: false
5
- segments:
6
- - 0
7
- - 0
8
- - 3
9
- version: 0.0.3
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.1
10
5
  platform: ruby
11
- authors:
6
+ authors:
12
7
  - Postmodern
13
- autorequire:
8
+ autorequire:
14
9
  bindir: bin
15
10
  cert_chain: []
16
-
17
- date: 2010-08-03 00:00:00 -07:00
18
- default_executable:
19
- dependencies:
20
- - !ruby/object:Gem::Dependency
11
+ date: 2021-09-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
21
14
  name: ffi
22
- requirement: &id001 !ruby/object:Gem::Requirement
23
- none: false
24
- requirements:
25
- - - ~>
26
- - !ruby/object:Gem::Version
27
- segments:
28
- - 0
29
- - 6
30
- - 0
31
- version: 0.6.0
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.0'
32
20
  type: :runtime
33
21
  prerelease: false
34
- version_requirements: *id001
35
- - !ruby/object:Gem::Dependency
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.0'
27
+ - !ruby/object:Gem::Dependency
36
28
  name: bundler
37
- requirement: &id002 !ruby/object:Gem::Requirement
38
- none: false
39
- requirements:
40
- - - ~>
41
- - !ruby/object:Gem::Version
42
- segments:
43
- - 0
44
- - 9
45
- - 25
46
- version: 0.9.25
47
- type: :development
48
- prerelease: false
49
- version_requirements: *id002
50
- - !ruby/object:Gem::Dependency
51
- name: rake
52
- requirement: &id003 !ruby/object:Gem::Requirement
53
- none: false
54
- requirements:
55
- - - ~>
56
- - !ruby/object:Gem::Version
57
- segments:
58
- - 0
59
- - 8
60
- - 7
61
- version: 0.8.7
62
- type: :development
63
- prerelease: false
64
- version_requirements: *id003
65
- - !ruby/object:Gem::Dependency
66
- name: jeweler
67
- requirement: &id004 !ruby/object:Gem::Requirement
68
- none: false
69
- requirements:
70
- - - ~>
71
- - !ruby/object:Gem::Version
72
- segments:
73
- - 1
74
- - 4
75
- - 0
76
- version: 1.4.0
77
- type: :development
78
- prerelease: false
79
- version_requirements: *id004
80
- - !ruby/object:Gem::Dependency
81
- name: rspec
82
- requirement: &id005 !ruby/object:Gem::Requirement
83
- none: false
84
- requirements:
85
- - - ~>
86
- - !ruby/object:Gem::Version
87
- segments:
88
- - 1
89
- - 3
90
- - 0
91
- version: 1.3.0
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
92
34
  type: :development
93
35
  prerelease: false
94
- version_requirements: *id005
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
95
41
  description: Useful Ruby FFI bindings for libc.
96
42
  email: postmodern.mod3@gmail.com
97
43
  executables: []
98
-
99
44
  extensions: []
100
-
101
- extra_rdoc_files:
45
+ extra_rdoc_files:
102
46
  - ChangeLog.md
103
47
  - LICENSE.txt
104
48
  - README.md
105
- files:
106
- - .gitignore
107
- - .specopts
108
- - .yardopts
49
+ files:
50
+ - ".github/workflows/ruby.yml"
51
+ - ".gitignore"
52
+ - ".rspec"
53
+ - ".yardopts"
109
54
  - ChangeLog.md
110
55
  - Gemfile
111
56
  - LICENSE.txt
112
57
  - README.md
113
58
  - Rakefile
114
- - VERSION
115
59
  - ffi-libc.gemspec
60
+ - gemspec.yml
116
61
  - lib/ffi/libc.rb
117
62
  - lib/ffi/libc/af.rb
63
+ - lib/ffi/libc/ifaddrs.rb
64
+ - lib/ffi/libc/ifaddrs_union.rb
118
65
  - lib/ffi/libc/in6_addr.rb
119
66
  - lib/ffi/libc/in_addr.rb
120
67
  - lib/ffi/libc/libc.rb
121
- - lib/ffi/libc/sock_addr.rb
122
- - lib/ffi/libc/sock_addr_dl.rb
123
- - lib/ffi/libc/sock_addr_family.rb
124
- - lib/ffi/libc/sock_addr_in.rb
125
- - lib/ffi/libc/sock_addr_in6.rb
68
+ - lib/ffi/libc/rusage.rb
69
+ - lib/ffi/libc/sockaddr.rb
70
+ - lib/ffi/libc/sockaddr_dl.rb
71
+ - lib/ffi/libc/sockaddr_family.rb
72
+ - lib/ffi/libc/sockaddr_in.rb
73
+ - lib/ffi/libc/sockaddr_in6.rb
126
74
  - lib/ffi/libc/timeval.rb
127
75
  - lib/ffi/libc/timezone.rb
128
76
  - lib/ffi/libc/types.rb
129
- has_rdoc: yard
130
- homepage: http://github.com/postmodern/ffi-libc
131
- licenses:
77
+ - spec/ifaddrs_spec.rb
78
+ - spec/libc_spec.rb
79
+ - spec/spec_helper.rb
80
+ homepage: https://github.com/postmodern/ffi-libc#redme
81
+ licenses:
132
82
  - MIT
133
- post_install_message:
83
+ metadata:
84
+ documentation_uri: https://rubydoc.info/gems/ffi-libc
85
+ source_code_uri: https://github.com/postmodern/ffi-libc
86
+ bug_tracker_uri: https://github.com/postmodern/ffi-libc/issues
87
+ changelog_uri: https://github.com/postmodern/ffi-libc/blob/master/ChangeLog.md
88
+ post_install_message:
134
89
  rdoc_options: []
135
-
136
- require_paths:
90
+ require_paths:
137
91
  - lib
138
- required_ruby_version: !ruby/object:Gem::Requirement
139
- none: false
140
- requirements:
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
141
94
  - - ">="
142
- - !ruby/object:Gem::Version
143
- hash: -2959684172308845082
144
- segments:
145
- - 0
146
- version: "0"
147
- required_rubygems_version: !ruby/object:Gem::Requirement
148
- none: false
149
- requirements:
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
150
99
  - - ">="
151
- - !ruby/object:Gem::Version
152
- segments:
153
- - 0
154
- version: "0"
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
155
102
  requirements: []
156
-
157
- rubyforge_project:
158
- rubygems_version: 1.3.7
159
- signing_key:
160
- specification_version: 3
103
+ rubygems_version: 3.2.22
104
+ signing_key:
105
+ specification_version: 4
161
106
  summary: Useful FFI bindings for libc
162
107
  test_files: []
163
-
data/.specopts DELETED
@@ -1 +0,0 @@
1
- --colour --format specdoc
data/VERSION DELETED
@@ -1 +0,0 @@
1
- 0.0.3
@@ -1,17 +0,0 @@
1
- require 'ffi/libc/types'
2
- require 'ffi/libc/sock_addr_family'
3
-
4
- module FFI
5
- module LibC
6
- #
7
- # The generic `sock_addr` structure.
8
- #
9
- class SockAddr < SockAddrFamily
10
-
11
- layout :len, :uint8,
12
- :family, :sa_family_t,
13
- :data, :char
14
-
15
- end
16
- end
17
- end
@@ -1,19 +0,0 @@
1
- require 'ffi/libc/types'
2
- require 'ffi/libc/sock_addr_family'
3
-
4
- module FFI
5
- module LibC
6
- #
7
- # sockaddr inet, always good to have around
8
- #
9
- class SockAddrIn < SockAddrFamily
10
-
11
- layout :len, :uint8,
12
- :family, :sa_family_t,
13
- :port, :in_port_t,
14
- :addr, :in_addr_t,
15
- :_sa_zero, [:uint8, 8]
16
-
17
- end
18
- end
19
- end