├── Gemfile
├── .gitignore
├── test
└── test_winsize.rb
├── rdoc
├── classes
│ ├── TermInfo.src
│ │ ├── M000013.html
│ │ ├── M000011.html
│ │ ├── M000019.html
│ │ ├── M000006.html
│ │ ├── M000021.html
│ │ ├── M000007.html
│ │ ├── M000008.html
│ │ ├── M000010.html
│ │ ├── M000009.html
│ │ ├── M000016.html
│ │ ├── M000004.html
│ │ ├── M000024.html
│ │ ├── M000003.html
│ │ ├── M000005.html
│ │ ├── M000002.html
│ │ ├── M000025.html
│ │ ├── M000015.html
│ │ ├── M000029.html
│ │ ├── M000028.html
│ │ ├── M000030.html
│ │ ├── M000012.html
│ │ ├── M000026.html
│ │ ├── M000001.html
│ │ ├── M000027.html
│ │ ├── M000023.html
│ │ ├── M000014.html
│ │ ├── M000017.html
│ │ └── M000018.html
│ ├── TermInfo
│ │ └── TermInfoError.html
│ └── TermInfo.html
├── index.html
├── fr_class_index.html
├── fr_file_index.html
├── files
│ ├── terminfo_c.html
│ ├── extconf_rb.html
│ └── lib
│ │ └── terminfo_rb.html
├── fr_method_index.html
└── rdoc-style.css
├── ChangeLog
├── ruby-terminfo.gemspec
├── sample
├── resize
└── fill
├── extconf.rb
├── README.md
├── Rakefile
├── lib
└── terminfo.rb
└── terminfo.c
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'http://rubygems.org'
2 |
3 | gemspec
4 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | pkg
2 | *.log
3 | Makefile
4 | extconf.h
5 | *.bundle
6 | *.o
7 |
--------------------------------------------------------------------------------
/test/test_winsize.rb:
--------------------------------------------------------------------------------
1 | require 'test/unit'
2 | require 'pty'
3 | require 'terminfo'
4 |
5 | class TestTermInfoWinsize < Test::Unit::TestCase
6 | def test_winsize
7 | PTY.open {|m, s|
8 | TermInfo.tiocswinsz(s, 80, 25)
9 | assert_equal([80,25], TermInfo.tiocgwinsz(s))
10 | TermInfo.tiocswinsz(s, 200, 300)
11 | assert_equal([200,300], TermInfo.tiocgwinsz(s))
12 | }
13 | end
14 | end
15 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000013.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | inspect (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def inspect
15 | "\#<#{self.class}:#{@term}>"
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/rdoc/index.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
11 |
12 |
13 | RDoc Documentation
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/rdoc/fr_class_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
14 | Classes
15 |
16 |
17 |
18 |
19 |
20 |
27 |
28 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000011.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | io (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .io () default_object .io () end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000019.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_lines (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def screen_lines
15 | self .screen_size [0 ]
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000006.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_size (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .screen_size () default_object .screen_size () end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000021.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_columns (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def screen_columns
15 | self .screen_size [1 ]
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000007.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_lines (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .screen_lines () default_object .screen_lines () end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000008.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_height (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .screen_height () default_object .screen_height () end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000010.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_width (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .screen_width () default_object .screen_width () end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000009.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_columns (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .screen_columns () default_object .screen_columns () end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/fr_file_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
14 | Files
15 |
16 |
17 |
18 |
19 |
20 |
28 |
29 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000016.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | write (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def write (str )
15 | @io .write (str )
16 | end
17 |
18 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000004.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | write (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .write (str ) default_object .write (str ) end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000024.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tigetflag (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo#tigetflag(capname) => int
15 | *
16 | * TermInfo#tigetflag returns a boolean capability specified by capname.
17 | */
18 | static VALUE
19 | rt_tigetflag(VALUE self, VALUE v_capname)
20 | {
21 | int ret;
22 | setup(self);
23 | ret = tigetflag(StringValueCStr(v_capname));
24 | if (ret == -1) { rb_raise(eTermInfoError, "not a boolean capability"); }
25 | return RTEST(ret) ? Qtrue : Qfalse;
26 | }
27 |
28 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000003.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | control (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .control (* args ) default_object .control (* args ) end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000005.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | flush (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .flush (& block ) default_object .flush (& block ) end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000002.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | control_string (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .control_string (* args ) default_object .control_string (* args ) end
15 |
16 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000025.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tigetnum (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo#tigetnum(capname) => int
15 | *
16 | * TermInfo#tigetnum returns a numeric capability specified by capname.
17 | */
18 | static VALUE
19 | rt_tigetnum(VALUE self, VALUE v_capname)
20 | {
21 | int ret;
22 | setup(self);
23 | ret = tigetnum(StringValueCStr(v_capname));
24 | if (ret == -2) { rb_raise(eTermInfoError, "not a numeric capability"); }
25 | if (ret == -1) { rb_raise(eTermInfoError, "canceled or absent numeric capability"); }
26 | return INT2NUM(ret);
27 | }
28 |
29 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000015.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | control (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def control (* args )
15 | @io .write (self .control_string (* args ))
16 | nil
17 | end
18 |
19 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000029.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tiocgwinsz (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo.tiocgwinsz(io) => [row, col]
15 | *
16 | * TermInfo.tiocgwinsz returns the screen size of the terminal refered by io,
17 | * using TIOCGWINSZ ioctl.
18 | */
19 | static VALUE
20 | rt_tiocgwinsz(VALUE self, VALUE io)
21 | {
22 | #ifdef TIOCGWINSZ
23 | rb_io_t *fptr;
24 | struct winsize sz;
25 | int ret;
26 |
27 | GetOpenFile(io, fptr);
28 |
29 | ret = ioctl(FILENO(fptr), TIOCGWINSZ, &sz);
30 | if (ret == -1) rb_raise(rb_eIOError, "TIOCGWINSZ failed");
31 |
32 | return rb_ary_new3(2, INT2NUM(sz.ws_row), INT2NUM(sz.ws_col));
33 | #else
34 | rb_notimplement();
35 | #endif
36 | }
37 |
38 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000028.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tputs (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo#tputs(str, affcnt) => str
15 | *
16 | * TermInfo#tputs expands padding informaiton using padding characters.
17 | * affcnt is a number of lines affected by the str.
18 | */
19 | static VALUE
20 | rt_tputs(VALUE self, VALUE v_str, VALUE v_affcnt)
21 | {
22 | int ret;
23 | char *str;
24 | int affcnt;
25 | VALUE output;
26 |
27 | setup(self);
28 | str = StringValueCStr(v_str);
29 | affcnt = NUM2INT(v_affcnt);
30 |
31 | putfunc_output = output = rb_str_new2("");
32 | ret = tputs(str, affcnt, putfunc);
33 | putfunc_output = Qnil;
34 |
35 | if (ret == ERR) { rb_raise(eTermInfoError, "tputs failed"); }
36 |
37 | return output;
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000030.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tiocswinsz (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo.tiocswinsz(io, row, col)
15 | *
16 | * TermInfo.tiocgwinsz update the screen size information of the terminal refered by io,
17 | * using TIOCSWINSZ ioctl.
18 | *
19 | * It returns nil.
20 | */
21 | static VALUE
22 | rt_tiocswinsz(VALUE self, VALUE io, VALUE row, VALUE col)
23 | {
24 | #ifdef TIOCSWINSZ
25 | rb_io_t *fptr;
26 | struct winsize sz;
27 | int ret;
28 |
29 | GetOpenFile(io, fptr);
30 |
31 | sz.ws_row = NUM2INT(row);
32 | sz.ws_col = NUM2INT(col);
33 |
34 | ret = ioctl(FILENO(fptr), TIOCSWINSZ, &sz);
35 | if (ret == -1) rb_raise(rb_eIOError, "TIOCSWINSZ failed");
36 |
37 | return Qnil;
38 | #else
39 | rb_notimplement();
40 | #endif
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000012.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | new (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def initialize (term =ENV ['TERM' ], io =STDERR )
15 | setupterm (term , io .fileno )
16 | @term = term
17 | @io = io
18 | end
19 |
20 |
--------------------------------------------------------------------------------
/ChangeLog:
--------------------------------------------------------------------------------
1 | 2009-03-06 Tanaka Akira
2 |
3 | * version 0.2 released.
4 |
5 | 2008-12-30 Tanaka Akira
6 |
7 | * terminfo.c (rt_wcswidth): check the return value of wcwidth.
8 |
9 | 2008-12-30 Tanaka Akira
10 |
11 | * terminfo.c: prefer ruby/io.h over rubyio.h.
12 | include wchar.h.
13 | (FILENO): condition refined.
14 | (rt_wcswidth): new method TermInfo.wcswidth.
15 |
16 | * extconf.rb: check ruby/io.h and ruby/encoding.h.
17 |
18 | 2007-05-30 Tanaka Akira
19 |
20 | * terminfo.c (TermInfo.ctermid): defined.
21 |
22 | * lib/terminfo.rb, sample/resize: use TermInfo.ctermid instead of
23 | "/dev/tty".
24 |
25 | 2007-05-29 Tanaka Akira
26 |
27 | * sample/resize: new sample program.
28 |
29 | 2007-04-29 Tanaka Akira
30 |
31 | * lib/terminfo.rb (TermInfo.default_object): Use File::NOCTTY for
32 | opening /dev/tty to avoid acquire a controlling terminal.
33 |
34 | 2007-04-19 Tanaka Akira
35 |
36 | * extconf.rb, terminfo.c: try ncurses.h when ncurses is used.
37 | NetBSD has curses.h which is incompatible with ncurses.
38 |
39 | * terminfo.c: define del_curterm empty on FreeBSD and OpenBSD to
40 | avoid warning and core dump.
41 |
42 | 2007-04-10 Tanaka Akira
43 |
44 | * version 0.1 released.
45 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000026.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tigetstr (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo#tigetstr(capname) => str
15 | *
16 | * TermInfo#tigetstr returns a string capability specified by capname.
17 | *
18 | * The return value should be printed after tputs is applied.
19 | * Also tparm should be applied if it has parameters.
20 | *
21 | * io.print ti.tputs(ti.tparm(ti.tigetstr("cuf"), 2))
22 | *
23 | * Note that "cuf" means "cursor forward".
24 | */
25 | static VALUE
26 | rt_tigetstr(VALUE self, VALUE v_capname)
27 | {
28 | char *ret;
29 | setup(self);
30 | ret = tigetstr(StringValueCStr(v_capname));
31 | if (ret == (char*)-1) {
32 | rb_raise(eTermInfoError, "not a string capability");
33 | }
34 | if (ret == 0) {
35 | rb_raise(eTermInfoError, "canceled or absent string capability");
36 | }
37 | return rb_str_new2(ret);
38 | }
39 |
40 |
--------------------------------------------------------------------------------
/ruby-terminfo.gemspec:
--------------------------------------------------------------------------------
1 | # -*- encoding: utf-8 -*-
2 | # stub: ruby-terminfo 0.1.1 ruby lib
3 | # stub: extconf.rb
4 |
5 | Gem::Specification.new do |s|
6 | s.name = "ruby-terminfo".freeze
7 | s.version = "0.1.1"
8 |
9 | s.required_rubygems_version = Gem::Requirement.new(">= 0".freeze) if s.respond_to? :required_rubygems_version=
10 | s.require_paths = ["lib".freeze]
11 | s.authors = ["Tanaka Akira".freeze]
12 | s.date = "2022-12-24"
13 | s.description = "terminfo binding for Ruby".freeze
14 | s.email = "akr@fsij.org".freeze
15 | s.extensions = ["extconf.rb".freeze]
16 | s.extra_rdoc_files = ["README".freeze, "ChangeLog".freeze]
17 | s.files = ["ChangeLog".freeze, "README".freeze, "Rakefile".freeze, "extconf.rb".freeze, "lib/terminfo.rb".freeze, "terminfo.c".freeze, "test/test_winsize.rb".freeze]
18 | s.homepage = "http://ruby-terminfo.rubyforge.org".freeze
19 | s.rdoc_options = ["--title".freeze, "ruby-terminfo documentation".freeze, "--charset".freeze, "utf-8".freeze, "--opname".freeze, "index.html".freeze, "--line-numbers".freeze, "--main".freeze, "README".freeze, "--inline-source".freeze, "--exclude".freeze, "^(examples|extras)/".freeze]
20 | s.rubygems_version = "3.3.7".freeze
21 | s.summary = "terminfo binding for Ruby".freeze
22 |
23 | if s.respond_to? :specification_version then
24 | s.specification_version = 4
25 | end
26 |
27 | if s.respond_to? :add_runtime_dependency then
28 | s.add_development_dependency(%q.freeze, ["~> 13.0"])
29 | else
30 | s.add_dependency(%q.freeze, ["~> 13.0"])
31 | end
32 | end
33 |
--------------------------------------------------------------------------------
/sample/resize:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | # xterm's "resize" command clone.
4 | #
5 | # It assumes VT100 compatible terminal.
6 |
7 | require 'terminfo'
8 | require 'termios'
9 |
10 | def stty(io)
11 | termios = Termios.getattr(io)
12 | old = Marshal.load(Marshal.dump(termios))
13 | begin
14 | yield termios
15 | ensure
16 | Termios.setattr(io, Termios::TCSADRAIN, old)
17 | end
18 | end
19 |
20 | def noecho_raw(io)
21 | stty(io) {|termios|
22 | termios.iflag &= ~(Termios::ISTRIP|Termios::PARMRK|Termios::INLCR|Termios::ICRNL|Termios::IGNCR|Termios::IXON|Termios::IXOFF)
23 | termios.oflag &= ~(Termios::OPOST|Termios::ONLCR|Termios::OCRNL|Termios::ONOCR|Termios::ONLRET)
24 | termios.lflag &= ~(Termios::ISIG|Termios::ICANON|Termios::ECHO|Termios::IEXTEN)
25 | termios.cc[Termios::VMIN] = 1
26 | termios.cc[Termios::VTIME] = 0
27 | Termios.setattr(io, Termios::TCSADRAIN, termios)
28 | yield
29 | }
30 | end
31 |
32 | tty = File.open(TermInfo.ctermid, "r+")
33 | tty.sync = true
34 |
35 | str = nil
36 | noecho_raw(tty) {
37 | tty.print(
38 | "\e7" + # DECSC -- Save Cursor (DEC Private)
39 | "\e[999;999H" + # CUP -- Cursor Position
40 | "\e[6n") # DSR -- Device Status Report
41 | str = tty.readpartial(16)
42 | tty.print "\e8" # DECRC -- Restore Cursor (DEC Private)
43 | }
44 |
45 | exit false if /\e\[(\d+);(\d+)R/ !~ str
46 |
47 | rows = $1.to_i
48 | cols = $2.to_i
49 |
50 | TermInfo.tiocswinsz(tty, rows, cols)
51 |
52 | print <<"End"
53 | COLUMNS=#{cols};
54 | LINES=#{rows};
55 | export COLUMNS LINES;
56 | End
57 |
58 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000001.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | default_object (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def TermInfo .default_object
15 | unless defined? @default_terminfo
16 | io = open ("/dev/tty" , "r+" )
17 | io .sync = true
18 | @default_terminfo = TermInfo .new (ENV ['TERM' ], io )
19 | end
20 | @default_terminfo
21 | end
22 |
23 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000027.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | tparm (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo#tparm(str, ...) => str
15 | *
16 | * TermInfo#tparm expands parameters in str returned by tigetstr.
17 | */
18 | static VALUE
19 | rt_tparm(int argc, VALUE *argv, VALUE self)
20 | {
21 | char *capname, *ret;
22 | setup(self);
23 | VALUE v_capname, v1, v2, v3, v4, v5, v6, v7, v8, v9;
24 | long p1, p2, p3, p4, p5, p6, p7, p8, p9;
25 | setup(self);
26 |
27 | if (rb_scan_args(argc, argv, "19", &v_capname, &v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9) == 0) {
28 | rb_raise(rb_eArgError, "capname required");
29 | }
30 |
31 | capname = StringValueCStr(v_capname);
32 | #define conv(p, v) do { if (v == Qnil) p = 0; else p = NUM2LONG(v); } while(0)
33 | conv(p1, v1);
34 | conv(p2, v2);
35 | conv(p3, v3);
36 | conv(p4, v4);
37 | conv(p5, v5);
38 | conv(p6, v6);
39 | conv(p7, v7);
40 | conv(p8, v8);
41 | conv(p9, v9);
42 |
43 | ret = tparm(capname, p1, p2, p3, p4, p5, p6, p7, p8, p9);
44 |
45 | if (ret == NULL) { rb_raise(eTermInfoError, "tparm failed"); }
46 |
47 | return rb_str_new2(ret);
48 | }
49 |
50 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000023.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | setupterm (TermInfo)
9 |
10 |
11 |
12 |
13 | /*
14 | * TermInfo#setupterm(term, fd) => int
15 | *
16 | * TermInfo#setupterm initializes TermInfo object.
17 | *
18 | * term is a string of nil.
19 | * If nil is given, the environment variable $TERM is used.
20 | *
21 | * fd is a file descriptor for target terminal.
22 | */
23 | static VALUE
24 | rt_setupterm(VALUE self, VALUE v_term, VALUE v_fd)
25 | {
26 | char *term;
27 | int fd;
28 | int err;
29 | int ret;
30 | if (check_rt(self) != NULL) { rb_raise(eTermInfoError, "terminfo object already initialized"); }
31 |
32 | if (v_term == Qnil)
33 | term = NULL;
34 | else
35 | term = StringValueCStr(v_term);
36 | fd = NUM2INT(v_fd);
37 |
38 | ret = setupterm(term, fd, &err);
39 | if (ret == ERR) {
40 | if (err == 1) rb_raise(eTermInfoError, "hardcopy terminal");
41 | else if (err == 0) rb_raise(eTermInfoError, "terminal could not be found");
42 | else if (err == -1) rb_raise(eTermInfoError, "terminfo database could not be found");
43 | else rb_raise(eTermInfoError, "unexpected setupterm error");
44 | }
45 |
46 | DATA_PTR(self) = cur_term;
47 |
48 | return INT2NUM(err);
49 | }
50 |
51 |
--------------------------------------------------------------------------------
/sample/fill:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env ruby
2 |
3 | require 'terminfo'
4 | require 'termios'
5 |
6 | def stty(io)
7 | termios = Termios.getattr(io)
8 | old = Marshal.load(Marshal.dump(termios))
9 | begin
10 | yield termios
11 | ensure
12 | Termios.setattr(io, Termios::TCSADRAIN, old)
13 | end
14 | end
15 |
16 |
17 | def noecho_raw(io)
18 | stty(io) {|termios|
19 | termios.iflag &= ~(Termios::ISTRIP|Termios::PARMRK|Termios::INLCR|Termios::ICRNL|Termios::IGNCR|Termios::IXON|Termios::IXOFF)
20 | termios.oflag &= ~(Termios::OPOST|Termios::ONLCR|Termios::OCRNL|Termios::ONOCR|Termios::ONLRET)
21 | termios.lflag &= ~(Termios::ISIG|Termios::ICANON|Termios::ECHO|Termios::IEXTEN)
22 | termios.cc[Termios::VMIN] = 1
23 | termios.cc[Termios::VTIME] = 0
24 | Termios.setattr(io, Termios::TCSADRAIN, termios)
25 | yield
26 | }
27 | end
28 |
29 | tty = STDERR
30 | ti = TermInfo.new
31 |
32 | chars = %w[! " # $ % & ' = - ^ ~ @ * . , ?]
33 | ch = chars[rand(chars.length)]
34 |
35 | def left_to_right(ch)
36 | lines, cols = TermInfo.screen_size
37 | 0.upto(cols-1) {|x|
38 | 0.upto(lines-1) {|y|
39 | TermInfo.control("cup", y, x)
40 | TermInfo.write ch
41 | }
42 | }
43 | end
44 |
45 | def topleft_to_bottomright(ch)
46 | lines, cols = TermInfo.screen_size
47 | 0.upto(lines+cols-1) {|i|
48 | 0.upto(lines-1) {|y|
49 | x = i-y
50 | next if x < 0 || cols <= x
51 | TermInfo.control("cup", y, x)
52 | TermInfo.write ch
53 | }
54 | }
55 | end
56 |
57 | def spiral(ch)
58 | lines, cols = TermInfo.screen_size
59 | cx = cols/2.0
60 | cy = lines/2.0
61 | r = 0.0
62 | t = 0.0
63 | rmax = Math.sqrt(lines**2 + cols**2)/2+1
64 | oldx = oldy = nil
65 | loop {
66 | r += 0.001
67 | t += 0.01
68 | break if rmax < r
69 | x = cx + Math.sin(t) * r
70 | y = cy + Math.cos(t) * r
71 | x = x.round.to_i
72 | y = y.round.to_i
73 | next if oldx == x && oldy == y
74 | next if x < 0 || cols <= x
75 | next if y < 0 || lines <= y
76 | TermInfo.control("cup", y, x)
77 | TermInfo.write ch
78 | oldx = x
79 | oldy = y
80 | }
81 | end
82 |
83 | methods = [
84 | :left_to_right,
85 | :topleft_to_bottomright,
86 | :spiral,
87 | ]
88 |
89 | noecho_raw(tty) {
90 | lines, cols = TermInfo.screen_size
91 | meth = methods[rand(methods.length)]
92 | send(meth, ch)
93 | TermInfo.control("cup", 999, 0)
94 | }
95 |
--------------------------------------------------------------------------------
/rdoc/files/terminfo_c.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | File: terminfo.c
9 |
10 |
11 |
12 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000014.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | control_string (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def control_string (* args )
15 | afflines = 1
16 | raise ArgumentError , "capname requried" if args .empty?
17 | afflines = args .shift .to_i if args .first .respond_to? (:to_int )
18 | raise ArgumentError , "capname not given" if ! args .first .respond_to? (:to_str )
19 | capname = args .shift .to_str
20 | self .tputs (self .tparm (self .tigetstr (capname ), * args ), afflines )
21 | end
22 |
23 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000017.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | flush (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def flush
15 | oldlevel = nil
16 | if block_given?
17 | oldlevel = Thread .current [:TermInfo_Flush_level ]
18 | oldsync = @io .sync
19 | begin
20 | Thread .current [:TermInfo_Flush_level ] = (oldlevel || 0 ) + 1
21 | @io .sync = false
22 | yield
23 | ensure
24 | Thread .current [:TermInfo_Flush_level ] = oldlevel
25 | @io .sync = oldsync
26 | end
27 | end
28 | @io .flush if oldlevel == nil
29 | nil
30 | end
31 |
32 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.src/M000018.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | screen_size (TermInfo)
9 |
10 |
11 |
12 |
13 |
14 | def screen_size
15 | begin
16 | size = TermInfo .tiocgwinsz (@io )
17 | rescue NotImplementedError
18 | size = [0 ,0 ]
19 | end
20 | if size [0 ] == 0
21 | size [0 ] = ENV .include? ('LINES' ) ? ENV ['LINES' ].to_i : self .tigetnum ("lines" )
22 | end
23 | if size [1 ] == 0
24 | size [1 ] = ENV .include? ('COLUMNS' ) ? ENV ['COLUMNS' ].to_i : self .tigetnum ("cols" )
25 | end
26 | size
27 | end
28 |
29 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo/TermInfoError.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | Class: TermInfo::TermInfoError
9 |
10 |
11 |
12 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
109 |
110 |
111 |
--------------------------------------------------------------------------------
/rdoc/fr_method_index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
6 |
7 |
12 |
13 |
14 | Methods
15 |
16 |
17 |
18 |
19 |
20 |
55 |
56 |
--------------------------------------------------------------------------------
/extconf.rb:
--------------------------------------------------------------------------------
1 | # extconf.rb - a part of a Ruby binding for terminfo library.
2 | #
3 | # Copyright (C) 2007 Tanaka Akira. All rights reserved.
4 | #
5 | # Redistribution and use in source and binary forms, with or without
6 | # modification, are permitted provided that the following conditions
7 | # are met:
8 | #
9 | # 1. Redistributions of source code must retain the above copyright
10 | # notice, this list of conditions and the following disclaimer.
11 | # 2. Redistributions in binary form must reproduce the above
12 | # copyright notice, this list of conditions and the following
13 | # disclaimer in the documentation and/or other materials provided
14 | # with the distribution.
15 | # 3. The name of the author may not be used to endorse or promote
16 | # products derived from this software without specific prior
17 | # written permission.
18 | #
19 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | require 'mkmf'
32 |
33 | # Debian GNU/Linux 4.0 (etch) curses.h, term.h, -lncurses (ncurses.h is linked to curses.h)
34 | # FreeBSD 6.2 curses.h, term.h, -lncurses (ncurses.h is linked to curses.h)
35 | # OpenBSD 4.0 curses.h, term.h, -lncurses (curses.h includes ncurses.h by default)
36 | # HP-UX 11i v3 term.h, -lcurses
37 | # SunOS 5.10 curses.h, term.h, -lcurses
38 |
39 | # NetBSD 3.1 with ncurses ncurses.h, -lncurses (curses.h is incompatible for ncurses)
40 |
41 | have_header("curses.h")
42 | have_header("term.h")
43 |
44 | have_func("ctermid", "stdio.h")
45 |
46 | has_setupterm = true
47 | if have_library("ncurses", "setupterm")
48 | have_header("ncurses.h")
49 | elsif have_library("curses", "setupterm")
50 | else
51 | has_setupterm = false
52 | end
53 |
54 | have_header("wchar.h")
55 |
56 | rubyio_h = nil
57 | rubyio_h = "ruby/io.h" if have_header("ruby/io.h")
58 | rubyio_h = "rubyio.h" unless rubyio_h
59 |
60 | if have_type("rb_io_t", ["ruby.h", rubyio_h])
61 | have_struct_member("rb_io_t", "fd", ["ruby.h", rubyio_h])
62 | else
63 | have_struct_member("OpenFile", "fd", ["ruby.h", rubyio_h])
64 | end
65 |
66 | have_header("ruby/encoding.h")
67 |
68 | if has_setupterm
69 | create_header
70 | create_makefile('terminfo')
71 |
72 | open("Makefile", "a") {|mfile|
73 | mfile.puts <<'End'
74 | rdoc:
75 | rdoc --op rdoc terminfo.c lib/terminfo.rb
76 | End
77 | }
78 | else
79 | puts "terminfo library not found"
80 | end
81 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ruby-terminfo - terminfo bindings for Ruby
2 |
3 | ruby-terminfo provides terminfo bindings for Ruby
4 |
5 | [](https://badge.fury.io/rb/ruby-terminfo)
6 |
7 | ## Author
8 |
9 | Tanaka Akira
10 |
11 | ## Home Page
12 |
13 | http://www.a-k-r.org/ruby-terminfo/
14 |
15 | ## Features
16 |
17 | * Easy to use methods
18 | * `control` (combination of `tigetstr`/`tparm`/`tputs`)
19 | * Low-level terminfo bindings
20 | * `setupterm`
21 | * `tigetflag`
22 | * `tigetnum`
23 | * `tigetstr`
24 | * `tparm`
25 | * `tputs`
26 | * TIOCGWINSZ/TIOCSWINSZ ioctl for screen size
27 | * `ctermid` to avoid hardcoding /dev/tty
28 | * `wcswidth` to measure a string width in number of columns
29 |
30 | ## Usage
31 |
32 | ### Easy to use methods
33 | ```ruby
34 | require 'terminfo'
35 |
36 | TermInfo.control("cuf", 7) # cursor forward 7 columns
37 | p TermInfo.screen_size # use TIOCGWINSZ, LINES/COLUMNS env. or terminfo lines#/cols#
38 | ```
39 |
40 | ### Low level methods
41 | ```ruby
42 | require 'terminfo'
43 |
44 | t = TermInfo.new(ENV["TERM"], File.open(TermInfo.ctermid, "r+"))
45 | print t.tputs(t.tparm(t.tigetstr("cuf"), 7), 1) # cursor forward 7 columns
46 | p TermInfo.tiocgwinsz(STDOUT) # use TIOCGWINSZ
47 | ```
48 |
49 | ## Requirements
50 |
51 | * Ruby : http://www.ruby-lang.org/
52 |
53 | ## Download
54 |
55 | * Latest release: http://www.a-k-r.org/ruby-terminfo/ruby-terminfo-0.2.tar.gz
56 |
57 | * Development version: http://github.com/akr/ruby-terminfo
58 |
59 | ## Install
60 |
61 | ```shell
62 | ruby extconf.rb
63 | make
64 | make install
65 | ```
66 |
67 | ## Reference Manual
68 |
69 | See rdoc/TermInfo.html or
70 | http://www.a-k-r.org/ruby-terminfo/rdoc/TermInfo.html
71 |
72 | ## License
73 |
74 |
75 | Redistribution and use in source and binary forms, with or without
76 | modification, are permitted provided that the following conditions are met:
77 |
78 | (1) Redistributions of source code must retain the above copyright notice, this
79 | list of conditions and the following disclaimer.
80 | (2) Redistributions in binary form must reproduce the above copyright notice,
81 | this list of conditions and the following disclaimer in the documentation
82 | and/or other materials provided with the distribution.
83 | (3) The name of the author may not be used to endorse or promote products
84 | derived from this software without specific prior written permission.
85 |
86 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
87 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
88 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
89 | EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
90 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
91 | OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
92 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
93 | CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
94 | IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
95 | OF SUCH DAMAGE.
96 |
97 | (The modified BSD licence)
98 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'rubygems'
2 | require 'rake'
3 | require 'rake/clean'
4 | require 'rake/testtask'
5 | require 'rake/packagetask'
6 | require 'rubygems/package_task'
7 | require 'rdoc/task'
8 | #require 'rake/contrib/rubyforgepublisher'
9 | #require 'rake/contrib/sshpublisher'
10 | require 'fileutils'
11 | include FileUtils
12 |
13 | NAME = "ruby-terminfo"
14 | AUTHOR = "Tanaka Akira"
15 | EMAIL = "akr@fsij.org"
16 | DESCRIPTION = "terminfo binding for Ruby"
17 | RUBYFORGE_PROJECT = "ruby-terminfo"
18 | HOMEPATH = "http://#{RUBYFORGE_PROJECT}.rubyforge.org"
19 | BIN_FILES = %w( )
20 |
21 | VERS = "0.1.1"
22 | REV = File.read(".svn/entries")[/committed-rev="(d+)"/, 1] rescue nil
23 | CLEAN.include ['**/.*.sw?', '*.gem', '.config']
24 | RDOC_OPTS = [
25 | '--title', "#{NAME} documentation",
26 | "--charset", "utf-8",
27 | "--opname", "index.html",
28 | "--line-numbers",
29 | "--main", "README",
30 | "--inline-source",
31 | ]
32 |
33 | task :default => [:test]
34 | task :package => [:clean]
35 |
36 | Rake::TestTask.new("test") do |t|
37 | t.libs << "test"
38 | t.pattern = "test/**/*_test.rb"
39 | t.verbose = true
40 | end
41 |
42 | spec = Gem::Specification.new do |s|
43 | s.name = NAME
44 | s.version = VERS
45 | s.platform = Gem::Platform::RUBY
46 | #s.has_rdoc = true
47 | s.extra_rdoc_files = ["README", "ChangeLog"]
48 | s.rdoc_options += RDOC_OPTS + ['--exclude', '^(examples|extras)/']
49 | s.summary = DESCRIPTION
50 | s.description = DESCRIPTION
51 | s.author = AUTHOR
52 | s.email = EMAIL
53 | s.homepage = HOMEPATH
54 | s.executables = BIN_FILES
55 | s.rubyforge_project = RUBYFORGE_PROJECT
56 | s.bindir = "bin"
57 | s.require_path = "lib"
58 | #s.autorequire = ""
59 | s.test_files = Dir["test/*_test.rb"]
60 |
61 | #s.add_dependency('activesupport', '>=1.3.1')
62 | #s.required_ruby_version = '>= 1.8.2'
63 | s.add_development_dependency('rake', '~> 13.0')
64 |
65 | s.files = %w(README ChangeLog Rakefile) +
66 | Dir.glob("{bin,doc,test,lib,templates,generator,extras,website,script}/**/*") +
67 | Dir.glob("*.{c,rb}") +
68 | Dir.glob("examples/**/*.rb") +
69 | Dir.glob("tools/*.rb") +
70 | Dir.glob("rails/*.rb")
71 |
72 | s.extensions = ["extconf.rb"]
73 | end
74 |
75 | Rake::PackageTask.new(spec.name, VERS) do |pkg|
76 | pkg.need_tar = true
77 | end
78 |
79 |
80 | task :install do
81 | name = "#{NAME}-#{VERS}.gem"
82 | sh %{rake package}
83 | sh %{sudo gem install pkg/#{name}}
84 | end
85 |
86 | task :uninstall => [:clean] do
87 | sh %{sudo gem uninstall #{NAME}}
88 | end
89 |
90 |
91 | Rake::RDocTask.new do |rdoc|
92 | rdoc.rdoc_dir = 'html'
93 | rdoc.options += RDOC_OPTS
94 | rdoc.template = "resh"
95 | #rdoc.template = "#{ENV['template']}.rb" if ENV['template']
96 | if ENV['DOC_FILES']
97 | rdoc.rdoc_files.include(ENV['DOC_FILES'].split(/,\s*/))
98 | else
99 | rdoc.rdoc_files.include('README', 'ChangeLog')
100 | rdoc.rdoc_files.include('lib/**/*.rb')
101 | rdoc.rdoc_files.include('**/*.c')
102 | end
103 | end
104 |
105 | desc "Publish to RubyForge"
106 | task :rubyforge => [:rdoc, :package] do
107 | require 'rubyforge'
108 | Rake::RubyForgePublisher.new(RUBYFORGE_PROJECT, 'takiuchi').upload
109 | end
110 |
111 | desc 'Package and upload the release to rubyforge.'
112 | task :release => [:clean, :package] do |t|
113 | v = ENV["VERSION"] or abort "Must supply VERSION=x.y.z"
114 | abort "Versions don't match #{v} vs #{VERS}" unless v == VERS
115 | pkg = "pkg/#{NAME}-#{VERS}"
116 |
117 | require 'rubyforge'
118 | rf = RubyForge.new.configure
119 | puts "Logging in"
120 | rf.login
121 |
122 | c = rf.userconfig
123 | # c["release_notes"] = description if description
124 | # c["release_changes"] = changes if changes
125 | c["preformatted"] = true
126 |
127 | files = [
128 | "#{pkg}.tgz",
129 | "#{pkg}.gem"
130 | ].compact
131 |
132 | puts "Releasing #{NAME} v. #{VERS}"
133 | rf.add_release RUBYFORGE_PROJECT, NAME, VERS, *files
134 | end
135 |
136 | desc 'Show information about the gem.'
137 | task :debug_gem do
138 | puts spec.to_ruby
139 | end
140 |
141 | desc 'Update gem spec'
142 | task :gemspec do
143 | open("#{NAME}.gemspec", 'w').write spec.to_ruby
144 | end
145 |
--------------------------------------------------------------------------------
/rdoc/files/extconf_rb.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | File: extconf.rb
9 |
10 |
11 |
12 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | extconf.rb - a part of a Ruby binding for terminfo library.
74 |
75 |
76 | Copyright (C) 2007 Tanaka Akira. All rights reserved.
77 |
78 |
79 | Redistribution and use in source and binary forms, with or without
80 | modification, are permitted provided that the following conditions are met:
81 |
82 |
83 | 1. Redistributions of source code must retain the above copyright
84 | notice, this list of conditions and the following disclaimer.
85 | 2. Redistributions in binary form must reproduce the above
86 | copyright notice, this list of conditions and the following
87 | disclaimer in the documentation and/or other materials provided
88 | with the distribution.
89 | 3. The name of the author may not be used to endorse or promote
90 | products derived from this software without specific prior
91 | written permission.
92 |
93 |
94 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS’’ AND ANY
95 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
96 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
97 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
98 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
99 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
100 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
101 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
102 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
103 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
104 | DAMAGE.
105 |
106 |
107 |
108 |
109 |
110 |
Required files
111 |
112 |
113 | mkmf
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/rdoc/files/lib/terminfo_rb.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | File: terminfo.rb
9 |
10 |
11 |
12 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 | terminfo.rb - a part of a Ruby binding for terminfo library.
74 |
75 |
76 | Copyright (C) 2007 Tanaka Akira. All rights reserved.
77 |
78 |
79 | Redistribution and use in source and binary forms, with or without
80 | modification, are permitted provided that the following conditions are met:
81 |
82 |
83 | 1. Redistributions of source code must retain the above copyright
84 | notice, this list of conditions and the following disclaimer.
85 | 2. Redistributions in binary form must reproduce the above
86 | copyright notice, this list of conditions and the following
87 | disclaimer in the documentation and/or other materials provided
88 | with the distribution.
89 | 3. The name of the author may not be used to endorse or promote
90 | products derived from this software without specific prior
91 | written permission.
92 |
93 |
94 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS’’ AND ANY
95 | EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
96 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
97 | DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
98 | INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
99 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
100 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
101 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
102 | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
103 | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
104 | DAMAGE.
105 |
106 |
107 |
108 |
109 |
110 |
Required files
111 |
112 |
113 | terminfo.so
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
143 |
144 |
145 |
--------------------------------------------------------------------------------
/lib/terminfo.rb:
--------------------------------------------------------------------------------
1 | # terminfo.rb - a part of a Ruby binding for terminfo library.
2 | #
3 | # Copyright (C) 2007 Tanaka Akira. All rights reserved.
4 | #
5 | # Redistribution and use in source and binary forms, with or without
6 | # modification, are permitted provided that the following conditions
7 | # are met:
8 | #
9 | # 1. Redistributions of source code must retain the above copyright
10 | # notice, this list of conditions and the following disclaimer.
11 | # 2. Redistributions in binary form must reproduce the above
12 | # copyright notice, this list of conditions and the following
13 | # disclaimer in the documentation and/or other materials provided
14 | # with the distribution.
15 | # 3. The name of the author may not be used to endorse or promote
16 | # products derived from this software without specific prior
17 | # written permission.
18 | #
19 | # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 | # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 | # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 | # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 | # WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 |
31 | require 'terminfo.so'
32 |
33 | class TermInfo
34 | def TermInfo.default_object
35 | unless defined? @default_terminfo
36 | io = File.open(TermInfo.ctermid, File::RDWR|File::NOCTTY)
37 | io.sync = true
38 | @default_terminfo = TermInfo.new(ENV['TERM'], io)
39 | end
40 | @default_terminfo
41 | end
42 |
43 | def TermInfo.control_string(*args) default_object.control_string(*args) end
44 | def TermInfo.control(*args) default_object.control(*args) end
45 | def TermInfo.write(str) default_object.write(str) end
46 | def TermInfo.flush(&block) default_object.flush(&block) end
47 | def TermInfo.screen_size() default_object.screen_size() end
48 | def TermInfo.screen_lines() default_object.screen_lines() end
49 | def TermInfo.screen_height() default_object.screen_height() end
50 | def TermInfo.screen_columns() default_object.screen_columns() end
51 | def TermInfo.screen_width() default_object.screen_width() end
52 | def TermInfo.io() default_object.io() end
53 |
54 | def initialize(term=ENV['TERM'], io=STDERR)
55 | setupterm(term, io.fileno)
56 | @term = term
57 | @io = io
58 | end
59 | attr_reader :io
60 |
61 | def inspect
62 | "\#<#{self.class}:#{@term}>"
63 | end
64 |
65 | # TermInfo#control_string return a string to control terminal.
66 | #
67 | # TermInfo#control_string([afflines,] capname, p1, p2, ...)
68 | #
69 | # capname is a terminfo string capability such as "cuu", "el".
70 | #
71 | # p1, p2, ... are parameters for the capability.
72 | #
73 | # afflines is a number of lines affected. (used for determining padding length)
74 | def control_string(*args)
75 | afflines = 1
76 | raise ArgumentError, "capname requried" if args.empty?
77 | afflines = args.shift.to_i if args.first.respond_to?(:to_int)
78 | raise ArgumentError, "capname not given" if !args.first.respond_to?(:to_str)
79 | capname = args.shift.to_str
80 | self.tputs(self.tparm(self.tigetstr(capname), *args), afflines)
81 | end
82 |
83 | # TermInfo#control controls a terminal.
84 | #
85 | # It prints the result of control_string to io specified at initialization.
86 | def control(*args)
87 | @io.write(self.control_string(*args))
88 | nil
89 | end
90 |
91 | def write(str)
92 | @io.write(str)
93 | end
94 |
95 | def flush
96 | oldlevel = nil
97 | if block_given?
98 | oldlevel = Thread.current[:TermInfo_Flush_level]
99 | oldsync = @io.sync
100 | begin
101 | Thread.current[:TermInfo_Flush_level] = (oldlevel || 0) + 1
102 | @io.sync = false
103 | yield
104 | ensure
105 | Thread.current[:TermInfo_Flush_level] = oldlevel
106 | @io.sync = oldsync
107 | end
108 | end
109 | @io.flush if oldlevel == nil
110 | nil
111 | end
112 |
113 | # returns terminal screen size in a two element array: [lines, columns].
114 | def screen_size
115 | begin
116 | size = TermInfo.tiocgwinsz(@io)
117 | rescue NotImplementedError
118 | size = [0,0]
119 | end
120 | if size[0] == 0
121 | size[0] = ENV.include?('LINES') ? ENV['LINES'].to_i : self.tigetnum("lines")
122 | end
123 | if size[1] == 0
124 | size[1] = ENV.include?('COLUMNS') ? ENV['COLUMNS'].to_i : self.tigetnum("cols")
125 | end
126 | size
127 | end
128 |
129 | # returns terminal screen height.
130 | def screen_lines
131 | self.screen_size[0]
132 | end
133 | alias screen_height screen_lines
134 |
135 | # returns terminal screen width.
136 | def screen_columns
137 | self.screen_size[1]
138 | end
139 | alias screen_width screen_columns
140 | end
141 |
--------------------------------------------------------------------------------
/rdoc/rdoc-style.css:
--------------------------------------------------------------------------------
1 |
2 | body {
3 | font-family: Verdana,Arial,Helvetica,sans-serif;
4 | font-size: 90%;
5 | margin: 0;
6 | margin-left: 40px;
7 | padding: 0;
8 | background: white;
9 | }
10 |
11 | h1,h2,h3,h4 { margin: 0; color: #efefef; background: transparent; }
12 | h1 { font-size: 150%; }
13 | h2,h3,h4 { margin-top: 1em; }
14 |
15 | a { background: #eef; color: #039; text-decoration: none; }
16 | a:hover { background: #039; color: #eef; }
17 |
18 | /* Override the base stylesheet's Anchor inside a table cell */
19 | td > a {
20 | background: transparent;
21 | color: #039;
22 | text-decoration: none;
23 | }
24 |
25 | /* and inside a section title */
26 | .section-title > a {
27 | background: transparent;
28 | color: #eee;
29 | text-decoration: none;
30 | }
31 |
32 | /* === Structural elements =================================== */
33 |
34 | div#index {
35 | margin: 0;
36 | margin-left: -40px;
37 | padding: 0;
38 | font-size: 90%;
39 | }
40 |
41 |
42 | div#index a {
43 | margin-left: 0.7em;
44 | }
45 |
46 | div#index .section-bar {
47 | margin-left: 0px;
48 | padding-left: 0.7em;
49 | background: #ccc;
50 | font-size: small;
51 | }
52 |
53 |
54 | div#classHeader, div#fileHeader {
55 | width: auto;
56 | color: white;
57 | padding: 0.5em 1.5em 0.5em 1.5em;
58 | margin: 0;
59 | margin-left: -40px;
60 | border-bottom: 3px solid #006;
61 | }
62 |
63 | div#classHeader a, div#fileHeader a {
64 | background: inherit;
65 | color: white;
66 | }
67 |
68 | div#classHeader td, div#fileHeader td {
69 | background: inherit;
70 | color: white;
71 | }
72 |
73 |
74 | div#fileHeader {
75 | background: #057;
76 | }
77 |
78 | div#classHeader {
79 | background: #048;
80 | }
81 |
82 |
83 | .class-name-in-header {
84 | font-size: 180%;
85 | font-weight: bold;
86 | }
87 |
88 |
89 | div#bodyContent {
90 | padding: 0 1.5em 0 1.5em;
91 | }
92 |
93 | div#description {
94 | padding: 0.5em 1.5em;
95 | background: #efefef;
96 | border: 1px dotted #999;
97 | }
98 |
99 | div#description h1,h2,h3,h4,h5,h6 {
100 | color: #125;;
101 | background: transparent;
102 | }
103 |
104 | div#validator-badges {
105 | text-align: center;
106 | }
107 | div#validator-badges img { border: 0; }
108 |
109 | div#copyright {
110 | color: #333;
111 | background: #efefef;
112 | font: 0.75em sans-serif;
113 | margin-top: 5em;
114 | margin-bottom: 0;
115 | padding: 0.5em 2em;
116 | }
117 |
118 |
119 | /* === Classes =================================== */
120 |
121 | table.header-table {
122 | color: white;
123 | font-size: small;
124 | }
125 |
126 | .type-note {
127 | font-size: small;
128 | color: #DEDEDE;
129 | }
130 |
131 | .xxsection-bar {
132 | background: #eee;
133 | color: #333;
134 | padding: 3px;
135 | }
136 |
137 | .section-bar {
138 | color: #333;
139 | border-bottom: 1px solid #999;
140 | margin-left: -20px;
141 | }
142 |
143 |
144 | .section-title {
145 | background: #79a;
146 | color: #eee;
147 | padding: 3px;
148 | margin-top: 2em;
149 | margin-left: -30px;
150 | border: 1px solid #999;
151 | }
152 |
153 | .top-aligned-row { vertical-align: top }
154 | .bottom-aligned-row { vertical-align: bottom }
155 |
156 | /* --- Context section classes ----------------------- */
157 |
158 | .context-row { }
159 | .context-item-name { font-family: monospace; font-weight: bold; color: black; }
160 | .context-item-value { font-size: small; color: #448; }
161 | .context-item-desc { color: #333; padding-left: 2em; }
162 |
163 | /* --- Method classes -------------------------- */
164 | .method-detail {
165 | background: #efefef;
166 | padding: 0;
167 | margin-top: 0.5em;
168 | margin-bottom: 1em;
169 | border: 1px dotted #ccc;
170 | }
171 | .method-heading {
172 | color: black;
173 | background: #ccc;
174 | border-bottom: 1px solid #666;
175 | padding: 0.2em 0.5em 0 0.5em;
176 | }
177 | .method-signature { color: black; background: inherit; }
178 | .method-name { font-weight: bold; }
179 | .method-args { font-style: italic; }
180 | .method-description { padding: 0 0.5em 0 0.5em; }
181 |
182 | /* --- Source code sections -------------------- */
183 |
184 | a.source-toggle { font-size: 90%; }
185 | div.method-source-code {
186 | background: #262626;
187 | color: #ffdead;
188 | margin: 1em;
189 | padding: 0.5em;
190 | border: 1px dashed #999;
191 | overflow: hidden;
192 | }
193 |
194 | div.method-source-code pre { color: #ffdead; overflow: hidden; }
195 |
196 | /* --- Ruby keyword styles --------------------- */
197 |
198 | .standalone-code { background: #221111; color: #ffdead; overflow: hidden; }
199 |
200 | .ruby-constant { color: #7fffd4; background: transparent; }
201 | .ruby-keyword { color: #00ffff; background: transparent; }
202 | .ruby-ivar { color: #eedd82; background: transparent; }
203 | .ruby-operator { color: #00ffee; background: transparent; }
204 | .ruby-identifier { color: #ffdead; background: transparent; }
205 | .ruby-node { color: #ffa07a; background: transparent; }
206 | .ruby-comment { color: #b22222; font-weight: bold; background: transparent; }
207 | .ruby-regexp { color: #ffa07a; background: transparent; }
208 | .ruby-value { color: #7fffd4; background: transparent; }
--------------------------------------------------------------------------------
/terminfo.c:
--------------------------------------------------------------------------------
1 | /* terminfo.c - Ruby binding for terminfo library.
2 |
3 | Copyright (C) 2007, 2008 Tanaka Akira. All rights reserved.
4 |
5 | Redistribution and use in source and binary forms, with or without
6 | modification, are permitted provided that the following conditions
7 | are met:
8 |
9 | 1. Redistributions of source code must retain the above copyright
10 | notice, this list of conditions and the following disclaimer.
11 | 2. Redistributions in binary form must reproduce the above
12 | copyright notice, this list of conditions and the following
13 | disclaimer in the documentation and/or other materials provided
14 | with the distribution.
15 | 3. The name of the author may not be used to endorse or promote
16 | products derived from this software without specific prior
17 | written permission.
18 |
19 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 | ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
23 | DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
25 | GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 | INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
27 | WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
28 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
29 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 | */
31 |
32 | #include "ruby.h"
33 | #ifdef HAVE_RUBY_IO_H
34 | # include "ruby/io.h"
35 | #else
36 | # include "rubyio.h"
37 | #endif
38 | #include "extconf.h"
39 |
40 | #if defined(HAVE_NCURSES_H)
41 | #include
42 | #elif defined(HAVE_CURSES_H)
43 | #include
44 | #endif
45 |
46 | #ifdef HAVE_TERM_H
47 | #include
48 | #endif
49 |
50 | #include
51 | #include
52 | #include
53 |
54 | #ifdef HAVE_WCHAR_H
55 | #include
56 | #endif
57 |
58 | static VALUE cTermInfo;
59 | static VALUE eTermInfoError;
60 |
61 | #ifndef HAVE_TYPE_RB_IO_T
62 | typedef OpenFile rb_io_t;
63 | #endif
64 |
65 | #if defined(HAVE_RB_IO_T_FD) || defined(HAVE_ST_FD)
66 | # define FILENO(fptr) (fptr->fd)
67 | #else
68 | # define FILENO(fptr) fileno(fptr->f)
69 | #endif
70 |
71 | #if (defined(__FreeBSD__) && __FreeBSD_cc_version <= 602001) || \
72 | defined(__OpenBSD__)
73 | /*
74 | * warning on FreeBSD
75 | http://www.FreeBSD.org/cgi/query-pr.cgi?pr=108117&cat=
76 | * core dump on OpenBSD
77 | http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&textonly=yes&numbers=5447
78 | */
79 | #define del_curterm(oterm) do {} while(0)
80 | #endif
81 |
82 | static void
83 | rt_free(void *ptr)
84 | {
85 | if(ptr != NULL)
86 | del_curterm(ptr);
87 | }
88 |
89 | static VALUE
90 | rt_alloc(VALUE klass)
91 | {
92 | return Data_Wrap_Struct(klass, NULL, rt_free, 0);
93 | }
94 |
95 | static TERMINAL *
96 | check_rt(VALUE self)
97 | {
98 | Check_Type(self, T_DATA);
99 | if (RDATA(self)->dfree != rt_free) {
100 | rb_raise(rb_eTypeError, "wrong argument type %s (expected TermInfo)",
101 | rb_class2name(CLASS_OF(self)));
102 | }
103 | return DATA_PTR(self);
104 | }
105 |
106 | static void
107 | setup(VALUE self)
108 | {
109 | TERMINAL *term = check_rt(self);
110 | if (term == NULL) { rb_raise(eTermInfoError, "terminfo object not initialized"); }
111 | if (cur_term == term)
112 | return;
113 | }
114 |
115 | /*
116 | * TermInfo#setupterm(term, fd) => int
117 | *
118 | * TermInfo#setupterm initializes TermInfo object.
119 | *
120 | * term is a string of nil.
121 | * If nil is given, the environment variable $TERM is used.
122 | *
123 | * fd is a file descriptor for target terminal.
124 | */
125 | static VALUE
126 | rt_setupterm(VALUE self, VALUE v_term, VALUE v_fd)
127 | {
128 | char *term;
129 | int fd;
130 | int err;
131 | int ret;
132 | if (check_rt(self) != NULL) { rb_raise(eTermInfoError, "terminfo object already initialized"); }
133 |
134 | if (v_term == Qnil)
135 | term = NULL;
136 | else
137 | term = StringValueCStr(v_term);
138 | fd = NUM2INT(v_fd);
139 |
140 | ret = setupterm(term, fd, &err);
141 | if (ret == ERR) {
142 | if (err == 1) rb_raise(eTermInfoError, "hardcopy terminal");
143 | else if (err == 0) rb_raise(eTermInfoError, "terminal could not be found");
144 | else if (err == -1) rb_raise(eTermInfoError, "terminfo database could not be found");
145 | else rb_raise(eTermInfoError, "unexpected setupterm error");
146 | }
147 |
148 | DATA_PTR(self) = cur_term;
149 |
150 | return INT2NUM(err);
151 | }
152 |
153 | /*
154 | * TermInfo#tigetflag(capname) => int
155 | *
156 | * TermInfo#tigetflag returns a boolean capability specified by capname.
157 | */
158 | static VALUE
159 | rt_tigetflag(VALUE self, VALUE v_capname)
160 | {
161 | int ret;
162 | setup(self);
163 | ret = tigetflag(StringValueCStr(v_capname));
164 | if (ret == -1) { rb_raise(eTermInfoError, "not a boolean capability"); }
165 | return RTEST(ret) ? Qtrue : Qfalse;
166 | }
167 |
168 | /*
169 | * TermInfo#tigetnum(capname) => int
170 | *
171 | * TermInfo#tigetnum returns a numeric capability specified by capname.
172 | */
173 | static VALUE
174 | rt_tigetnum(VALUE self, VALUE v_capname)
175 | {
176 | int ret;
177 | setup(self);
178 | ret = tigetnum(StringValueCStr(v_capname));
179 | if (ret == -2) { rb_raise(eTermInfoError, "not a numeric capability"); }
180 | if (ret == -1) { rb_raise(eTermInfoError, "canceled or absent numeric capability"); }
181 | return INT2NUM(ret);
182 | }
183 |
184 | /*
185 | * TermInfo#tigetstr(capname) => str
186 | *
187 | * TermInfo#tigetstr returns a string capability specified by capname.
188 | *
189 | * The return value should be printed after tputs is applied.
190 | * Also tparm should be applied if it has parameters.
191 | *
192 | * io.print ti.tputs(ti.tparm(ti.tigetstr("cuf"), 2))
193 | *
194 | * Note that "cuf" means "cursor forward".
195 | */
196 | static VALUE
197 | rt_tigetstr(VALUE self, VALUE v_capname)
198 | {
199 | char *ret;
200 | setup(self);
201 | ret = tigetstr(StringValueCStr(v_capname));
202 | if (ret == (char*)-1) {
203 | rb_raise(eTermInfoError, "not a string capability");
204 | }
205 | if (ret == 0) {
206 | rb_raise(eTermInfoError, "canceled or absent string capability");
207 | }
208 | return rb_str_new2(ret);
209 | }
210 |
211 | /*
212 | * TermInfo#tparm(str, ...) => str
213 | *
214 | * TermInfo#tparm expands parameters in str returned by tigetstr.
215 | */
216 | static VALUE
217 | rt_tparm(int argc, VALUE *argv, VALUE self)
218 | {
219 | char *capname, *ret;
220 | setup(self);
221 | VALUE v_capname, v1, v2, v3, v4, v5, v6, v7, v8, v9;
222 | long p1, p2, p3, p4, p5, p6, p7, p8, p9;
223 | setup(self);
224 |
225 | if (rb_scan_args(argc, argv, "19", &v_capname, &v1, &v2, &v3, &v4, &v5, &v6, &v7, &v8, &v9) == 0) {
226 | rb_raise(rb_eArgError, "capname required");
227 | }
228 |
229 | capname = StringValueCStr(v_capname);
230 | #define conv(p, v) do { if (v == Qnil) p = 0; else p = NUM2LONG(v); } while(0)
231 | conv(p1, v1);
232 | conv(p2, v2);
233 | conv(p3, v3);
234 | conv(p4, v4);
235 | conv(p5, v5);
236 | conv(p6, v6);
237 | conv(p7, v7);
238 | conv(p8, v8);
239 | conv(p9, v9);
240 |
241 | ret = tparm(capname, p1, p2, p3, p4, p5, p6, p7, p8, p9);
242 |
243 | if (ret == NULL) { rb_raise(eTermInfoError, "tparm failed"); }
244 |
245 | return rb_str_new2(ret);
246 | }
247 |
248 | static VALUE putfunc_output; /* xxx: not thread safe */
249 |
250 | static int
251 | putfunc(int arg)
252 | {
253 | char ch = arg;
254 | rb_str_cat(putfunc_output, &ch, 1);
255 | return arg;
256 | }
257 |
258 | /*
259 | * TermInfo#tputs(str, affcnt) => str
260 | *
261 | * TermInfo#tputs expands padding informaiton using padding characters.
262 | * affcnt is a number of lines affected by the str.
263 | */
264 | static VALUE
265 | rt_tputs(VALUE self, VALUE v_str, VALUE v_affcnt)
266 | {
267 | int ret;
268 | char *str;
269 | int affcnt;
270 | VALUE output;
271 |
272 | setup(self);
273 | str = StringValueCStr(v_str);
274 | affcnt = NUM2INT(v_affcnt);
275 |
276 | putfunc_output = output = rb_str_new2("");
277 | ret = tputs(str, affcnt, putfunc);
278 | putfunc_output = Qnil;
279 |
280 | if (ret == ERR) { rb_raise(eTermInfoError, "tputs failed"); }
281 |
282 | return output;
283 | }
284 |
285 | /*
286 | * TermInfo.tiocgwinsz(io) => [row, col]
287 | *
288 | * TermInfo.tiocgwinsz returns the screen size of the terminal refered by io,
289 | * using TIOCGWINSZ ioctl.
290 | */
291 | static VALUE
292 | rt_tiocgwinsz(VALUE self, VALUE io)
293 | {
294 | #ifdef TIOCGWINSZ
295 | struct winsize sz;
296 | int ret;
297 |
298 | ret = ioctl(rb_io_descriptor(io), TIOCGWINSZ, &sz);
299 | if (ret == -1) rb_raise(rb_eIOError, "TIOCGWINSZ failed");
300 |
301 | return rb_ary_new3(2, INT2NUM(sz.ws_row), INT2NUM(sz.ws_col));
302 | #else
303 | rb_notimplement();
304 | #endif
305 | }
306 |
307 | /*
308 | * TermInfo.tiocswinsz(io, row, col)
309 | *
310 | * TermInfo.tiocgwinsz update the screen size information of the terminal refered by io,
311 | * using TIOCSWINSZ ioctl.
312 | *
313 | * It returns nil.
314 | */
315 | static VALUE
316 | rt_tiocswinsz(VALUE self, VALUE io, VALUE row, VALUE col)
317 | {
318 | #ifdef TIOCSWINSZ
319 | struct winsize sz;
320 | int ret;
321 |
322 | sz.ws_row = NUM2INT(row);
323 | sz.ws_col = NUM2INT(col);
324 |
325 | ret = ioctl(rb_io_descriptor(io), TIOCSWINSZ, &sz);
326 | if (ret == -1) rb_raise(rb_eIOError, "TIOCSWINSZ failed");
327 |
328 | return Qnil;
329 | #else
330 | rb_notimplement();
331 | #endif
332 | }
333 |
334 | /*
335 | * TermInfo.ctermid
336 | *
337 | * TermInfo.ctermid returns a pathname for the current controling terminal,
338 | * such as "/dev/tty".
339 | */
340 | static VALUE
341 | rt_ctermid(VALUE self)
342 | {
343 | #ifdef HAVE_CTERMID
344 | char buf[L_ctermid];
345 | return rb_str_new2(ctermid(buf));
346 | #else
347 | return rb_str_new2("/dev/tty");
348 | #endif
349 | }
350 |
351 | /*
352 | * TermInfo.wcswidth(str)
353 | *
354 | * TermInfo.wcswidth returns a the number of columns of str,
355 | * according to current locale.
356 | */
357 | static VALUE
358 | rt_wcswidth(VALUE self, VALUE str)
359 | {
360 | char *s;
361 | size_t l, r;
362 | mbstate_t mbs;
363 | wchar_t wc;
364 | long cols;
365 | int width;
366 |
367 | #ifdef HAVE_RUBY_ENCODING_H
368 | /* The encoding of str is assumed to be the locale encoding on Ruby 1.8. */
369 | str = rb_str_encode(str, rb_enc_from_encoding(rb_locale_encoding()), 0, Qnil);
370 | #endif
371 |
372 | memset(&mbs,0,sizeof(mbstate_t));
373 |
374 | s = StringValueCStr(str);
375 | l = RSTRING_LEN(str);
376 |
377 | cols = 0;
378 | while (0 < l) {
379 | r = mbrtowc(&wc, s, l, &mbs);
380 | if (r == 0)
381 | rb_raise(rb_eArgError, "NUL found");
382 |
383 | width = wcwidth(wc);
384 | if (width == -1)
385 | rb_raise(rb_eArgError, "non-printable charactor found");
386 | cols += width;
387 |
388 | l -= r;
389 | s += r;
390 | }
391 |
392 | return LONG2NUM(cols);
393 | }
394 |
395 | void
396 | Init_terminfo(void)
397 | {
398 | putfunc_output = Qnil;
399 | rb_global_variable(&putfunc_output);
400 |
401 | cTermInfo = rb_define_class("TermInfo", rb_cObject);
402 | eTermInfoError = rb_define_class_under(cTermInfo, "TermInfoError", rb_eRuntimeError);
403 |
404 | rb_define_alloc_func(cTermInfo, rt_alloc);
405 |
406 | rb_define_method(cTermInfo, "setupterm", rt_setupterm, 2);
407 | rb_define_method(cTermInfo, "tigetflag", rt_tigetflag, 1);
408 | rb_define_method(cTermInfo, "tigetnum", rt_tigetnum, 1);
409 | rb_define_method(cTermInfo, "tigetstr", rt_tigetstr, 1);
410 | rb_define_method(cTermInfo, "tparm", rt_tparm, -1);
411 | rb_define_method(cTermInfo, "tputs", rt_tputs, 2);
412 |
413 | rb_define_module_function(cTermInfo, "tiocgwinsz", rt_tiocgwinsz, 1);
414 | rb_define_module_function(cTermInfo, "tiocswinsz", rt_tiocswinsz, 3);
415 |
416 | rb_define_module_function(cTermInfo, "ctermid", rt_ctermid, 0);
417 |
418 | rb_define_module_function(cTermInfo, "wcswidth", rt_wcswidth, 1);
419 | }
420 |
--------------------------------------------------------------------------------
/rdoc/classes/TermInfo.html:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 | Class: TermInfo
9 |
10 |
11 |
12 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
Methods
91 |
92 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
139 |
140 |
141 |
142 |
143 |
144 |
Attributes
145 |
146 |
147 |
148 |
149 | io
150 | [R]
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
Public Class methods
162 |
163 |
164 |
165 |
166 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
242 |
243 |
244 |
245 |
246 |
247 |
248 |
249 |
250 |
256 |
257 |
258 |
259 |
260 |
261 |
262 |
263 |
264 |
270 |
271 |
272 |
273 |
274 |
275 |
276 |
277 |
278 |
284 |
285 |
286 |
287 |
288 |
289 |
290 |
291 |
292 |
298 |
299 |
300 |
301 |
302 |
303 |
304 |
305 |
306 |
312 |
313 |
314 |
315 |
316 |
317 |
318 |
319 |
320 |
326 |
327 |
338 |
339 |
340 |
341 |
342 |
343 |
349 |
350 |
351 |
352 | TermInfo.tiocswinsz (io , row, col)
354 |
355 |
356 | TermInfo.tiocgwinsz update the screen
357 | size information of the terminal refered by io , using TIOCSWINSZ ioctl.
359 |
360 |
361 | It returns nil.
362 |
363 |
364 |
365 |
366 |
367 |
368 |
369 |
375 |
376 |
377 |
378 |
379 |
380 |
Public Instance methods
381 |
382 |
383 |
384 |
385 |
391 |
392 |
401 |
402 |
403 |
404 |
405 |
406 |
412 |
413 |
414 |
415 | TermInfo#control_string return a string
416 | to control terminal.
417 |
418 |
419 | TermInfo#control_string([afflines,] capname, p1, p2, ...)
420 |
421 |
422 | capname is a terminfo string capability such as "cuu",
423 | "el".
424 |
425 |
426 | p1, p2, … are parameters for the capability.
427 |
428 |
429 | afflines is a number of lines affected. (used for determining padding
430 | length)
431 |
432 |
433 |
434 |
435 |
436 |
437 |
438 |
444 |
445 |
446 |
447 |
448 |
449 |
450 |
451 |
452 |
458 |
459 |
460 |
461 |
462 |
463 |
464 |
465 |
466 |
472 |
473 |
474 |
475 | returns terminal screen width.
476 |
477 |
478 |
479 |
480 |
481 |
482 |
483 |
484 | screen_height ()
485 |
486 |
487 |
492 |
493 |
494 |
495 |
496 |
497 |
503 |
504 |
505 |
506 | returns terminal screen height.
507 |
508 |
509 |
510 |
511 |
512 |
513 |
514 |
520 |
521 |
522 |
523 | returns terminal screen size in a two element array: [lines, columns].
524 |
525 |
526 |
527 |
528 |
529 |
530 |
531 |
532 | screen_width ()
533 |
534 |
535 |
540 |
541 |
542 |
543 |
544 |
545 |
551 |
552 |
553 |
554 | TermInfo#setupterm (term, fd) => int
555 |
556 |
557 | TermInfo#setupterm initializes TermInfo object.
559 |
560 |
561 | term is a string of nil. If nil is given, the environment variable $TERM is
562 | used.
563 |
564 |
565 | fd is a file descriptor for target terminal.
566 |
567 |
568 |
569 |
570 |
571 |
572 |
573 |
579 |
580 |
589 |
590 |
591 |
592 |
593 |
594 |
600 |
601 |
610 |
611 |
612 |
613 |
614 |
615 |
621 |
622 |
623 |
624 | TermInfo#tigetstr(capname) => str
625 |
626 |
627 | TermInfo#tigetstr returns a string
628 | capability specified by capname.
629 |
630 |
631 | The return value should be printed after tputs is applied. Also tparm should be applied if it has
634 | parameters.
635 |
636 |
637 | io.print ti.tputs(ti.tparm(ti.tigetstr("cuf"), 2))
638 |
639 |
640 | Note that "cuf" means "cursor forward".
641 |
642 |
643 |
644 |
645 |
646 |
647 |
648 |
654 |
655 |
664 |
665 |
666 |
667 |
668 |
669 |
675 |
676 |
677 |
678 | TermInfo#tputs (str, affcnt) => str
679 |
680 |
681 | TermInfo#tputs expands padding
682 | informaiton using padding characters. affcnt is a number of lines affected
683 | by the str.
684 |
685 |
686 |
687 |
688 |
689 |
690 |
691 |
697 |
698 |
699 |
700 |
701 |
702 |
703 |
704 |
705 |
706 |
707 |
708 |
709 |
712 |
713 |
714 |
--------------------------------------------------------------------------------