Ruby-termios

Hi,

I wrote a program on Linux using ruby-termios which was supposed to run
on
Solaris 9. Short description: It doesn’t.

Long description: I use ruby-termios to change some terminal settings
for
my simple user interface, a menu in this case. It looks like this:

def fetch
    letter = nil

    print @data['text']
    menuMode {
        letter = $stdin.readchar.chr
        until @data['options'].include?(letter.upcase) do
            letter = $stdin.readchar.chr
        end
    }

    return letter
end

In this part, @data[‘text’] contains a menu text, @data[‘options’] is a
list of valid characters. Here is the termios part of the code:

def menuMode
    term = Termios::getattr($stdin)
    oldterm = term

    term.c_lflag &= ~(Termios::ECHO | Termios::ICANON)

    Termios::setattr($stdin, Termios::TCSANOW, term)

    yield

    Termios::setattr($stdin, Termios::TCSANOW, oldterm)
    Termios::flush($stdin, Termios::TCIOFLUSH)
end

The result on Linux is what I expected: I get the characters one by one
and
can work on them before they are displayed or in any buffer I care for.

Some strange things happen on Solaris: First of all, my debugging shows
that something changes the termios flags where I don’t expect it:

def menuMode
    term = Termios::getattr($stdin)
    oldterm = term
    @logger.debug("c_lflag is #{term.c_lflag}")

    term.c_lflag &= ~(Termios::ECHO | Termios::ICANON)

    Termios::setattr($stdin, Termios::TCSANOW, term)

    yield

    @logger.debug("c_lflag is #{oldterm.c_lflag}")
    Termios::setattr($stdin, Termios::TCSANOW, oldterm)
    Termios::flush($stdin, Termios::TCIOFLUSH)
end

Here is a fragment from the logfile:

D, [2006-06-13T15:45:23.732487 #18771] DEBUG – : c_lflag is 35387
D, [2006-06-13T15:45:29.987362 #18771] DEBUG – : c_lflag is 35377

Why are the two flags different?

Second, some buffering is going on. If I enter a character, the program
blocks at the readchar. If I run this version of fetch()

 1      def fetch
 2          letter = nil

 3          print @data['text']
 4          menuMode {
 5              @logger.debug("Enter yielded block")
 6              letter = $stdin.readchar.chr
 7              @logger.debug("Read in letter '#{letter}'")

 8              until @data['options'].include?(letter.upcase) do
 9                  @logger.debug("Enter loop block")
10                  letter = $stdin.readchar.chr
11                  @logger.debug("Read in letter '#{letter}'")
12              end
13          }

14          return letter
15      end

…the program blocks at lines 6 and 10 until I enter four characters.
Then
all input is passed to the program, so for an invalid character the
result
looks like this:

D, [2006-06-13T15:55:09.230396 #19028] DEBUG – : Enter yielded block
D, [2006-06-13T15:55:13.383131 #19028] DEBUG – : Read in letter ‘t’
D, [2006-06-13T15:55:13.383816 #19028] DEBUG – : Enter loop block
D, [2006-06-13T15:55:13.384062 #19028] DEBUG – : Read in letter ‘t’
D, [2006-06-13T15:55:13.384284 #19028] DEBUG – : Enter loop block
D, [2006-06-13T15:55:13.384498 #19028] DEBUG – : Read in letter ‘t’
D, [2006-06-13T15:55:13.384710 #19028] DEBUG – : Enter loop block
D, [2006-06-13T15:55:13.384918 #19028] DEBUG – : Read in letter ‘t’
D, [2006-06-13T15:55:13.385132 #19028] DEBUG – : Enter loop block

For valid character this means that the first chracter picks a menu
option
and the next three characters are entered in whatever is behind that
menu
option. Nearly unusable and pretty dangerous.

At the moment I don’t know where to look next. It may be some simple
omission, but I can’t find it, so any ideas are appreciated. Please let
me
know if you need any other information, the debugging is a bit awkward,
but
I didn’t dare to call the debugger with broken terminal.

Thanks in advance!

Thorsten Radiohead: Subterranean Homesick
Alien

In Message-Id: [email protected]
Thorsten H. [email protected] writes:

    oldterm = term
    @logger.debug("c_lflag is #{term.c_lflag}")

(snip)

    term.c_lflag &= ~(Termios::ECHO | Termios::ICANON)
    @logger.debug("c_lflag is #{oldterm.c_lflag}")

(snip)

Why are the two flags different?

Since YOU clear ECHO and ICANON. Note both oldterm and term are
pointing a same Termios structure.

Second, some buffering is going on. If I enter a character, the program
blocks at the readchar. If I run this version of fetch()
(snip)
…the program blocks at lines 6 and 10 until I enter four characters. Then
all input is passed to the program, so for an invalid character the result
looks like this:

Are you sure VMIN and VTIME are properly set? From termios(4) on
NetBSD:

Noncanonical Mode Input Processing
In noncanonical mode input processing, input bytes are not
assembled into
lines, and erase and kill processing does not occur. The values of
the
VMIN and VTIME members of the c_cc array are used to determine how
to
process the bytes received.

 VMIN represents the minimum number of bytes that should be received 

when
the read(2) system call successfully returns. VTIME is a timer of
0.1
second granularity that is used to time out bursty and short term
data
transmissions. (snip)

Well, that’s my wild guess…

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs