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
···
--
Be alert - Some terrorists look normal.