├── .gitignore ├── Gemfile ├── README.md ├── Rakefile ├── bin ├── console └── setup ├── examples ├── modem_check0.rb ├── modem_check1.rb ├── modem_check2.rb ├── secret_input1.rb └── secret_input2.rb ├── ext ├── extconf.rb └── termios.c ├── lib ├── termios.rb └── termios │ └── version.rb ├── ruby-termios.gemspec ├── termios.rd └── test └── test0.rb /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by https://www.gitignore.io/api/ruby,osx,vim 2 | 3 | ### Ruby ### 4 | *.gem 5 | *.rbc 6 | *.so 7 | *.o 8 | *.bundle 9 | /.config 10 | /coverage/ 11 | /InstalledFiles 12 | /pkg/ 13 | /spec/reports/ 14 | /spec/examples.txt 15 | /test/tmp/ 16 | /test/version_tmp/ 17 | /tmp/ 18 | /Makefile 19 | /mkmf.log 20 | 21 | # Used by dotenv library to load environment variables. 22 | # .env 23 | 24 | ## Specific to RubyMotion: 25 | .dat* 26 | .repl_history 27 | build/ 28 | *.bridgesupport 29 | build-iPhoneOS/ 30 | build-iPhoneSimulator/ 31 | 32 | ## Specific to RubyMotion (use of CocoaPods): 33 | # 34 | # We recommend against adding the Pods directory to your .gitignore. However 35 | # you should judge for yourself, the pros and cons are mentioned at: 36 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 37 | # 38 | # vendor/Pods/ 39 | 40 | ## Documentation cache and generated files: 41 | /.yardoc/ 42 | /_yardoc/ 43 | /doc/ 44 | /rdoc/ 45 | 46 | ## Environment normalization: 47 | /.bundle/ 48 | /vendor/bundle 49 | /lib/bundler/man/ 50 | 51 | # for a library or gem, you might want to ignore these files since the code is 52 | # intended to run in multiple environments; otherwise, check them in: 53 | Gemfile.lock 54 | .ruby-version 55 | .ruby-gemset 56 | 57 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 58 | .rvmrc 59 | 60 | 61 | ### OSX ### 62 | *.DS_Store 63 | .AppleDouble 64 | .LSOverride 65 | 66 | # Icon must end with two \r 67 | Icon 68 | 69 | # Thumbnails 70 | ._* 71 | 72 | # Files that might appear in the root of a volume 73 | .DocumentRevisions-V100 74 | .fseventsd 75 | .Spotlight-V100 76 | .TemporaryItems 77 | .Trashes 78 | .VolumeIcon.icns 79 | .com.apple.timemachine.donotpresent 80 | 81 | # Directories potentially created on remote AFP share 82 | .AppleDB 83 | .AppleDesktop 84 | Network Trash Folder 85 | Temporary Items 86 | .apdisk 87 | 88 | 89 | ### Vim ### 90 | # swap 91 | [._]*.s[a-w][a-z] 92 | [._]s[a-w][a-z] 93 | # session 94 | Session.vim 95 | # temporary 96 | .netrwhist 97 | *~ 98 | # auto-generated tag files 99 | tags 100 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source 'https://rubygems.org' 4 | 5 | # Specify your gem's dependencies in termios.gemspec 6 | gemspec 7 | 8 | gem 'rake', '~> 13.0' 9 | 10 | gem 'rake-compiler' 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ruby-Termios 2 | 3 | This extension library provides Termios module. It enables you to use 4 | termios(3) interface. 5 | 6 | Termios module is simple wrapper of termios(3). It can be included into 7 | IO-family classes and can extend IO-family objects. In addition, the 8 | methods can use as module function. 9 | 10 | ## Installation 11 | 12 | ### Gem 13 | 14 | Add this line to your application's Gemfile: 15 | 16 | ```ruby 17 | gem 'ruby-termios', require: 'termios' 18 | ``` 19 | 20 | And then execute: 21 | 22 | $ bundle 23 | 24 | Or install it yourself as: 25 | 26 | $ gem install ruby-termios 27 | 28 | ### Make 29 | 30 | $ ruby ext/extconf.rb 31 | $ make install 32 | 33 | ## Development 34 | 35 | After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment. 36 | 37 | To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org). 38 | 39 | ## Contributing 40 | 41 | Bug reports and pull requests are welcome on GitHub at https://github.com/arika/ruby-termios. 42 | 43 | 44 | ## License 45 | 46 | The gem is available as open source under the terms of the [Ruby's Licens](https://www.ruby-lang.org/en/about/license.txt). 47 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require 'bundler/gem_tasks' 2 | require 'rake/extensiontask' 3 | 4 | task build: :compile 5 | 6 | Rake::ExtensionTask.new('termios') do |ext| 7 | ext.ext_dir = 'ext' 8 | ext.lib_dir = 'lib' 9 | end 10 | 11 | task default: [:clobber, :compile] 12 | -------------------------------------------------------------------------------- /bin/console: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'bundler/setup' 4 | require 'termios' 5 | 6 | # You can add fixtures and/or initialization code here to make experimenting 7 | # with your gem easier. You can also use a different console, if you like. 8 | 9 | # (If you use this, don't forget to add pry to your Gemfile!) 10 | # require 'pry' 11 | # Pry.start 12 | 13 | require 'irb' 14 | IRB.start 15 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | set -vx 5 | 6 | bundle install 7 | 8 | # Do any other automated setup that you need to do here 9 | -------------------------------------------------------------------------------- /examples/modem_check0.rb: -------------------------------------------------------------------------------- 1 | require 'fcntl' 2 | require 'termios' 3 | include Termios 4 | 5 | DEVICE = '/dev/modem' 6 | BAUDRATE = B115200 7 | 8 | def dev_open(path) 9 | dev = open(DEVICE, File::RDWR | File::NONBLOCK) 10 | mode = dev.fcntl(Fcntl::F_GETFL, 0) 11 | dev.fcntl(Fcntl::F_SETFL, mode & ~File::NONBLOCK) 12 | dev 13 | end 14 | 15 | def dump_termios(tio, banner) 16 | puts banner 17 | puts " ispeed = #{BAUDS[tio.ispeed]}, ospeed = #{BAUDS[tio.ospeed]}" 18 | ["iflag", "oflag", "cflag", "lflag"].each do |x| 19 | flag = tio.send(x) 20 | flags = [] 21 | eval("#{x.upcase}S").each do |f, sym| 22 | flags << sym.to_s if flag & f != 0 23 | end 24 | puts " #{x} = #{flags.sort.join(' | ')}" 25 | end 26 | print " cc =" 27 | cc = tio.cc 28 | cc.each_with_index do |x, idx| 29 | print " #{CCINDEX[idx]}=#{x}" if CCINDEX.include?(idx) 30 | end 31 | puts 32 | end 33 | 34 | dev = dev_open(DEVICE) 35 | 36 | oldtio = getattr(dev) 37 | dump_termios(oldtio, "current tio:") 38 | 39 | newtio = new_termios() 40 | newtio.iflag = IGNPAR 41 | newtio.oflag = 0 42 | newtio.cflag = (CRTSCTS | CS8 | CREAD) 43 | newtio.lflag = 0 44 | newtio.cc[VTIME] = 0 45 | newtio.cc[VMIN] = 1 46 | newtio.ispeed = BAUDRATE 47 | newtio.ospeed = BAUDRATE 48 | dump_termios(newtio, "new tio:") 49 | 50 | flush(dev, TCIOFLUSH) 51 | setattr(dev, TCSANOW, newtio) 52 | dump_termios(getattr(dev), "current tio:") 53 | 54 | "AT\x0d".each_byte {|c| 55 | c = c.chr 56 | p [:write_char, c] 57 | dev.putc c 58 | d = dev.getc 59 | p [:echo_back, d && d.chr || nil] 60 | } 61 | 62 | r = '' 63 | while /OK\x0d\x0a/o !~ r 64 | r << dev.getc.chr 65 | p [:response, r] 66 | end 67 | 68 | setattr(dev, TCSANOW, oldtio) 69 | dump_termios(getattr(dev), "current tio:") 70 | -------------------------------------------------------------------------------- /examples/modem_check1.rb: -------------------------------------------------------------------------------- 1 | require 'fcntl' 2 | require 'termios' 3 | 4 | DEVICE = '/dev/modem' 5 | BAUDRATE = Termios::B115200 6 | 7 | def dev_open(path) 8 | dev = open(DEVICE, File::RDWR | File::NONBLOCK) 9 | mode = dev.fcntl(Fcntl::F_GETFL, 0) 10 | dev.fcntl(Fcntl::F_SETFL, mode & ~File::NONBLOCK) 11 | dev 12 | end 13 | 14 | def dump_termios(tio, banner) 15 | puts banner 16 | puts " ispeed = #{Termios::BAUDS[tio.ispeed]}, ospeed = #{Termios::BAUDS[tio.ospeed]}" 17 | ["iflag", "oflag", "cflag", "lflag"].each do |x| 18 | flag = tio.send(x) 19 | flags = [] 20 | eval("Termios::#{x.upcase}S").each do |f, sym| 21 | flags << sym.to_s if flag & f != 0 22 | end 23 | puts " #{x} = #{flags.sort.join(' | ')}" 24 | end 25 | print " cc =" 26 | cc = tio.cc 27 | cc.each_with_index do |x, idx| 28 | print " #{Termios::CCINDEX[idx]}=#{x}" if Termios::CCINDEX.include?(idx) 29 | end 30 | puts 31 | end 32 | 33 | dev = dev_open(DEVICE) 34 | 35 | oldtio = Termios::tcgetattr(dev) 36 | dump_termios(oldtio, "current tio:") 37 | 38 | newtio = Termios::new_termios() 39 | newtio.iflag = Termios::IGNPAR 40 | newtio.oflag = 0 41 | newtio.cflag = (Termios::CRTSCTS | Termios::CS8 | Termios::CREAD) 42 | newtio.lflag = 0 43 | newtio.cc[Termios::VTIME] = 0 44 | newtio.cc[Termios::VMIN] = 1 45 | newtio.ispeed = BAUDRATE 46 | newtio.ospeed = BAUDRATE 47 | dump_termios(newtio, "new tio:") 48 | 49 | Termios::tcflush(dev, Termios::TCIOFLUSH) 50 | Termios::tcsetattr(dev, Termios::TCSANOW, newtio) 51 | dump_termios(Termios::tcgetattr(dev), "current tio:") 52 | 53 | "AT\x0d".each_byte {|c| 54 | c = c.chr 55 | p [:write_char, c] 56 | dev.putc c 57 | d = dev.getc 58 | p [:echo_back, d && d.chr || nil] 59 | } 60 | 61 | r = '' 62 | while /OK\x0d\x0a/o !~ r 63 | r << dev.getc.chr 64 | p [:response, r] 65 | end 66 | 67 | Termios::tcsetattr(dev, Termios::TCSANOW, oldtio) 68 | dump_termios(Termios::tcgetattr(dev), "current tio:") 69 | -------------------------------------------------------------------------------- /examples/modem_check2.rb: -------------------------------------------------------------------------------- 1 | require 'fcntl' 2 | require 'termios' 3 | 4 | DEVICE = '/dev/modem' 5 | BAUDRATE = Termios::B115200 6 | 7 | def dev_open(path) 8 | dev = open(DEVICE, File::RDWR | File::NONBLOCK) 9 | mode = dev.fcntl(Fcntl::F_GETFL, 0) 10 | dev.fcntl(Fcntl::F_SETFL, mode & ~File::NONBLOCK) 11 | dev 12 | end 13 | 14 | def dump_termios(tio, banner) 15 | puts banner 16 | puts " ispeed = #{Termios::BAUDS[tio.ispeed]}, ospeed = #{Termios::BAUDS[tio.ospeed]}" 17 | ["iflag", "oflag", "cflag", "lflag"].each do |x| 18 | flag = tio.send(x) 19 | flags = [] 20 | eval("Termios::#{x.upcase}S").each do |f, sym| 21 | flags << sym.to_s if flag & f != 0 22 | end 23 | puts " #{x} = #{flags.sort.join(' | ')}" 24 | end 25 | print " cc =" 26 | cc = tio.cc 27 | cc.each_with_index do |x, idx| 28 | print " #{Termios::CCINDEX[idx]}=#{x}" if Termios::CCINDEX.include?(idx) 29 | end 30 | puts 31 | end 32 | 33 | dev = dev_open(DEVICE) 34 | dev.extend Termios 35 | 36 | oldtio = dev.tcgetattr 37 | dump_termios(oldtio, "current tio:") 38 | 39 | newtio = Termios::new_termios() 40 | newtio.iflag = Termios::IGNPAR 41 | newtio.oflag = 0 42 | newtio.cflag = (Termios::CRTSCTS | Termios::CS8 | Termios::CREAD) 43 | newtio.lflag = 0 44 | newtio.cc[Termios::VTIME] = 0 45 | newtio.cc[Termios::VMIN] = 1 46 | newtio.ispeed = BAUDRATE 47 | newtio.ospeed = BAUDRATE 48 | dump_termios(newtio, "new tio:") 49 | 50 | dev.tcflush(Termios::TCIOFLUSH) 51 | dev.tcsetattr(Termios::TCSANOW, newtio) 52 | dump_termios(dev.tcgetattr, "current tio:") 53 | 54 | "AT\x0d".each_byte {|c| 55 | c = c.chr 56 | p [:write_char, c] 57 | dev.putc c 58 | d = dev.getc 59 | p [:echo_back, d && d.chr || nil] 60 | } 61 | 62 | r = '' 63 | while /OK\x0d\x0a/o !~ r 64 | r << dev.getc.chr 65 | p [:response, r] 66 | end 67 | 68 | dev.tcsetattr(Termios::TCSANOW, oldtio) 69 | dump_termios(dev.tcgetattr, "current tio:") 70 | -------------------------------------------------------------------------------- /examples/secret_input1.rb: -------------------------------------------------------------------------------- 1 | # to input secretly [ruby-list:15968] 2 | require 'termios' 3 | 4 | oldt = Termios.tcgetattr($stdin) 5 | newt = oldt.dup 6 | newt.lflag &= ~Termios::ECHO 7 | Termios.tcsetattr($stdin, Termios::TCSANOW, newt) 8 | print "noecho> " 9 | a = $stdin.gets 10 | Termios.tcsetattr($stdin, Termios::TCSANOW, oldt) 11 | print "\n" 12 | p a 13 | -------------------------------------------------------------------------------- /examples/secret_input2.rb: -------------------------------------------------------------------------------- 1 | # to input secretly [ruby-list:15968] 2 | require 'termios' 3 | 4 | $stdin.extend Termios 5 | 6 | oldt = $stdin.tcgetattr 7 | newt = oldt.dup 8 | newt.lflag &= ~Termios::ECHO 9 | $stdin.tcsetattr(Termios::TCSANOW, newt) 10 | print "noecho> " 11 | a = $stdin.gets 12 | $stdin.tcsetattr(Termios::TCSANOW, oldt) 13 | print "\n" 14 | p a 15 | -------------------------------------------------------------------------------- /ext/extconf.rb: -------------------------------------------------------------------------------- 1 | require 'mkmf' 2 | 3 | Dir.glob('./lib/**/*.rb') do |f| 4 | $INSTALLFILES << [f, '$(RUBYLIBDIR)', 'lib'] 5 | end 6 | 7 | if have_header('termios.h') && 8 | have_header('unistd.h') 9 | have_header('sys/ioctl.h') 10 | 11 | if RUBY_VERSION >= '1.7' 12 | if have_header('ruby/io.h') 13 | have_type("rb_io_t", ["ruby/io.h"]) 14 | have_struct_member("rb_io_t", "fd", ["ruby/io.h"]) 15 | else 16 | if have_type("rb_io_t", ["ruby.h", "rubyio.h"]) 17 | have_struct_member("rb_io_t", "fd", ["ruby.h", "rubyio.h"]) 18 | else 19 | have_struct_member("OpenFile", "fd", ["ruby.h", "rubyio.h"]) 20 | end 21 | if have_macro("OpenFile", ["ruby.h", "rubyio.h"]) 22 | $defs.push("-DHAVE_MACRO_OPENFILE") 23 | end 24 | end 25 | end 26 | 27 | create_makefile('termios') 28 | end 29 | -------------------------------------------------------------------------------- /ext/termios.c: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | A termios library for Ruby. 4 | Copyright (C) 1999, 2000, 2002 akira yamada. 5 | 6 | */ 7 | 8 | #include "ruby.h" 9 | #if defined(HAVE_RUBY_IO_H) 10 | #include "ruby/io.h" 11 | #else 12 | #include "rubyio.h" 13 | #endif 14 | #include 15 | #include 16 | #if defined(HAVE_SYS_IOCTL_H) 17 | #include 18 | #endif 19 | #include 20 | 21 | #if defined(HAVE_TYPE_RB_IO_T) && !defined(HAVE_MACRO_OPENFILE) 22 | typedef rb_io_t OpenFile; 23 | #endif 24 | 25 | #if defined(HAVE_ST_FD) 26 | #define FILENO(fptr) (fptr->fd) 27 | #else 28 | #define FILENO(fptr) fileno(fptr->f) 29 | #endif 30 | 31 | #define validate_ulong(v) ULONG2NUM(NUM2ULONG(v)) 32 | 33 | static VALUE mTermios; 34 | static VALUE cTermios; 35 | static VALUE tcsetattr_opt, tcflush_qs, tcflow_act; 36 | static ID id_iflag, id_oflag, id_cflag, id_lflag, id_cc, id_ispeed, id_ospeed; 37 | 38 | /* 39 | * Document-class: Termios::Termios 40 | * 41 | * Encupsalates termios parameters. 42 | * 43 | * See also: termios(3) 44 | */ 45 | 46 | /* 47 | * call-seq: 48 | * termios.iflag = flag 49 | * 50 | * Updates input modes of the object. 51 | */ 52 | static VALUE 53 | termios_set_iflag(self, value) 54 | VALUE self, value; 55 | { 56 | rb_ivar_set(self, id_iflag, validate_ulong(value)); 57 | 58 | return value; 59 | } 60 | 61 | /* 62 | * call-seq: 63 | * termios.oflag = flag 64 | * 65 | * Updates output modes of the object. 66 | */ 67 | static VALUE 68 | termios_set_oflag(self, value) 69 | VALUE self, value; 70 | { 71 | rb_ivar_set(self, id_oflag, validate_ulong(value)); 72 | 73 | return value; 74 | } 75 | 76 | /* 77 | * call-seq: 78 | * termios.cflag = flag 79 | * 80 | * Updates control modes of the object. 81 | */ 82 | static VALUE 83 | termios_set_cflag(self, value) 84 | VALUE self, value; 85 | { 86 | rb_ivar_set(self, id_cflag, validate_ulong(value)); 87 | 88 | return value; 89 | } 90 | 91 | /* 92 | * call-seq: 93 | * termios.lflag = flag 94 | * 95 | * Updates local modes of the object. 96 | */ 97 | static VALUE 98 | termios_set_lflag(self, value) 99 | VALUE self, value; 100 | { 101 | rb_ivar_set(self, id_lflag, validate_ulong(value)); 102 | 103 | return value; 104 | } 105 | 106 | /* 107 | * call-seq: 108 | * termios.cc = value 109 | * 110 | * Updates control characters of the object. 111 | */ 112 | static VALUE 113 | termios_set_cc(self, value) 114 | VALUE self, value; 115 | { 116 | Check_Type(value, T_ARRAY); 117 | rb_ivar_set(self, id_cc, value); 118 | 119 | return value; 120 | } 121 | 122 | /* 123 | * call-seq: 124 | * termios.ispeed = speed 125 | * 126 | * Updates input baud rate of the object. 127 | */ 128 | static VALUE 129 | termios_set_ispeed(self, value) 130 | VALUE self, value; 131 | { 132 | rb_ivar_set(self, id_ispeed, validate_ulong(value)); 133 | 134 | return value; 135 | } 136 | 137 | /* 138 | * call-seq: 139 | * termios.ospeed = speed 140 | * 141 | * Updates output baud rate of the object. 142 | */ 143 | static VALUE 144 | termios_set_ospeed(self, value) 145 | VALUE self, value; 146 | { 147 | rb_ivar_set(self, id_ospeed, validate_ulong(value)); 148 | 149 | return value; 150 | } 151 | 152 | /* 153 | * call-seq: 154 | * Termios.new 155 | * 156 | * Returns new Termios::Termios object. 157 | */ 158 | static VALUE 159 | termios_initialize(argc, argv, self) 160 | int argc; 161 | VALUE *argv; 162 | VALUE self; 163 | { 164 | VALUE c_iflag, c_oflag, c_cflag, c_lflag, c_cc, c_ispeed, c_ospeed; 165 | VALUE cc_ary; 166 | int i; 167 | 168 | cc_ary = rb_ary_new2(NCCS); 169 | for (i = 0; i < NCCS; i++) { 170 | rb_ary_store(cc_ary, i, INT2FIX(0)); 171 | } 172 | 173 | rb_ivar_set(self, id_iflag, INT2FIX(0)); 174 | rb_ivar_set(self, id_oflag, INT2FIX(0)); 175 | rb_ivar_set(self, id_cflag, INT2FIX(0)); 176 | rb_ivar_set(self, id_lflag, INT2FIX(0)); 177 | rb_ivar_set(self, id_cc, cc_ary); 178 | rb_ivar_set(self, id_ispeed, INT2FIX(0)); 179 | rb_ivar_set(self, id_ospeed, INT2FIX(0)); 180 | 181 | rb_scan_args(argc, argv, "07", 182 | &c_iflag, &c_oflag, &c_cflag, &c_lflag, 183 | &c_cc, &c_ispeed, &c_ospeed); 184 | 185 | if (!NIL_P(c_iflag)) 186 | termios_set_iflag(self, c_iflag); 187 | 188 | if (!NIL_P(c_oflag)) 189 | termios_set_oflag(self, c_oflag); 190 | 191 | if (!NIL_P(c_cflag)) 192 | termios_set_cflag(self, c_cflag); 193 | 194 | if (!NIL_P(c_lflag)) 195 | termios_set_lflag(self, c_lflag); 196 | 197 | if (!NIL_P(c_cc)) 198 | termios_set_cc(self, c_cc); 199 | 200 | if (!NIL_P(c_ispeed)) 201 | termios_set_ispeed(self, c_ispeed); 202 | 203 | if (!NIL_P(c_ospeed)) 204 | termios_set_ispeed(self, c_ospeed); 205 | 206 | return self; 207 | } 208 | 209 | /* 210 | * Document-module: Termios 211 | * 212 | * = Description 213 | * 214 | * Termios module is simple wrapper of termios(3). It can be included 215 | * into IO-family classes and can extend IO-family objects. In addition, 216 | * the methods can use as module function. 217 | * 218 | * You can call termios(3) function as module methods. Or you can use these 219 | * methods as instance method by including Termios module to the target IO 220 | * object. 221 | * 222 | * == Constants 223 | * 224 | * Many constants which are derived from "termios.h" are defined on Termios 225 | * module. You can use these constants as the same name in "termios.h" 226 | * basically. 227 | * 228 | * IFLAGS, OFLAGS, CFLAGS and LFLAGS are Hash object. They contains Symbols 229 | * of constants for c_iflag, c_oflag, c_cflag and c_lflag. CCINDEX and BAUDS 230 | * are Hash object too. They contains Symbols of constats for c_cc or ispeed 231 | * and ospeed. 232 | * 233 | * == See also 234 | * 235 | * termios(3) 236 | */ 237 | 238 | static VALUE 239 | termios_to_Termios(t) 240 | struct termios *t; 241 | { 242 | int i; 243 | VALUE obj, cc_ary; 244 | 245 | obj = rb_funcall(cTermios, rb_intern("new"), 0); 246 | 247 | termios_set_iflag(obj, ULONG2NUM(t->c_iflag)); 248 | termios_set_oflag(obj, ULONG2NUM(t->c_oflag)); 249 | termios_set_cflag(obj, ULONG2NUM(t->c_cflag)); 250 | termios_set_lflag(obj, ULONG2NUM(t->c_lflag)); 251 | 252 | cc_ary = rb_ary_new2(NCCS); 253 | for (i = 0; i < NCCS; i++) { 254 | rb_ary_store(cc_ary, i, CHR2FIX(t->c_cc[i])); 255 | } 256 | termios_set_cc(obj, cc_ary); 257 | 258 | termios_set_ispeed(obj, ULONG2NUM(cfgetispeed(t))); 259 | termios_set_ospeed(obj, ULONG2NUM(cfgetospeed(t))); 260 | 261 | return obj; 262 | } 263 | 264 | static void 265 | Termios_to_termios(obj, t) 266 | VALUE obj; 267 | struct termios *t; 268 | { 269 | int i; 270 | VALUE cc_ary; 271 | 272 | t->c_iflag = NUM2ULONG(rb_ivar_get(obj, id_iflag)); 273 | t->c_oflag = NUM2ULONG(rb_ivar_get(obj, id_oflag)); 274 | t->c_cflag = NUM2ULONG(rb_ivar_get(obj, id_cflag)); 275 | t->c_lflag = NUM2ULONG(rb_ivar_get(obj, id_lflag)); 276 | 277 | cc_ary = rb_ivar_get(obj, id_cc); 278 | for (i = 0; i < NCCS; i++) { 279 | VALUE elt = rb_ary_entry(cc_ary, i); 280 | t->c_cc[i] = NUM2CHR(elt); 281 | } 282 | 283 | cfsetispeed(t, NUM2ULONG(rb_ivar_get(obj, id_ispeed))); 284 | cfsetospeed(t, NUM2ULONG(rb_ivar_get(obj, id_ospeed))); 285 | } 286 | 287 | /* 288 | * call-seq: 289 | * Termios.tcgetattr(io) 290 | * io.tcgetattr 291 | * 292 | * Returns new Termios::Termios object which stores termios parameters 293 | * associated with the io. 294 | * 295 | * require 'termios' 296 | * 297 | * Termios.tcgetattr($stdin) 298 | * #=> # 299 | * 300 | * $stdout.extend(Termios) 301 | * $stdout.tcgetattr 302 | * #=> # 303 | * 304 | * See also: tcgetattr(3) 305 | */ 306 | static VALUE 307 | termios_tcgetattr(io) 308 | VALUE io; 309 | { 310 | struct termios t; 311 | OpenFile *fptr; 312 | 313 | Check_Type(io, T_FILE); 314 | GetOpenFile(io, fptr); 315 | if (tcgetattr(FILENO(fptr), &t) < 0) { 316 | rb_sys_fail("tcgetattr"); 317 | } 318 | 319 | return termios_to_Termios(&t); 320 | } 321 | 322 | static VALUE 323 | termios_s_tcgetattr(obj, io) 324 | VALUE obj, io; 325 | { 326 | return termios_tcgetattr(io); 327 | } 328 | 329 | /* 330 | * call-seq: 331 | * Termios.tcsetattr(io, option, termios) 332 | * io.tcsetattr(option, termios) 333 | * 334 | * Sets the Termios::Termios object as the termios paramter to the io 335 | * and returns the old termios parameter. 336 | * 337 | * Option are specifies when the parameter is changed. What option are 338 | * available is plathome dependent, but usually Termios::TCSANOW, 339 | * Termios::TCSADRAIN and Termios::TCSAFLUSH are provided. 340 | * 341 | * require 'termios' 342 | * 343 | * oldt = Termios.tcgetattr($stdin) 344 | * newt = oldt.dup 345 | * newt.lflag &= ~Termios::ECHO 346 | * 347 | * secret = nil 348 | * begin 349 | * Termios.tcsetattr($stdin, Termios::TCSANOW, newt) 350 | * print "noecho> " 351 | * secret = $stdin.gets 352 | * print "\n" 353 | * ensure 354 | * Termios.tcsetattr($stdin, Termios::TCSANOW, oldt) 355 | * end 356 | * 357 | * puts secret 358 | * 359 | * See also: tcsetattr(3) 360 | */ 361 | static VALUE 362 | termios_tcsetattr(io, opt, param) 363 | VALUE io, opt, param; 364 | { 365 | VALUE old; 366 | OpenFile *fptr; 367 | struct termios t; 368 | int tcsetattr_option; 369 | 370 | Check_Type(io, T_FILE); 371 | Check_Type(opt, T_FIXNUM); 372 | if (CLASS_OF(param) != cTermios) { 373 | const char *type = rb_class2name(CLASS_OF(param)); 374 | rb_raise(rb_eTypeError, 375 | "wrong argument type %s (expected Termios::Termios)", 376 | type); 377 | } 378 | 379 | tcsetattr_option = FIX2INT(opt); 380 | if (rb_ary_includes(tcsetattr_opt, opt) != Qtrue) { 381 | rb_raise(rb_eArgError, 382 | "wrong option value %d", tcsetattr_option); 383 | } 384 | 385 | old = termios_tcgetattr(io); 386 | GetOpenFile(io, fptr); 387 | Termios_to_termios(param, &t); 388 | if (tcsetattr(FILENO(fptr), tcsetattr_option, &t) < 0) { 389 | rb_sys_fail("tcsetattr"); 390 | } 391 | 392 | return old; 393 | } 394 | 395 | static VALUE 396 | termios_s_tcsetattr(obj, io, opt, param) 397 | VALUE obj, io, opt, param; 398 | { 399 | return termios_tcsetattr(io, opt, param); 400 | } 401 | 402 | /* 403 | * call-seq: 404 | * Termios.tcsendbreak(io, duration) 405 | * io.tcsendbreak(duration) 406 | * 407 | * Sends a continuous stream of 0-bits for a specific duration. 408 | * 409 | * See also: tcsendbreak(3) 410 | */ 411 | static VALUE 412 | termios_tcsendbreak(io, duration) 413 | VALUE io, duration; 414 | { 415 | OpenFile *fptr; 416 | 417 | Check_Type(io, T_FILE); 418 | Check_Type(duration, T_FIXNUM); 419 | 420 | GetOpenFile(io, fptr); 421 | if (tcsendbreak(FILENO(fptr), FIX2INT(duration)) < 0) { 422 | rb_sys_fail("tcsendbreak"); 423 | } 424 | 425 | return Qtrue; 426 | } 427 | 428 | static VALUE 429 | termios_s_tcsendbreak(obj, io, duration) 430 | VALUE obj, io, duration; 431 | { 432 | return termios_tcsendbreak(io, duration); 433 | } 434 | 435 | /* 436 | * call-seq: 437 | * Termios.tcdrain(io) 438 | * io.tcdrain 439 | * 440 | * Waits until all output to the object has been sent. 441 | * 442 | * See also: tcdrain(3) 443 | */ 444 | static VALUE 445 | termios_tcdrain(io) 446 | VALUE io; 447 | { 448 | OpenFile *fptr; 449 | 450 | Check_Type(io, T_FILE); 451 | 452 | GetOpenFile(io, fptr); 453 | if (tcdrain(FILENO(fptr)) < 0) { 454 | rb_sys_fail("tcdrain"); 455 | } 456 | 457 | return Qtrue; 458 | } 459 | 460 | static VALUE 461 | termios_s_tcdrain(obj, io) 462 | VALUE obj, io; 463 | { 464 | return termios_tcdrain(io); 465 | } 466 | 467 | /* 468 | * call-seq: 469 | * Termios.tcflush(io, qs) 470 | * io.tcflush(qs) 471 | * 472 | * Cancels data written to the object but not send or data received but not 473 | * read. 474 | * 475 | * See also: tcflush(3) 476 | */ 477 | static VALUE 478 | termios_tcflush(io, qs) 479 | VALUE io, qs; 480 | { 481 | OpenFile *fptr; 482 | int queue_selector; 483 | 484 | Check_Type(io, T_FILE); 485 | Check_Type(qs, T_FIXNUM); 486 | queue_selector = FIX2INT(qs); 487 | if (rb_ary_includes(tcflush_qs, qs) != Qtrue) { 488 | rb_raise(rb_eArgError, 489 | "wrong queue-selector value %d", queue_selector); 490 | } 491 | 492 | GetOpenFile(io, fptr); 493 | if (tcflush(FILENO(fptr), queue_selector) < 0) { 494 | rb_sys_fail("tcflush"); 495 | } 496 | 497 | return Qtrue; 498 | } 499 | 500 | static VALUE 501 | termios_s_tcflush(obj, io, qs) 502 | VALUE obj, io, qs; 503 | { 504 | return termios_tcflush(io, qs); 505 | } 506 | 507 | /* 508 | * call-seq: 509 | * Termios.tcflow(io, action) 510 | * io.tcflow(action) 511 | * 512 | * Suspends write or read of data on the object. 513 | * 514 | * See also: tcflow(3) 515 | */ 516 | static VALUE 517 | termios_tcflow(io, act) 518 | VALUE io, act; 519 | { 520 | OpenFile *fptr; 521 | int action; 522 | 523 | Check_Type(io, T_FILE); 524 | Check_Type(act, T_FIXNUM); 525 | action = FIX2INT(act); 526 | if (rb_ary_includes(tcflow_act, act) != Qtrue) { 527 | rb_raise(rb_eArgError, 528 | "wrong action value %d", action); 529 | } 530 | 531 | GetOpenFile(io, fptr); 532 | if (tcflow(FILENO(fptr), action) < 0) { 533 | rb_sys_fail("tcflow"); 534 | } 535 | 536 | return Qtrue; 537 | } 538 | 539 | static VALUE 540 | termios_s_tcflow(obj, io, act) 541 | VALUE obj, io, act; 542 | { 543 | return termios_tcflow(io, act); 544 | } 545 | 546 | /* 547 | * call-seq: 548 | * Termios.tcgetpgrp(io) 549 | * io.tcgetpgrp 550 | * 551 | * Returns the process group ID of the foreground process group the 552 | * terminal associated to the object. 553 | * 554 | * See also: tcgetpgrp(3) 555 | */ 556 | static VALUE 557 | termios_tcgetpgrp(io) 558 | VALUE io; 559 | { 560 | OpenFile *fptr; 561 | pid_t pid; 562 | 563 | Check_Type(io, T_FILE); 564 | GetOpenFile(io, fptr); 565 | if ((pid = tcgetpgrp(FILENO(fptr))) < 0) { 566 | rb_sys_fail("tcgetpgrp"); 567 | } 568 | 569 | return LONG2NUM(pid); 570 | } 571 | 572 | static VALUE 573 | termios_s_tcgetpgrp(obj, io) 574 | VALUE obj, io; 575 | { 576 | return termios_tcgetpgrp(io); 577 | } 578 | 579 | /* 580 | * call-seq: 581 | * Termios.tcsetpgrp(io, pgrpid) 582 | * io.tcsetpgrp(pgrpid) 583 | * 584 | * Makes the process group with pgrpid the foreground process group on the 585 | * terminal associated to the object. 586 | * 587 | * See also: tcsetpgrp(3) 588 | */ 589 | static VALUE 590 | termios_tcsetpgrp(io, pgrpid) 591 | VALUE io, pgrpid; 592 | { 593 | OpenFile *fptr; 594 | pid_t pgrp; 595 | 596 | Check_Type(io, T_FILE); 597 | pgrp = NUM2LONG(pgrpid); 598 | 599 | GetOpenFile(io, fptr); 600 | if (tcsetpgrp(FILENO(fptr), pgrp) < 0) { 601 | rb_sys_fail("tcsetpgrp"); 602 | } 603 | 604 | return Qtrue; 605 | } 606 | 607 | static VALUE 608 | termios_s_tcsetpgrp(obj, io, pgrpid) 609 | VALUE obj, io, pgrpid; 610 | { 611 | return termios_tcsetpgrp(io, pgrpid); 612 | } 613 | 614 | /* 615 | * call-seq: 616 | * Termios.new_termios 617 | * 618 | * Returns new Termios::Termios object. 619 | */ 620 | static VALUE 621 | termios_s_newtermios(argc, argv, klass) 622 | int argc; 623 | VALUE *argv; 624 | VALUE klass; 625 | { 626 | return rb_funcall2(cTermios, rb_intern("new"), argc, argv); 627 | } 628 | 629 | /* 630 | * call-seq: 631 | * termios.dup 632 | * 633 | * Produces a shallow copy of the object. 634 | */ 635 | static VALUE 636 | termios_dup(self) 637 | VALUE self; 638 | { 639 | VALUE result; 640 | VALUE cc_ary; 641 | 642 | result = rb_call_super(0, 0); 643 | cc_ary = rb_ivar_get(self, id_cc); 644 | rb_ivar_set(result, id_cc, rb_ary_dup(cc_ary)); 645 | 646 | return result; 647 | } 648 | 649 | void 650 | Init_termios() 651 | { 652 | VALUE ccindex, ccindex_names; 653 | VALUE iflags, iflags_names; 654 | VALUE oflags, oflags_names, oflags_choices; 655 | VALUE cflags, cflags_names, cflags_choices; 656 | VALUE lflags, lflags_names; 657 | VALUE bauds, bauds_names; 658 | VALUE ioctl_commands, ioctl_commands_names; 659 | VALUE modem_signals, modem_signals_names; 660 | VALUE pty_pkt_options, pty_pkt_options_names; 661 | VALUE line_disciplines, line_disciplines_names; 662 | 663 | /* module Termios */ 664 | 665 | mTermios = rb_define_module("Termios"); 666 | 667 | rb_define_singleton_method(mTermios,"tcgetattr", termios_s_tcgetattr, 1); 668 | rb_define_module_function(mTermios, "getattr", termios_s_tcgetattr, 1); 669 | rb_define_method(mTermios, "tcgetattr", termios_tcgetattr, 0); 670 | 671 | rb_define_singleton_method(mTermios,"tcsetattr", termios_s_tcsetattr, 3); 672 | rb_define_module_function(mTermios, "setattr", termios_s_tcsetattr, 3); 673 | rb_define_method(mTermios, "tcsetattr", termios_tcsetattr, 2); 674 | 675 | rb_define_singleton_method(mTermios,"tcsendbreak",termios_s_tcsendbreak,2); 676 | rb_define_module_function(mTermios, "sendbreak",termios_s_tcsendbreak,2); 677 | rb_define_method(mTermios, "tcsendbreak",termios_tcsendbreak, 1); 678 | 679 | rb_define_singleton_method(mTermios,"tcdrain", termios_s_tcdrain, 1); 680 | rb_define_module_function(mTermios, "drain", termios_s_tcdrain, 1); 681 | rb_define_method(mTermios, "tcdrain", termios_tcdrain, 0); 682 | 683 | rb_define_singleton_method(mTermios,"tcflush", termios_s_tcflush, 2); 684 | rb_define_module_function(mTermios, "flush", termios_s_tcflush, 2); 685 | rb_define_method(mTermios, "tcflush", termios_tcflush, 1); 686 | 687 | rb_define_singleton_method(mTermios,"tcflow", termios_s_tcflow, 2); 688 | rb_define_module_function(mTermios, "flow", termios_s_tcflow, 2); 689 | rb_define_method(mTermios, "tcflow", termios_tcflow, 1); 690 | 691 | rb_define_singleton_method(mTermios,"tcgetpgrp", termios_s_tcgetpgrp, 1); 692 | rb_define_module_function(mTermios, "getpgrp", termios_s_tcgetpgrp, 1); 693 | rb_define_method(mTermios, "tcgetpgrp", termios_tcgetpgrp, 0); 694 | 695 | rb_define_singleton_method(mTermios,"tcsetpgrp", termios_s_tcsetpgrp, 2); 696 | rb_define_module_function(mTermios, "setpgrp", termios_s_tcsetpgrp, 2); 697 | rb_define_method(mTermios, "tcsetpgrp", termios_tcsetpgrp, 1); 698 | 699 | rb_define_module_function(mTermios,"new_termios",termios_s_newtermios, -1); 700 | 701 | /* class Termios::Termios */ 702 | 703 | cTermios = rb_define_class_under(mTermios, "Termios", rb_cObject); 704 | 705 | id_iflag = rb_intern("@iflag"); 706 | id_oflag = rb_intern("@oflag"); 707 | id_cflag = rb_intern("@cflag"); 708 | id_lflag = rb_intern("@lflag"); 709 | id_cc = rb_intern("@cc"); 710 | id_ispeed = rb_intern("@ispeed"); 711 | id_ospeed = rb_intern("@ospeed"); 712 | 713 | /* input modes */ 714 | rb_define_attr(cTermios, "iflag", 1, 0); 715 | /* output modes */ 716 | rb_define_attr(cTermios, "oflag", 1, 0); 717 | /* control modes */ 718 | rb_define_attr(cTermios, "cflag", 1, 0); 719 | /* local modes */ 720 | rb_define_attr(cTermios, "lflag", 1, 0); 721 | /* control characters */ 722 | rb_define_attr(cTermios, "cc", 1, 0); 723 | /* input baud rate */ 724 | rb_define_attr(cTermios, "ispeed", 1, 0); 725 | /* output baud rate */ 726 | rb_define_attr(cTermios, "ospeed", 1, 0); 727 | 728 | rb_define_private_method(cTermios, "initialize", termios_initialize, -1); 729 | rb_define_method(cTermios, "dup", termios_dup, 0); 730 | rb_define_method(cTermios, "clone", termios_dup, 0); 731 | 732 | rb_define_method(cTermios, "iflag=", termios_set_iflag, 1); 733 | rb_define_method(cTermios, "oflag=", termios_set_oflag, 1); 734 | rb_define_method(cTermios, "cflag=", termios_set_cflag, 1); 735 | rb_define_method(cTermios, "lflag=", termios_set_lflag, 1); 736 | rb_define_method(cTermios, "cc=", termios_set_cc, 1); 737 | rb_define_method(cTermios, "ispeed=", termios_set_ispeed, 1); 738 | rb_define_method(cTermios, "ospeed=", termios_set_ospeed, 1); 739 | 740 | rb_define_alias(cTermios, "c_iflag", "iflag"); 741 | rb_define_alias(cTermios, "c_iflag=", "iflag="); 742 | rb_define_alias(cTermios, "c_oflag", "oflag"); 743 | rb_define_alias(cTermios, "c_oflag=", "oflag="); 744 | rb_define_alias(cTermios, "c_cflag", "cflag"); 745 | rb_define_alias(cTermios, "c_cflag=", "cflag="); 746 | rb_define_alias(cTermios, "c_lflag", "lflag"); 747 | rb_define_alias(cTermios, "c_lflag=", "lflag="); 748 | rb_define_alias(cTermios, "c_cc", "cc"); 749 | rb_define_alias(cTermios, "c_cc=", "cc="); 750 | rb_define_alias(cTermios, "c_ispeed", "ispeed"); 751 | rb_define_alias(cTermios, "c_ispeed=", "ispeed="); 752 | rb_define_alias(cTermios, "c_ospeed", "ospeed"); 753 | rb_define_alias(cTermios, "c_ospeed=", "ospeed="); 754 | 755 | /* constants under Termios module */ 756 | 757 | /* number of control characters */ 758 | rb_define_const(mTermios, "NCCS", INT2FIX(NCCS)); 759 | rb_define_const(mTermios, "POSIX_VDISABLE", INT2FIX(_POSIX_VDISABLE)); 760 | 761 | ccindex = rb_hash_new(); 762 | ccindex_names = rb_ary_new(); 763 | /* Hash of control character index and control character names */ 764 | rb_define_const(mTermios, "CCINDEX", ccindex); 765 | /* List of control character names */ 766 | rb_define_const(mTermios, "CCINDEX_NAMES", ccindex_names); 767 | 768 | iflags = rb_hash_new(); 769 | iflags_names = rb_ary_new(); 770 | /* Hash of input mode names and values */ 771 | rb_define_const(mTermios, "IFLAGS", iflags); 772 | /* List of input mode names */ 773 | rb_define_const(mTermios, "IFLAG_NAMES", iflags_names); 774 | 775 | oflags = rb_hash_new(); 776 | oflags_names = rb_ary_new(); 777 | oflags_choices = rb_hash_new(); 778 | /* Hash of output mode names and values */ 779 | rb_define_const(mTermios, "OFLAGS", oflags); 780 | /* List of output mode names */ 781 | rb_define_const(mTermios, "OFLAG_NAMES", oflags_names); 782 | rb_define_const(mTermios, "OFLAG_CHOICES", oflags_choices); 783 | 784 | cflags = rb_hash_new(); 785 | cflags_names = rb_ary_new(); 786 | cflags_choices = rb_hash_new(); 787 | /* Hash of control mode names and values */ 788 | rb_define_const(mTermios, "CFLAGS", cflags); 789 | /* List of control mode names */ 790 | rb_define_const(mTermios, "CFLAG_NAMES", cflags_names); 791 | rb_define_const(mTermios, "CFLAG_CHOICES", cflags_choices); 792 | 793 | lflags = rb_hash_new(); 794 | lflags_names = rb_ary_new(); 795 | /* Hash of local mode names and values */ 796 | rb_define_const(mTermios, "LFLAGS", lflags); 797 | /* List of local mode names */ 798 | rb_define_const(mTermios, "LFLAG_NAMES", lflags_names); 799 | 800 | bauds = rb_hash_new(); 801 | bauds_names = rb_ary_new(); 802 | /* List of baud rates */ 803 | rb_define_const(mTermios, "BAUDS", bauds); 804 | /* List of baud rate names */ 805 | rb_define_const(mTermios, "BAUD_NAMES", bauds_names); 806 | 807 | tcsetattr_opt = rb_ary_new(); 808 | /* List of tcsetattr options */ 809 | rb_define_const(mTermios, "SETATTR_OPTS", tcsetattr_opt); 810 | 811 | tcflush_qs = rb_ary_new(); 812 | /* List of tcflush qselectors */ 813 | rb_define_const(mTermios, "FLUSH_QSELECTORS", tcflush_qs); 814 | 815 | tcflow_act = rb_ary_new(); 816 | /* List of tcflow actions */ 817 | rb_define_const(mTermios, "FLOW_ACTIONS", tcflow_act); 818 | 819 | ioctl_commands = rb_hash_new(); 820 | ioctl_commands_names = rb_ary_new(); 821 | rb_define_const(mTermios, "IOCTL_COMMANDS", ioctl_commands); 822 | rb_define_const(mTermios, "IOCTL_COMMAND_NAMES", ioctl_commands_names); 823 | 824 | modem_signals = rb_hash_new(); 825 | modem_signals_names = rb_ary_new(); 826 | rb_define_const(mTermios, "MODEM_SIGNALS", modem_signals); 827 | rb_define_const(mTermios, "MODEM_SIGNAL_NAMES", modem_signals_names); 828 | 829 | pty_pkt_options = rb_hash_new(); 830 | pty_pkt_options_names = rb_ary_new(); 831 | rb_define_const(mTermios, "PTY_PACKET_OPTIONS", pty_pkt_options); 832 | rb_define_const(mTermios, "PTY_PACKET_OPTION_NAMES", pty_pkt_options_names); 833 | 834 | line_disciplines = rb_hash_new(); 835 | line_disciplines_names = rb_ary_new(); 836 | rb_define_const(mTermios, "LINE_DISCIPLINES", line_disciplines); 837 | rb_define_const(mTermios, "LINE_DISCIPLINE_NAMES", line_disciplines_names); 838 | 839 | #define define_flag(hash, flag) \ 840 | { \ 841 | rb_define_const(mTermios, #flag, ULONG2NUM(flag)); \ 842 | rb_hash_aset(hash, rb_const_get(mTermios, rb_intern(#flag)), \ 843 | ID2SYM(rb_intern(#flag))); \ 844 | rb_ary_push(hash##_names, ID2SYM(rb_intern(#flag)));\ 845 | } 846 | #define define_flag2(ary, flag) \ 847 | { \ 848 | rb_define_const(mTermios, #flag, INT2FIX(flag)); \ 849 | rb_ary_push(ary, rb_const_get(mTermios, rb_intern(#flag)));\ 850 | } 851 | #define define_choice(hash, mask, value) \ 852 | { \ 853 | VALUE a; \ 854 | rb_define_const(mTermios, #value, ULONG2NUM(value)); \ 855 | rb_hash_aset(hash, rb_const_get(mTermios, rb_intern(#value)), \ 856 | ID2SYM(rb_intern(#value))); \ 857 | rb_ary_push(hash##_names, ID2SYM(rb_intern(#value)));\ 858 | a = rb_hash_aref(hash##_choices, ID2SYM(rb_intern(#mask))); \ 859 | if (a == Qnil) { \ 860 | a = rb_ary_new(); \ 861 | rb_hash_aset(hash##_choices, ID2SYM(rb_intern(#mask)), a); \ 862 | } \ 863 | rb_ary_push(a, ID2SYM(rb_intern(#value))); \ 864 | } 865 | 866 | /* c_cc characters */ 867 | #ifdef VINTR 868 | define_flag(ccindex, VINTR); 869 | #endif 870 | #ifdef VQUIT 871 | define_flag(ccindex, VQUIT); 872 | #endif 873 | #ifdef VERASE 874 | define_flag(ccindex, VERASE); 875 | #endif 876 | #ifdef VKILL 877 | define_flag(ccindex, VKILL); 878 | #endif 879 | #ifdef VEOF 880 | define_flag(ccindex, VEOF); 881 | #endif 882 | #ifdef VEOL 883 | define_flag(ccindex, VEOL); 884 | #endif 885 | #ifdef VEOL2 886 | define_flag(ccindex, VEOL2); 887 | #endif 888 | #ifdef VSWTC 889 | define_flag(ccindex, VSWTC); 890 | #endif 891 | #ifdef VSTART 892 | define_flag(ccindex, VSTART); 893 | #endif 894 | #ifdef VSTOP 895 | define_flag(ccindex, VSTOP); 896 | #endif 897 | #ifdef VSUSP 898 | define_flag(ccindex, VSUSP); 899 | #endif 900 | #ifdef VDSUSP 901 | define_flag(ccindex, VDSUSP); 902 | #endif 903 | #ifdef VREPRINT 904 | define_flag(ccindex, VREPRINT); 905 | #endif 906 | #ifdef VDISCARD 907 | define_flag(ccindex, VDISCARD); 908 | #endif 909 | #ifdef VWERASE 910 | define_flag(ccindex, VWERASE); 911 | #endif 912 | #ifdef VLNEXT 913 | define_flag(ccindex, VLNEXT); 914 | #endif 915 | #ifdef VSTATUS 916 | define_flag(ccindex, VSTATUS); 917 | #endif 918 | #ifdef VTIME 919 | define_flag(ccindex, VTIME); 920 | #endif 921 | #ifdef VMIN 922 | define_flag(ccindex, VMIN); 923 | #endif 924 | 925 | /* c_iflag bits */ 926 | #ifdef IGNBRK 927 | define_flag(iflags, IGNBRK); 928 | #endif 929 | #ifdef BRKINT 930 | define_flag(iflags, BRKINT); 931 | #endif 932 | #ifdef IGNPAR 933 | define_flag(iflags, IGNPAR); 934 | #endif 935 | #ifdef PARMRK 936 | define_flag(iflags, PARMRK); 937 | #endif 938 | #ifdef INPCK 939 | define_flag(iflags, INPCK); 940 | #endif 941 | #ifdef ISTRIP 942 | define_flag(iflags, ISTRIP); 943 | #endif 944 | #ifdef INLCR 945 | define_flag(iflags, INLCR); 946 | #endif 947 | #ifdef IGNCR 948 | define_flag(iflags, IGNCR); 949 | #endif 950 | #ifdef ICRNL 951 | define_flag(iflags, ICRNL); 952 | #endif 953 | #ifdef IXON 954 | define_flag(iflags, IXON); 955 | #endif 956 | #ifdef IXOFF 957 | define_flag(iflags, IXOFF); 958 | #endif 959 | #ifdef IUCLC 960 | define_flag(iflags, IUCLC); 961 | #endif 962 | #ifdef IXANY 963 | define_flag(iflags, IXANY); 964 | #endif 965 | #ifdef IMAXBEL 966 | define_flag(iflags, IMAXBEL); 967 | #endif 968 | #ifdef IUTF8 969 | define_flag(iflags, IUTF8); 970 | #endif 971 | 972 | /* c_oflag bits */ 973 | #ifdef OPOST 974 | define_flag(oflags, OPOST); 975 | #endif 976 | #ifdef OLCUC 977 | define_flag(oflags, OLCUC); 978 | #endif 979 | #ifdef OCRNL 980 | define_flag(oflags, OCRNL); 981 | #endif 982 | #ifdef ONLCR 983 | define_flag(oflags, ONLCR); 984 | #endif 985 | #ifdef ONOCR 986 | define_flag(oflags, ONOCR); 987 | #endif 988 | #ifdef ONLRET 989 | define_flag(oflags, ONLRET); 990 | #endif 991 | #ifdef OFILL 992 | define_flag(oflags, OFILL); 993 | #endif 994 | #ifdef OFDEL 995 | define_flag(oflags, OFDEL); 996 | #endif 997 | #ifdef ONOEOT 998 | define_flag(oflags, ONOEOT); 999 | #endif 1000 | #ifdef OXTABS 1001 | define_flag(oflags, OXTABS); 1002 | #endif 1003 | #ifdef NLDLY 1004 | define_flag(oflags, NLDLY); 1005 | #endif 1006 | #ifdef NL0 1007 | define_choice(oflags, NLDLY, NL0); 1008 | #endif 1009 | #ifdef NL1 1010 | define_choice(oflags, NLDLY, NL1); 1011 | #endif 1012 | #ifdef CRDLY 1013 | define_flag(oflags, CRDLY); 1014 | #endif 1015 | #ifdef CR0 1016 | define_choice(oflags, CRDLY, CR0); 1017 | #endif 1018 | #ifdef CR1 1019 | define_choice(oflags, CRDLY, CR1); 1020 | #endif 1021 | #ifdef CR2 1022 | define_choice(oflags, CRDLY, CR2); 1023 | #endif 1024 | #ifdef CR3 1025 | define_choice(oflags, CRDLY, CR3); 1026 | #endif 1027 | #ifdef TABDLY 1028 | define_flag(oflags, TABDLY); 1029 | #endif 1030 | #ifdef TAB0 1031 | define_choice(oflags, TABDLY, TAB0); 1032 | #endif 1033 | #ifdef TAB1 1034 | define_choice(oflags, TABDLY, TAB1); 1035 | #endif 1036 | #ifdef TAB2 1037 | define_choice(oflags, TABDLY, TAB2); 1038 | #endif 1039 | #ifdef TAB3 1040 | define_choice(oflags, TABDLY, TAB3); 1041 | #endif 1042 | #ifdef XTABS 1043 | define_choice(oflags, TABDLY, XTABS); 1044 | #endif 1045 | #ifdef BSDLY 1046 | define_flag(oflags, BSDLY); 1047 | #endif 1048 | #ifdef BS0 1049 | define_choice(oflags, BSDLY, BS0); 1050 | #endif 1051 | #ifdef BS1 1052 | define_choice(oflags, BSDLY, BS1); 1053 | #endif 1054 | #ifdef VTDLY 1055 | define_flag(oflags, VTDLY); 1056 | #endif 1057 | #ifdef VT0 1058 | define_choice(oflags, VTDLY, VT0); 1059 | #endif 1060 | #ifdef VT1 1061 | define_choice(oflags, VTDLY, VT1); 1062 | #endif 1063 | #ifdef FFDLY 1064 | define_flag(oflags, FFDLY); 1065 | #endif 1066 | #ifdef FF0 1067 | define_choice(oflags, FFDLY, FF0); 1068 | #endif 1069 | #ifdef FF1 1070 | define_choice(oflags, FFDLY, FF1); 1071 | #endif 1072 | 1073 | /* c_cflag bit meaning */ 1074 | #ifdef CBAUD 1075 | define_flag(cflags, CBAUD); 1076 | #endif 1077 | #ifdef B0 1078 | define_flag(bauds, B0); 1079 | #endif 1080 | #ifdef B50 1081 | define_flag(bauds, B50); 1082 | #endif 1083 | #ifdef B75 1084 | define_flag(bauds, B75); 1085 | #endif 1086 | #ifdef B110 1087 | define_flag(bauds, B110); 1088 | #endif 1089 | #ifdef B134 1090 | define_flag(bauds, B134); 1091 | #endif 1092 | #ifdef B150 1093 | define_flag(bauds, B150); 1094 | #endif 1095 | #ifdef B200 1096 | define_flag(bauds, B200); 1097 | #endif 1098 | #ifdef B300 1099 | define_flag(bauds, B300); 1100 | #endif 1101 | #ifdef B600 1102 | define_flag(bauds, B600); 1103 | #endif 1104 | #ifdef B1200 1105 | define_flag(bauds, B1200); 1106 | #endif 1107 | #ifdef B1800 1108 | define_flag(bauds, B1800); 1109 | #endif 1110 | #ifdef B2400 1111 | define_flag(bauds, B2400); 1112 | #endif 1113 | #ifdef B4800 1114 | define_flag(bauds, B4800); 1115 | #endif 1116 | #ifdef B9600 1117 | define_flag(bauds, B9600); 1118 | #endif 1119 | #ifdef B19200 1120 | define_flag(bauds, B19200); 1121 | #endif 1122 | #ifdef B38400 1123 | define_flag(bauds, B38400); 1124 | #endif 1125 | #ifdef EXTA 1126 | define_flag(cflags, EXTA); 1127 | #endif 1128 | #ifdef EXTB 1129 | define_flag(cflags, EXTB); 1130 | #endif 1131 | #ifdef PARENB 1132 | define_flag(cflags, PARENB); 1133 | #endif 1134 | #ifdef PARODD 1135 | define_flag(cflags, PARODD); 1136 | #endif 1137 | #ifdef CSIZE 1138 | define_flag(cflags, CSIZE); 1139 | #endif 1140 | #ifdef CS5 1141 | define_choice(cflags, CSIZE, CS5); 1142 | #endif 1143 | #ifdef CS6 1144 | define_choice(cflags, CSIZE, CS6); 1145 | #endif 1146 | #ifdef CS7 1147 | define_choice(cflags, CSIZE, CS7); 1148 | #endif 1149 | #ifdef CS8 1150 | define_choice(cflags, CSIZE, CS8); 1151 | #endif 1152 | #ifdef HUPCL 1153 | define_flag(cflags, HUPCL); 1154 | #endif 1155 | #ifdef CSTOPB 1156 | define_flag(cflags, CSTOPB); 1157 | #endif 1158 | #ifdef CREAD 1159 | define_flag(cflags, CREAD); 1160 | #endif 1161 | #ifdef CLOCAL 1162 | define_flag(cflags, CLOCAL); 1163 | #endif 1164 | #ifdef CBAUDEX 1165 | define_flag(cflags, CBAUDEX); 1166 | #endif 1167 | #ifdef B57600 1168 | define_flag(bauds, B57600); 1169 | #endif 1170 | #ifdef B115200 1171 | define_flag(bauds, B115200); 1172 | #endif 1173 | #ifdef B230400 1174 | define_flag(bauds, B230400); 1175 | #endif 1176 | #ifdef B460800 1177 | define_flag(bauds, B460800); 1178 | #endif 1179 | #ifdef B500000 1180 | define_flag(bauds, B500000); 1181 | #endif 1182 | #ifdef B576000 1183 | define_flag(bauds, B576000); 1184 | #endif 1185 | #ifdef B921600 1186 | define_flag(bauds, B921600); 1187 | #endif 1188 | #ifdef B1000000 1189 | define_flag(bauds, B1000000); 1190 | #endif 1191 | #ifdef B1152000 1192 | define_flag(bauds, B1152000); 1193 | #endif 1194 | #ifdef B1500000 1195 | define_flag(bauds, B1500000); 1196 | #endif 1197 | #ifdef B2000000 1198 | define_flag(bauds, B2000000); 1199 | #endif 1200 | #ifdef B2500000 1201 | define_flag(bauds, B2500000); 1202 | #endif 1203 | #ifdef B3000000 1204 | define_flag(bauds, B3000000); 1205 | #endif 1206 | #ifdef B3500000 1207 | define_flag(bauds, B3500000); 1208 | #endif 1209 | #ifdef B4000000 1210 | define_flag(bauds, B4000000); 1211 | #endif 1212 | #ifdef CIBAUD 1213 | define_flag(cflags, CIBAUD); 1214 | #endif 1215 | #ifdef CRTSCTS 1216 | define_flag(cflags, CRTSCTS); 1217 | #endif 1218 | #ifdef MDMBUF 1219 | define_flag(cflags, MDMBUF); 1220 | #endif 1221 | 1222 | /* c_lflag bits */ 1223 | #ifdef ISIG 1224 | define_flag(lflags, ISIG); 1225 | #endif 1226 | #ifdef ICANON 1227 | define_flag(lflags, ICANON); 1228 | #endif 1229 | #ifdef IEXTEN 1230 | define_flag(lflags, IEXTEN); 1231 | #endif 1232 | #ifdef ECHO 1233 | define_flag(lflags, ECHO); 1234 | #endif 1235 | #ifdef ECHOE 1236 | define_flag(lflags, ECHOE); 1237 | #endif 1238 | #ifdef ECHOK 1239 | define_flag(lflags, ECHOK); 1240 | #endif 1241 | #ifdef ECHONL 1242 | define_flag(lflags, ECHONL); 1243 | #endif 1244 | #ifdef NOFLSH 1245 | define_flag(lflags, NOFLSH); 1246 | #endif 1247 | #ifdef XCASE 1248 | define_flag(lflags, XCASE); 1249 | #endif 1250 | #ifdef TOSTOP 1251 | define_flag(lflags, TOSTOP); 1252 | #endif 1253 | #ifdef ECHOPRT 1254 | define_flag(lflags, ECHOPRT); 1255 | #endif 1256 | #ifdef ECHOCTL 1257 | define_flag(lflags, ECHOCTL); 1258 | #endif 1259 | #ifdef ECHOKE 1260 | define_flag(lflags, ECHOKE); 1261 | #endif 1262 | #ifdef FLUSHO 1263 | define_flag(lflags, FLUSHO); 1264 | #endif 1265 | #ifdef PENDIN 1266 | define_flag(lflags, PENDIN); 1267 | #endif 1268 | #ifdef ALTWERASE 1269 | define_flag(lflags, ALTWERASE); 1270 | #endif 1271 | #ifdef EXTPROC 1272 | define_flag(lflags, EXTPROC); 1273 | #endif 1274 | #ifdef NOKERNINFO 1275 | define_flag(lflags, NOKERNINFO); 1276 | #endif 1277 | 1278 | /* tcflow() and TCXONC use these */ 1279 | #ifdef TCOOFF 1280 | define_flag2(tcflow_act, TCOOFF); 1281 | #endif 1282 | #ifdef TCOON 1283 | define_flag2(tcflow_act, TCOON); 1284 | #endif 1285 | #ifdef TCIOFF 1286 | define_flag2(tcflow_act, TCIOFF); 1287 | #endif 1288 | #ifdef TCION 1289 | define_flag2(tcflow_act, TCION); 1290 | #endif 1291 | 1292 | /* tcflush() and TCFLSH use these */ 1293 | #ifdef TCIFLUSH 1294 | define_flag2(tcflush_qs, TCIFLUSH); 1295 | #endif 1296 | #ifdef TCOFLUSH 1297 | define_flag2(tcflush_qs, TCOFLUSH); 1298 | #endif 1299 | #ifdef TCIOFLUSH 1300 | define_flag2(tcflush_qs, TCIOFLUSH); 1301 | #endif 1302 | 1303 | /* tcsetattr uses these */ 1304 | #ifdef TCSANOW 1305 | define_flag2(tcsetattr_opt, TCSANOW); 1306 | #endif 1307 | #ifdef TCSADRAIN 1308 | define_flag2(tcsetattr_opt, TCSADRAIN); 1309 | #endif 1310 | #ifdef TCSAFLUSH 1311 | define_flag2(tcsetattr_opt, TCSAFLUSH); 1312 | #endif 1313 | #ifdef TCSASOFT 1314 | define_flag2(tcsetattr_opt, TCSASOFT); 1315 | #endif 1316 | 1317 | /* Constants useful to ioctl for controlling lines */ 1318 | #ifdef TIOCMODG 1319 | define_flag(ioctl_commands, TIOCMODG) 1320 | #endif 1321 | #ifdef TIOCMODS 1322 | define_flag(ioctl_commands, TIOCMODS) 1323 | #endif 1324 | #ifdef TIOCM_LE 1325 | define_flag(modem_signals, TIOCM_LE) 1326 | #endif 1327 | #ifdef TIOCM_DTR 1328 | define_flag(modem_signals, TIOCM_DTR) 1329 | #endif 1330 | #ifdef TIOCM_RTS 1331 | define_flag(modem_signals, TIOCM_RTS) 1332 | #endif 1333 | #ifdef TIOCM_ST 1334 | define_flag(modem_signals, TIOCM_ST) 1335 | #endif 1336 | #ifdef TIOCM_SR 1337 | define_flag(modem_signals, TIOCM_SR) 1338 | #endif 1339 | #ifdef TIOCM_CTS 1340 | define_flag(modem_signals, TIOCM_CTS) 1341 | #endif 1342 | #ifdef TIOCM_CAR 1343 | define_flag(modem_signals, TIOCM_CAR) 1344 | #endif 1345 | #ifdef TIOCM_CD 1346 | define_flag(modem_signals, TIOCM_CD) 1347 | #endif 1348 | #ifdef TIOCM_RNG 1349 | define_flag(modem_signals, TIOCM_RNG) 1350 | #endif 1351 | #ifdef TIOCM_RI 1352 | define_flag(modem_signals, TIOCM_RI) 1353 | #endif 1354 | #ifdef TIOCM_DSR 1355 | define_flag(modem_signals, TIOCM_DSR) 1356 | #endif 1357 | #ifdef TIOCEXCL 1358 | define_flag(ioctl_commands, TIOCEXCL) 1359 | #endif 1360 | #ifdef TIOCNXCL 1361 | define_flag(ioctl_commands, TIOCNXCL) 1362 | #endif 1363 | #ifdef TIOCFLUSH 1364 | define_flag(ioctl_commands, TIOCFLUSH) 1365 | #endif 1366 | #ifdef TIOCGETA 1367 | define_flag(ioctl_commands, TIOCGETA) 1368 | #endif 1369 | #ifdef TIOCSETA 1370 | define_flag(ioctl_commands, TIOCSETA) 1371 | #endif 1372 | #ifdef TIOCSETAW 1373 | define_flag(ioctl_commands, TIOCSETAW) 1374 | #endif 1375 | #ifdef TIOCSETAF 1376 | define_flag(ioctl_commands, TIOCSETAF) 1377 | #endif 1378 | #ifdef TIOCGETD 1379 | define_flag(ioctl_commands, TIOCGETD) 1380 | #endif 1381 | #ifdef TIOCSETD 1382 | define_flag(ioctl_commands, TIOCSETD) 1383 | #endif 1384 | #ifdef TIOCIXON 1385 | define_flag(ioctl_commands, TIOCIXON) 1386 | #endif 1387 | #ifdef TIOCIXOFF 1388 | define_flag(ioctl_commands, TIOCIXOFF) 1389 | #endif 1390 | #ifdef TIOCSBRK 1391 | define_flag(ioctl_commands, TIOCSBRK) 1392 | #endif 1393 | #ifdef TIOCCBRK 1394 | define_flag(ioctl_commands, TIOCCBRK) 1395 | #endif 1396 | #ifdef TIOCSDTR 1397 | define_flag(ioctl_commands, TIOCSDTR) 1398 | #endif 1399 | #ifdef TIOCCDTR 1400 | define_flag(ioctl_commands, TIOCCDTR) 1401 | #endif 1402 | #ifdef TIOCGPGRP 1403 | define_flag(ioctl_commands, TIOCGPGRP) 1404 | #endif 1405 | #ifdef TIOCSPGRP 1406 | define_flag(ioctl_commands, TIOCSPGRP) 1407 | #endif 1408 | #ifdef TIOCOUTQ 1409 | define_flag(ioctl_commands, TIOCOUTQ) 1410 | #endif 1411 | #ifdef TIOCSTI 1412 | define_flag(ioctl_commands, TIOCSTI) 1413 | #endif 1414 | #ifdef TIOCNOTTY 1415 | define_flag(ioctl_commands, TIOCNOTTY) 1416 | #endif 1417 | #ifdef TIOCPKT 1418 | define_flag(ioctl_commands, TIOCPKT) 1419 | #endif 1420 | #ifdef TIOCPKT_DATA 1421 | define_flag(pty_pkt_options, TIOCPKT_DATA) 1422 | #endif 1423 | #ifdef TIOCPKT_FLUSHREAD 1424 | define_flag(pty_pkt_options, TIOCPKT_FLUSHREAD) 1425 | #endif 1426 | #ifdef TIOCPKT_FLUSHWRITE 1427 | define_flag(pty_pkt_options, TIOCPKT_FLUSHWRITE) 1428 | #endif 1429 | #ifdef TIOCPKT_STOP 1430 | define_flag(pty_pkt_options, TIOCPKT_STOP) 1431 | #endif 1432 | #ifdef TIOCPKT_START 1433 | define_flag(pty_pkt_options, TIOCPKT_START) 1434 | #endif 1435 | #ifdef TIOCPKT_NOSTOP 1436 | define_flag(pty_pkt_options, TIOCPKT_NOSTOP) 1437 | #endif 1438 | #ifdef TIOCPKT_DOSTOP 1439 | define_flag(pty_pkt_options, TIOCPKT_DOSTOP) 1440 | #endif 1441 | #ifdef TIOCPKT_IOCTL 1442 | define_flag(pty_pkt_options, TIOCPKT_IOCTL) 1443 | #endif 1444 | #ifdef TIOCSTOP 1445 | define_flag(ioctl_commands, TIOCSTOP) 1446 | #endif 1447 | #ifdef TIOCSTART 1448 | define_flag(ioctl_commands, TIOCSTART) 1449 | #endif 1450 | #ifdef TIOCMSET 1451 | define_flag(ioctl_commands, TIOCMSET) 1452 | #endif 1453 | #ifdef TIOCMBIS 1454 | define_flag(ioctl_commands, TIOCMBIS) 1455 | #endif 1456 | #ifdef TIOCMBIC 1457 | define_flag(ioctl_commands, TIOCMBIC) 1458 | #endif 1459 | #ifdef TIOCMGET 1460 | define_flag(ioctl_commands, TIOCMGET) 1461 | #endif 1462 | #ifdef TIOCREMOTE 1463 | define_flag(ioctl_commands, TIOCREMOTE) 1464 | #endif 1465 | #ifdef TIOCGWINSZ 1466 | define_flag(ioctl_commands, TIOCGWINSZ) 1467 | #endif 1468 | #ifdef TIOCSWINSZ 1469 | define_flag(ioctl_commands, TIOCSWINSZ) 1470 | #endif 1471 | #ifdef TIOCUCNTL 1472 | define_flag(ioctl_commands, TIOCUCNTL) 1473 | #endif 1474 | #ifdef TIOCSTAT 1475 | define_flag(ioctl_commands, TIOCSTAT) 1476 | #endif 1477 | #ifdef TIOCSCONS 1478 | define_flag(ioctl_commands, TIOCSCONS) 1479 | #endif 1480 | #ifdef TIOCCONS 1481 | define_flag(ioctl_commands, TIOCCONS) 1482 | #endif 1483 | #ifdef TIOCSCTTY 1484 | define_flag(ioctl_commands, TIOCSCTTY) 1485 | #endif 1486 | #ifdef TIOCEXT 1487 | define_flag(ioctl_commands, TIOCEXT) 1488 | #endif 1489 | #ifdef TIOCSIG 1490 | define_flag(ioctl_commands, TIOCSIG) 1491 | #endif 1492 | #ifdef TIOCDRAIN 1493 | define_flag(ioctl_commands, TIOCDRAIN) 1494 | #endif 1495 | #ifdef TIOCMSDTRWAIT 1496 | define_flag(ioctl_commands, TIOCMSDTRWAIT) 1497 | #endif 1498 | #ifdef TIOCMGDTRWAIT 1499 | define_flag(ioctl_commands, TIOCMGDTRWAIT) 1500 | #endif 1501 | #ifdef TIOCTIMESTAMP 1502 | define_flag(ioctl_commands, TIOCTIMESTAMP) 1503 | #endif 1504 | #ifdef TIOCDCDTIMESTAMP 1505 | define_flag(ioctl_commands, TIOCDCDTIMESTAMP) 1506 | #endif 1507 | #ifdef TIOCSDRAINWAIT 1508 | define_flag(ioctl_commands, TIOCSDRAINWAIT) 1509 | #endif 1510 | #ifdef TIOCGDRAINWAIT 1511 | define_flag(ioctl_commands, TIOCGDRAINWAIT) 1512 | #endif 1513 | #ifdef TIOCDSIMICROCODE 1514 | define_flag(ioctl_commands, TIOCDSIMICROCODE) 1515 | #endif 1516 | #ifdef TIOCPTYGRANT 1517 | define_flag(ioctl_commands, TIOCPTYGRANT) 1518 | #endif 1519 | #ifdef TIOCPTYGNAME 1520 | define_flag(ioctl_commands, TIOCPTYGNAME) 1521 | #endif 1522 | #ifdef TIOCPTYUNLK 1523 | define_flag(ioctl_commands, TIOCPTYUNLK) 1524 | #endif 1525 | #ifdef TTYDISC 1526 | define_flag(line_disciplines, TTYDISC) 1527 | #endif 1528 | #ifdef TABLDISC 1529 | define_flag(line_disciplines, TABLDISC) 1530 | #endif 1531 | #ifdef SLIPDISC 1532 | define_flag(line_disciplines, SLIPDISC) 1533 | #endif 1534 | #ifdef PPPDISC 1535 | define_flag(line_disciplines, PPPDISC) 1536 | #endif 1537 | } 1538 | -------------------------------------------------------------------------------- /lib/termios.rb: -------------------------------------------------------------------------------- 1 | require 'termios.so' 2 | 3 | module Termios 4 | VISIBLE_CHAR = {} 5 | [ 6 | "^@", "^A", "^B", "^C", "^D", "^E", "^F", "^G", 7 | "^H", "^I", "^J", "^K", "^L", "^M", "^N", "^O", 8 | "^P", "^Q", "^R", "^S", "^T", "^U", "^V", "^W", 9 | "^X", "^Y", "^Z", "^[", "^\\", "^]", "^^", "^_", 10 | "", "!", "\"", "#", "$", "%", "&", "'", 11 | "(", ")", "*", "+", ",", "-", ".", "/", 12 | "0", "1", "2", "3", "4", "5", "6", "7", 13 | "8", "9", ":", ";", "<", "=", ">", "?", 14 | "@", "A", "B", "C", "D", "E", "F", "G", 15 | "H", "I", "J", "K", "L", "M", "N", "O", 16 | "P", "Q", "R", "S", "T", "U", "V", "W", 17 | "X", "Y", "Z", "[", "\\", "]", "^", "_", 18 | "`", "a", "b", "c", "d", "e", "f", "g", 19 | "h", "i", "j", "k", "l", "m", "n", "o", 20 | "p", "q", "r", "s", "t", "u", "v", "w", 21 | "x", "y", "z", "{", "|", "}", "~", "^?", 22 | "M-^@", "M-^A", "M-^B", "M-^C", "M-^D", "M-^E", "M-^F", "M-^G", 23 | "M-^H", "M-^I", "M-^J", "M-^K", "M-^L", "M-^M", "M-^N", "M-^O", 24 | "M-^P", "M-^Q", "M-^R", "M-^S", "M-^T", "M-^U", "M-^V", "M-^W", 25 | "M-^X", "M-^Y", "M-^Z", "M-^[", "M-^\\", "M-^]", "M-^^", "M-^_", 26 | "M-", "M-!", "M-\"", "M-#", "M-$", "M-%", "M-&", "M-'", 27 | "M-(", "M-)", "M-*", "M-+", "M-,", "M--", "M-.", "M-/", 28 | "M-0", "M-1", "M-2", "M-3", "M-4", "M-5", "M-6", "M-7", 29 | "M-8", "M-9", "M-:", "M-;", "M-<", "M-=", "M->", "M-?", 30 | "M-@", "M-A", "M-B", "M-C", "M-D", "M-E", "M-F", "M-G", 31 | "M-H", "M-I", "M-J", "M-K", "M-L", "M-M", "M-N", "M-O", 32 | "M-P", "M-Q", "M-R", "M-S", "M-T", "M-U", "M-V", "M-W", 33 | "M-X", "M-Y", "M-Z", "M-[", "M-\\", "M-]", "M-^", "M-_", 34 | "M-`", "M-a", "M-b", "M-c", "M-d", "M-e", "M-f", "M-g", 35 | "M-h", "M-i", "M-j", "M-k", "M-l", "M-m", "M-n", "M-o", 36 | "M-p", "M-q", "M-r", "M-s", "M-t", "M-u", "M-v", "M-w", 37 | "M-x", "M-y", "M-z", "M-{", "M-|", "M-}", "M-~", "M-^?", 38 | ].each_with_index {|s, i| 39 | VISIBLE_CHAR[i] = s 40 | VISIBLE_CHAR[[i].pack("C")] = s 41 | } 42 | VISIBLE_CHAR[POSIX_VDISABLE] = "" 43 | VISIBLE_CHAR[[POSIX_VDISABLE].pack("C")] = "" 44 | 45 | class Termios 46 | def inspect 47 | str = "\#<#{self.class}" 48 | if self.ispeed == self.ospeed 49 | speed = (BAUDS[self.ispeed] || "B???").to_s[1..-1] 50 | str << " speed #{speed} baud;" 51 | else 52 | ispeed = (BAUDS[self.ispeed] || "B???").to_s[1..-1] 53 | ospeed = (BAUDS[self.ospeed] || "B???").to_s[1..-1] 54 | str << " ispeed #{ispeed} baud; ospeed #{ospeed} baud;" 55 | end 56 | 57 | CCINDEX_NAMES.each {|ccindex| 58 | next if ccindex == :VMIN || ccindex == :VTIME 59 | str << " #{ccindex.to_s[1..-1].downcase}" 60 | str << "=#{VISIBLE_CHAR[self.cc[::Termios.const_get(ccindex)]]}" 61 | } 62 | str << " min=#{self.cc[VMIN]}" 63 | str << " time=#{self.cc[VTIME]}" 64 | 65 | [ 66 | [:cflag, 67 | CFLAG_NAMES-[:CBAUD, :CBAUDEX, :CIBAUD, :EXTA, :EXTB], 68 | CFLAG_CHOICES], 69 | [:iflag, IFLAG_NAMES, nil], 70 | [:oflag, OFLAG_NAMES, OFLAG_CHOICES], 71 | [:lflag, LFLAG_NAMES, nil] 72 | ].each {|l| 73 | str << ";" 74 | flag_type, flag_names, choices = l 75 | flags = self.send(flag_type) 76 | choice_names = choices ? choices.values.flatten : [] 77 | (flag_names-choice_names).each {|name| 78 | str << " " 79 | if choices and ns = choices[name] 80 | mask = ::Termios.const_get(name) 81 | ns.each {|n| 82 | if (flags & mask) == ::Termios.const_get(n) 83 | str << n.to_s.downcase 84 | break 85 | end 86 | } 87 | else 88 | str << "-" if (flags & ::Termios.const_get(name)) == 0 89 | str << name.to_s.downcase 90 | end 91 | } 92 | } 93 | 94 | str << ">" 95 | str 96 | end 97 | 98 | def pretty_print(q) # :nodoc: 99 | q.object_group(self) { 100 | if self.ispeed == self.ospeed 101 | speed = (BAUDS[self.ispeed] || "B???").to_s[1..-1] 102 | q.fill_breakable; q.text "speed #{speed} baud;" 103 | else 104 | ispeed = (BAUDS[self.ispeed] || "B???").to_s[1..-1] 105 | ospeed = (BAUDS[self.ospeed] || "B???").to_s[1..-1] 106 | q.fill_breakable; q.text "ispeed #{ispeed} baud;" 107 | q.fill_breakable; q.text "ospeed #{ospeed} baud;" 108 | end 109 | q.breakable 110 | 111 | q.seplist(CCINDEX_NAMES-[:VMIN, :VTIME], 112 | lambda { q.fill_breakable }) {|ccindex| 113 | q.text ccindex.to_s[1..-1].downcase 114 | q.text "=#{VISIBLE_CHAR[self.cc[::Termios.const_get(ccindex)]]}" 115 | } 116 | q.breakable; q.text "min=#{self.cc[VMIN]}" 117 | q.fill_breakable; q.text "time=#{self.cc[VTIME]}" 118 | 119 | [ 120 | [:cflag, 121 | CFLAG_NAMES-[:CBAUD, :CBAUDEX, :CIBAUD, :EXTA, :EXTB], 122 | CFLAG_CHOICES], 123 | [:iflag, IFLAG_NAMES, nil], 124 | [:oflag, OFLAG_NAMES, OFLAG_CHOICES], 125 | [:lflag, LFLAG_NAMES, nil] 126 | ].each {|l| 127 | q.text ";" 128 | q.breakable 129 | flag_type, flag_names, choices = l 130 | flags = self.send(flag_type) 131 | choice_names = choices ? choices.values.flatten : [] 132 | q.seplist(flag_names-choice_names, 133 | lambda { q.fill_breakable }) {|name| 134 | if choices and ns = choices[name] 135 | mask = ::Termios.const_get(name) 136 | ns.each {|n| 137 | if (flags & mask) == ::Termios.const_get(n) 138 | q.text n.to_s.downcase 139 | break 140 | end 141 | } 142 | else 143 | q.text "-" if (flags & ::Termios.const_get(name)) == 0 144 | q.text name.to_s.downcase 145 | end 146 | } 147 | } 148 | } 149 | end 150 | end 151 | end 152 | -------------------------------------------------------------------------------- /lib/termios/version.rb: -------------------------------------------------------------------------------- 1 | module Termios 2 | VERSION = '1.1.0' 3 | end 4 | -------------------------------------------------------------------------------- /ruby-termios.gemspec: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative 'lib/termios/version' 4 | 5 | Gem::Specification.new do |spec| 6 | spec.name = 'ruby-termios' 7 | spec.version = Termios::VERSION 8 | spec.authors = ['akira yamada'] 9 | spec.email = ['akira@arika.org'] 10 | 11 | spec.summary = 'a simple wrapper of termios(3)' 12 | spec.description = <<-E 13 | Termios module is simple wrapper of termios(3). 14 | It can be included into IO-family classes and can extend IO-family objects. 15 | In addition, the methods can use as module function. 16 | E 17 | spec.homepage = 'https://github.com/arika/ruby-termios' 18 | spec.license = "Ruby's" 19 | spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0') 20 | 21 | spec.metadata['homepage_uri'] = spec.homepage 22 | spec.metadata['source_code_ri'] = spec.homepage 23 | spec.metadata['bug_tracker_uri'] = spec.homepage + '/issues' 24 | 25 | spec.files = Dir.chdir(File.expand_path(__dir__)) do 26 | `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) } 27 | end 28 | spec.bindir = 'exe' 29 | spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } 30 | spec.require_paths = ['lib'] 31 | spec.extensions = ['ext/extconf.rb'] 32 | end 33 | -------------------------------------------------------------------------------- /termios.rd: -------------------------------------------------------------------------------- 1 | =begin 2 | 3 | = ruby-termios 4 | 5 | Ruby-termios enables you to use termios(3) interface. 6 | 7 | 8 | == Termios module 9 | 10 | Termios module are simple wrapper for termios(3). It can be included 11 | into IO-family classes and can extend IO-family objects. In addition, 12 | the methods can use as module function. 13 | 14 | === Module Functions 15 | 16 | --- Termios.tcdrain(io) 17 | --- Termios.drain(io) 18 | It calls tcdrain(3) for ((|io|)). 19 | 20 | --- Termios.tcflow(io, action) 21 | --- Termios.flow(io, action) 22 | It calls tcflow(3) for ((|io|)). 23 | 24 | --- Termios.tcflush(io, queue_selector) 25 | --- Termios.flush(io, queue_selector) 26 | It calls tcflush(3) for ((|io|)). 27 | 28 | --- Termios.tcgetattr(io) 29 | --- Termios.getattr(io) 30 | It calls tcgetattr(3) for ((|io|)). 31 | 32 | --- Termios.tcgetpgrp(io) 33 | --- Termios.getpgrp(io) 34 | It calls tcgetpgrp(3) for ((|io|)). 35 | 36 | --- Termios.tcsendbreak(io, duration) 37 | --- Termios.sendbreak(io, duration) 38 | It calls tcsendbreak(3) for ((|io|)). 39 | 40 | --- Termios.tcsetattr(io, flag, termios) 41 | --- Termios.setattr(io, flag, termios) 42 | It calls tcsetattr(3) for ((|io|)). 43 | 44 | --- Termios.tcsetpgrp(io, pgrpid) 45 | --- Termios.setpgrp(io, pgrpid) 46 | It calls tcsetpgrp(3) for ((|io|)). 47 | 48 | --- Termios.new_termios 49 | It is alias of (()). 50 | 51 | === Methods 52 | 53 | The methods can use for objects which include Termios module or are 54 | extended by Termios module. 55 | 56 | --- tcdrain 57 | It calls tcdrain(3) for ((|self|)). 58 | 59 | --- tcflow 60 | It calls tcflow(3) for ((|self|)). 61 | 62 | --- tcflush(queue_selector) 63 | It calls tcflush(3) for ((|self|)). 64 | 65 | --- tcgetattr 66 | It calls tcgetattr(3) for ((|self|)). 67 | 68 | --- tcgetpgrp 69 | It calls tcgetpgrp(3) for ((|self|)). 70 | 71 | --- tcsendbreak(duratiofn) 72 | It calls tcsendbreak(3) for ((|self|)). 73 | 74 | --- tcsetattr(flag, termios) 75 | It calls tcsetattr(3) for ((|self|)). 76 | 77 | --- tcsetpgrp(pgrpid) 78 | It calls tcsetpgrp(3) for ((|self|)). 79 | 80 | === Constants 81 | 82 | Many constants which are derived from "termios.h" are defined on Termios 83 | module. 84 | 85 | IFLAGS, OFLAGS, CFLAGS and LFLAGS are Hash object. They contains Symbols of 86 | constants for c_iflag, c_oflag, c_cflag and c_lflag. 87 | 88 | CCINDEX and BAUDS are Hash object too. They contains Symbols of constats for 89 | c_cc or ispeed and ospeed. 90 | 91 | == Termios::Termios class 92 | 93 | A wrapper class for "struct termios" in C. 94 | 95 | === Class Methods 96 | 97 | --- Termios::Termios.new 98 | It creates a new Termios::Termios object. 99 | 100 | === Instance Methods 101 | 102 | --- iflag 103 | --- c_iflag 104 | It returns value of c_iflag. 105 | 106 | --- iflag=(flag) 107 | --- c_iflag=(flag) 108 | It sets flag to c_iflag. 109 | 110 | --- oflag 111 | --- c_oflag 112 | It returns value of c_oflag. 113 | 114 | --- oflag=(flag) 115 | --- c_oflag=(flag) 116 | It sets flag to c_oflag. 117 | 118 | --- cflag 119 | --- c_cflag 120 | It returns value of c_cflag. 121 | 122 | --- cflag=(flag) 123 | --- c_cflag=(flag) 124 | It sets flag to c_cflag. 125 | 126 | --- lflag 127 | --- c_lflag 128 | It returns value of c_lflag. 129 | 130 | --- lflag=(flag) 131 | --- c_lflag=(flag) 132 | It sets flag to c_lflag. 133 | 134 | --- cc 135 | --- c_cc 136 | It returns values of c_cc. 137 | 138 | --- cc=(cc_ary) 139 | --- c_cc=(cc_ary) 140 | It sets cc_ary to c_cc. 141 | 142 | --- ispeed 143 | --- c_ispeed 144 | It returns c_ispeeed. 145 | 146 | --- ispeed=(speed) 147 | --- c_ispeed=(speed) 148 | It sets speed to c_ispeed. 149 | 150 | --- ospeed 151 | --- c_ospeed 152 | It returns c_ospeeed. 153 | 154 | --- ospeed=(speed) 155 | --- c_ospeed=(speed) 156 | It sets speed to c_ospeed. 157 | 158 | =end 159 | -------------------------------------------------------------------------------- /test/test0.rb: -------------------------------------------------------------------------------- 1 | require 'termios' 2 | 3 | def dump_termios(tio, banner) 4 | puts banner 5 | puts " ispeed = #{Termios::BAUDS[tio.ispeed]}, ospeed = #{Termios::BAUDS[tio.ospeed]}" 6 | ["iflag", "oflag", "cflag", "lflag"].each do |x| 7 | flag = tio.send(x) 8 | flags = [] 9 | eval("Termios::#{x.upcase}S").each do |f, sym| 10 | flags << sym.to_s if flag & f != 0 11 | end 12 | puts " #{x} = #{flags.sort.join(' | ')}" 13 | end 14 | print " cc =" 15 | cc = tio.cc 16 | cc.each_with_index do |x, idx| 17 | print " #{Termios::CCINDEX[idx]}=#{x}" if Termios::CCINDEX.include?(idx) 18 | end 19 | puts 20 | end 21 | 22 | tio = Termios::getattr($stdin) 23 | dump_termios(tio, "STDIN:") 24 | Termios::setattr($stdin, Termios::TCSANOW, tio) 25 | dump_termios(tio, "STDIN:") 26 | 27 | puts 28 | puts " pid = #{$$}" 29 | puts "pgrp = #{Termios::getpgrp($stdin)}" 30 | --------------------------------------------------------------------------------