"hSetBuffering stdin NoBuffering" messes up terminal

On my terminal (aterm), calling hSetBuffering stdin NoBuffering within my program messes up the terminal settings somehow, so that backspace no longer works when I run my program (without the NoBuffering) a second time. The 'reset' command fixes the problem, so once again backspace works, but my program shouldn't be affecting the terminal state at all. A simple call to hSetBuffering stdin LineBuffering doesn't seem to fix the problem. Any ideas what might be going on here? It's really annoying to not be able to use backspace when entering data. -- David Roundy http://www.abridgegame.org

On Tuesday 14 October 2003 2:11 pm, David Roundy wrote:
On my terminal (aterm), calling
hSetBuffering stdin NoBuffering
within my program messes up the terminal settings somehow, [...]
If I understand recent changes correctly, this is a deliberate decision. The idea is that if you wanted to write a program like 'stty' in Haskell, you'd be very disappointed if the terminal settings got switched back the moment your Haskell program terminated. Given this (reasonable) change, it might be worth providing an additional function: hWithBuffering :: Handle -> BufferMode -> IO a -> IO a which sets the buffering mode back when it finishes. (There's a bunch of alternative designs possible here - this has the virtue of being simple.) -- Alastair Reid www.haskell-consulting.com

Alastair Reid wrote:
On my terminal (aterm), calling
hSetBuffering stdin NoBuffering
within my program messes up the terminal settings somehow, [...]
If I understand recent changes correctly, this is a deliberate decision. The idea is that if you wanted to write a program like 'stty' in Haskell, you'd be very disappointed if the terminal settings got switched back the moment your Haskell program terminated.
It's deliberate, but (AFAIK) not for those reasons. The idea is so that "simple, stupid programs" do what the programmer expects (and saving the list from lots of "my program doesn't get any input until the user hits Return" questions). If you were writing "stty" in Haskell, you would presumably use the PosixTTY functions directly.
Given this (reasonable) change, it might be worth providing an additional function:
hWithBuffering :: Handle -> BufferMode -> IO a -> IO a
which sets the buffering mode back when it finishes.
The main issue here is that this really needs to handle abnormal exits
(i.e. crashes). The user-space buffering (which is all that C's
setvbuf() etc affect) is, er, in user space, so it ceases to be an
issue as soon as the process terminates.
OTOH, the terminal settings are tied to the device, not to any
particular process.
There's also the issue that the settings should be restored
temporarily if the user suspends the program via SIGTSTP (i.e.
Ctrl-Z).
When writing such programs in C, you have to control the tty buffering
yourself (via e.g. tcsetattr()), as well as disabling the user-space
buffering with e.g. setvbuf(). You would typically install signal
handlers to restore the settings upon abnormal exits (and atexit() for
normal exits), and also restore them on SIGTSTP and re-restore them on
SIGCONT.
Yes, it's awkward, and results in certain frequently-asked questions
from people who are use to using getch() etc from
(There's a bunch of alternative designs possible here - this has the virtue of being simple.)
Removing the TTY handling from hSetBuffering is even simpler. For
"simple, stupid programs", we could just provide e.g. hSetCooked, so
programs which want the current behaviour can use:
hSetBuffering stdin NoBuffering
hSetCooked stdin False
Programs which don't want this behaviour would just omit the
hSetCooked call, which is substantially easier than the current
situation (figure out if stdin is a tty, save the terminal settings,
disable buffering, restore the settings).
--
Glynn Clements

On Tue, Oct 14, 2003 at 03:47:29PM +0100, Glynn Clements wrote:
Removing the TTY handling from hSetBuffering is even simpler. For "simple, stupid programs", we could just provide e.g. hSetCooked, so programs which want the current behaviour can use:
hSetBuffering stdin NoBuffering hSetCooked stdin False
Programs which don't want this behaviour would just omit the hSetCooked call, which is substantially easier than the current situation (figure out if stdin is a tty, save the terminal settings, disable buffering, restore the settings).
yes! this would be ideal. John -- --------------------------------------------------------------------------- John Meacham - California Institute of Technology, Alum. - john@foo.net ---------------------------------------------------------------------------

David Roundy wrote:
On my terminal (aterm), calling
hSetBuffering stdin NoBuffering
within my program messes up the terminal settings somehow, so that backspace no longer works when I run my program (without the NoBuffering) a second time. The 'reset' command fixes the problem, so once again backspace works, but my program shouldn't be affecting the terminal state at all. A simple call to hSetBuffering stdin LineBuffering doesn't seem to fix the problem. Any ideas what might be going on here? It's really annoying to not be able to use backspace when entering data.
Disabling buffering with hSetBuffering not only disables the
user-space buffering (analogous to setvbuf() etc in C), it also
disables the terminal's buffering (more precisely, disables canonical
mode).
However, re-enabling buffering (setting the mode to something other
than NoBuffering) should re-enable canonical mode in the terminal. Of
course, this doesn't help if your program terminates before buffering
is re-enabled.
You can use the functions in the PosixTTY module to explicitly
control the terminal state.
BTW, if your program actually needs unbuffered terminal input (i.e.
you want to receive individual key codes without waiting for the user
to hit Return), and hSetBuffering didn't change the terminal settings,
you would have to do it yourself anyhow, leading to the same issues.
--
Glynn Clements

Glynn Clements
David Roundy wrote:
On my terminal (aterm), calling
hSetBuffering stdin NoBuffering
within my program messes up the terminal settings somehow [...]
Disabling buffering with hSetBuffering not only disables the user-space buffering (analogous to setvbuf() etc in C), it also disables the terminal's buffering (more precisely, disables canonical mode).
According to me, hSetBuffering should not touch the terminal settings ever. It is not mentioned in the Report and it is not implied by its name. It only leads to confusion.
BTW, if your program actually needs unbuffered terminal input (i.e. you want to receive individual key codes without waiting for the user to hit Return), and hSetBuffering didn't change the terminal settings, you would have to do it yourself anyhow, leading to the same issues.
In my experience, one seldom wants to do this. There are specialised libraries which do things like this well and easily. Each time I wanted unbuffered input terminal was used for testing only, in which case backspace is useful. For stupid little programs we could provide some stupid little functions which have the word 'Magic' in their name, instead of abusing standard operations. Strictly in my opinion, Feri.

On Tue, Oct 14, 2003 at 09:11:47AM -0400, I wrote:
On my terminal (aterm), calling
hSetBuffering stdin NoBuffering
within my program messes up the terminal settings somehow, so that backspace no longer works when I run my program (without the NoBuffering) a second time. [...] A simple call to hSetBuffering stdin LineBuffering doesn't seem to fix the problem.
That is actually not true. My call of hSetBuffering stdin LineBuffering wasn't actually happening (I put it after a call to exitWith). Just for the archives (and anyone interested) I figured I should clarify that bit of misinformation. It seems that as long as you set stdin's buffering back to LineBuffering before you exit, you are safe from messing up the terminal settings. -- David Roundy http://www.abridgegame.org
participants (5)
-
Alastair Reid
-
David Roundy
-
Ferenc Wagner
-
Glynn Clements
-
John Meacham